Skip to content

Instantly share code, notes, and snippets.

@gouravd
Forked from sbaar/AACStream.java
Created April 26, 2016 07:10
Show Gist options
  • Save gouravd/300317d9e3fefd7c6ac91240add30180 to your computer and use it in GitHub Desktop.
Save gouravd/300317d9e3fefd7c6ac91240add30180 to your computer and use it in GitHub Desktop.
libstreaming muxer
protected void encodeWithMediaCodec(){
...
mAudioRecord.startRecording();
mMediaCodec.start();
final MediaCodecInputStream inputStream = new MediaCodecInputStream(mMediaCodec);
if (mMuxer!=null) inputStream.setMuxer(mMuxer);
final ByteBuffer[] inputBuffers = mMediaCodec.getInputBuffers();
}
if (BuildConfig.DEBUG && Build.VERSION.SDK_INT>=18){
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES), "movie.mp4");
mMuxer = new Muxer(file.getAbsolutePath());
session.getVideoTrack().setMuxer(mMuxer);
session.getAudioTrack().setMuxer(mMuxer);
}
(RTSPClient) mClient.startStream()
//Modify your media codec input stream to look like this You'll have to handle setting the muxer yourself
@Override
public void close() {
mClosed = true;
Debug.d("MediaCodecInputStream","mcis close called");
if (mMuxer!=null){
mBufferInfo.flags = MediaCodec.BUFFER_FLAG_END_OF_STREAM;
// mBufferInfo.size=0;
mMuxer.writeSampleData(mTrackIndex,mIndex,mBuffers[0],mBufferInfo);
}
}
@Override
public int read() throws IOException {
return 0;
}
@Override
public int read(byte[] buffer, int offset, int length) throws IOException {
int min = 0;
try {
if (mBuffer==null) {
while (!Thread.interrupted() && !mClosed) {
mIndex = mMediaCodec.dequeueOutputBuffer(mBufferInfo, 500000);
if (mIndex>=0 ){
//Log.d(TAG,"Index: "+mIndex+" Time: "+mBufferInfo.presentationTimeUs+" size: "+mBufferInfo.size);
if (mMuxer!=null) mMuxer.writeSampleData(mTrackIndex,mIndex,mBuffers[mIndex],mBufferInfo);
mBuffer = mBuffers[mIndex];
mBuffer.position(0);
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) !=0)
mClosed=true;
break;
} else if (mIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
mBuffers = mMediaCodec.getOutputBuffers();
} else if (mIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
mMediaFormat = mMediaCodec.getOutputFormat();
if (mMuxer!=null) mTrackIndex = mMuxer.addTrack(mMediaFormat);
Log.i(TAG,mMediaFormat.toString());
} else if (mIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
Log.v(TAG,"No buffer available...");
//return 0;
} else {
Log.e(TAG,"Message: "+mIndex);
//return 0;
}
}
}
...
package net.majorkernelpanic.streaming;
import android.annotation.TargetApi;
import android.media.MediaCodec;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.util.Log;
import android.util.SparseIntArray;
import com.vg.hangwith.utils.Debug;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.HashSet;
import java.util.Set;
/**
* @hide
*/
@TargetApi(18)
public class Muxer {
private static final String TAG = "Muxer";
private static final boolean VERBOSE = true;
protected String mOutputPath;
protected int mNumTracks;
protected int mNumTracksFinished;
protected long mFirstPts;
protected long mLastPts[];
private MediaMuxer mMuxer;
private boolean mStarted;
private int mExpectedNumTracks = 2;
public Muxer(String outputPath){
Log.i(TAG, "Created muxer for output: " + outputPath);
mNumTracks = 0;
mNumTracksFinished = 0;
mFirstPts = 0;
mLastPts = new long[2];
for(int i=0; i< mLastPts.length; i++) {
mLastPts[i] = 0;
}
try {
mMuxer = new MediaMuxer(outputPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
} catch (Exception e) {
throw new RuntimeException("MediaMuxer creation failed", e);
}
mStarted = false;
}
public int addTrack(MediaFormat trackFormat) {
mNumTracks++;
if(mStarted)
throw new RuntimeException("format changed twice");
int track = mMuxer.addTrack(trackFormat);
if(allTracksAdded()){
start();
}
return track;
}
protected void start() {
mMuxer.start();
mStarted = true;
}
protected void stop() {
mMuxer.stop();
mMuxer.release();
mStarted = false;
}
public void release() {
mMuxer.release();
}
public boolean isStarted() {
return mStarted;
}
Set<Integer> endedTracks = new HashSet<>();
public synchronized void writeSampleData( int trackIndex, int bufferIndex, ByteBuffer encodedData, MediaCodec.BufferInfo bufferInfo) {
if (endedTracks.contains(trackIndex))
{
Debug.d("not writing a track that has ended");
return;
}
if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
signalEndOfTrack();
endedTracks.add(trackIndex);
}
if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
// MediaMuxer gets the codec config info via the addTrack command
if (VERBOSE) Log.d(TAG, "ignoring BUFFER_FLAG_CODEC_CONFIG");
return;
}
if(bufferInfo.size == 0){
if(VERBOSE) Log.d(TAG, "ignoring zero size buffer");
return;
}
if (!mStarted) {
Log.e(TAG, "writeSampleData called before muxer started. Ignoring packet. Track index: " + trackIndex + " tracks added: " + mNumTracks);
return;
}
// bufferInfo.presentationTimeUs = getNextRelativePts(bufferInfo.presentationTimeUs, trackIndex);
mMuxer.writeSampleData(trackIndex, encodedData, bufferInfo);
if(allTracksFinished()){
stop();
}
}
protected boolean allTracksFinished(){
return (mNumTracks == mNumTracksFinished);
}
protected boolean allTracksAdded(){
return (mNumTracks == mExpectedNumTracks);
}
protected void signalEndOfTrack(){
Log.i(TAG,"mpeg4 end of track");
mNumTracksFinished++;
}
}
protected void encodeWithMediaCodecMethod2(){
...
// The packetizer encapsulates the bit stream in an RTP stream and send it over the network
MediaCodecInputStream mcis = new MediaCodecInputStream(mMediaCodec);
if (mMuxer!=null) mcis.setMuxer(mMuxer);
mPacketizer.setInputStream(mcis);
mPacketizer.start();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment