diff options
Diffstat (limited to 'libs/android-transcoder/src/main/java/net/ypresto/androidtranscoder/engine/QueuedMuxer.java')
-rw-r--r-- | libs/android-transcoder/src/main/java/net/ypresto/androidtranscoder/engine/QueuedMuxer.java | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/libs/android-transcoder/src/main/java/net/ypresto/androidtranscoder/engine/QueuedMuxer.java b/libs/android-transcoder/src/main/java/net/ypresto/androidtranscoder/engine/QueuedMuxer.java new file mode 100644 index 000000000..df58e9923 --- /dev/null +++ b/libs/android-transcoder/src/main/java/net/ypresto/androidtranscoder/engine/QueuedMuxer.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2015 Yuya Tanaka + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.ypresto.androidtranscoder.engine; + +import android.media.MediaCodec; +import android.media.MediaFormat; +import android.media.MediaMuxer; +import android.util.Log; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.List; + +/** + * This class queues until all output track formats are determined. + */ +public class QueuedMuxer { + private static final String TAG = "QueuedMuxer"; + private static final int BUFFER_SIZE = 64 * 1024; // I have no idea whether this value is appropriate or not... + private final MediaMuxer mMuxer; + private final Listener mListener; + private MediaFormat mVideoFormat; + private MediaFormat mAudioFormat; + private int mVideoTrackIndex; + private int mAudioTrackIndex; + private ByteBuffer mByteBuffer; + private final List<SampleInfo> mSampleInfoList; + private boolean mStarted; + + public QueuedMuxer(MediaMuxer muxer, Listener listener) { + mMuxer = muxer; + mListener = listener; + mSampleInfoList = new ArrayList<>(); + } + + public void setOutputFormat(SampleType sampleType, MediaFormat format) { + switch (sampleType) { + case VIDEO: + mVideoFormat = format; + break; + case AUDIO: + mAudioFormat = format; + break; + default: + throw new AssertionError(); + } + onSetOutputFormat(); + } + + private void onSetOutputFormat() { + if (mVideoFormat == null || mAudioFormat == null) return; + mListener.onDetermineOutputFormat(); + + mVideoTrackIndex = mMuxer.addTrack(mVideoFormat); + Log.v(TAG, "Added track #" + mVideoTrackIndex + " with " + mVideoFormat.getString(MediaFormat.KEY_MIME) + " to muxer"); + mAudioTrackIndex = mMuxer.addTrack(mAudioFormat); + Log.v(TAG, "Added track #" + mAudioTrackIndex + " with " + mAudioFormat.getString(MediaFormat.KEY_MIME) + " to muxer"); + mMuxer.start(); + mStarted = true; + + if (mByteBuffer == null) { + mByteBuffer = ByteBuffer.allocate(0); + } + mByteBuffer.flip(); + Log.v(TAG, "Output format determined, writing " + mSampleInfoList.size() + + " samples / " + mByteBuffer.limit() + " bytes to muxer."); + MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); + int offset = 0; + for (SampleInfo sampleInfo : mSampleInfoList) { + sampleInfo.writeToBufferInfo(bufferInfo, offset); + mMuxer.writeSampleData(getTrackIndexForSampleType(sampleInfo.mSampleType), mByteBuffer, bufferInfo); + offset += sampleInfo.mSize; + } + mSampleInfoList.clear(); + mByteBuffer = null; + } + + public void writeSampleData(SampleType sampleType, ByteBuffer byteBuf, MediaCodec.BufferInfo bufferInfo) { + if (mStarted) { + mMuxer.writeSampleData(getTrackIndexForSampleType(sampleType), byteBuf, bufferInfo); + return; + } + byteBuf.limit(bufferInfo.offset + bufferInfo.size); + byteBuf.position(bufferInfo.offset); + if (mByteBuffer == null) { + mByteBuffer = ByteBuffer.allocateDirect(BUFFER_SIZE).order(ByteOrder.nativeOrder()); + } + mByteBuffer.put(byteBuf); + mSampleInfoList.add(new SampleInfo(sampleType, bufferInfo.size, bufferInfo)); + } + + private int getTrackIndexForSampleType(SampleType sampleType) { + switch (sampleType) { + case VIDEO: + return mVideoTrackIndex; + case AUDIO: + return mAudioTrackIndex; + default: + throw new AssertionError(); + } + } + + public enum SampleType {VIDEO, AUDIO} + + private static class SampleInfo { + private final SampleType mSampleType; + private final int mSize; + private final long mPresentationTimeUs; + private final int mFlags; + + private SampleInfo(SampleType sampleType, int size, MediaCodec.BufferInfo bufferInfo) { + mSampleType = sampleType; + mSize = size; + mPresentationTimeUs = bufferInfo.presentationTimeUs; + mFlags = bufferInfo.flags; + } + + private void writeToBufferInfo(MediaCodec.BufferInfo bufferInfo, int offset) { + bufferInfo.set(offset, mSize, mPresentationTimeUs, mFlags); + } + } + + public interface Listener { + void onDetermineOutputFormat(); + } +} |