How to create mp4 file from h264 encoded frames on android? - android

I have some h264 frames already encoded with android encoder. Now i want to create and write them one by one to the mp4 file. Please advise how to do this on android in Java. I don't want to use OpenCV or native code.
mp4-parser can't do this as i understand
navite MPEG4Writer is too complicated to use
Wondering why such a common and very useful thing as mp4 writer NOT FROM CAMERA is not implemented in android

You may use my mp4parser project. You can mux H264 and AAC in pure Java with it:
H264TrackImpl h264Track = new H264TrackImpl(new FileInputStream("raw.h264").getChannel());
Movie m = new Movie();
m.addTrack(h264Track);
IsoFile out = new DefaultMp4Builder().build(m);
FileOutputStream fos = new FileOutputStream(new File("h264_output.mp4"));
out.getBox(fos.getChannel());
fos.close();

Related

Get audio input stream from a locale file on android

I am trying to get the audio input stream from a file in the local file system on an android device.
This is so that i can use this library to show a wave form for the audio file.
https://github.com/newventuresoftware/WaveformControl/blob/master/app/src/main/java/com/newventuresoftware/waveformdemo/MainActivity.java#L125
The example in the project uses rawResource like so
InputStream is = getResources().openRawResource(R.raw.jinglebells);
This input stream is later converted into byte array and passed to somewhere that uses it to paint a wave picture and sound.
however when I did
InputStream is = new InputFileSystem(new File(filePath));
But this does not seem to work properly. The image generated is wrong, and the sound played is nothing like what the file actually is.
This is the body of the function in that library that gets the input stream and convert it into byte arrays.
private short[] getAudioSample() throws IOException {
// If i replace this part with new FileInput(new File(filePath))
// the generated "samples" from it does not work properly with the library.
InputStream is = getResources().openRawResource(R.raw.jinglebells);
byte[] data;
try {
data = IOUtils.toByteArray(is);
} finally {
if (is != null) {
is.close();
}
}
ShortBuffer sb = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
short[] samples = new short[sb.limit()];
sb.get(samples);
return samples;
}
The sound file that I would like to get processed and pass to that library is created by a MediaRecorder with the following configurations
MediaRecorder recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
Basically that library requires PCM samples. Using that 3gp FileInputStream generated by MediaRecorder directly is not gonna cut it.
What I did is to use MediaExtractor and MediaCodec to convert the 3gp audio data into PCM samples by samples. and then it is fed into that library. Then everything worked =)
The logic in encoding audio data can be almost directly taken from here this awesome github repo

Add second audio track to MediaMuxer

I have a video file .mp4 - video track only.
I'm using MediaExtractor and MediaMuxer to add audio file.
this Works good.
On the processed file i want to add another audio track.
So i'm using again MediaExtractor and MediaMuxer to kind of copy the file, (Creating video and audio tracks, reading [extractor] and writing [muxer]). In addition i'm trying to add the second audio track to the muxer. but this throws the error Failed to add the track to the muxer.
in this link we can see that muxer does not support multiple tracks.
Code From the link:
// Throws exception b/c 2 audio tracks were added.
muxer = new MediaMuxer(outputFile, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
muxer.addTrack(MediaFormat.createAudioFormat("audio/mp4a-latm", 48000, 1));
try {
muxer.addTrack(MediaFormat.createAudioFormat("audio/mp4a-latm", 48000, 1));
fail("should throw IllegalStateException.");
} catch (IllegalStateException e) {
// expected
}
Is there other way to do it ?
Elegant way ?
BTW, i'm trying to avoid using 3rd parties - like ffmpeg or so.. But if would be my only solution...
--EDIT--
Relevant piece of my code
MediaMuxer muxer = new MediaMuxer(outputFile, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
MediaExtractor extractor = new MediaExtractor();
extractor.setDataSource(videoAndAudioFile);
for (int currTrackIdx = 0; currTrackIdx < extractor.getTrackCount(); currTrackIdx++) {
MediaFormat trackFormat = extractor.getTrackFormat(currTrackIdx);
tracksIdx.add(muxer.addTrack(trackFormat));
}
MediaExtractor extractor2 = new MediaExtractor();
extractor2.setDataSource(secondAudioFile);
MediaFormat trackFormat = extractor2.getTrackFormat(0);
tracksIdx.add(muxer.addTrack(trackFormat)); // Crashes here
For someone who reaches here, I found this official doc at link. Muxing Multiple Video/Audio Tracks seems not supported in old API versions and even restricted in the latest version.

Extract a specific portion of video using MediaExtractor

I am trying to use a portion of a pre-recorded video file for processing on Android. Currently I am working with MediaCodec library on Android. I am using MediaExtractor to extract the data from video file. The idea is to extract only required gata stream for processing. The code looks like:
extractor = new MediaExtractor();
File file = new File(mInputFile);
FileInputStream inputStream = new FileInputStream(file);
long len = file.length();
long start = 200L;
extractor.setDataSource(inputStream.getFD(),start,len);
inputStream.close();
Logcat is:
java.io.IOException: Failed to instantiate extractor.
at android.media.MediaExtractor.setDataSource(Native Method).
It works well if I set starting bytes to 0. What am I doing wrong ? Can we not extract portion of videos using mediaextractor ?

Using AudioTrack in AudioTrack.MODE_STATIC?

I've found lots of tutorials and posts showing how to use AudioTrack to play wav files in AudioTrack.MODE_STREAM and I've successfully implemented this example.
However I'm having issues with performance when playing multiple audio tracks at once and thinking that I should first create the tracks using AudioTrack.MODE_STATIC then just call play each time.
I can't find any resources on how to implement this. How can I do this?
Thanks
The two main sticking points for me were realizing that .write() comes first and that the instantiated player must have the size of the entire clip as the buffer_size_in_bytes.
Assuming you have recorded a PCM file using AudioRecord, you can play it back with STATIC_MODE like so...
File file = new File(FILENAME);
int audioLength = (int)file.length();
byte filedata[] = new byte[audioLength];
try{
InputStream inputStream = new BufferedInputStream(new FileInputStream(FILENAME));
int lengthOfAudioClip = inputStream.read(filedata, 0, audioLength);
player = new AudioTrack(STREAM_TYPE, SAMPLE_RATE, CHANNEL_OUT_CONFIG, AUDIO_FORMAT,audioLength, AUDIO_MODE);
player.write(filedata, OFFSET, lengthOfAudioClip);
player.setPlaybackRate(playbackRate);
player.play();
}

Android: Convert Audio into float[]

I'm developing an app in Android that has to record sound and display in the screen some vaules that represents the frequency or the intensity of the sound.
For the record thing I use this piece of code:
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mRecorder.setOutputFile(name);
mRecorder.prepare();
mRecorder.start();
Then I was initially trying to convert the stored file into byte like this:
DataInputStream dis1 = new DataInputStream ( new FileInputStream (name));
byte[] datainBytes1 = new byte[dis1.available()];
dis1.readFully(datainBytes1);
dis1.close();
But I want to convert that byte values into short or floats to display them by using a drawing method:
canvas.drawLine(xini,yini,xfinal,yfinal,paint)
Could you recommend me another way to convert the audio file into short values that I could draw?
Thank you very much for your help!!
I think the way you are trying to display recorded sounds is not correct. As starting point you need to study audio encoding format and have a look to the following android class: http://developer.android.com/reference/android/media/AudioTrack.html
Here You will find a Library class for converting between floats and bytes taking into account signed/unsigned, big/little endian, and sample size.
https://java.net/projects/gervill/sources/Mercurial/content/src/com/sun/media/sound/AudioFloatConverter.java

Categories

Resources