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

Unified Diff: media/base/android/ndk_media_codec_bridge.cc

Issue 1472943002: Refactor MediaCodecBridge to add support for NDK APIs (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: add media_codec_util.cc(h) Created 5 years, 1 month 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
Index: media/base/android/ndk_media_codec_bridge.cc
diff --git a/media/base/android/ndk_media_codec_bridge.cc b/media/base/android/ndk_media_codec_bridge.cc
new file mode 100644
index 0000000000000000000000000000000000000000..bb353ebbb27c6f93647ebb0b3546678e16ddc6be
--- /dev/null
+++ b/media/base/android/ndk_media_codec_bridge.cc
@@ -0,0 +1,229 @@
+// Copyright 2015 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.
+
+#include "media/base/android/ndk_media_codec_bridge.h"
+
+#include <media/NdkMediaError.h>
+#include <media/NdkMediaFormat.h>
+
+#include "base/strings/string_util.h"
+#include "media/base/decrypt_config.h"
+
+namespace {
+const char* kMediaFormatKeyCropLeft = "crop-left";
+const char* kMediaFormatKeyCropRight = "crop-right";
+const char* kMediaFormatKeyCropBottom = "crop-bottom";
+const char* kMediaFormatKeyCropTop = "crop-top";
xhwang 2015/11/30 23:11:50 we prefer const array to const pointer. where are
qinmin 2015/12/03 22:46:24 These are hidden keys, but you can check MediaCode
+}
+
+namespace media {
+
+// Translate media_status_t to MediaCodecStatus.
+static MediaCodecStatus TranslateMediaCodecStatus(media_status_t status) {
+ switch (status) {
+ case AMEDIA_OK:
+ return MEDIA_CODEC_OK;
+ case AMEDIA_DRM_NEED_KEY:
+ return MEDIA_CODEC_NO_KEY;
+ default:
+ return MEDIA_CODEC_ERROR;
+ }
+}
+
+NdkMediaCodecBridge::~NdkMediaCodecBridge() {}
+
+NdkMediaCodecBridge::NdkMediaCodecBridge(const std::string& mime,
+ bool is_secure,
+ MediaCodecDirection direction) {
+ if (base::StartsWith(mime, "video", base::CompareCase::SENSITIVE) &&
+ is_secure && direction == MEDIA_CODEC_DECODER) {
+ // TODO(qinmin): get the secure decoder name from java.
+ NOTIMPLEMENTED();
+ return;
+ }
+
+ if (direction == MEDIA_CODEC_DECODER)
+ media_codec_.reset(AMediaCodec_createDecoderByType(mime.c_str()));
+ else
+ media_codec_.reset(AMediaCodec_createEncoderByType(mime.c_str()));
+}
+
+MediaCodecStatus NdkMediaCodecBridge::Reset() {
+ media_status_t status = AMediaCodec_flush(media_codec_.get());
+ return TranslateMediaCodecStatus(status);
+}
+
+bool NdkMediaCodecBridge::Start() {
+ return AMEDIA_OK == AMediaCodec_start(media_codec_.get());
+}
+
+void NdkMediaCodecBridge::Stop() {
+ AMediaCodec_stop(media_codec_.get());
+}
+
+void NdkMediaCodecBridge::GetOutputFormat(int* width, int* height) {
+ AMediaFormat* format = AMediaCodec_getOutputFormat(media_codec_.get());
+ int left, right, bottom, top;
+ bool has_left = AMediaFormat_getInt32(format, kMediaFormatKeyCropLeft, &left);
+ bool has_right =
+ AMediaFormat_getInt32(format, kMediaFormatKeyCropRight, &right);
+ bool has_bottom =
+ AMediaFormat_getInt32(format, kMediaFormatKeyCropBottom, &bottom);
+ bool has_top = AMediaFormat_getInt32(format, kMediaFormatKeyCropTop, &top);
+ if (has_left && has_right && has_bottom && has_top) {
+ *width = right - left + 1;
+ *height = top - bottom + 1;
xhwang 2015/11/30 23:11:50 so "right" and "bottom" are inclusive? maybe worth
qinmin 2015/12/03 22:46:23 Done.
+ } else {
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, width);
xhwang 2015/11/30 23:11:50 Q: Why we can't always use AMEDIAFORMAT_KEY_WIDTH?
qinmin 2015/12/03 22:46:24 It is not as accurate as crop_width, see b/1822476
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, height);
+ }
+}
+
+int NdkMediaCodecBridge::GetOutputSamplingRate() {
+ AMediaFormat* format = AMediaCodec_getOutputFormat(media_codec_.get());
+ int sample_rate;
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &sample_rate);
xhwang 2015/11/30 23:11:50 what if this returns false?
qinmin 2015/12/03 22:46:24 This is a mandatory key, so it should never return
+ return sample_rate;
+}
+
+MediaCodecStatus NdkMediaCodecBridge::QueueInputBuffer(
+ int index,
+ const uint8* data,
+ size_t data_size,
+ const base::TimeDelta& presentation_time) {
+ if (data_size > base::checked_cast<size_t>(kint32max))
+ return MEDIA_CODEC_ERROR;
+ if (data && !FillInputBuffer(index, data, data_size))
+ return MEDIA_CODEC_ERROR;
+
+ media_status_t status =
+ AMediaCodec_queueInputBuffer(media_codec_.get(), index, 0, data_size,
+ presentation_time.InMicroseconds(), 0);
+ return TranslateMediaCodecStatus(status);
+}
+
+MediaCodecStatus NdkMediaCodecBridge::QueueSecureInputBuffer(
+ int index,
+ const uint8* data,
+ size_t data_size,
+ const uint8* key_id,
+ int key_id_size,
+ const uint8* iv,
+ int iv_size,
+ const SubsampleEntry* subsamples,
+ int subsamples_size,
+ const base::TimeDelta& presentation_time) {
+ if (data_size > base::checked_cast<size_t>(kint32max))
+ return MEDIA_CODEC_ERROR;
+ if (key_id_size > 16 || iv_size > 16)
+ return MEDIA_CODEC_ERROR;
+ if (data && !FillInputBuffer(index, data, data_size))
+ return MEDIA_CODEC_ERROR;
+
+ int new_subsamples_size = subsamples_size == 0 ? 1 : subsamples_size;
+ std::vector<size_t> clear_data, encrypted_data;
+ if (subsamples_size == 0) {
+ DCHECK(!subsamples);
+ clear_data.push_back(0);
+ encrypted_data.push_back(data_size);
+ } else {
+ DCHECK_GT(subsamples_size, 0);
+ DCHECK(subsamples);
+ for (int i = 0; i < subsamples_size; ++i) {
+ DCHECK(subsamples[i].clear_bytes <= std::numeric_limits<uint16>::max());
+ if (subsamples[i].cypher_bytes >
+ static_cast<uint32>(std::numeric_limits<int32>::max())) {
+ return MEDIA_CODEC_ERROR;
+ }
+ clear_data.push_back(subsamples[i].clear_bytes);
+ encrypted_data.push_back(subsamples[i].cypher_bytes);
+ }
+ }
+
+ uint8_t key_array[16], iv_array[16];
+ memcpy(key_array, key_id, 16);
+ memcpy(iv_array, iv, 16);
xhwang 2015/11/30 23:11:50 The caller actually has the key and iv as vectors.
qinmin 2015/12/03 22:46:24 Done.
+ AMediaCodecCryptoInfo* crypto_info =
+ AMediaCodecCryptoInfo_new(new_subsamples_size, key_array, iv_array,
+ AMEDIACODECRYPTOINFO_MODE_AES_CTR,
+ clear_data.data(), encrypted_data.data());
+
+ media_status_t status = AMediaCodec_queueSecureInputBuffer(
+ media_codec_.get(), index, 0, crypto_info,
+ presentation_time.InMicroseconds(), 0);
+ return TranslateMediaCodecStatus(status);
+}
+
+void NdkMediaCodecBridge::QueueEOS(int input_buffer_index) {
+ AMediaCodec_queueInputBuffer(media_codec_.get(), input_buffer_index, 0, 0, 0,
+ AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM);
+}
+
+MediaCodecStatus NdkMediaCodecBridge::DequeueInputBuffer(
+ const base::TimeDelta& timeout,
+ int* index) {
+ *index = AMediaCodec_dequeueInputBuffer(media_codec_.get(),
+ timeout.InMicroseconds());
+ if (*index >= 0)
+ return MEDIA_CODEC_OK;
+ else if (*index == AMEDIACODEC_INFO_TRY_AGAIN_LATER)
+ return MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER;
+ else
+ return MEDIA_CODEC_ERROR;
+}
+
+MediaCodecStatus NdkMediaCodecBridge::DequeueOutputBuffer(
+ const base::TimeDelta& timeout,
+ int* index,
+ size_t* offset,
+ size_t* size,
+ base::TimeDelta* presentation_time,
+ bool* end_of_stream,
+ bool* key_frame) {
+ AMediaCodecBufferInfo buffer_info;
+ *index = AMediaCodec_dequeueOutputBuffer(media_codec_.get(), &buffer_info,
+ timeout.InMicroseconds());
+ *offset = buffer_info.offset;
+ *size = buffer_info.size;
+ *presentation_time =
+ base::TimeDelta::FromMicroseconds(buffer_info.presentationTimeUs);
+ if (end_of_stream)
+ *end_of_stream = buffer_info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
+ if (key_frame)
+ *key_frame = false; // This is deprecated.
+ if (*index >= 0)
+ return MEDIA_CODEC_OK;
+ else if (*index == AMEDIACODEC_INFO_TRY_AGAIN_LATER)
+ return MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER;
+ else
+ return MEDIA_CODEC_ERROR;
+}
+
+void NdkMediaCodecBridge::ReleaseOutputBuffer(int index, bool render) {
+ AMediaCodec_releaseOutputBuffer(media_codec_.get(), index, render);
+}
+
+void NdkMediaCodecBridge::GetInputBuffer(int input_buffer_index,
+ uint8** data,
+ size_t* capacity) {
+ *data = AMediaCodec_getInputBuffer(media_codec_.get(), input_buffer_index,
+ capacity);
+}
+
+bool NdkMediaCodecBridge::CopyFromOutputBuffer(int index,
+ size_t offset,
+ void* dst,
+ int dst_size) {
+ size_t capacity;
+ uint8_t* src_data =
+ AMediaCodec_getOutputBuffer(media_codec_.get(), index, &capacity);
+
+ if (capacity < offset || capacity - offset < static_cast<size_t>(dst_size))
+ return false;
+
+ memcpy(dst, src_data + offset, dst_size);
+ return true;
+}
+
+} // namespace media

Powered by Google App Engine
This is Rietveld 408576698