im having an issue while video mixing with audio. everytime when I try to make it.
That always give me an error which is
Java.lang.RuntimeException: A cast to int has gone wrong. Please contact the mp4parser discussion group.
Im using googlecode mp4 parser : implementation com.googlecode.mp4parser:isoparser:1.1.22 and also tried that but no success implementation 'org.mp4parser:isoparser:1.9.41'
Also on forum there's no proper answer on that question.
here's my code
public Track CropAudio(String videopath, Track fullAudio) {
try {
IsoFile isoFile = new IsoFile(videopath);
double lengthInSeconds = (double)
isoFile.getMovieBox().getMovieHeaderBox().getDuration() /
isoFile.getMovieBox().getMovieHeaderBox().getTimescale();
Track audioTrack = (Track) fullAudio;
double startTime1 = 0;
double endTime1 = lengthInSeconds;
long currentSample = 0;
double currentTime = 0;
double lastTime = -1;
long startSample1 = -1;
long endSample1 = -1;
for (int i = 0; i < audioTrack.getSampleDurations().length; i++) {
long delta = audioTrack.getSampleDurations()[i];
if (currentTime > lastTime && currentTime <= startTime1) {
// current sample is still before the new starttime
startSample1 = currentSample;
}
if (currentTime > lastTime && currentTime <= endTime1) {
// current sample is after the new start time and still before the new endtime
endSample1 = currentSample;
}
lastTime = currentTime;
currentTime += (double) delta / (double) audioTrack.getTrackMetaData().getTimescale();
currentSample++;
}
CroppedTrack cropperAacTrack = new CroppedTrack(fullAudio, startSample1, endSample1);
return cropperAacTrack;
} catch (IOException e) {
e.printStackTrace();
}
return fullAudio;
}
public Runnable runnable = new Runnable() {
#Override
public void run() {
try {
Movie m = MovieCreator.build(video);
List nuTracks = new ArrayList<>();
for (Track t : m.getTracks()) {
if (!"soun".equals(t.getHandler())) {
nuTracks.add(t);
}
}
Track nuAudio = new AACTrackImpl(new FileDataSourceImpl(audio));
Track crop_track = CropAudio(video, nuAudio);
nuTracks.add(crop_track);
m.setTracks(nuTracks);
Container mp4file = new DefaultMp4Builder().build(m);
FileChannel fc = new FileOutputStream(new File(output)).getChannel();
mp4file.writeContainer(fc);
fc.close();
try {
Variables.closeProgressDialog();
} catch (Exception e) {
Log.d(Variables.tag, e.toString());
} finally {
Go_To_preview_Activity();
}
} catch (Exception e) {
Variables.closeProgressDialog();
// Toast.makeText(context, "Something went wrong"+ e.toString(), Toast.LENGTH_SHORT).show();
//Go_To_preview_Activity();
e.printStackTrace();
Log.d(Variables.tag, e.toString());
}
}
};
Related
ArrayList<String> list1 = splitFileList;
for (int i = 0; i < list1.size(); i++) {
tempFileName = splitFileList.get(i);
String splitFileCheckinDirectory = splitVideofilepath + Constant.SPLIT_VIDEO + "/" + list1.get(i) + Constant.FILE_EXTENSION;
File myfile = new File(splitFileCheckinDirectory);
if (!myfile.exists()) {
new TrimmVideo(getExternalFilesDir(null) + "/" + getFileNameFromFilePath(mFilePath), mStartTImelist.get(i), mEndTimelist.get(i) - mStartTImelist.get(i)).execute();
}
}
below is my Asynktask which i am trying execute inside for loop
private class TrimmVideo extends AsyncTask<Void, Void, Void> {
private final String mediaPath;
private final double endTime;
private final int length;
private double startTime;
private ProgressDialog progressDialog;
private TrimmVideo(String mediaPath, int startTime, int length) {
this.mediaPath = mediaPath;
this.startTime = startTime;
this.length = length;
this.endTime = this.startTime + this.length;
}
#Override
protected void onPreExecute() {
progressDialog = ProgressDialog.show(VideoPlayActvity.this,
"Trimming videos", "Please wait...", true);
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... params) {
trimVideo();
return null;
}
#Override
protected void onPostExecute(Void result) {
progressDialog.dismiss();
dbHandler.updateFlag(fileModel == null ? tempFileName : fileModel.getfilename());
btn_save_video.setVisibility(View.INVISIBLE);
super.onPostExecute(result);
}
private void trimVideo() {
try {
File file = new File(mediaPath);
FileInputStream fis = new FileInputStream(file);
FileChannel in = fis.getChannel();
Movie movie = MovieCreator.build(in);
List<Track> tracks = movie.getTracks();
movie.setTracks(new LinkedList<Track>());
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.");
} else {
startTime = correctTimeToNextSyncSample(track, startTime);
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;
} else 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));
}
IsoFile out = new DefaultMp4Builder().build(movie);
File storagePath = new File(getExternalFilesDir(null) + "/" + Constant.SPLIT_VIDEO + "/");
storagePath.mkdirs();
File myMovie = new File(storagePath, fileModel == null ? "/" + tempFileName + Constant.FILE_EXTENSION : fileModel.getfilename() + Constant.FILE_EXTENSION);
FileOutputStream fos = new FileOutputStream(myMovie);
FileChannel fc = fos.getChannel();
out.getBox(fc);
dbHandler.updateFlag(fileModel == null ? tempFileName : fileModel.getfilename());
fc.close();
fos.close();
fis.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private double correctTimeToNextSyncSample(Track track, double cutHere) {
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++;
}
}
for (double timeOfSyncSample : timeOfSyncSamples) {
if (timeOfSyncSample > cutHere) {
return timeOfSyncSample;
}
}
return timeOfSyncSamples[timeOfSyncSamples.length - 1];
}
}
splitFileList list Contain 2 Size data a,b i want to execute synchronously one by one i.e loop start from 0 then it should complete asynk task for 0 then if loop will go one then it should complete please suggest me how to execute asynk task one by one in for loop .
You can't run synchronously by AsyncTask You must use thread some thing like this:
Thread t = new Thread(
new Runnable() {
public void run() {
try {
ArrayList<String> list1 = splitFileList;
for (int i = 0; i < list1.size(); i++) {
tempFileName = splitFileList.get(i);
String splitFileCheckinDirectory = splitVideofilepath + Constant.SPLIT_VIDEO + "/" + list1.get(i) + Constant.FILE_EXTENSION;
File myfile = new File(splitFileCheckinDirectory);
if (!myfile.exists()) {
trimVideo(getExternalFilesDir(null) + "/" + getFileNameFromFilePath(mFilePath), mStartTImelist.get(i), mEndTimelist.get(i) - mStartTImelist.get(i)); //here you can run synchronously work
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
t.start();
try {
t.join();
.....
} catch (Exception e) {
e.printStackTrace();
}
private void trimVideo(String mediaPath, int startTime, int length) {
try {
File file = new File(mediaPath);
FileInputStream fis = new FileInputStream(file);
FileChannel in = fis.getChannel();
Movie movie = MovieCreator.build(in);
List<Track> tracks = movie.getTracks();
movie.setTracks(new LinkedList<Track>());
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.");
} else {
startTime = correctTimeToNextSyncSample(track, startTime);
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;
} else 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));
}
IsoFile out = new DefaultMp4Builder().build(movie);
File storagePath = new File(getExternalFilesDir(null) + "/" + Constant.SPLIT_VIDEO + "/");
storagePath.mkdirs();
File myMovie = new File(storagePath, fileModel == null ? "/" + tempFileName + Constant.FILE_EXTENSION : fileModel.getfilename() + Constant.FILE_EXTENSION);
FileOutputStream fos = new FileOutputStream(myMovie);
FileChannel fc = fos.getChannel();
out.getBox(fc);
dbHandler.updateFlag(fileModel == null ? tempFileName : fileModel.getfilename());
fc.close();
fos.close();
fis.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private double correctTimeToNextSyncSample(Track track, double cutHere) {
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++;
}
}
for (double timeOfSyncSample : timeOfSyncSamples) {
if (timeOfSyncSample > cutHere) {
return timeOfSyncSample;
}
}
return timeOfSyncSamples[timeOfSyncSamples.length - 1];
}
If you can't implement #Hazem answer you can go with another approach.
For this you need to maintain counter for each of your data and forget about for loop.
First you need to call asynctask for first position of your list.Something like this:
if(list1.size() > 0) {
fileCounter=0;
tempFileName = splitFileList.get(fileCounter);
String splitFileCheckinDirectory = splitVideofilepath + Constant.SPLIT_VIDEO + "/" + tempFileName + Constant.FILE_EXTENSION;
File myfile = new File(splitFileCheckinDirectory);
if (!myfile.exists()) {
new TrimmVideo(getExternalFilesDir(null) + "/" + getFileNameFromFilePath(mFilePath), mStartTImelist.get(i), mEndTimelist.get(i) - mStartTImelist.get(i)).execute();
}
}
Then in onPostExecute of your asyncTask
#Override
protected void onPostExecute(Void result) {
progressDialog.dismiss();
dbHandler.updateFlag(fileModel == null ? tempFileName : fileModel.getfilename());
btn_save_video.setVisibility(View.INVISIBLE);
super.onPostExecute(result);
// Update your counter here
fileCounter++;
// Check if your incremented counter doesn't exceed your list size
if(fileCounter < list1.size()) {
// Then call your asynctask again with updated counter data
empFileName = splitFileList.get(fileCounter);
String splitFileCheckinDirectory = splitVideofilepath + Constant.SPLIT_VIDEO + "/" + tempFileName + Constant.FILE_EXTENSION;
File myfile = new File(splitFileCheckinDirectory);
if (!myfile.exists()) {
new TrimmVideo(getExternalFilesDir(null) + "/" + getFileNameFromFilePath(mFilePath), mStartTImelist.get(i), mEndTimelist.get(i) - mStartTImelist.get(i)).execute();
}
}
}
Hope this will help you.
I am using Raspberry pi3 and DHT11 sensor for temperature monitoring project.
I have following pin positions
VCC to pin no : 2
Ground to pin no : 6
Output to GPIO : BCM22 i.e pin no 15
Code that I have used:
public class WeatherStationActivity extends Activity {
private Handler mHandler = new Handler();
private TextView mTxtStatus;
private PeripheralManagerService service = new PeripheralManagerService();
private Gpio tempGpio;
private int i = 0;
int[] dht11_dat = {0, 0, 0, 0, 0};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("Weather station", "Started Weather Station");
setContentView(R.layout.activity_main);
mTxtStatus = (TextView) findViewById(R.id.txtStatus);
try {
tempGpio = service.openGpio("BCM22");
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (i == 10) {
handler.removeCallbacks(this);
} else {
getTemp();
handler.postDelayed(this, 5000);
}
i++;
}
}, 5000);
} catch (Exception e) {
e.printStackTrace();
}
}
private void getTemp() {
boolean laststate = false;
try {
laststate = tempGpio.getValue();
} catch (IOException e) {
e.printStackTrace();
}
int j = 0;
final int MAXTIMINGS = 85;
dht11_dat[0] = dht11_dat[1] = dht11_dat[2] = dht11_dat[3] = dht11_dat[4] = 0;
try {
tempGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
// tempGpio.setActiveType(Gpio.ACTIVE_LOW);
tempGpio.setValue(false);
// Thread.sleep(18);
TimeUnit.MILLISECONDS.sleep(18);
// tempGpio.setActiveType(Gpio.ACTIVE_HIGH);
// tempGpio.setActiveType(Gpio.ACTIVE_HIGH);
tempGpio.setValue(true);
TimeUnit.MICROSECONDS.sleep(40);
tempGpio.setDirection(Gpio.DIRECTION_IN);
/* tempGpio.setActiveType(Gpio.ACTIVE_HIGH);
tempGpio.setValue(true);*/
// tempGpio.setValue(true);
StringBuilder value = new StringBuilder();
for (int i = 0; i < MAXTIMINGS; i++) {
int counter = 0;
while (tempGpio.getValue() == laststate) {
counter++;
TimeUnit.MICROSECONDS.sleep(1);
if (counter == 255) {
break;
}
}
laststate = tempGpio.getValue();
mTxtStatus.append("\nLast State of Sensor " + laststate);
if (counter == 255) {
break;
}
//* ignore first 3 transitions *//*
if ((i >= 4) && (i % 2 == 0)) {
//* shove each bit into the storage bytes *//*
dht11_dat[j / 8] <<= 1;
if (counter > 16) {
dht11_dat[j / 8] |= 1;
}
j++;
}
}
// check we read 40 bits (8bit x 5 ) + verify checksum in the last
// byte
if ((j >= 40) && checkParity()) {
value.append(dht11_dat[2]).append(".").append(dht11_dat[3]);
Log.i("Logger", "temperature value readed: " + value.toString());
mTxtStatus.append("\nTemp " + value.toString());
} else {
mTxtStatus.append("\nNothing is working ");
Log.i("Logger", "Nothing is working ");
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
}
}
private boolean checkParity() {
return dht11_dat[4] == (dht11_dat[0] + dht11_dat[1] + dht11_dat[2] + dht11_dat[3] & 0xFF);
}
}
Above code is giving me "Nothing is working" as output.
Any suggestion where I might be doing wrong?
You can't read data from DHT11 using Raspberry Pi 3 with Android Things because duration of DHT11 response pulses is from 26-28 us to 70 us, but max frequency of RP3 with AT GPIO is around 3kHz, which means around 300 us pulse duration. Take a look at answers to this question.
Given a video url (ex: www.example.com/video.mp4), how can I programatically save a short clip of the video (ex: 5 seconds, 00:00:10 - 00:00:15) in an Android application onto the phone?
At the moment, here is what I have - but this saves the entire video from the url to the device. It appears I'll need to use a MediaExtractor and MediaMuxer.
URL url = new URL(http_url_path);
URLConnection ucon = url.openConnection();
// Define InputStreams to read from the URLConnection.
// uses 5KB download buffer
InputStream is = ucon.getInputStream();
BufferedInputStream in = new BufferedInputStream(is, BUFFER_SIZE);
FileOutputStream out = new FileOutputStream(file);
byte[] buff = new byte[BUFFER_SIZE];
int len = 0;
while ((len = in.read(buff)) != -1) {
out.write(buff, 0, len);
}
rely on isoviewer-1.0-RC-27.
public static double[] startTrim(File src, File dst, int startMs, int endMs) throws IOException {
Movie movie = MovieCreator.build(src.getAbsolutePath());
List<Track> tracks = movie.getTracks();
movie.setTracks(new LinkedList<Track>());
double startTime = startMs/1000;
double endTime = endMs/1000;
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) {
throw new RuntimeException("The startTime has already been corrected by another track with SyncSample. Not Supported.");
}
//false,Short interception;true,Long interception
startTime = correctTimeToSyncSample(track, startTime, true);
endTime = correctTimeToSyncSample(track, endTime, false);
timeCorrected = true;
}
}
int x = 0;
for (Track track : tracks) {
long currentSample = 0;
double currentTime = 0;
long startSample = -1;
long endSample = -1;
x++;
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));
break;
}
Container container = new DefaultMp4Builder().build(movie);
if (!dst.exists()) {
dst.createNewFile();
}
FileOutputStream fos = new FileOutputStream(dst);
FileChannel fc = fos.getChannel();
container.writeContainer(fc);
fc.close();
fos.close();
double[] doubleArray = new double[2] ;
doubleArray[0] = startTime;
doubleArray[1] = endTime;
return doubleArray;
}
:D or easily you can use this website :D just send link you want using intent
http://www.videograbber.net/
I am trying to trim or cut a video for specific time, Example:- Video-1 which is of 30 Sec trim to Video-2 10 sec (0.10 sec to 0.20 sec). I am able to do this and able to play this video but in the end of video it gives error saying- Sorry! cant play this video.
public static void main(String args) throws IOException {
Movie movie = new MovieCreator()
.build(new RandomAccessFileIsoBufferWrapperImpl(
new File(
"/sdcard/Videos11/"+args+".mp4")));
List<Track> tracks = movie.getTracks();
movie.setTracks(new LinkedList<Track>());
// remove all tracks we will create new tracks from the old
double startTime = 3.000;
double endTime = 9.000;
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.");
}
}
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));
}
IsoFile out = new DefaultMp4Builder().build(movie);
String filePath = "sdcard/test"+i+".mp4";
i++;
File f = new File(filePath);
FileOutputStream fos = new FileOutputStream(f);
BufferedOutputStream bos = new BufferedOutputStream(fos, 65535);
out.getBox(new IsoOutputStream(bos));
bos.close();
fos.close();
}
P.S:-I am not much familiar with this code but some how am able to trim video but it shows error in last.
You should "normalize" your start and stop values them to correspond to mp4 sync samples, otherwise you'll get some glitches on an output video or even broken file.
Please have a look at correctTimeToSyncSample method:
Android Gallery source (uses mp4parser 0.9.x, I guess)
My sample project (uses mp4parser 1.1.18).
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 = 0) {
timeOfSyncSamples[Arrays.binarySearch(track.getSyncSamples(), currentSample + 1)] = currentTime;
}
currentTime += (double) delta / (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];
}
Usage:
for (Track track : tracks) {
if (track.getSyncSamples() != null && track.getSyncSamples().length > 0) {
if (timeCorrected) {
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;
}
}
Maybe the position which you want to cut is at the middle of an Iframe. I'm facing a similar problem. I can not cut exactly where I want, because at the begin of video I get bad frames. Did you get bad frames at the begin of trimmed video?
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];
}
}
The Problem was only in emulator. When we record video in emulator it records less seconds that actual time. Code working on actual device fine.
BTW, for duration in seconds, you need to divide by the timescale. I find the entry (or sample ) counts vary between audio and video tracks of same duration. But I'm a total noob, don't listen to me.
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;
}