下面列出了android.media.MediaCodec# start ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* @param media_extractor
* @param trackIndex
* @return
*/
protected MediaCodec internal_start_video(final MediaExtractor media_extractor, final int trackIndex) {
if (DEBUG) Log.v(TAG, "internal_start_video:");
MediaCodec codec = null;
if (trackIndex >= 0) {
final MediaFormat format = media_extractor.getTrackFormat(trackIndex);
final String mime = format.getString(MediaFormat.KEY_MIME);
try {
codec = MediaCodec.createDecoderByType(mime);
codec.configure(format, mOutputSurface, null, 0);
codec.start();
if (DEBUG) Log.v(TAG, "internal_start_video:codec started");
} catch (final IOException e) {
Log.w(TAG, e);
}
}
return codec;
}
@TargetApi(MIN_API_LEVEL_AUDIO)
public static int checkMediaCodecAudioEncoderSupport(){
if(getApiLevel()<MIN_API_LEVEL_AUDIO){
Log.d(TAG, "checkMediaCodecAudioEncoderSupport: Min API is 16");
return CODEC_REQ_API_NOT_SATISFIED;
}
final MediaFormat audioFormat = MediaFormat.createAudioFormat(MIME_TYPE_AUDIO, TEST_SAMPLE_RATE, 1);
audioFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
audioFormat.setInteger(MediaFormat.KEY_CHANNEL_MASK, AudioFormat.CHANNEL_IN_MONO);
audioFormat.setInteger(MediaFormat.KEY_BIT_RATE, TEST_AUDIO_BIT_RATE);
audioFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
MediaCodec mediaCodec;
try {
mediaCodec = MediaCodec.createEncoderByType(MIME_TYPE_AUDIO);
mediaCodec.configure(audioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
mediaCodec.start();
mediaCodec.stop();
mediaCodec.release();
mediaCodec = null;
} catch (Exception ex) {
Log.e(TAG, "Failed on creation of codec #", ex);
return CODEC_ERROR;
}
return CODEC_SUPPORTED;
}
/**
* Creates an encoder for the given format using the specified codec, taking input from a
* surface.
*
* <p>The surface to use as input is stored in the given reference.
*
* @param codecName of the codec to use
* @param format of the stream to be produced
* @param surfaceReference to store the surface to use as input
*/
private MediaCodec createVideoEncoder(
String codecName,
MediaFormat format,
AtomicReference<Surface> surfaceReference) {
try {
MediaCodec encoder = MediaCodec.createByCodecName(codecName);
encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
// Must be called before start() is.
surfaceReference.set(encoder.createInputSurface());
encoder.start();
return encoder;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
protected MediaCodec createMediaCodec() throws IOException {
MediaFormat format = MediaFormat.createVideoFormat(mMimeType, 0, 0);
if (mCsd0 != null) {
format.setByteBuffer("csd-0", mCsd0);
}
if (mCsd1 != null) {
format.setByteBuffer("csd-1", mCsd1);
}
MediaCodec mediaCodec = MediaCodec.createDecoderByType(mMimeType);
mediaCodec.configure(format, getSurface(), null, 0);
mediaCodec.setVideoScalingMode(MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
mediaCodec.start();
return mediaCodec;
}
@TargetApi(MIN_API_LEVEL_VIDEO)
public static int checkMediaCodecVideoEncoderSupport(){
if(getApiLevel()<MIN_API_LEVEL_VIDEO){
Log.d(TAG, "checkMediaCodecVideoEncoderSupport: Min API is 18");
return CODEC_REQ_API_NOT_SATISFIED;
}
MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE_VIDEO, TEST_WIDTH, TEST_HEIGHT);
format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
format.setInteger(MediaFormat.KEY_BIT_RATE, TEST_VIDEO_BIT_RATE);
format.setInteger(MediaFormat.KEY_FRAME_RATE, TEST_FRAME_RATE);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, TEST_IFRAME_INTERVAL);
MediaCodec mediaCodec;
try {
mediaCodec = MediaCodec.createEncoderByType(MIME_TYPE_VIDEO);
mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
mediaCodec.createInputSurface();
mediaCodec.start();
mediaCodec.stop();
mediaCodec.release();
mediaCodec = null;
} catch (Exception ex) {
Log.e(TAG, "Failed on creation of codec #", ex);
return CODEC_ERROR;
}
return CODEC_SUPPORTED;
}
private @NonNull
MediaCodec createVideoDecoder(
final @NonNull MediaFormat inputFormat,
final @NonNull Surface surface) throws IOException {
final MediaCodec decoder = MediaCodec.createDecoderByType(MediaConverter.getMimeTypeFor(inputFormat));
decoder.configure(inputFormat, surface, null, 0);
decoder.start();
return decoder;
}
private @NonNull
MediaCodec createVideoEncoder(
final @NonNull MediaCodecInfo codecInfo,
final @NonNull MediaFormat format,
final @NonNull AtomicReference<Surface> surfaceReference) throws IOException {
final MediaCodec encoder = MediaCodec.createByCodecName(codecInfo.getName());
encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
// Must be called before start()
surfaceReference.set(encoder.createInputSurface());
encoder.start();
return encoder;
}
private static @NonNull
MediaCodec createAudioDecoder(final @NonNull MediaFormat inputFormat) throws IOException {
final MediaCodec decoder = MediaCodec.createDecoderByType(MediaConverter.getMimeTypeFor(inputFormat));
decoder.configure(inputFormat, null, null, 0);
decoder.start();
return decoder;
}
@Override
public void run() {
MediaFormat format = MediaFormat.createVideoFormat("video/avc",
mWidth, mHeight);
format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
format.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);
format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL,
I_FRAME_INTERVAL);
MediaCodec codec = MediaCodec.createEncoderByType("video/avc");
codec.configure(format, null, null,
MediaCodec.CONFIGURE_FLAG_ENCODE);
Surface surface = codec.createInputSurface();
codec.start();
VirtualDisplay virtualDisplay = mDisplayManager
.createVirtualDisplay(DISPLAY_NAME, mWidth, mHeight,
mDensityDpi, surface,
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC);
if (virtualDisplay != null) {
stream(codec);
virtualDisplay.release();
}
codec.signalEndOfInputStream();
codec.stop();
}
@Override
protected MediaCodec createMediaCodec() throws IOException {
parseSps();
MediaFormat format = MediaFormat.createVideoFormat(mMimeType, mWidth, mHeight);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {
format.setInteger(MediaFormat.KEY_COLOR_RANGE, MediaFormat.COLOR_RANGE_FULL);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
format.setInteger(MediaFormat.KEY_OPERATING_RATE, Short.MAX_VALUE);
}
ByteBuffer csd0 = ByteBuffer.allocateDirect(mVPS.length + mSPS.length + mPPS.length);
csd0.put(mVPS);
csd0.position(mVPS.length);
csd0.put(mSPS);
csd0.position(mVPS.length + mSPS.length);
csd0.put(mPPS);
format.setByteBuffer("csd-0", csd0);
if (DEBUG) {
Log.d(TAG, "H265Decoder::createMediaCodec: " + format);
}
MediaCodec mediaCodec = MediaCodec.createDecoderByType(mMimeType);
mediaCodec.configure(format, getSurface(), null, 0);
mediaCodec.setVideoScalingMode(MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT);
mediaCodec.start();
return mediaCodec;
}
/**
* Creates a decoder for the given format, which outputs to the given surface.
*
* @param inputFormat the format of the stream to decode
* @param surface into which to decode the frames
*/
private MediaCodec createVideoDecoder(
MediaCodecList mcl, MediaFormat inputFormat, Surface surface){
try {
MediaCodec decoder = MediaCodec.createByCodecName(mcl.findDecoderForFormat(inputFormat));
decoder.configure(inputFormat, surface, null, 0);
decoder.start();
return decoder;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* Creates a decoder for the given format.
*
* @param inputFormat the format of the stream to decode
*/
private MediaCodec createAudioDecoder(
MediaCodecList mcl, MediaFormat inputFormat) {
try {
MediaCodec decoder = MediaCodec.createByCodecName("OMX.google.aac.decoder");//mcl.findDecoderForFormat(inputFormat));
decoder.configure(inputFormat, null, null, 0);
decoder.start();
return decoder;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* MediaCodec を作成します.
*
* @return MediaCodec
* @throws IOException MediaCodec の作成に失敗した場合に発生
*/
private MediaCodec createMediaCodec() throws IOException {
MediaFormat format = MediaFormat.createAudioFormat("audio/mp4a-latm",
getSamplingRate(), getChannelCount());
format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
int audioProfile = MediaCodecInfo.CodecProfileLevel.AACObjectLC;
int sampleIndex = getFreqIdx(getSamplingRate());
int channelConfig = getChannelCount();
ByteBuffer csd = ByteBuffer.allocateDirect(2);
csd.put((byte) ((audioProfile << 3) | (sampleIndex >> 1)));
csd.position(1);
csd.put((byte) ((byte) ((sampleIndex << 7) & 0x80) | (channelConfig << 3)));
csd.flip();
format.setByteBuffer("csd-0", csd);
if (DEBUG) {
Log.d(TAG, "AACDecoder::createMediaCodec: " + format);
}
MediaCodec mediaCodec = MediaCodec.createDecoderByType("audio/mp4a-latm");
mediaCodec.configure(format, null, null, 0);
mediaCodec.start();
return mediaCodec;
}
private MediaCodecWrapper(MediaCodec codec) {
mDecoder = codec;
codec.start();
mInputBuffers = codec.getInputBuffers();
mOutputBuffers = codec.getOutputBuffers();
mOutputBufferInfo = new MediaCodec.BufferInfo[mOutputBuffers.length];
mAvailableInputBuffers = new ArrayDeque<Integer>(mOutputBuffers.length);
mAvailableOutputBuffers = new ArrayDeque<Integer>(mInputBuffers.length);
}
private MediaCodecWrapper(MediaCodec codec) {
mDecoder = codec;
codec.start();
mInputBuffers = codec.getInputBuffers();
mOutputBuffers = codec.getOutputBuffers();
mOutputBufferInfo = new MediaCodec.BufferInfo[mOutputBuffers.length];
mAvailableInputBuffers = new ArrayDeque<>(mOutputBuffers.length);
mAvailableOutputBuffers = new ArrayDeque<>(mInputBuffers.length);
}
@TargetApi(MIN_API_LEVEL_VIDEO)
public static int checkMediaCodecVideoEncoderSupport(){
if(getApiLevel()<MIN_API_LEVEL_VIDEO){
Log.d(TAG, "checkMediaCodecVideoEncoderSupport: Min API is 18");
return CODEC_REQ_API_NOT_SATISFIED;
}
MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE_VIDEO, TEST_WIDTH, TEST_HEIGHT);
format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
format.setInteger(MediaFormat.KEY_BIT_RATE, TEST_VIDEO_BIT_RATE);
format.setInteger(MediaFormat.KEY_FRAME_RATE, TEST_FRAME_RATE);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, TEST_IFRAME_INTERVAL);
MediaCodec mediaCodec;
try {
mediaCodec = MediaCodec.createEncoderByType(MIME_TYPE_VIDEO);
mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
mediaCodec.createInputSurface();
mediaCodec.start();
mediaCodec.stop();
mediaCodec.release();
mediaCodec = null;
} catch (Exception ex) {
Log.e(TAG, "Failed on creation of codec #", ex);
return CODEC_ERROR;
}
return CODEC_SUPPORTED;
}
private void feedClipToEncoder( SamplerClip clip ) {
mLastSampleTime = 0;
MediaCodec decoder = null;
MediaExtractor extractor = setupExtractorForClip(clip);
if(extractor == null ) {
return;
}
int trackIndex = getVideoTrackIndex(extractor);
extractor.selectTrack( trackIndex );
MediaFormat clipFormat = extractor.getTrackFormat( trackIndex );
if ( clip.getStartTime() != -1 ) {
extractor.seekTo( clip.getStartTime() * 1000, MediaExtractor.SEEK_TO_PREVIOUS_SYNC );
clip.setStartTime( extractor.getSampleTime() / 1000 );
}
try {
decoder = MediaCodec.createDecoderByType( MediaHelper.MIME_TYPE_AVC );
mOutputSurface = new OutputSurface();
decoder.configure( clipFormat, mOutputSurface.getSurface(), null, 0 );
decoder.start();
resampleVideo( extractor, decoder, clip );
} finally {
if ( mOutputSurface != null ) {
mOutputSurface.release();
}
if ( decoder != null ) {
decoder.stop();
decoder.release();
}
if ( extractor != null ) {
extractor.release();
extractor = null;
}
}
}
/**
* 需要改变音频速率的情况下,需要先解码->改变速率->编码
*/
public static void decodeToPCM(VideoProcessor.MediaSource audioSource, String outPath, Integer startTimeUs, Integer endTimeUs) throws IOException {
MediaExtractor extractor = new MediaExtractor();
audioSource.setDataSource(extractor);
int audioTrack = VideoUtil.selectTrack(extractor, true);
extractor.selectTrack(audioTrack);
if (startTimeUs == null) {
startTimeUs = 0;
}
extractor.seekTo(startTimeUs, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
MediaFormat oriAudioFormat = extractor.getTrackFormat(audioTrack);
int maxBufferSize;
if (oriAudioFormat.containsKey(MediaFormat.KEY_MAX_INPUT_SIZE)) {
maxBufferSize = oriAudioFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
} else {
maxBufferSize = 100 * 1000;
}
ByteBuffer buffer = ByteBuffer.allocateDirect(maxBufferSize);
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
//调整音频速率需要重解码音频帧
MediaCodec decoder = MediaCodec.createDecoderByType(oriAudioFormat.getString(MediaFormat.KEY_MIME));
decoder.configure(oriAudioFormat, null, null, 0);
decoder.start();
boolean decodeDone = false;
boolean decodeInputDone = false;
final int TIMEOUT_US = 2500;
File pcmFile = new File(outPath);
FileChannel writeChannel = new FileOutputStream(pcmFile).getChannel();
try {
while (!decodeDone) {
if (!decodeInputDone) {
boolean eof = false;
int decodeInputIndex = decoder.dequeueInputBuffer(TIMEOUT_US);
if (decodeInputIndex >= 0) {
long sampleTimeUs = extractor.getSampleTime();
if (sampleTimeUs == -1) {
eof = true;
} else if (sampleTimeUs < startTimeUs) {
extractor.advance();
continue;
} else if (endTimeUs != null && sampleTimeUs > endTimeUs) {
eof = true;
}
if (eof) {
decodeInputDone = true;
decoder.queueInputBuffer(decodeInputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
} else {
info.size = extractor.readSampleData(buffer, 0);
info.presentationTimeUs = sampleTimeUs;
info.flags = extractor.getSampleFlags();
ByteBuffer inputBuffer = decoder.getInputBuffer(decodeInputIndex);
inputBuffer.put(buffer);
CL.it(TAG, "audio decode queueInputBuffer " + info.presentationTimeUs / 1000);
decoder.queueInputBuffer(decodeInputIndex, 0, info.size, info.presentationTimeUs, info.flags);
extractor.advance();
}
}
}
while (!decodeDone) {
int outputBufferIndex = decoder.dequeueOutputBuffer(info, TIMEOUT_US);
if (outputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
break;
} else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
MediaFormat newFormat = decoder.getOutputFormat();
CL.it(TAG, "audio decode newFormat = " + newFormat);
} else if (outputBufferIndex < 0) {
//ignore
CL.et(TAG, "unexpected result from audio decoder.dequeueOutputBuffer: " + outputBufferIndex);
} else {
if (info.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) {
decodeDone = true;
} else {
ByteBuffer decodeOutputBuffer = decoder.getOutputBuffer(outputBufferIndex);
CL.it(TAG, "audio decode saveFrame " + info.presentationTimeUs / 1000);
writeChannel.write(decodeOutputBuffer);
}
decoder.releaseOutputBuffer(outputBufferIndex, false);
}
}
}
} finally {
writeChannel.close();
extractor.release();
decoder.stop();
decoder.release();
}
}
/**
* Reads bytes from the given recorder and encodes them with the given encoder.
* Uses the (deprecated) Synchronous Processing using Buffer Arrays.
* <p/>
* Encoders (or codecs that generate compressed data) will create and return the codec specific
* data before any valid output buffer in output buffers marked with the codec-config flag.
* Buffers containing codec-specific-data have no meaningful timestamps.
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void recorderEncoderLoop(MediaCodec codec, SpeechRecord speechRecord) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
codec.start();
// Getting some buffers (e.g. 4 of each) to communicate with the codec
ByteBuffer[] codecInputBuffers = codec.getInputBuffers();
ByteBuffer[] codecOutputBuffers = codec.getOutputBuffers();
Log.i("input buffers " + codecInputBuffers.length + "; output buffers: " + codecOutputBuffers.length);
boolean doneSubmittingInput = false;
int numRetriesDequeueOutputBuffer = 0;
int index;
while (true) {
if (!doneSubmittingInput) {
index = codec.dequeueInputBuffer(DEQUEUE_TIMEOUT);
if (index >= 0) {
int size = queueInputBuffer(codec, codecInputBuffers, index, speechRecord);
if (size == -1) {
codec.queueInputBuffer(index, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
Log.i("enc: in: EOS");
doneSubmittingInput = true;
} else {
Log.i("enc: in: " + size);
mNumBytesSubmitted += size;
}
} else {
Log.i("enc: in: timeout, will try again");
}
}
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
index = codec.dequeueOutputBuffer(info, DEQUEUE_TIMEOUT);
Log.i("enc: out: flags/index: " + info.flags + "/" + index);
if (index == MediaCodec.INFO_TRY_AGAIN_LATER) {
Log.i("enc: out: INFO_TRY_AGAIN_LATER: " + numRetriesDequeueOutputBuffer);
if (++numRetriesDequeueOutputBuffer > MAX_NUM_RETRIES_DEQUEUE_OUTPUT_BUFFER) {
break;
}
} else if (index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
MediaFormat format = codec.getOutputFormat();
Log.i("enc: out: INFO_OUTPUT_FORMAT_CHANGED: " + format.toString());
} else if (index == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
codecOutputBuffers = codec.getOutputBuffers();
Log.i("enc: out: INFO_OUTPUT_BUFFERS_CHANGED");
} else {
dequeueOutputBuffer(codec, codecOutputBuffers, index, info);
mNumBytesDequeued += info.size;
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
Log.i("enc: out: EOS");
break;
}
}
}
codec.stop();
codec.release();
}
}
/**
* Generates a test video file, saving it as VideoChunks. We generate frames with GL to
* avoid having to deal with multiple YUV formats.
*
* @return true on success, false on "soft" failure
*/
private boolean generateVideoFile(VideoChunks output) {
if (VERBOSE) Log.d(TAG, "generateVideoFile " + mWidth + "x" + mHeight);
MediaCodec encoder = null;
InputSurface inputSurface = null;
try {
MediaCodecInfo codecInfo = selectCodec(MIME_TYPE);
if (codecInfo == null) {
// Don't fail CTS if they don't have an AVC codec (not here, anyway).
Log.e(TAG, "Unable to find an appropriate codec for " + MIME_TYPE);
return false;
}
if (VERBOSE) Log.d(TAG, "found codec: " + codecInfo.getName());
// We avoid the device-specific limitations on width and height by using values that
// are multiples of 16, which all tested devices seem to be able to handle.
MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, mWidth, mHeight);
// Set some properties. Failing to specify some of these can cause the MediaCodec
// configure() call to throw an unhelpful exception.
format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
format.setInteger(MediaFormat.KEY_BIT_RATE, mBitRate);
format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);
if (VERBOSE) Log.d(TAG, "format: " + format);
output.setMediaFormat(format);
// Create a MediaCodec for the desired codec, then configure it as an encoder with
// our desired properties.
encoder = MediaCodec.createByCodecName(codecInfo.getName());
encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
inputSurface = new InputSurface(encoder.createInputSurface());
inputSurface.makeCurrent();
encoder.start();
generateVideoData(encoder, inputSurface, output);
} finally {
if (encoder != null) {
if (VERBOSE) Log.d(TAG, "releasing encoder");
encoder.stop();
encoder.release();
if (VERBOSE) Log.d(TAG, "released encoder");
}
if (inputSurface != null) {
inputSurface.release();
}
}
return true;
}