Created
June 23, 2017 00:57
-
-
Save doggan/2d787ec650e949c3bcbe8ce1a1536636 to your computer and use it in GitHub Desktop.
Use MediaMuxer to overlay a WAV onto an MP4
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.test.mytest; | |
import java.io.File; | |
import java.io.FileInputStream; | |
import java.io.FileNotFoundException; | |
import java.io.IOException; | |
import java.nio.ByteBuffer; | |
import android.app.ProgressDialog; | |
import android.media.MediaCodec; | |
import android.media.MediaCodecInfo; | |
import android.media.MediaFormat; | |
import android.media.MediaMuxer; | |
import android.os.Bundle; | |
import android.os.Environment; | |
import android.support.v4.app.FragmentActivity; | |
import android.util.Log; | |
import android.view.View; | |
import android.view.View.OnClickListener; | |
// Ref: https://github.com/tqnst/MP4ParserMergeAudioVideo | |
public class TestOverlayAudio extends FragmentActivity { | |
private final TestOverlayAudio self = this; | |
private ProgressDialog mProgressDialog; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main); | |
findViewById(R.id.button1).setOnClickListener(new OnClickListener() { | |
@Override | |
public void onClick(View v) { | |
/* | |
mProgressDialog = ProgressDialog.show(self, null, null); | |
Bundle args = new Bundle(); | |
args.putInt("type", 1); | |
getSupportLoaderManager().initLoader(0, args, self); | |
*/ | |
Thread thread = new Thread(convert); | |
thread.start(); | |
} | |
}); | |
} | |
public static final String AUDIO_RECORDING_FILE_NAME = "audio_Capturing-190814-034638.422.wav"; // Input PCM file | |
public static final String COMPRESSED_AUDIO_FILE_NAME = "convertedmp4.m4a"; // Output MP4/M4A file | |
public static final String COMPRESSED_AUDIO_FILE_MIME_TYPE = "audio/mp4a-latm"; | |
public static final int COMPRESSED_AUDIO_FILE_BIT_RATE = 64000; // 64kbps | |
public static final int SAMPLING_RATE = 48000; | |
public static final int BUFFER_SIZE = 48000; | |
public static final int CODEC_TIMEOUT_IN_MS = 5000; | |
String LOGTAG = "CONVERT AUDIO"; | |
Runnable convert = new Runnable() { | |
// @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) | |
@Override | |
public void run() { | |
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND); | |
try { | |
String filePath = Environment.getExternalStorageDirectory().getPath() + "/" + AUDIO_RECORDING_FILE_NAME; | |
File inputFile = new File(filePath); | |
FileInputStream fis = new FileInputStream(inputFile); | |
File outputFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + COMPRESSED_AUDIO_FILE_NAME); | |
if (outputFile.exists()) outputFile.delete(); | |
MediaMuxer mux = new MediaMuxer(outputFile.getAbsolutePath(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); | |
MediaFormat outputFormat = MediaFormat.createAudioFormat(COMPRESSED_AUDIO_FILE_MIME_TYPE,SAMPLING_RATE, 1); | |
outputFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC); | |
outputFormat.setInteger(MediaFormat.KEY_BIT_RATE, COMPRESSED_AUDIO_FILE_BIT_RATE); | |
outputFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 16384); | |
MediaCodec codec = MediaCodec.createEncoderByType(COMPRESSED_AUDIO_FILE_MIME_TYPE); | |
codec.configure(outputFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); | |
codec.start(); | |
ByteBuffer[] codecInputBuffers = codec.getInputBuffers(); // Note: Array of buffers | |
ByteBuffer[] codecOutputBuffers = codec.getOutputBuffers(); | |
MediaCodec.BufferInfo outBuffInfo = new MediaCodec.BufferInfo(); | |
byte[] tempBuffer = new byte[BUFFER_SIZE]; | |
boolean hasMoreData = true; | |
double presentationTimeUs = 0; | |
int audioTrackIdx = 0; | |
int totalBytesRead = 0; | |
int percentComplete = 0; | |
do { | |
int inputBufIndex = 0; | |
while (inputBufIndex != -1 && hasMoreData) { | |
inputBufIndex = codec.dequeueInputBuffer(CODEC_TIMEOUT_IN_MS); | |
if (inputBufIndex >= 0) { | |
ByteBuffer dstBuf = codecInputBuffers[inputBufIndex]; | |
dstBuf.clear(); | |
int bytesRead = fis.read(tempBuffer, 0, dstBuf.limit()); | |
Log.e("bytesRead","Readed "+bytesRead); | |
if (bytesRead == -1) { // -1 implies EOS | |
hasMoreData = false; | |
codec.queueInputBuffer(inputBufIndex, 0, 0, (long) presentationTimeUs, MediaCodec.BUFFER_FLAG_END_OF_STREAM); | |
} else { | |
totalBytesRead += bytesRead; | |
dstBuf.put(tempBuffer, 0, bytesRead); | |
codec.queueInputBuffer(inputBufIndex, 0, bytesRead, (long) presentationTimeUs, 0); | |
presentationTimeUs = 1000000l * (totalBytesRead / 2) / SAMPLING_RATE; | |
} | |
} | |
} | |
// Drain audio | |
int outputBufIndex = 0; | |
while (outputBufIndex != MediaCodec.INFO_TRY_AGAIN_LATER) { | |
outputBufIndex = codec.dequeueOutputBuffer(outBuffInfo, CODEC_TIMEOUT_IN_MS); | |
if (outputBufIndex >= 0) { | |
ByteBuffer encodedData = codecOutputBuffers[outputBufIndex]; | |
encodedData.position(outBuffInfo.offset); | |
encodedData.limit(outBuffInfo.offset + outBuffInfo.size); | |
if ((outBuffInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0 && outBuffInfo.size != 0) { | |
codec.releaseOutputBuffer(outputBufIndex, false); | |
}else{ | |
mux.writeSampleData(audioTrackIdx, codecOutputBuffers[outputBufIndex], outBuffInfo); | |
codec.releaseOutputBuffer(outputBufIndex, false); | |
} | |
} else if (outputBufIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { | |
outputFormat = codec.getOutputFormat(); | |
Log.v(LOGTAG, "Output format changed - " + outputFormat); | |
audioTrackIdx = mux.addTrack(outputFormat); | |
mux.start(); | |
} else if (outputBufIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { | |
Log.e(LOGTAG, "Output buffers changed during encode!"); | |
} else if (outputBufIndex == MediaCodec.INFO_TRY_AGAIN_LATER) { | |
// NO OP | |
} else { | |
Log.e(LOGTAG, "Unknown return code from dequeueOutputBuffer - " + outputBufIndex); | |
} | |
} | |
percentComplete = (int) Math.round(((float) totalBytesRead / (float) inputFile.length()) * 100.0); | |
Log.v(LOGTAG, "Conversion % - " + percentComplete); | |
} while (outBuffInfo.flags != MediaCodec.BUFFER_FLAG_END_OF_STREAM); | |
fis.close(); | |
mux.stop(); | |
mux.release(); | |
Log.v(LOGTAG, "Compression done ..."); | |
} catch (FileNotFoundException e) { | |
Log.e(LOGTAG, "File not found!", e); | |
} catch (IOException e) { | |
Log.e(LOGTAG, "IO exception!", e); | |
} | |
//mStop = false; | |
// Notify UI thread... | |
} | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment