Appending videos doesn't work properly - Android - android

I am using Sebastian Annies example for the mp4parser where I append 3 videos. The result should be one video that plays all the three videos simultaneously. However, I get one video that plays the last video three times. Here is my code...
// int i = number of videos....
try {
String[] f = new String[i];
for (int count = 0; count < i; count++) {
f[count] = "/sdcard/vid" + i + ".mp4";
}
Movie[] inMovies = new Movie[i];
for (int count = 0; count < i; count++) {
inMovies[count] = MovieCreator.build(f[count]);
}
List<Track> videoTracks = new LinkedList<Track>();
List<Track> audioTracks = new LinkedList<Track>();
for (Movie m : inMovies) {
for (Track t : m.getTracks()) {
if (t.getHandler().equals("soun")) {
audioTracks.add(t);
}
if (t.getHandler().equals("vide")) {
videoTracks.add(t);
}
}
}
Movie result = new Movie();
if (audioTracks.size() > 0) {
result.addTrack(new AppendTrack(audioTracks.toArray(new Track[audioTracks.size()])));
}
if (videoTracks.size() > 0) {
result.addTrack(new AppendTrack(videoTracks.toArray(new Track[videoTracks.size()])));
}
Container out = new DefaultMp4Builder().build(result);
FileChannel fc = new RandomAccessFile(String.format
("/sdcard/output.mp4"),
"rw").getChannel();
out.writeContainer(fc);
fc.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
VideoView v = (VideoView) findViewById(R.id.videoView1);
// v.setVideoPath("/sdcard/aaa" + i + ".mp4");
v.setVideoPath("/sdcard/output.mp4");
v.setMediaController(new MediaController(this));
v.start();
I dont know why it isn't doing what it's supposed to do. Please help me. Thanks

Your problem is that you're filling the input file-names with the same file:
for (int count = 0; count < i; count++) {
f[count] = "/sdcard/vid" + i + ".mp4";
}
Should be
for (int count = 0; count < i; count++) {
f[count] = "/sdcard/vid" + count + ".mp4";
}
You might be better off, for readability, to make i the loop variable, and have count be the number of files.

Related

Failed to stop the muxer

I'm facing a problem with media muxer. Why does my app crash? and what is the solution?
java.lang.IllegalStateException: Failed to stop the muxer
at android.media.MediaMuxer.nativeStop(Native Method)
at android.media.MediaMuxer.stop(MediaMuxer.java:245)
at com.app.filter.helper.config.VideoInfoUtils.combineVideo(VideoInfoUtils.java:159)
at com.app.filter.helper.filter.video.VideoFilterView.handleSaveCompleted(VideoFilterView.java:74)
at com.app.filter.helper.filter.video.VideoFilterView$ViewHandler.handleMessage(VideoFilterView.java:167)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
and my java code is
public class VideoInfoUtils {
public static MediaFormat getVideoInfo(String path) {
MediaExtractor audioExtractor = new MediaExtractor();
try {
audioExtractor.setDataSource(path);
} catch (IOException e) {
e.printStackTrace();
}
int selectTrack = selectTrack(audioExtractor);
if (selectTrack < 0) {
throw new RuntimeException("No video track found in " + path);
}
MediaFormat format = audioExtractor.getTrackFormat(selectTrack);
return format;
}
/**
* Selects the video track, if any.
*
* #return the track index, or -1 if no video track is found.
*/
private static int selectTrack(MediaExtractor mMediaExtractor) {
// Select the first video track we find, ignore the rest.
int numTracks = mMediaExtractor.getTrackCount();
for (int i = 0; i < numTracks; i++) {
MediaFormat format = mMediaExtractor.getTrackFormat(i);
String mime = format.getString(MediaFormat.KEY_MIME);
if (mime.startsWith("video/")) {
return i;
}
}
return -1;
}
#SuppressLint("NewApi")
public static void combineVideo(String videoPath, String newVideo, String output) throws IllegalArgumentException {
try {
MediaExtractor videoExtractor = new MediaExtractor();
videoExtractor.setDataSource(newVideo);
MediaFormat videoFormat = null;
int videoTrackIndex = -1;
int videoTrackCount = videoExtractor.getTrackCount();
for (int i = 0; i < videoTrackCount; i++) {
videoFormat = videoExtractor.getTrackFormat(i);
String mimeType = videoFormat.getString(MediaFormat.KEY_MIME);
if (mimeType.startsWith("video/")) {
videoTrackIndex = i;
break;
}
}
MediaExtractor audioExtractor = new MediaExtractor();
audioExtractor.setDataSource(videoPath);
MediaFormat audioFormat = null;
int audioTrackIndex = -1;
int audioTrackCount = audioExtractor.getTrackCount();
for (int i = 0; i < audioTrackCount; i++) {
audioFormat = audioExtractor.getTrackFormat(i);
String mimeType = audioFormat.getString(MediaFormat.KEY_MIME);
if (mimeType.startsWith("audio/")) {
audioTrackIndex = i;
break;
}
}
videoExtractor.selectTrack(videoTrackIndex);
audioExtractor.selectTrack(audioTrackIndex);
MediaCodec.BufferInfo videoBufferInfo = new MediaCodec.BufferInfo();
MediaCodec.BufferInfo audioBufferInfo = new MediaCodec.BufferInfo();
MediaMuxer mediaMuxer;
int writeVideoTrackIndex;
int writeAudioTrackIndex;
try {
mediaMuxer = new MediaMuxer(output, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
writeVideoTrackIndex = mediaMuxer.addTrack(videoFormat);
writeAudioTrackIndex = mediaMuxer.addTrack(audioFormat);
mediaMuxer.start();
} catch (IOException ioe) {
throw new RuntimeException("MediaMuxer creation failed", ioe);
}
ByteBuffer byteBuffer = ByteBuffer.allocate(500 * 1024);
long videoStampTime = 0;
{
videoExtractor.readSampleData(byteBuffer, 0);
if (videoExtractor.getSampleFlags() == MediaExtractor.SAMPLE_FLAG_SYNC) {
videoExtractor.advance();
}
videoExtractor.readSampleData(byteBuffer, 0);
long secondTime = videoExtractor.getSampleTime();
videoExtractor.advance();
long thirdTime = videoExtractor.getSampleTime();
videoStampTime = Math.abs(thirdTime - secondTime);
}
videoExtractor.unselectTrack(videoTrackIndex);
videoExtractor.selectTrack(videoTrackIndex);
long audioStampTime = 0;
//获取帧之间的间隔时间
{
audioExtractor.readSampleData(byteBuffer, 0);
if (audioExtractor.getSampleFlags() == MediaExtractor.SAMPLE_FLAG_SYNC) {
audioExtractor.advance();
}
audioExtractor.readSampleData(byteBuffer, 0);
long secondTime = audioExtractor.getSampleTime();
audioExtractor.advance();
audioExtractor.readSampleData(byteBuffer, 0);
long thirdTime = audioExtractor.getSampleTime();
audioStampTime = Math.abs(thirdTime - secondTime);
Log.e("time", audioStampTime + "");
}
audioExtractor.unselectTrack(audioTrackIndex);
audioExtractor.selectTrack(audioTrackIndex);
while (true) {
int readVideoSampleSize = videoExtractor.readSampleData(byteBuffer, 0);
if (readVideoSampleSize < 0) {
break;
}
videoBufferInfo.size = readVideoSampleSize;
videoBufferInfo.presentationTimeUs += videoStampTime;
videoBufferInfo.offset = 0;
videoBufferInfo.flags = videoExtractor.getSampleFlags();
mediaMuxer.writeSampleData(writeVideoTrackIndex, byteBuffer, videoBufferInfo);
videoExtractor.advance();
}
while (true) {
int readAudioSampleSize = audioExtractor.readSampleData(byteBuffer, 0);
if (readAudioSampleSize < 0) {
break;
}
audioBufferInfo.size = readAudioSampleSize;
audioBufferInfo.presentationTimeUs += audioStampTime;
audioBufferInfo.offset = 0;
audioBufferInfo.flags = videoExtractor.getSampleFlags();
mediaMuxer.writeSampleData(writeAudioTrackIndex, byteBuffer, audioBufferInfo);
audioExtractor.advance();
}
if (mediaMuxer != null) {
mediaMuxer.stop();
mediaMuxer.release();
}
videoExtractor.release();
audioExtractor.release();
} catch (IOException e) {
e.printStackTrace();
}
}
}
In my application i'm trying to add filters on video.
But sometimes my app crashes and sometimes it works fine.
The error is "Failed to stop the muxer"
I got below code from https://android.googlesource.com/platform/cts/+/jb-mr2-release/tests/tests/media/src/android/media/cts/MediaMuxerTest.java
// Throws exception b/c start() is not called.
muxer = new MediaMuxer(outputFile, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
muxer.addTrack(MediaFormat.createVideoFormat("video/avc", 480, 320));
try {
muxer.stop();
fail("should throw IllegalStateException.");
} catch (IllegalStateException e) {
// expected
}
according to this, you need to make sure you stated mutex before you stop it. You can keep variable like isMutextStarted like to store state. But it is just hack.
I recommand you to initalize it only muxer going to start next. Otherwise it is keep as null then your mediaMuxer.stop() and release parts are not executed.

how to call Asynktask for list of String inside forloop in android

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.

android merging with MP4Parser issue

I have a problem related to the merging of two videos. When I'm trying to merge two videos from different landscape modes (left/right) one of the videos is displaying upside down. I'm using MP4Parser as a library to manage the trimming and merging
protected void combineClips() throws IOException {
MediaMetadataRetriever m = new MediaMetadataRetriever();
for (int i = 0; i < paths.size(); i++) {
m.setDataSource(paths.get(i));
if (Build.VERSION.SDK_INT >= 17) {
String s = m.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
if (Integer.valueOf(s) == 0) {
isLeftLandscape = true;
}
if (Integer.valueOf(s) == 180) {
isRightLandscape = true;
}
}
}
for (int i = 0; i < paths.size(); i++) {
Movie tm = MovieCreator.build(paths.get(i));
Log.d(TAG, files.size() + "files");
files.add(tm);
}
if (isLeftLandscape && isRightLandscape) {
for (int i = 0; i < paths.size(); i++) {
m.setDataSource(paths.get(i));
if (Build.VERSION.SDK_INT >= 17) {
String s = m.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
if (Integer.valueOf(s) == 0)
{
Log.d(TAG, "the rotation is " + s);
rotate(paths.get(i), i);
}}
}
}
List<Track> videoTracks = new ArrayList<Track>();
List<Track> audioTracks = new ArrayList<Track>();
for (Movie movie : files) {
for (Track t : movie.getTracks()) {
if (t.getHandler().equals("soun")) {
audioTracks.add(t);
}
if (t.getHandler().equals("vide")) {
videoTracks.add(t);
}
}
}
Movie result = new Movie();
if (audioTracks.size() > 0) {
Log.d(TAG, String.valueOf(audioTracks.size()) + "audi");
result.addTrack(new AppendTrack(audioTracks.toArray(new Track[audioTracks.size()])));
}
if (videoTracks.size() > 0) {
Log.d(TAG, String.valueOf(audioTracks.size()) + "vide");
result.addTrack(new AppendTrack(videoTracks.toArray(new Track[videoTracks.size()])));
}
Container out = new DefaultMp4Builder().build(result);
String folder_main = "VidApp";
File f = new File(Environment.getExternalStorageDirectory(), folder_main);
if (!f.exists()) {
f.mkdirs();
}
FileChannel fc = new RandomAccessFile(String.format(System.getenv("EXTERNAL_STORAGE") + "/VidApp" + "/output.mp4"), "rw").getChannel();
out.writeContainer(fc);
fc.close();
while (!audioTracks.isEmpty()) {
audioTracks.remove(0);
}
while (!videoTracks.isEmpty()) {
videoTracks.remove(0);
}
while (!files.isEmpty()) {
files.remove(0);
}
}
public void rotate(String path, int position) throws IOException {
IsoFile isoFile = new IsoFile(path);
Movie m = new Movie();
List<TrackBox> trackBoxes = isoFile.getMovieBox().getBoxes(
TrackBox.class);
for (TrackBox trackBox : trackBoxes) {
trackBox.getTrackHeaderBox().setMatrix(Matrix.ROTATE_180);
m.addTrack(new Mp4TrackImpl(trackBox));
}
Log.d(TAG, position + " of " + files.size());
files.set(position, m);
}

How to concat/merge mp4, with setting correct duration?

I need merge a few mp4 files on android, so I am tried using mp4parser merge a few mp4.
private void mergeMp4(File output, String[] files) throws IOException {
Movie[] inMovies = new Movie[files.length];
for (int i=0, len = files.length; i<len; ++i) {
inMovies[i] = MovieCreator.build("/tmp/tmp/" + files[i]);
}
List<Track> videoTracks = new LinkedList<Track>();
List<Track> audioTracks = new LinkedList<Track>();
for (Movie m : inMovies) {
for (Track t : m.getTracks()) {
if (t.getHandler().equals("soun")) {
audioTracks.add(t);
}
if (t.getHandler().equals("vide")) {
videoTracks.add(t);
}
}
}
Movie result = new Movie();
if (audioTracks.size() > 0) {
result.addTrack(new AppendTrack(audioTracks.toArray(new Track[audioTracks.size()])));
}
if (videoTracks.size() > 0) {
result.addTrack(new AppendTrack(videoTracks.toArray(new Track[videoTracks.size()])));
}
Container out = new DefaultMp4Builder().build(result);
FileChannel fc = new RandomAccessFile(output, "rw").getChannel();
out.writeContainer(fc);
fc.close();
}
// work correct for non-merged mp4 file
private long getDuration(String filename) throws IOException {
IsoFile isoFile = new IsoFile(filename);
long lengthInSeconds = isoFile.getMovieBox().getMovieHeaderBox().getDuration() / isoFile.getMovieBox().getMovieHeaderBox().getTimescale();
return lengthInSeconds * 1000;
}
somewhere in code
File tmp = new File("/tmp/tmp");
String[] tmpFiles = tmp.list();
File recordedFile = new File("/mnt/sdcard/app/output.mp4")
mergeMp4(recordedFile, tmpFiles);
// both print value near 0 (about 20 millis)
Log.d("TAG", String.valueOf(getDuration(recordedFile)));
System.out.println(getDuration(recordedFile));
If I trying play merged file with android MediaPlayer or any other player:
player = new MediaPlayer();
try {
player.setDataSource(getFilename());
player.prepare();
player.start();
int duration = player.getDuaration();
// both print value near 0 (about 20 millis)
Log.d("TAG", String.valueOf(duration));
System.out.println(duration);
} catch (IOException e) {
Log.e(TAG, "prepare() failed", e);
}
It is merges files but all mediaplayers and even method of mp4parser author of getting duration returns that duration always about 0 (zero) seconds.

Android: mixing audio

I'm developing an Android app that record voice using mediarecorder and play music using mediaplayer.
My goal is to make possible to mix the two audio's into one file, and because Android do not offer any API for it, I am looking for a reasonable solution.
At moment, at play time I'm using a new mediarecorder with MIC source to capture the audio and save it, but this is very poor !!!
Anyway to mix the audio? including any native solution lix SOX or FFMPEG?
Or, anyway to recorder into file using as source the mediaplayer output instead to use the MIC?
Any suggestion is appreciate.
Thank you.
When I faced the same problem I was able to find a solution for mixing the files.
Since mixing of two mp3 file is not possible, you have to first convert it in wave format , then set the header value .after that add the data field. I did this in following way. Hope my code will help you.
class MixFile extends AsyncTask{
ProgressDialog dialog;
protected void onPreExecute() {
dialog= new ProgressDialog(MainActivity.this);
dialog.setCancelable(false);
dialog.setMessage("Mixing two wav files");
dialog.show();
}
#Override
protected Void doInBackground(Void... arg0) {
short[] audioData1 = null;
short[] audioData2 = null;
int n = 0;
try {
DataInputStream in1;
// in1 = new DataInputStream(new FileInputStream(Environment.getExternalStorageDirectory() + "/Soundrecpluspro/one.wav"));
in1 = new DataInputStream(new FileInputStream(path1));
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
while ((n = in1.read()) != -1) {
bos.write(n);
}
} catch (IOException e) {
e.printStackTrace();
}
ByteBuffer bb = ByteBuffer.wrap(bos.toByteArray());
bb.order(ByteOrder.LITTLE_ENDIAN);
ShortBuffer sb = bb.asShortBuffer();
audioData1 = new short[sb.capacity()];
for (int i = 0; i < sb.capacity(); i++) {
audioData1[i] = sb.get(i);
}
} catch (IOException e) {
e.printStackTrace();
}
try {
DataInputStream in1;
in1 = new DataInputStream(new FileInputStream(path2));
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
while ((n = in1.read()) != -1) {
bos.write(n);
}
} catch (IOException e) {
e.printStackTrace();
}
ByteBuffer bb = ByteBuffer.wrap(bos.toByteArray());
bb.order(ByteOrder.LITTLE_ENDIAN);
ShortBuffer sb = bb.asShortBuffer();
audioData2= new short[sb.capacity()];
sb.get(audioData2);
System.out.println();
} catch (IOException e) {
e.printStackTrace();
}
// find the max:
float max = 0;
Log.d("File audio lenght 1 ", ""+audioData1.length);
Log.d("File audio lenght 2 ", ""+audioData2.length);
System.out.println("MainActivity.MixFile.doInBackground() 1"+audioData1.length);
System.out.println("MainActivity.MixFile.doInBackground() 2"+audioData2.length);
if(audioData1.length > audioData2.length){
for (int i = 22; i < audioData2.length; i++) {
if (Math.abs(audioData1[i] + audioData2[i]) > max)
max = Math.abs(audioData1[i] + audioData2[i]);
}
System.out.println("" + (Short.MAX_VALUE - max));
int a, b, c;
// now find the result, with scaling:
for (int i = 22; i < audioData2.length; i++) {
a = audioData1[i];
b = audioData2[i];
c = Math.round(Short.MAX_VALUE * (audioData1[i] + audioData2[i])
/ max);
if (c > Short.MAX_VALUE)
c = Short.MAX_VALUE;
if (c < Short.MIN_VALUE)
c = Short.MIN_VALUE;
audioData1[i] = (short) c;
}
// to turn shorts back to bytes.
byte[] end = new byte[audioData1.length * 2];
ByteBuffer.wrap(end).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(audioData1);
try {
OutputStream out = new FileOutputStream(Environment.getExternalStorageDirectory() + "/assets/mixer12.wav");
for (int i = 0; i < end.length; i++) {
out.write(end[i]);
out.flush();
}
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
System.out.println("MainActivity.MixFile.doInBackground() smaller one");
for (int i = 22; i < audioData1.length; i++) {
if (Math.abs(audioData2[i] + audioData1[i]) > max)
max = Math.abs(audioData2[i] + audioData1[i]);
}
System.out.println("" + (Short.MAX_VALUE - max));
int a, b, c;
// now find the result, with scaling:
for (int i = 22; i < audioData1.length; i++) {
a = audioData2[i];
b = audioData1[i];
c = Math.round(Short.MAX_VALUE * (audioData2[i] + audioData1[i])
/ max);
if (c > Short.MAX_VALUE)
c = Short.MAX_VALUE;
if (c < Short.MIN_VALUE)
c = Short.MIN_VALUE;
audioData2[i] = (short) c;
}
// to turn shorts back to bytes.
byte[] end = new byte[audioData2.length * 2];
ByteBuffer.wrap(end).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(audioData2);
try {
OutputStream out = new FileOutputStream(Environment.getExternalStorageDirectory() + "/Assets/mixer1.wav");
for (int i = 0; i < end.length; i++) {
out.write(end[i]);
out.flush();
}
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
and in activity i called it as below
public class MainActivity extends Activity implements OnClickListener {
new MixFile().execute();
}
here path1 and path2 is the path of wav file that you want to mix

Categories

Resources