blob: f9a50080bbe11c58004d06c7bf4bc09670ebc986 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.media;
import android.media.MediaCodec;
import android.media.MediaCrypto;
import android.media.MediaFormat;
import android.view.Surface;
import org.chromium.base.Log;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.MainDex;
import org.chromium.media.MediaCodecUtil.CodecCreationInfo;
import org.chromium.media.MediaCodecUtil.MimeTypes;
@JNINamespace("media")
@MainDex
class MediaCodecBridgeBuilder {
private static final String TAG = "MediaCodecBridge";
@CalledByNative
static MediaCodecBridge createVideoDecoder(String mime, @CodecType int codecType,
MediaCrypto mediaCrypto, int width, int height, Surface surface, byte[] csd0,
byte[] csd1, HdrMetadata hdrMetadata, boolean allowAdaptivePlayback,
boolean useAsyncApi) {
CodecCreationInfo info = new CodecCreationInfo();
try {
Log.i(TAG, "create MediaCodec video decoder, mime %s", mime);
info = MediaCodecUtil.createDecoder(mime, codecType, mediaCrypto);
if (info.mediaCodec == null) return null;
MediaCodecBridge bridge =
new MediaCodecBridge(info.mediaCodec, info.bitrateAdjuster, useAsyncApi);
byte[][] csds = {csd0, csd1};
MediaFormat format = MediaFormatBuilder.createVideoDecoderFormat(mime, width, height,
csds, hdrMetadata, info.supportsAdaptivePlayback && allowAdaptivePlayback);
if (!bridge.configureVideo(format, surface, mediaCrypto, 0)) return null;
if (!bridge.start()) {
bridge.release();
return null;
}
return bridge;
} catch (Exception e) {
Log.e(TAG, "Failed to create MediaCodec video decoder: %s, codecType: %d", mime,
codecType, e);
}
return null;
}
@CalledByNative
static MediaCodecBridge createVideoEncoder(String mime, int width, int height, int bitrateMode,
int bitRate, int frameRate, int iFrameInterval, int colorFormat) {
CodecCreationInfo info = new CodecCreationInfo();
try {
Log.i(TAG, "create MediaCodec video encoder, mime %s", mime);
info = MediaCodecUtil.createEncoder(mime);
} catch (Exception e) {
Log.e(TAG, "Failed to create MediaCodec video encoder: %s", mime, e);
}
if (info.mediaCodec == null) return null;
// Create MediaCodecEncoder for H264 to meet WebRTC requirements to IDR/keyframes.
// See https://crbug.com/761336 for more details.
MediaCodecBridge bridge = mime.equals(MimeTypes.VIDEO_H264)
? new MediaCodecEncoder(info.mediaCodec, info.bitrateAdjuster)
: new MediaCodecBridge(info.mediaCodec, info.bitrateAdjuster, false);
MediaFormat format = MediaFormatBuilder.createVideoEncoderFormat(mime, width, height,
bitrateMode, bitRate,
BitrateAdjuster.getInitialFrameRate(info.bitrateAdjuster, frameRate),
iFrameInterval, colorFormat, info.supportsAdaptivePlayback);
if (!bridge.configureVideo(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)) {
return null;
}
if (!bridge.start()) {
bridge.release();
return null;
}
return bridge;
}
@CalledByNative
static MediaCodecBridge createAudioDecoder(String mime, MediaCrypto mediaCrypto, int sampleRate,
int channelCount, byte[] csd0, byte[] csd1, byte[] csd2, boolean frameHasAdtsHeader,
boolean useAsyncApi) {
CodecCreationInfo info = new CodecCreationInfo();
try {
Log.i(TAG, "create MediaCodec audio decoder, mime %s", mime);
info = MediaCodecUtil.createDecoder(mime, CodecType.ANY, mediaCrypto);
} catch (Exception e) {
Log.e(TAG, "Failed to create MediaCodec audio decoder: %s", mime, e);
}
if (info.mediaCodec == null) return null;
MediaCodecBridge bridge =
new MediaCodecBridge(info.mediaCodec, info.bitrateAdjuster, useAsyncApi);
byte[][] csds = {csd0, csd1, csd2};
MediaFormat format = MediaFormatBuilder.createAudioFormat(
mime, sampleRate, channelCount, csds, frameHasAdtsHeader);
if (!bridge.configureAudio(format, mediaCrypto, 0)) return null;
if (!bridge.start()) {
bridge.release();
return null;
}
return bridge;
}
}