Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(552)

Unified Diff: media/base/android/java/src/org/chromium/media/MediaCodecBridge.java

Issue 74563002: AndroidVideoEncodeAccelerator is born! (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « gpu/config/software_rendering_list_json.cc ('k') | media/base/android/media_codec_bridge.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
index ad98a5060cacb41213abe79d9bfeb093f538c959..683d2e796e92b065f70d631afaafd76253c37439 100644
--- a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
+++ b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
@@ -13,12 +13,14 @@ import android.media.MediaCodecList;
import android.media.MediaCrypto;
import android.media.MediaFormat;
import android.os.Build;
+import android.os.Bundle;
import android.util.Log;
import android.view.Surface;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@@ -46,6 +48,10 @@ class MediaCodecBridge {
private static final int MEDIA_CODEC_STOPPED = 8;
private static final int MEDIA_CODEC_ERROR = 9;
+ // Codec direction. Keep this in sync with media_codec_bridge.h.
+ private static final int MEDIA_CODEC_DECODER = 0;
+ private static final int MEDIA_CODEC_ENCODER = 1;
+
// After a flush(), dequeueOutputBuffer() can often produce empty presentation timestamps
// for several frames. As a result, the player may find that the time does not increase
// after decoding a frame. To detect this, we check whether the presentation timestamp from
@@ -84,10 +90,13 @@ class MediaCodecBridge {
private static class CodecInfo {
private final String mCodecType; // e.g. "video/x-vnd.on2.vp8".
private final String mCodecName; // e.g. "OMX.google.vp8.decoder".
+ private final int mDirection;
- private CodecInfo(String codecType, String codecName) {
+ private CodecInfo(String codecType, String codecName,
+ int direction) {
mCodecType = codecType;
mCodecName = codecName;
+ mDirection = direction;
}
@CalledByNative("CodecInfo")
@@ -95,6 +104,9 @@ class MediaCodecBridge {
@CalledByNative("CodecInfo")
private String codecName() { return mCodecName; }
+
+ @CalledByNative("CodecInfo")
+ private int direction() { return mDirection; }
}
private static class DequeueOutputResult {
@@ -139,25 +151,29 @@ class MediaCodecBridge {
*/
@CalledByNative
private static CodecInfo[] getCodecsInfo() {
- Map<String, CodecInfo> CodecInfoMap = new HashMap<String, CodecInfo>();
+ // Return the first (highest-priority) codec for each MIME type.
+ Map<String, CodecInfo> encoderInfoMap = new HashMap<String, CodecInfo>();
+ Map<String, CodecInfo> decoderInfoMap = new HashMap<String, CodecInfo>();
int count = MediaCodecList.getCodecCount();
for (int i = 0; i < count; ++i) {
MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
- if (info.isEncoder()) {
- continue;
- }
-
+ int direction =
+ info.isEncoder() ? MEDIA_CODEC_ENCODER : MEDIA_CODEC_DECODER;
String codecString = info.getName();
String[] supportedTypes = info.getSupportedTypes();
for (int j = 0; j < supportedTypes.length; ++j) {
- if (!CodecInfoMap.containsKey(supportedTypes[j])) {
- CodecInfoMap.put(supportedTypes[j], new CodecInfo(
- supportedTypes[j], codecString));
+ Map<String, CodecInfo> map = info.isEncoder() ? encoderInfoMap : decoderInfoMap;
+ if (!map.containsKey(supportedTypes[j])) {
+ map.put(supportedTypes[j], new CodecInfo(
+ supportedTypes[j], codecString, direction));
}
}
}
- return CodecInfoMap.values().toArray(
- new CodecInfo[CodecInfoMap.size()]);
+ ArrayList<CodecInfo> codecInfos = new ArrayList<CodecInfo>(
+ decoderInfoMap.size() + encoderInfoMap.size());
+ codecInfos.addAll(encoderInfoMap.values());
+ codecInfos.addAll(decoderInfoMap.values());
+ return codecInfos.toArray(new CodecInfo[codecInfos.size()]);
}
private static String getSecureDecoderNameForMime(String mime) {
@@ -187,7 +203,7 @@ class MediaCodecBridge {
}
@CalledByNative
- private static MediaCodecBridge create(String mime, boolean isSecure) {
+ private static MediaCodecBridge create(String mime, boolean isSecure, int direction) {
// Creation of ".secure" codecs sometimes crash instead of throwing exceptions
// on pre-JBMR2 devices.
if (isSecure && Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
@@ -196,14 +212,18 @@ class MediaCodecBridge {
MediaCodec mediaCodec = null;
try {
// |isSecure| only applies to video decoders.
- if (mime.startsWith("video") && isSecure) {
+ if (mime.startsWith("video") && isSecure && direction == MEDIA_CODEC_DECODER) {
mediaCodec = MediaCodec.createByCodecName(getSecureDecoderNameForMime(mime));
} else {
- mediaCodec = MediaCodec.createDecoderByType(mime);
+ if (direction == MEDIA_CODEC_ENCODER) {
+ mediaCodec = MediaCodec.createEncoderByType(mime);
+ } else {
+ mediaCodec = MediaCodec.createDecoderByType(mime);
+ }
}
} catch (Exception e) {
Log.e(TAG, "Failed to create MediaCodec: " + mime + ", isSecure: "
- + isSecure + ", " + e.toString());
+ + isSecure + ", direction: " + direction, e);
}
if (mediaCodec == null) {
@@ -215,7 +235,9 @@ class MediaCodecBridge {
@CalledByNative
private void release() {
+ mMediaCodec.stop();
mMediaCodec.release();
+ mMediaCodec = null;
if (mAudioTrack != null) {
mAudioTrack.release();
}
@@ -227,7 +249,7 @@ class MediaCodecBridge {
mMediaCodec.start();
mInputBuffers = mMediaCodec.getInputBuffers();
} catch (IllegalStateException e) {
- Log.e(TAG, "Cannot start the media codec " + e.toString());
+ Log.e(TAG, "Cannot start the media codec", e);
return false;
}
return true;
@@ -246,10 +268,11 @@ class MediaCodecBridge {
Log.e(TAG, "dequeueInputBuffer: MediaCodec.INFO_TRY_AGAIN_LATER");
status = MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER;
} else {
+ Log.e(TAG, "Unexpected index_or_status: " + index_or_status);
assert(false);
}
} catch(Exception e) {
- Log.e(TAG, "Failed to dequeue input buffer: " + e.toString());
+ Log.e(TAG, "Failed to dequeue input buffer", e);
}
return new DequeueInputResult(status, index);
}
@@ -263,7 +286,7 @@ class MediaCodecBridge {
}
mMediaCodec.flush();
} catch(IllegalStateException e) {
- Log.e(TAG, "Failed to flush MediaCodec " + e.toString());
+ Log.e(TAG, "Failed to flush MediaCodec", e);
return MEDIA_CODEC_ERROR;
}
return MEDIA_CODEC_OK;
@@ -298,19 +321,59 @@ class MediaCodecBridge {
}
@CalledByNative
+ private int getInputBuffersCount() {
+ return mInputBuffers.length;
+ }
+
+ @CalledByNative
+ private int getOutputBuffersCount() {
+ return mOutputBuffers != null ? mOutputBuffers.length : -1;
+ }
+
+ @CalledByNative
+ private int getOutputBuffersCapacity() {
+ return mOutputBuffers != null ? mOutputBuffers[0].capacity() : -1;
+ }
+
+ @CalledByNative
+ private boolean getOutputBuffers() {
+ try {
+ mOutputBuffers = mMediaCodec.getOutputBuffers();
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Cannot get output buffers", e);
+ return false;
+ }
+ return true;
+ }
+
+ @CalledByNative
private int queueInputBuffer(
int index, int offset, int size, long presentationTimeUs, int flags) {
resetLastPresentationTimeIfNeeded(presentationTimeUs);
try {
mMediaCodec.queueInputBuffer(index, offset, size, presentationTimeUs, flags);
} catch(Exception e) {
- Log.e(TAG, "Failed to queue input buffer: " + e.toString());
+ Log.e(TAG, "Failed to queue input buffer", e);
return MEDIA_CODEC_ERROR;
}
return MEDIA_CODEC_OK;
}
@CalledByNative
+ private void setVideoBitrate(int bps) {
+ Bundle b = new Bundle();
+ b.putInt(MediaCodec.PARAMETER_KEY_VIDEO_BITRATE, bps);
+ mMediaCodec.setParameters(b);
+ }
+
+ @CalledByNative
+ private void requestKeyFrameSoon() {
+ Bundle b = new Bundle();
+ b.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
+ mMediaCodec.setParameters(b);
+ }
+
+ @CalledByNative
private int queueSecureInputBuffer(
int index, int offset, byte[] iv, byte[] keyId, int[] numBytesOfClearData,
int[] numBytesOfEncryptedData, int numSubSamples, long presentationTimeUs) {
@@ -321,7 +384,7 @@ class MediaCodecBridge {
keyId, iv, MediaCodec.CRYPTO_MODE_AES_CTR);
mMediaCodec.queueSecureInputBuffer(index, offset, cryptoInfo, presentationTimeUs, 0);
} catch (MediaCodec.CryptoException e) {
- Log.e(TAG, "Failed to queue secure input buffer: " + e.toString());
+ Log.e(TAG, "Failed to queue secure input buffer", e);
if (e.getErrorCode() == MediaCodec.CryptoException.ERROR_NO_KEY) {
Log.e(TAG, "MediaCodec.CryptoException.ERROR_NO_KEY");
return MEDIA_CODEC_NO_KEY;
@@ -329,7 +392,7 @@ class MediaCodecBridge {
Log.e(TAG, "MediaCodec.CryptoException with error code " + e.getErrorCode());
return MEDIA_CODEC_ERROR;
} catch(IllegalStateException e) {
- Log.e(TAG, "Failed to queue secure input buffer: " + e.toString());
+ Log.e(TAG, "Failed to queue secure input buffer", e);
return MEDIA_CODEC_ERROR;
}
return MEDIA_CODEC_OK;
@@ -341,17 +404,6 @@ class MediaCodecBridge {
}
@CalledByNative
- private boolean getOutputBuffers() {
- try {
- mOutputBuffers = mMediaCodec.getOutputBuffers();
- } catch (IllegalStateException e) {
- Log.e(TAG, "Cannot get output buffers " + e.toString());
- return false;
- }
- return true;
- }
-
- @CalledByNative
private DequeueOutputResult dequeueOutputBuffer(long timeoutUs) {
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
int status = MEDIA_CODEC_ERROR;
@@ -376,10 +428,11 @@ class MediaCodecBridge {
} else if (index_or_status == MediaCodec.INFO_TRY_AGAIN_LATER) {
status = MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER;
} else {
+ Log.e(TAG, "Unexpected index_or_status: " + index_or_status);
assert(false);
}
} catch (IllegalStateException e) {
- Log.e(TAG, "Failed to dequeue output buffer: " + e.toString());
+ Log.e(TAG, "Failed to dequeue output buffer", e);
}
return new DequeueOutputResult(
@@ -393,7 +446,7 @@ class MediaCodecBridge {
mMediaCodec.configure(format, surface, crypto, flags);
return true;
} catch (IllegalStateException e) {
- Log.e(TAG, "Cannot configure the video codec " + e.toString());
+ Log.e(TAG, "Cannot configure the video codec", e);
}
return false;
}
@@ -404,11 +457,22 @@ class MediaCodecBridge {
}
@CalledByNative
- private static MediaFormat createVideoFormat(String mime, int width, int height) {
+ private static MediaFormat createVideoDecoderFormat(String mime, int width, int height) {
return MediaFormat.createVideoFormat(mime, width, height);
}
@CalledByNative
+ private static MediaFormat createVideoEncoderFormat(String mime, int width, int height,
+ int bitRate, int frameRate, int iFrameInterval, int colorFormat) {
+ MediaFormat format = MediaFormat.createVideoFormat(mime, width, height);
+ format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
+ format.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
+ format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, iFrameInterval);
+ format.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
+ return format;
+ }
+
+ @CalledByNative
private static void setCodecSpecificData(MediaFormat format, int index, byte[] bytes) {
String name = null;
if (index == 0) {
@@ -445,7 +509,7 @@ class MediaCodecBridge {
}
return true;
} catch (IllegalStateException e) {
- Log.e(TAG, "Cannot configure the audio codec " + e.toString());
+ Log.e(TAG, "Cannot configure the audio codec", e);
}
return false;
}
« no previous file with comments | « gpu/config/software_rendering_list_json.cc ('k') | media/base/android/media_codec_bridge.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698