| 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..b8c5fc1bf5cde36ddea530d21010a6d601e22277
|
| --- /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";
|
| +}
|
| +
|
| +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);
|
| +}
|
| +
|
| +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;
|
| + } else {
|
| + AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, width);
|
| + 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);
|
| + 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);
|
| + 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;
|
| +}
|
| +
|
| +bool NdkMediaCodecBridge::StartInternal() {
|
| + return AMEDIA_OK == AMediaCodec_start(media_codec_.get());
|
| +}
|
| +
|
| +} // namespace media
|
|
|