Reputation: 39836
I've manage to compile halfninja ffmpeg scripts for Android NDK using NDK version r5c. (Unfortunately any attempt to compile with earlier NDK generated some error), also I'm not very knowledgeable on the whole NDK process, so it's a bit hit-n-miss for me.
His scripts are compiling ffmpeg version N-30996-gf925b24 (the specific commit he did the scripts for)
Moving forward to my actual app.
I manage to trim videos without problems, now I need to join/concatenate them but any attemp at using any and several combinations of the commands found on those 3 links (link1, link2, link3) generate errors such as cat is not valid
, > is undefinined
, unknown option filter_complex
or trying to override some of the input files.
Does anyone know if it's possible and (how to do it), to join/concatenate mp4 videos (all same codec, size, quality, etc) using half-ninja compile of ffmpeg on Android, or how to compile/get a ffmpeg for Android using latest source codes?
I've also gave a quick try on the mp4Parser without much success.
ultimately I was trying to get this pseudo-method to work:
public static File concatenate(String[] inputPaths, String outputPath){
// ... do stuff do generate ffmpeg commands....
VideoKit v = new VideoKit();
v.run(cmds);
File f = new File(outputPath);
return f;
}
Upvotes: 14
Views: 5767
Reputation: 161
Hello I have got that soultion. I Use Mp4parser library
public class Mp4ParserWrapper {
public static final String TAG = Mp4ParserWrapper.class.getSimpleName();
public static final int FILE_BUFFER_SIZE = 1024;
/**
* Appends mp4 audio/video from {@code anotherFileName} to {@code mainFileName}.
*/
public static boolean append(String mainFileName, String anotherFileName) {
boolean rvalue = false;
try {
File targetFile = new File(mainFileName);
File anotherFile = new File(anotherFileName);
if (targetFile.exists() && targetFile.length()>0) {
String tmpFileName = mainFileName + ".tmp";
//mainfile=vishal0
//another file=vishal1
//tmpfile=vishal0.tmp
append(mainFileName, anotherFileName, tmpFileName);
copyFile(tmpFileName, mainFileName);
anotherFile.delete();
new File(tmpFileName).delete();
rvalue = true;
} else if ( targetFile.createNewFile() ) {
copyFile(anotherFileName, mainFileName);
anotherFile.delete();
rvalue = true;
}
} catch (IOException e) {
Log.e(TAG, "Append two mp4 files exception", e);
}
return rvalue;
}
public static void copyFile(final String from, final String destination)
throws IOException {
FileInputStream in = new FileInputStream(from);
FileOutputStream out = new FileOutputStream(destination);
copy(in, out);
in.close();
out.close();
}
public static void copy(FileInputStream in, FileOutputStream out) throws IOException {
byte[] buf = new byte[FILE_BUFFER_SIZE];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
}
public static void append(
final String firstFile,
final String secondFile,
final String newFile) throws IOException {
final FileInputStream fisOne = new FileInputStream(new File(secondFile));
final FileInputStream fisTwo = new FileInputStream(new File(firstFile));
final FileOutputStream fos = new FileOutputStream(new File(String.format(newFile)));
append(fisOne, fisTwo, fos);
fisOne.close();
fisTwo.close();
fos.close();
}
// FIXME remove deprecated code
public static void append(
final FileInputStream fisOne,
final FileInputStream fisTwo,
final FileOutputStream out) throws IOException {
final Movie movieOne = MovieCreator.build(Channels.newChannel(fisOne));
final Movie movieTwo = MovieCreator.build(Channels.newChannel(fisTwo));
final Movie finalMovie = new Movie();
final List<Track> movieOneTracks = movieOne.getTracks();
final List<Track> movieTwoTracks = movieTwo.getTracks();
for (int i = 0; i <movieOneTracks.size() || i < movieTwoTracks.size(); ++i) {
finalMovie.addTrack(new AppendTrack(movieTwoTracks.get(i), movieOneTracks.get(i)));
}
final IsoFile isoFile = new DefaultMp4Builder().build(finalMovie);
isoFile.getBox(out.getChannel());
}
}
And invoke with:
Mp4ParserWrapper.append(firstfilename,secondfilename);
Upvotes: 0
Reputation: 1
The answer provided by LordNeckbeard is really the way to go.
How to concatenate flv file into one?
Working with your restrictions
-f concat
-c
-bsf
ffmpeg -i q.mp4 -vcodec copy -acodec copy -vbsf h264_mp4toannexb q.ts
ffmpeg -i r.mp4 -vcodec copy -acodec copy -vbsf h264_mp4toannexb r.ts
ffmpeg -i 'concat:q.ts|r.ts' -vcodec copy -acodec copy -absf aac_adtstoasc qr.mp4
Joining H264 *without* re-encoding
Upvotes: 4
Reputation: 1129
Since the halfninja version of FFmpeg isn't able to use the concatenate functionality, I advice you to update the FFmpeg library to at least version 1.1.
In my opinion you have two options:
Try to compile a newer version of FFmpeg using one of these two Compiling FFmpeg on Android guides. Then you possibly also need a newer revision of the Android NDK. This is the most simple solution.
Or try to implement a newer version of FFmpeg in the halfninja libraries, which is harder, but then you can keep almost the same interface.
Upvotes: 1
Reputation: 69
ffmpeg concat demuxer has been added to FFMPEG Fire Flower (Version 1.1). Use FFmpeg fire flower or Magic to get this feature. Once you build ffmpeg, use the demuxer. Which is explained in this http://ffmpeg.org/trac/ffmpeg/wiki/How%20to%20concatenate%20(join,%20merge)%20media%20files site as concat demuxer.
Upvotes: 1
Reputation: 6289
this sequence will cat mp4's on the CLI. its from the ffmpeg faq page on concatenation...
$FFMPEG_HOME/ffmpeg -i gpsclip_seg1.mp4 -vn -f u16le -acodec pcm_s16le -ac 1 -ar 44100 - > temp1.a < /dev/null
$FFMPEG_HOME/ffmpeg -i gpsclip_seg2.mp4 -vn -f u16le -acodec pcm_s16le -ac 1 -ar 44100 - > temp2.a < /dev/null
$FFMPEG_HOME/ffmpeg -i gpsclip_seg3.mp4 -vn -f u16le -acodec pcm_s16le -ac 1 -ar 44100 - > temp3.a < /dev/null
cat temp1.a temp2.a temp3.a > all.a
$FFMPEG_HOME/ffmpeg -i gpsclip_seg1.mp4 -an -f yuv4mpegpipe - > temp1.v < /dev/null &
$FFMPEG_HOME/ffmpeg -i gpsclip_seg2.mp4 -an -f yuv4mpegpipe - < /dev/null | tail -n +2 > temp2.v
$FFMPEG_HOME/ffmpeg -i gpsclip_seg3.mp4 -an -f yuv4mpegpipe - < /dev/null | tail -n +2 > temp3.v
cat temp1.v temp2.v temp3.v > all.v
$FFMPEG_HOME/ffmpeg -f u16le -acodec pcm_s16le -ac 1 -ar 44100 -i all.a -f yuv4mpegpipe -i all.v -same_quant -y output.mp4
i looked at halfninja's 'Android.mk' ... and for testing, you should be able to use adb to push 'ffmpeg' executable from halfninja build to /data/local/... on the phone. On building the project, I think the executable will be in ../output folder , above the JNI folder in his project.
Assuming you can get root on the device, you can then do testing on the CLI interface on the phone by getting a shell, then getting root using 'su', then copying cli expressions from ffmpeg/MP4/concat threads such as this one and running them on the phone with outputs to a folder where you have access.
In test mode, if you can get the desired result using step at a time CLI invocations as shown in the link's accepted answer, you can then move back to your JNI interfaces , calling into halfninja's 'videokit' package, implementing the same sequence of commands that you used in test.
Added Note on multiple calls...
Since you will be calling in to ffmpeg lib in the JNI multiple times, you should be aware of this issue that can impact multiple calls into ffmpeg thru JNI. If halfninja has not already done mediated this issue, you may have to change the Android.mk structure to implement the wrapper library talked about in the thread so that you can load/unload the required shared libs in between each call to ffmpeg via the JNI.
android and 'cat'
you should have a symlink in /system/bin on the phone
lrwxr-xr-x root shell 2012-07-09 13:02 cat -> toolbox
if not , try 'busybox' install on the phone so you can simulate scripting on the cli on the phone.
Upvotes: 2