This source file includes following definitions.
- JNINamespace
- CreateTempFile
- decodeAudioFile
- nativeOnChunkDecoded
- nativeInitializeDestination
package org.chromium.media;
import android.content.Context;
import android.media.MediaCodec;
import android.media.MediaCodec.BufferInfo;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
import java.io.File;
import java.nio.ByteBuffer;
@JNINamespace("media")
class WebAudioMediaCodecBridge {
static final String LOG_TAG = "WebAudioMediaCodec";
static final long TIMEOUT_MICROSECONDS = 500;
@CalledByNative
private static String CreateTempFile(Context ctx) throws java.io.IOException {
File outputDirectory = ctx.getCacheDir();
File outputFile = File.createTempFile("webaudio", ".dat", outputDirectory);
return outputFile.getAbsolutePath();
}
@CalledByNative
private static boolean decodeAudioFile(Context ctx,
long nativeMediaCodecBridge,
int inputFD,
long dataSize) {
if (dataSize < 0 || dataSize > 0x7fffffff)
return false;
MediaExtractor extractor = new MediaExtractor();
ParcelFileDescriptor encodedFD;
encodedFD = ParcelFileDescriptor.adoptFd(inputFD);
try {
extractor.setDataSource(encodedFD.getFileDescriptor(), 0, dataSize);
} catch (Exception e) {
e.printStackTrace();
encodedFD.detachFd();
return false;
}
if (extractor.getTrackCount() <= 0) {
encodedFD.detachFd();
return false;
}
MediaFormat format = extractor.getTrackFormat(0);
int inputChannelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
int outputChannelCount = inputChannelCount;
int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
String mime = format.getString(MediaFormat.KEY_MIME);
long durationMicroseconds = 0;
if (format.containsKey(MediaFormat.KEY_DURATION)) {
try {
durationMicroseconds = format.getLong(MediaFormat.KEY_DURATION);
} catch (Exception e) {
Log.d(LOG_TAG, "Cannot get duration");
}
}
if (durationMicroseconds > 0x7fffffff) {
durationMicroseconds = 0;
}
Log.d(LOG_TAG, "Initial: Tracks: " + extractor.getTrackCount() +
" Format: " + format);
MediaCodec codec;
try {
codec = MediaCodec.createDecoderByType(mime);
} catch (Exception e) {
Log.w(LOG_TAG, "Failed to create MediaCodec for mime type: " + mime);
encodedFD.detachFd();
return false;
}
codec.configure(format, null , null , 0 );
codec.start();
ByteBuffer[] codecInputBuffers = codec.getInputBuffers();
ByteBuffer[] codecOutputBuffers = codec.getOutputBuffers();
extractor.selectTrack(0);
boolean sawInputEOS = false;
boolean sawOutputEOS = false;
boolean destinationInitialized = false;
while (!sawOutputEOS) {
if (!sawInputEOS) {
int inputBufIndex = codec.dequeueInputBuffer(TIMEOUT_MICROSECONDS);
if (inputBufIndex >= 0) {
ByteBuffer dstBuf = codecInputBuffers[inputBufIndex];
int sampleSize = extractor.readSampleData(dstBuf, 0);
long presentationTimeMicroSec = 0;
if (sampleSize < 0) {
sawInputEOS = true;
sampleSize = 0;
} else {
presentationTimeMicroSec = extractor.getSampleTime();
}
codec.queueInputBuffer(inputBufIndex,
0,
sampleSize,
presentationTimeMicroSec,
sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
if (!sawInputEOS) {
extractor.advance();
}
}
}
MediaCodec.BufferInfo info = new BufferInfo();
final int outputBufIndex = codec.dequeueOutputBuffer(info, TIMEOUT_MICROSECONDS);
if (outputBufIndex >= 0) {
ByteBuffer buf = codecOutputBuffers[outputBufIndex];
if (!destinationInitialized) {
Log.d(LOG_TAG, "Final: Rate: " + sampleRate +
" Channels: " + inputChannelCount +
" Mime: " + mime +
" Duration: " + durationMicroseconds + " microsec");
nativeInitializeDestination(nativeMediaCodecBridge,
inputChannelCount,
sampleRate,
durationMicroseconds);
destinationInitialized = true;
}
if (destinationInitialized && info.size > 0) {
nativeOnChunkDecoded(nativeMediaCodecBridge, buf, info.size,
inputChannelCount, outputChannelCount);
}
buf.clear();
codec.releaseOutputBuffer(outputBufIndex, false );
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
sawOutputEOS = true;
}
} else if (outputBufIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
codecOutputBuffers = codec.getOutputBuffers();
} else if (outputBufIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
MediaFormat newFormat = codec.getOutputFormat();
outputChannelCount = newFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
sampleRate = newFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);
Log.d(LOG_TAG, "output format changed to " + newFormat);
}
}
encodedFD.detachFd();
codec.stop();
codec.release();
codec = null;
return true;
}
private static native void nativeOnChunkDecoded(
long nativeWebAudioMediaCodecBridge, ByteBuffer buf, int size,
int inputChannelCount, int outputChannelCount);
private static native void nativeInitializeDestination(
long nativeWebAudioMediaCodecBridge,
int inputChannelCount,
int sampleRate,
long durationMicroseconds);
}