ericdlee / mp4parser

Automatically exported from code.google.com/p/mp4parser
0 stars 0 forks source link

Issue in Cutting Multiple clips from a Movie #57

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
I am using mp4parser Library for cutting multiple clips from a recored video. 
It is working fine If I cut one part from the video. But when I try to cutt 
multiple clips from video only 1st clip is proper cut. Other are of just 0 or 1 
second. 
Following is the My Code:

import android.app.ProgressDialog;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;

import com.coremedia.iso.IsoFile;
import com.coremedia.iso.boxes.TimeToSampleBox;
import com.googlecode.mp4parser.authoring.Movie;
import com.googlecode.mp4parser.authoring.Track;
import com.googlecode.mp4parser.authoring.builder.DefaultMp4Builder;
import com.googlecode.mp4parser.authoring.container.mp4.MovieCreator;
import com.googlecode.mp4parser.authoring.tracks.CroppedTrack;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import uk.org.humanfocus.hfi.Beans.TrimPoint;
import uk.org.humanfocus.hfi.Utils.Constants;
import uk.org.humanfocus.hfi.Utils.SimpleThreadFactory;
import uk.org.humanfocus.hfi.Utils.Ut;

/**
 * Shortens/Crops a track
 */
public class ShortenExample {

    private static final String TAG = "ShortenExample";
    private final Context mCxt;
    private ExecutorService mThreadExecutor = null;
    private SimpleInvalidationHandler mHandler;
    private ProgressDialog mProgressDialog;
    String filePath;
    ArrayList<TrimPoint> mTrimPoints;
    int videoLength;
    ArrayList<String> trimVideos;
    private class SimpleInvalidationHandler extends Handler {

        @Override
        public void handleMessage(final Message msg) {
            switch (msg.what) {
            case R.id.shorten:
                mProgressDialog.dismiss();

                if (msg.arg1 == 0)
                    Toast.makeText(mCxt,
                            mCxt.getString(R.string.message_error) + " " + (String) msg.obj,
                            Toast.LENGTH_LONG).show();
                else
                    Toast.makeText(mCxt,
                            mCxt.getString(R.string.message_shortened) + " " + (String) msg.obj,
                            Toast.LENGTH_LONG).show();
                break;
            }
        }
    }

    public ShortenExample(Context context) {
        mCxt = context;
        mHandler = new SimpleInvalidationHandler();
        //mProgressDialog = new ProgressDialog(mCxt);
        //mProgressDialog.setMessage("Wait Saving..");
        //mProgressDialog.setCancelable(false);
    }

    public void shorten(String filePath,ArrayList<TrimPoint> trimPoints, int endTime) {
        trimVideos = new ArrayList<String>();
        this.filePath = filePath;
        this.videoLength = endTime;
        this.mTrimPoints = trimPoints;
        Log.d(Constants.TAG,"End Time: "+endTime+" Trim Points: "+mTrimPoints.size());
        for (int i=0;i<trimPoints.size();i++){
            TrimPoint point = trimPoints.get(i);
            int start=0;
            int end = 0;
            if(point.getTime()-5<0){
                start = 0;
            }else{
                start = point.getTime()-5;
            }

            if(point.getTime()+5>videoLength){
                end = videoLength-1;
            }else {
                end = point.getTime() + 5;
            }
            Log.d(Constants.TAG,"Clip: "+start+" : "+end);
            doShorten(start,end);   
        }
        Log.d(Constants.TAG,"Done: "+trimVideos.size());
    }

    private void doShorten(final int _startTime, final int _endTime) {
        //mProgressDialog = Ut.ShowWaitDialog(mCxt, 0);

        //mProgressDialog.show();

        if(mThreadExecutor == null)
            mThreadExecutor = Executors.newSingleThreadExecutor(new SimpleThreadFactory("doShorten"));

        //this.mThreadExecutor.execute(new Runnable() {
        //  public void run() {
                try {
                    File folder = Ut.getTestMp4ParserVideosDir(mCxt);
                    //File folder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),"HFVideos"+File.separator+"TEMP");
                    //Log.d(Constants.TAG, folder.toString());
                    if (!folder.exists()) {
                        Log.d(TAG, "failed to create directory");
                    }

                    //Movie movie = new MovieCreator().build(new RandomAccessFile("/home/sannies/suckerpunch-distantplanet_h1080p/suckerpunch-distantplanet_h1080p.mov", "r").getChannel());
//                  Movie movie = MovieCreator.build(new 
FileInputStream("/home/sannies/CSI.S13E02.HDTV.x264-LOL.mp4").getChannel());
                    Movie movie = MovieCreator.build(new FileInputStream(new File(filePath)).getChannel());
                    //Log.d(Constants.TAG,"Movie: "+movie.toString());
                    List<Track> tracks = movie.getTracks();
                    movie.setTracks(new LinkedList<Track>());
                    // remove all tracks we will create new tracks from the old

                    double startTime = _startTime;
                    double endTime = _endTime;//(double) getDuration(tracks.get(0)) / tracks.get(0).getTrackMetaData().getTimescale();

                    boolean timeCorrected = false;

                    // Here we try to find a track that has sync samples. Since we can only start decoding
                    // at such a sample we SHOULD make sure that the start of the new fragment is exactly
                    // such a frame
                    for (Track track : tracks) {
                        if (track.getSyncSamples() != null && track.getSyncSamples().length > 0) {
                            if (timeCorrected) {
                                // This exception here could be a false positive in case we have multiple tracks
                                // with sync samples at exactly the same positions. E.g. a single movie containing
                                // multiple qualities of the same video (Microsoft Smooth Streaming file)

                                throw new RuntimeException("The startTime has already been corrected by another track with SyncSample. Not Supported.");
                            }
                            startTime = correctTimeToSyncSample(track, startTime, false);
                            endTime = correctTimeToSyncSample(track, endTime, true);
                            timeCorrected = true;
                        }
                    }

                    for (Track track : tracks) {
                        long currentSample = 0;
                        double currentTime = 0;
                        long startSample = -1;
                        long endSample = -1;

                        for (int i = 0; i < track.getDecodingTimeEntries().size(); i++) {
                            TimeToSampleBox.Entry entry = track.getDecodingTimeEntries().get(i);
                            for (int j = 0; j < entry.getCount(); j++) {
                                // entry.getDelta() is the amount of time the current sample covers.

                                if (currentTime <= startTime) {
                                    // current sample is still before the new starttime
                                    startSample = currentSample;
                                }
                                if (currentTime <= endTime) {
                                    // current sample is after the new start time and still before the new endtime
                                    endSample = currentSample;
                                } else {
                                    // current sample is after the end of the cropped video
                                    break;
                                }
                                currentTime += (double) entry.getDelta() / (double) track.getTrackMetaData().getTimescale();
                                currentSample++;
                            }
                        }
                        movie.addTrack(new CroppedTrack(track, startSample, endSample));
                    }
                    long start1 = System.currentTimeMillis();
                    IsoFile out = new DefaultMp4Builder().build(movie);
                    long start2 = System.currentTimeMillis();

//                  FileOutputStream fos = new 
FileOutputStream(String.format("output-%f-%f.mp4", startTime, endTime));
                    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
                    String filename = folder.getPath() + File.separator + String.format("TMP4_APP_OUT-%f-%f", startTime, endTime) + "_" + timeStamp + ".mp4";
                    trimVideos.add(filename);
                    FileOutputStream fos = new FileOutputStream(filename);

                    FileChannel fc = fos.getChannel();
                    out.getBox(fc);
                    fc.close();
                    fos.close();
                    long start3 = System.currentTimeMillis();
                    System.err.println("Building IsoFile took : " + (start2 - start1) + "ms");
                    System.err.println("Writing IsoFile took  : " + (start3 - start2) + "ms");
                    System.err.println("Writing IsoFile speed : " + (new File(String.format("TMP4_APP_OUT-%f-%f", startTime, endTime)).length() / (start3 - start2) / 1000) + "MB/s");

                    Message.obtain(mHandler, R.id.shorten, 1, 0, filename).sendToTarget();
                } catch (FileNotFoundException e) {
                    Message.obtain(mHandler, R.id.shorten, 0, 0, e.getMessage()).sendToTarget();
                    e.printStackTrace();
                } catch (IOException e) {
                    Message.obtain(mHandler, R.id.shorten, 0, 0, e.getMessage()).sendToTarget();
                    e.printStackTrace();
                }

                //mProgressDialog.dismiss();
        //  }
        //});

    }

    protected static long getDuration(Track track) {
        long duration = 0;
        for (TimeToSampleBox.Entry entry : track.getDecodingTimeEntries()) {
            duration += entry.getCount() * entry.getDelta();
        }
        return duration;
    }

    private static double correctTimeToSyncSample(Track track, double cutHere, boolean next) {
        double[] timeOfSyncSamples = new double[track.getSyncSamples().length];
        long currentSample = 0;
        double currentTime = 0;
        for (int i = 0; i < track.getDecodingTimeEntries().size(); i++) {
            TimeToSampleBox.Entry entry = track.getDecodingTimeEntries().get(i);
            for (int j = 0; j < entry.getCount(); j++) {
                if (Arrays.binarySearch(track.getSyncSamples(), currentSample + 1) >= 0) {
                    // samples always start with 1 but we start with zero therefore +1
                    timeOfSyncSamples[Arrays.binarySearch(track.getSyncSamples(), currentSample + 1)] = currentTime;
                }
                currentTime += (double) entry.getDelta() / (double) track.getTrackMetaData().getTimescale();
                currentSample++;
            }
        }
        double previous = 0;
        for (double timeOfSyncSample : timeOfSyncSamples) {
            if (timeOfSyncSample > cutHere) {
                if (next) {
                    return timeOfSyncSample;
                } else {
                    return previous;
                }
            }
            previous = timeOfSyncSample;
        }
        return timeOfSyncSamples[timeOfSyncSamples.length - 1];
    }

}

Original issue reported on code.google.com by djahmednawaz on 27 Mar 2013 at 10:08

GoogleCodeExporter commented 8 years ago
I can't reproduce the problem. Your code runs on Android and it's quite 
complicated for me to reproduce. I enhanced the ShortenExample in the trunk to 
cut two parts of the input file and it seems to work. 
Could you try to reproduce the behavior with my example? 

Original comment by Sebastian.Annies on 20 Apr 2013 at 10:19

GoogleCodeExporter commented 8 years ago
Hmm. Either there is no problem anymore or no interest or a workaround was 
applied. closing. 

Original comment by Sebastian.Annies on 6 Aug 2013 at 3:31

GoogleCodeExporter commented 8 years ago
Problem was in emulator. Emulator was not recording less time video than spend 
time.

Original comment by djahmednawaz on 26 Sep 2013 at 12:41

GoogleCodeExporter commented 8 years ago
Can any one tell me how to use the  code in isoparser-1.0-RC-35 . I cannot able 
to see any method getDecodingTimeEntries() in the updated library.

Original comment by radhakri...@ileafsolutions.net on 6 Feb 2015 at 7:27