我正在使用mp4parser Library从剪辑的视频中剪切多个剪辑。它正常工作如果我从视频中剪切了一部分。但是当我尝试从视频中剪切多个剪辑时,只有第一个剪辑被正确剪切。其他只有0或1秒。 以下是我的代码:
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];
}
}
答案 0 :(得分:3)
问题仅出现在模拟器中。当我们在模拟器中录制视频时,它会记录实际时间的秒数。代码在实际设备上工作正常。
答案 1 :(得分:0)
BTW,持续时间以秒为单位,您需要除以时间刻度。我发现相同持续时间的音频和视频轨道之间的条目(或样本)计数不同。但我是一个完全的菜鸟,不要听我的。
protected static double getDuration(Track track) {
double duration = 0;
for (TimeToSampleBox.Entry entry : track.getDecodingTimeEntries()) {
duration += entry.getCount() * entry.getDelta() / (double) track.getTrackMetaData().getTimescale();
}
return duration;
}