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

Unified Diff: talk/app/webrtc/java/jni/androidmediadecoder_jni.cc

Issue 1610243002: Move talk/app/webrtc to webrtc/api (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Removed processing of api.gyp for Chromium builds Created 4 years, 10 months 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: talk/app/webrtc/java/jni/androidmediadecoder_jni.cc
diff --git a/talk/app/webrtc/java/jni/androidmediadecoder_jni.cc b/talk/app/webrtc/java/jni/androidmediadecoder_jni.cc
deleted file mode 100644
index a462b6c70d23c0014258e8cb6d933369961d0c91..0000000000000000000000000000000000000000
--- a/talk/app/webrtc/java/jni/androidmediadecoder_jni.cc
+++ /dev/null
@@ -1,944 +0,0 @@
-/*
- * libjingle
- * Copyright 2015 Google Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <algorithm>
-#include <vector>
-
-#include "talk/app/webrtc/java/jni/androidmediadecoder_jni.h"
-// NOTICE: androidmediadecoder_jni.h must be included before
-// androidmediacodeccommon.h to avoid build errors.
-#include "talk/app/webrtc/java/jni/androidmediacodeccommon.h"
-#include "talk/app/webrtc/java/jni/classreferenceholder.h"
-#include "talk/app/webrtc/java/jni/native_handle_impl.h"
-#include "talk/app/webrtc/java/jni/surfacetexturehelper_jni.h"
-#include "third_party/libyuv/include/libyuv/convert.h"
-#include "third_party/libyuv/include/libyuv/convert_from.h"
-#include "third_party/libyuv/include/libyuv/video_common.h"
-#include "webrtc/base/bind.h"
-#include "webrtc/base/checks.h"
-#include "webrtc/base/logging.h"
-#include "webrtc/base/scoped_ref_ptr.h"
-#include "webrtc/base/thread.h"
-#include "webrtc/base/timeutils.h"
-#include "webrtc/common_video/include/i420_buffer_pool.h"
-#include "webrtc/modules/video_coding/include/video_codec_interface.h"
-#include "webrtc/system_wrappers/include/logcat_trace_context.h"
-#include "webrtc/system_wrappers/include/tick_util.h"
-
-using rtc::Bind;
-using rtc::Thread;
-using rtc::ThreadManager;
-using rtc::scoped_ptr;
-
-using webrtc::CodecSpecificInfo;
-using webrtc::DecodedImageCallback;
-using webrtc::EncodedImage;
-using webrtc::VideoFrame;
-using webrtc::RTPFragmentationHeader;
-using webrtc::TickTime;
-using webrtc::VideoCodec;
-using webrtc::VideoCodecType;
-using webrtc::kVideoCodecH264;
-using webrtc::kVideoCodecVP8;
-using webrtc::kVideoCodecVP9;
-
-namespace webrtc_jni {
-
-// Logging macros.
-#define TAG_DECODER "MediaCodecVideoDecoder"
-#ifdef TRACK_BUFFER_TIMING
-#define ALOGV(...)
- __android_log_print(ANDROID_LOG_VERBOSE, TAG_DECODER, __VA_ARGS__)
-#else
-#define ALOGV(...)
-#endif
-#define ALOGD LOG_TAG(rtc::LS_INFO, TAG_DECODER)
-#define ALOGW LOG_TAG(rtc::LS_WARNING, TAG_DECODER)
-#define ALOGE LOG_TAG(rtc::LS_ERROR, TAG_DECODER)
-
-enum { kMaxWarningLogFrames = 2 };
-
-class MediaCodecVideoDecoder : public webrtc::VideoDecoder,
- public rtc::MessageHandler {
- public:
- explicit MediaCodecVideoDecoder(
- JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context);
- virtual ~MediaCodecVideoDecoder();
-
- int32_t InitDecode(const VideoCodec* codecSettings, int32_t numberOfCores)
- override;
-
- int32_t Decode(
- const EncodedImage& inputImage, bool missingFrames,
- const RTPFragmentationHeader* fragmentation,
- const CodecSpecificInfo* codecSpecificInfo = NULL,
- int64_t renderTimeMs = -1) override;
-
- int32_t RegisterDecodeCompleteCallback(DecodedImageCallback* callback)
- override;
-
- int32_t Release() override;
-
- bool PrefersLateDecoding() const override { return true; }
-
- // rtc::MessageHandler implementation.
- void OnMessage(rtc::Message* msg) override;
-
- const char* ImplementationName() const override;
-
- private:
- // CHECK-fail if not running on |codec_thread_|.
- void CheckOnCodecThread();
-
- int32_t InitDecodeOnCodecThread();
- int32_t ReleaseOnCodecThread();
- int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
- // Deliver any outputs pending in the MediaCodec to our |callback_| and return
- // true on success.
- bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us);
- int32_t ProcessHWErrorOnCodecThread();
- void EnableFrameLogOnWarning();
-
- // Type of video codec.
- VideoCodecType codecType_;
-
- // Render EGL context - owned by factory, should not be allocated/destroyed
- // by VideoDecoder.
- jobject render_egl_context_;
-
- bool key_frame_required_;
- bool inited_;
- bool sw_fallback_required_;
- bool use_surface_;
- VideoCodec codec_;
- webrtc::I420BufferPool decoded_frame_pool_;
- rtc::scoped_refptr<SurfaceTextureHelper> surface_texture_helper_;
- DecodedImageCallback* callback_;
- int frames_received_; // Number of frames received by decoder.
- int frames_decoded_; // Number of frames decoded by decoder.
- // Number of decoded frames for which log information is displayed.
- int frames_decoded_logged_;
- int64_t start_time_ms_; // Start time for statistics.
- int current_frames_; // Number of frames in the current statistics interval.
- int current_bytes_; // Encoded bytes in the current statistics interval.
- int current_decoding_time_ms_; // Overall decoding time in the current second
- int current_delay_time_ms_; // Overall delay time in the current second.
- uint32_t max_pending_frames_; // Maximum number of pending input frames.
-
- // State that is constant for the lifetime of this object once the ctor
- // returns.
- scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
- ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_;
- ScopedGlobalRef<jobject> j_media_codec_video_decoder_;
- jmethodID j_init_decode_method_;
- jmethodID j_release_method_;
- jmethodID j_dequeue_input_buffer_method_;
- jmethodID j_queue_input_buffer_method_;
- jmethodID j_dequeue_byte_buffer_method_;
- jmethodID j_dequeue_texture_buffer_method_;
- jmethodID j_return_decoded_byte_buffer_method_;
- // MediaCodecVideoDecoder fields.
- jfieldID j_input_buffers_field_;
- jfieldID j_output_buffers_field_;
- jfieldID j_color_format_field_;
- jfieldID j_width_field_;
- jfieldID j_height_field_;
- jfieldID j_stride_field_;
- jfieldID j_slice_height_field_;
- // MediaCodecVideoDecoder.DecodedTextureBuffer fields.
- jfieldID j_texture_id_field_;
- jfieldID j_transform_matrix_field_;
- jfieldID j_texture_presentation_timestamp_ms_field_;
- jfieldID j_texture_timestamp_ms_field_;
- jfieldID j_texture_ntp_timestamp_ms_field_;
- jfieldID j_texture_decode_time_ms_field_;
- jfieldID j_texture_frame_delay_ms_field_;
- // MediaCodecVideoDecoder.DecodedOutputBuffer fields.
- jfieldID j_info_index_field_;
- jfieldID j_info_offset_field_;
- jfieldID j_info_size_field_;
- jfieldID j_presentation_timestamp_ms_field_;
- jfieldID j_timestamp_ms_field_;
- jfieldID j_ntp_timestamp_ms_field_;
- jfieldID j_byte_buffer_decode_time_ms_field_;
-
- // Global references; must be deleted in Release().
- std::vector<jobject> input_buffers_;
-};
-
-MediaCodecVideoDecoder::MediaCodecVideoDecoder(
- JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context) :
- codecType_(codecType),
- render_egl_context_(render_egl_context),
- key_frame_required_(true),
- inited_(false),
- sw_fallback_required_(false),
- codec_thread_(new Thread()),
- j_media_codec_video_decoder_class_(
- jni,
- FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
- j_media_codec_video_decoder_(
- jni,
- jni->NewObject(*j_media_codec_video_decoder_class_,
- GetMethodID(jni,
- *j_media_codec_video_decoder_class_,
- "<init>",
- "()V"))) {
- ScopedLocalRefFrame local_ref_frame(jni);
- codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
- RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
-
- j_init_decode_method_ = GetMethodID(
- jni, *j_media_codec_video_decoder_class_, "initDecode",
- "(Lorg/webrtc/MediaCodecVideoDecoder$VideoCodecType;"
- "IILorg/webrtc/SurfaceTextureHelper;)Z");
- j_release_method_ =
- GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
- j_dequeue_input_buffer_method_ = GetMethodID(
- jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
- j_queue_input_buffer_method_ = GetMethodID(
- jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJJJ)Z");
- j_dequeue_byte_buffer_method_ = GetMethodID(
- jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer",
- "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer;");
- j_dequeue_texture_buffer_method_ = GetMethodID(
- jni, *j_media_codec_video_decoder_class_, "dequeueTextureBuffer",
- "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer;");
- j_return_decoded_byte_buffer_method_ =
- GetMethodID(jni, *j_media_codec_video_decoder_class_,
- "returnDecodedOutputBuffer", "(I)V");
-
- j_input_buffers_field_ = GetFieldID(
- jni, *j_media_codec_video_decoder_class_,
- "inputBuffers", "[Ljava/nio/ByteBuffer;");
- j_output_buffers_field_ = GetFieldID(
- jni, *j_media_codec_video_decoder_class_,
- "outputBuffers", "[Ljava/nio/ByteBuffer;");
- j_color_format_field_ = GetFieldID(
- jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
- j_width_field_ = GetFieldID(
- jni, *j_media_codec_video_decoder_class_, "width", "I");
- j_height_field_ = GetFieldID(
- jni, *j_media_codec_video_decoder_class_, "height", "I");
- j_stride_field_ = GetFieldID(
- jni, *j_media_codec_video_decoder_class_, "stride", "I");
- j_slice_height_field_ = GetFieldID(
- jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
-
- jclass j_decoded_texture_buffer_class = FindClass(jni,
- "org/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer");
- j_texture_id_field_ = GetFieldID(
- jni, j_decoded_texture_buffer_class, "textureID", "I");
- j_transform_matrix_field_ = GetFieldID(
- jni, j_decoded_texture_buffer_class, "transformMatrix", "[F");
- j_texture_presentation_timestamp_ms_field_ = GetFieldID(
- jni, j_decoded_texture_buffer_class, "presentationTimeStampMs", "J");
- j_texture_timestamp_ms_field_ = GetFieldID(
- jni, j_decoded_texture_buffer_class, "timeStampMs", "J");
- j_texture_ntp_timestamp_ms_field_ = GetFieldID(
- jni, j_decoded_texture_buffer_class, "ntpTimeStampMs", "J");
- j_texture_decode_time_ms_field_ = GetFieldID(
- jni, j_decoded_texture_buffer_class, "decodeTimeMs", "J");
- j_texture_frame_delay_ms_field_ = GetFieldID(
- jni, j_decoded_texture_buffer_class, "frameDelayMs", "J");
-
- jclass j_decoded_output_buffer_class = FindClass(jni,
- "org/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer");
- j_info_index_field_ = GetFieldID(
- jni, j_decoded_output_buffer_class, "index", "I");
- j_info_offset_field_ = GetFieldID(
- jni, j_decoded_output_buffer_class, "offset", "I");
- j_info_size_field_ = GetFieldID(
- jni, j_decoded_output_buffer_class, "size", "I");
- j_presentation_timestamp_ms_field_ = GetFieldID(
- jni, j_decoded_output_buffer_class, "presentationTimeStampMs", "J");
- j_timestamp_ms_field_ = GetFieldID(
- jni, j_decoded_output_buffer_class, "timeStampMs", "J");
- j_ntp_timestamp_ms_field_ = GetFieldID(
- jni, j_decoded_output_buffer_class, "ntpTimeStampMs", "J");
- j_byte_buffer_decode_time_ms_field_ = GetFieldID(
- jni, j_decoded_output_buffer_class, "decodeTimeMs", "J");
-
- CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed";
- use_surface_ = (render_egl_context_ != NULL);
- ALOGD << "MediaCodecVideoDecoder ctor. Use surface: " << use_surface_;
- memset(&codec_, 0, sizeof(codec_));
- AllowBlockingCalls();
-}
-
-MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
- // Call Release() to ensure no more callbacks to us after we are deleted.
- Release();
-}
-
-int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
- int32_t numberOfCores) {
- ALOGD << "InitDecode.";
- if (inst == NULL) {
- ALOGE << "NULL VideoCodec instance";
- return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
- }
- // Factory should guard against other codecs being used with us.
- RTC_CHECK(inst->codecType == codecType_)
- << "Unsupported codec " << inst->codecType << " for " << codecType_;
-
- if (sw_fallback_required_) {
- ALOGE << "InitDecode() - fallback to SW decoder";
- return WEBRTC_VIDEO_CODEC_OK;
- }
- // Save VideoCodec instance for later.
- if (&codec_ != inst) {
- codec_ = *inst;
- }
- // If maxFramerate is not set then assume 30 fps.
- codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 30;
-
- // Call Java init.
- return codec_thread_->Invoke<int32_t>(
- Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
-}
-
-int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
- CheckOnCodecThread();
- JNIEnv* jni = AttachCurrentThreadIfNeeded();
- ScopedLocalRefFrame local_ref_frame(jni);
- ALOGD << "InitDecodeOnCodecThread Type: " << (int)codecType_ << ". "
- << codec_.width << " x " << codec_.height << ". Fps: " <<
- (int)codec_.maxFramerate;
-
- // Release previous codec first if it was allocated before.
- int ret_val = ReleaseOnCodecThread();
- if (ret_val < 0) {
- ALOGE << "Release failure: " << ret_val << " - fallback to SW codec";
- sw_fallback_required_ = true;
- return WEBRTC_VIDEO_CODEC_ERROR;
- }
-
- // Always start with a complete key frame.
- key_frame_required_ = true;
- frames_received_ = 0;
- frames_decoded_ = 0;
- frames_decoded_logged_ = kMaxDecodedLogFrames;
-
- jobject java_surface_texture_helper_ = nullptr;
- if (use_surface_) {
- java_surface_texture_helper_ = jni->CallStaticObjectMethod(
- FindClass(jni, "org/webrtc/SurfaceTextureHelper"),
- GetStaticMethodID(jni,
- FindClass(jni, "org/webrtc/SurfaceTextureHelper"),
- "create",
- "(Lorg/webrtc/EglBase$Context;)"
- "Lorg/webrtc/SurfaceTextureHelper;"),
- render_egl_context_);
- RTC_CHECK(java_surface_texture_helper_ != nullptr);
- surface_texture_helper_ = new rtc::RefCountedObject<SurfaceTextureHelper>(
- jni, java_surface_texture_helper_);
- }
-
- jobject j_video_codec_enum = JavaEnumFromIndexAndClassName(
- jni, "MediaCodecVideoDecoder$VideoCodecType", codecType_);
- bool success = jni->CallBooleanMethod(
- *j_media_codec_video_decoder_,
- j_init_decode_method_,
- j_video_codec_enum,
- codec_.width,
- codec_.height,
- java_surface_texture_helper_);
- if (CheckException(jni) || !success) {
- ALOGE << "Codec initialization error - fallback to SW codec.";
- sw_fallback_required_ = true;
- return WEBRTC_VIDEO_CODEC_ERROR;
- }
- inited_ = true;
-
- switch (codecType_) {
- case kVideoCodecVP8:
- max_pending_frames_ = kMaxPendingFramesVp8;
- break;
- case kVideoCodecVP9:
- max_pending_frames_ = kMaxPendingFramesVp9;
- break;
- case kVideoCodecH264:
- max_pending_frames_ = kMaxPendingFramesH264;
- break;
- default:
- max_pending_frames_ = 0;
- }
- start_time_ms_ = GetCurrentTimeMs();
- current_frames_ = 0;
- current_bytes_ = 0;
- current_decoding_time_ms_ = 0;
- current_delay_time_ms_ = 0;
-
- jobjectArray input_buffers = (jobjectArray)GetObjectField(
- jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
- size_t num_input_buffers = jni->GetArrayLength(input_buffers);
- ALOGD << "Maximum amount of pending frames: " << max_pending_frames_;
- input_buffers_.resize(num_input_buffers);
- for (size_t i = 0; i < num_input_buffers; ++i) {
- input_buffers_[i] =
- jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
- if (CheckException(jni)) {
- ALOGE << "NewGlobalRef error - fallback to SW codec.";
- sw_fallback_required_ = true;
- return WEBRTC_VIDEO_CODEC_ERROR;
- }
- }
-
- codec_thread_->PostDelayed(kMediaCodecPollMs, this);
-
- return WEBRTC_VIDEO_CODEC_OK;
-}
-
-int32_t MediaCodecVideoDecoder::Release() {
- ALOGD << "DecoderRelease request";
- return codec_thread_->Invoke<int32_t>(
- Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
-}
-
-int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
- if (!inited_) {
- return WEBRTC_VIDEO_CODEC_OK;
- }
- CheckOnCodecThread();
- JNIEnv* jni = AttachCurrentThreadIfNeeded();
- ALOGD << "DecoderReleaseOnCodecThread: Frames received: " <<
- frames_received_ << ". Frames decoded: " << frames_decoded_;
- ScopedLocalRefFrame local_ref_frame(jni);
- for (size_t i = 0; i < input_buffers_.size(); i++) {
- jni->DeleteGlobalRef(input_buffers_[i]);
- }
- input_buffers_.clear();
- jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
- surface_texture_helper_ = nullptr;
- inited_ = false;
- rtc::MessageQueueManager::Clear(this);
- if (CheckException(jni)) {
- ALOGE << "Decoder release exception";
- return WEBRTC_VIDEO_CODEC_ERROR;
- }
- ALOGD << "DecoderReleaseOnCodecThread done";
- return WEBRTC_VIDEO_CODEC_OK;
-}
-
-void MediaCodecVideoDecoder::CheckOnCodecThread() {
- RTC_CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
- << "Running on wrong thread!";
-}
-
-void MediaCodecVideoDecoder::EnableFrameLogOnWarning() {
- // Log next 2 output frames.
- frames_decoded_logged_ = std::max(
- frames_decoded_logged_, frames_decoded_ + kMaxWarningLogFrames);
-}
-
-int32_t MediaCodecVideoDecoder::ProcessHWErrorOnCodecThread() {
- CheckOnCodecThread();
- int ret_val = ReleaseOnCodecThread();
- if (ret_val < 0) {
- ALOGE << "ProcessHWError: Release failure";
- }
- if (codecType_ == kVideoCodecH264) {
- // For now there is no SW H.264 which can be used as fallback codec.
- // So try to restart hw codec for now.
- ret_val = InitDecodeOnCodecThread();
- ALOGE << "Reset H.264 codec done. Status: " << ret_val;
- if (ret_val == WEBRTC_VIDEO_CODEC_OK) {
- // H.264 codec was succesfully reset - return regular error code.
- return WEBRTC_VIDEO_CODEC_ERROR;
- } else {
- // Fail to restart H.264 codec - return error code which should stop the
- // call.
- return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
- }
- } else {
- sw_fallback_required_ = true;
- ALOGE << "Return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE";
- return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
- }
-}
-
-int32_t MediaCodecVideoDecoder::Decode(
- const EncodedImage& inputImage,
- bool missingFrames,
- const RTPFragmentationHeader* fragmentation,
- const CodecSpecificInfo* codecSpecificInfo,
- int64_t renderTimeMs) {
- if (sw_fallback_required_) {
- ALOGE << "Decode() - fallback to SW codec";
- return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
- }
- if (callback_ == NULL) {
- ALOGE << "Decode() - callback_ is NULL";
- return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
- }
- if (inputImage._buffer == NULL && inputImage._length > 0) {
- ALOGE << "Decode() - inputImage is incorrect";
- return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
- }
- if (!inited_) {
- ALOGE << "Decode() - decoder is not initialized";
- return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
- }
-
- // Check if encoded frame dimension has changed.
- if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
- (inputImage._encodedWidth != codec_.width ||
- inputImage._encodedHeight != codec_.height)) {
- codec_.width = inputImage._encodedWidth;
- codec_.height = inputImage._encodedHeight;
- int32_t ret = InitDecode(&codec_, 1);
- if (ret < 0) {
- ALOGE << "InitDecode failure: " << ret << " - fallback to SW codec";
- sw_fallback_required_ = true;
- return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
- }
- }
-
- // Always start with a complete key frame.
- if (key_frame_required_) {
- if (inputImage._frameType != webrtc::kVideoFrameKey) {
- ALOGE << "Decode() - key frame is required";
- return WEBRTC_VIDEO_CODEC_ERROR;
- }
- if (!inputImage._completeFrame) {
- ALOGE << "Decode() - complete frame is required";
- return WEBRTC_VIDEO_CODEC_ERROR;
- }
- key_frame_required_ = false;
- }
- if (inputImage._length == 0) {
- return WEBRTC_VIDEO_CODEC_ERROR;
- }
-
- return codec_thread_->Invoke<int32_t>(Bind(
- &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
-}
-
-int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
- const EncodedImage& inputImage) {
- CheckOnCodecThread();
- JNIEnv* jni = AttachCurrentThreadIfNeeded();
- ScopedLocalRefFrame local_ref_frame(jni);
-
- // Try to drain the decoder and wait until output is not too
- // much behind the input.
- if (frames_received_ > frames_decoded_ + max_pending_frames_) {
- ALOGW << "Decoder is too far behind. Try to drain. Received: " <<
- frames_received_ << ". Decoded: " << frames_decoded_;
- EnableFrameLogOnWarning();
- }
- const int64 drain_start = GetCurrentTimeMs();
- while ((frames_received_ > frames_decoded_ + max_pending_frames_) &&
- (GetCurrentTimeMs() - drain_start) < kMediaCodecTimeoutMs) {
- if (!DeliverPendingOutputs(jni, kMediaCodecPollMs)) {
- ALOGE << "DeliverPendingOutputs error. Frames received: " <<
- frames_received_ << ". Frames decoded: " << frames_decoded_;
- return ProcessHWErrorOnCodecThread();
- }
- }
- if (frames_received_ > frames_decoded_ + max_pending_frames_) {
- ALOGE << "Output buffer dequeue timeout. Frames received: " <<
- frames_received_ << ". Frames decoded: " << frames_decoded_;
- return ProcessHWErrorOnCodecThread();
- }
-
- // Get input buffer.
- int j_input_buffer_index = jni->CallIntMethod(
- *j_media_codec_video_decoder_, j_dequeue_input_buffer_method_);
- if (CheckException(jni) || j_input_buffer_index < 0) {
- ALOGE << "dequeueInputBuffer error: " << j_input_buffer_index <<
- ". Retry DeliverPendingOutputs.";
- EnableFrameLogOnWarning();
- // Try to drain the decoder.
- if (!DeliverPendingOutputs(jni, kMediaCodecPollMs)) {
- ALOGE << "DeliverPendingOutputs error. Frames received: " <<
- frames_received_ << ". Frames decoded: " << frames_decoded_;
- return ProcessHWErrorOnCodecThread();
- }
- // Try dequeue input buffer one last time.
- j_input_buffer_index = jni->CallIntMethod(
- *j_media_codec_video_decoder_, j_dequeue_input_buffer_method_);
- if (CheckException(jni) || j_input_buffer_index < 0) {
- ALOGE << "dequeueInputBuffer critical error: " << j_input_buffer_index;
- return ProcessHWErrorOnCodecThread();
- }
- }
-
- // Copy encoded data to Java ByteBuffer.
- jobject j_input_buffer = input_buffers_[j_input_buffer_index];
- uint8_t* buffer =
- reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_input_buffer));
- RTC_CHECK(buffer) << "Indirect buffer??";
- int64_t buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
- if (CheckException(jni) || buffer_capacity < inputImage._length) {
- ALOGE << "Input frame size "<< inputImage._length <<
- " is bigger than buffer size " << buffer_capacity;
- return ProcessHWErrorOnCodecThread();
- }
- jlong presentation_timestamp_us = static_cast<jlong>(
- static_cast<int64_t>(frames_received_) * 1000000 / codec_.maxFramerate);
- memcpy(buffer, inputImage._buffer, inputImage._length);
-
- if (frames_decoded_ < frames_decoded_logged_) {
- ALOGD << "Decoder frame in # " << frames_received_ <<
- ". Type: " << inputImage._frameType <<
- ". Buffer # " << j_input_buffer_index <<
- ". TS: " << presentation_timestamp_us / 1000 <<
- ". Size: " << inputImage._length;
- }
-
- // Save input image timestamps for later output.
- frames_received_++;
- current_bytes_ += inputImage._length;
-
- // Feed input to decoder.
- bool success = jni->CallBooleanMethod(
- *j_media_codec_video_decoder_,
- j_queue_input_buffer_method_,
- j_input_buffer_index,
- inputImage._length,
- presentation_timestamp_us,
- static_cast<int64_t> (inputImage._timeStamp),
- inputImage.ntp_time_ms_);
- if (CheckException(jni) || !success) {
- ALOGE << "queueInputBuffer error";
- return ProcessHWErrorOnCodecThread();
- }
-
- // Try to drain the decoder
- if (!DeliverPendingOutputs(jni, 0)) {
- ALOGE << "DeliverPendingOutputs error";
- return ProcessHWErrorOnCodecThread();
- }
-
- return WEBRTC_VIDEO_CODEC_OK;
-}
-
-bool MediaCodecVideoDecoder::DeliverPendingOutputs(
- JNIEnv* jni, int dequeue_timeout_ms) {
- if (frames_received_ <= frames_decoded_) {
- // No need to query for output buffers - decoder is drained.
- return true;
- }
- // Get decoder output.
- jobject j_decoder_output_buffer =
- jni->CallObjectMethod(*j_media_codec_video_decoder_,
- use_surface_ ? j_dequeue_texture_buffer_method_
- : j_dequeue_byte_buffer_method_,
- dequeue_timeout_ms);
-
- if (CheckException(jni)) {
- ALOGE << "dequeueOutputBuffer() error";
- return false;
- }
- if (IsNull(jni, j_decoder_output_buffer)) {
- // No decoded frame ready.
- return true;
- }
-
- // Get decoded video frame properties.
- int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
- j_color_format_field_);
- int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
- int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
- int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
- int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
- j_slice_height_field_);
-
- rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_buffer;
- int64_t presentation_timestamps_ms = 0;
- int64_t output_timestamps_ms = 0;
- int64_t output_ntp_timestamps_ms = 0;
- int decode_time_ms = 0;
- int64_t frame_delayed_ms = 0;
- if (use_surface_) {
- // Extract data from Java DecodedTextureBuffer.
- presentation_timestamps_ms = GetLongField(
- jni, j_decoder_output_buffer,
- j_texture_presentation_timestamp_ms_field_);
- output_timestamps_ms = GetLongField(
- jni, j_decoder_output_buffer, j_texture_timestamp_ms_field_);
- output_ntp_timestamps_ms = GetLongField(
- jni, j_decoder_output_buffer, j_texture_ntp_timestamp_ms_field_);
- decode_time_ms = GetLongField(
- jni, j_decoder_output_buffer, j_texture_decode_time_ms_field_);
-
- const int texture_id =
- GetIntField(jni, j_decoder_output_buffer, j_texture_id_field_);
- if (texture_id != 0) { // |texture_id| == 0 represents a dropped frame.
- const jfloatArray j_transform_matrix =
- reinterpret_cast<jfloatArray>(GetObjectField(
- jni, j_decoder_output_buffer, j_transform_matrix_field_));
- frame_delayed_ms = GetLongField(
- jni, j_decoder_output_buffer, j_texture_frame_delay_ms_field_);
-
- // Create webrtc::VideoFrameBuffer with native texture handle.
- frame_buffer = surface_texture_helper_->CreateTextureFrame(
- width, height, NativeHandleImpl(jni, texture_id, j_transform_matrix));
- } else {
- EnableFrameLogOnWarning();
- }
- } else {
- // Extract data from Java ByteBuffer and create output yuv420 frame -
- // for non surface decoding only.
- const int output_buffer_index = GetIntField(
- jni, j_decoder_output_buffer, j_info_index_field_);
- const int output_buffer_offset = GetIntField(
- jni, j_decoder_output_buffer, j_info_offset_field_);
- const int output_buffer_size = GetIntField(
- jni, j_decoder_output_buffer, j_info_size_field_);
- presentation_timestamps_ms = GetLongField(
- jni, j_decoder_output_buffer, j_presentation_timestamp_ms_field_);
- output_timestamps_ms = GetLongField(
- jni, j_decoder_output_buffer, j_timestamp_ms_field_);
- output_ntp_timestamps_ms = GetLongField(
- jni, j_decoder_output_buffer, j_ntp_timestamp_ms_field_);
-
- decode_time_ms = GetLongField(jni, j_decoder_output_buffer,
- j_byte_buffer_decode_time_ms_field_);
-
- if (output_buffer_size < width * height * 3 / 2) {
- ALOGE << "Insufficient output buffer size: " << output_buffer_size;
- return false;
- }
- jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
- jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
- jobject output_buffer =
- jni->GetObjectArrayElement(output_buffers, output_buffer_index);
- uint8_t* payload = reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(
- output_buffer));
- if (CheckException(jni)) {
- return false;
- }
- payload += output_buffer_offset;
-
- // Create yuv420 frame.
- frame_buffer = decoded_frame_pool_.CreateBuffer(width, height);
- if (color_format == COLOR_FormatYUV420Planar) {
- RTC_CHECK_EQ(0, stride % 2);
- RTC_CHECK_EQ(0, slice_height % 2);
- const int uv_stride = stride / 2;
- const int u_slice_height = slice_height / 2;
- const uint8_t* y_ptr = payload;
- const uint8_t* u_ptr = y_ptr + stride * slice_height;
- const uint8_t* v_ptr = u_ptr + uv_stride * u_slice_height;
- libyuv::I420Copy(y_ptr, stride,
- u_ptr, uv_stride,
- v_ptr, uv_stride,
- frame_buffer->MutableData(webrtc::kYPlane),
- frame_buffer->stride(webrtc::kYPlane),
- frame_buffer->MutableData(webrtc::kUPlane),
- frame_buffer->stride(webrtc::kUPlane),
- frame_buffer->MutableData(webrtc::kVPlane),
- frame_buffer->stride(webrtc::kVPlane),
- width, height);
- } else {
- // All other supported formats are nv12.
- const uint8_t* y_ptr = payload;
- const uint8_t* uv_ptr = y_ptr + stride * slice_height;
- libyuv::NV12ToI420(
- y_ptr, stride,
- uv_ptr, stride,
- frame_buffer->MutableData(webrtc::kYPlane),
- frame_buffer->stride(webrtc::kYPlane),
- frame_buffer->MutableData(webrtc::kUPlane),
- frame_buffer->stride(webrtc::kUPlane),
- frame_buffer->MutableData(webrtc::kVPlane),
- frame_buffer->stride(webrtc::kVPlane),
- width, height);
- }
- // Return output byte buffer back to codec.
- jni->CallVoidMethod(
- *j_media_codec_video_decoder_,
- j_return_decoded_byte_buffer_method_,
- output_buffer_index);
- if (CheckException(jni)) {
- ALOGE << "returnDecodedOutputBuffer error";
- return false;
- }
- }
- VideoFrame decoded_frame(frame_buffer, 0, 0, webrtc::kVideoRotation_0);
- decoded_frame.set_timestamp(output_timestamps_ms);
- decoded_frame.set_ntp_time_ms(output_ntp_timestamps_ms);
-
- if (frames_decoded_ < frames_decoded_logged_) {
- ALOGD << "Decoder frame out # " << frames_decoded_ <<
- ". " << width << " x " << height <<
- ". " << stride << " x " << slice_height <<
- ". Color: " << color_format <<
- ". TS: " << presentation_timestamps_ms <<
- ". DecTime: " << (int)decode_time_ms <<
- ". DelayTime: " << (int)frame_delayed_ms;
- }
-
- // Calculate and print decoding statistics - every 3 seconds.
- frames_decoded_++;
- current_frames_++;
- current_decoding_time_ms_ += decode_time_ms;
- current_delay_time_ms_ += frame_delayed_ms;
- int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
- if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
- current_frames_ > 0) {
- int current_bitrate = current_bytes_ * 8 / statistic_time_ms;
- int current_fps =
- (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms;
- ALOGD << "Frames decoded: " << frames_decoded_ <<
- ". Received: " << frames_received_ <<
- ". Bitrate: " << current_bitrate << " kbps" <<
- ". Fps: " << current_fps <<
- ". DecTime: " << (current_decoding_time_ms_ / current_frames_) <<
- ". DelayTime: " << (current_delay_time_ms_ / current_frames_) <<
- " for last " << statistic_time_ms << " ms.";
- start_time_ms_ = GetCurrentTimeMs();
- current_frames_ = 0;
- current_bytes_ = 0;
- current_decoding_time_ms_ = 0;
- current_delay_time_ms_ = 0;
- }
-
- // |.IsZeroSize())| returns true when a frame has been dropped.
- if (!decoded_frame.IsZeroSize()) {
- // Callback - output decoded frame.
- const int32_t callback_status =
- callback_->Decoded(decoded_frame, decode_time_ms);
- if (callback_status > 0) {
- ALOGE << "callback error";
- }
- }
- return true;
-}
-
-int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
- DecodedImageCallback* callback) {
- callback_ = callback;
- return WEBRTC_VIDEO_CODEC_OK;
-}
-
-void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
- JNIEnv* jni = AttachCurrentThreadIfNeeded();
- ScopedLocalRefFrame local_ref_frame(jni);
- if (!inited_) {
- return;
- }
- // We only ever send one message to |this| directly (not through a Bind()'d
- // functor), so expect no ID/data.
- RTC_CHECK(!msg->message_id) << "Unexpected message!";
- RTC_CHECK(!msg->pdata) << "Unexpected message!";
- CheckOnCodecThread();
-
- if (!DeliverPendingOutputs(jni, 0)) {
- ALOGE << "OnMessage: DeliverPendingOutputs error";
- ProcessHWErrorOnCodecThread();
- return;
- }
- codec_thread_->PostDelayed(kMediaCodecPollMs, this);
-}
-
-MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() {
- ALOGD << "MediaCodecVideoDecoderFactory ctor";
- JNIEnv* jni = AttachCurrentThreadIfNeeded();
- ScopedLocalRefFrame local_ref_frame(jni);
- jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
- supported_codec_types_.clear();
-
- bool is_vp8_hw_supported = jni->CallStaticBooleanMethod(
- j_decoder_class,
- GetStaticMethodID(jni, j_decoder_class, "isVp8HwSupported", "()Z"));
- if (CheckException(jni)) {
- is_vp8_hw_supported = false;
- }
- if (is_vp8_hw_supported) {
- ALOGD << "VP8 HW Decoder supported.";
- supported_codec_types_.push_back(kVideoCodecVP8);
- }
-
- bool is_vp9_hw_supported = jni->CallStaticBooleanMethod(
- j_decoder_class,
- GetStaticMethodID(jni, j_decoder_class, "isVp9HwSupported", "()Z"));
- if (CheckException(jni)) {
- is_vp9_hw_supported = false;
- }
- if (is_vp9_hw_supported) {
- ALOGD << "VP9 HW Decoder supported.";
- supported_codec_types_.push_back(kVideoCodecVP9);
- }
-
- bool is_h264_hw_supported = jni->CallStaticBooleanMethod(
- j_decoder_class,
- GetStaticMethodID(jni, j_decoder_class, "isH264HwSupported", "()Z"));
- if (CheckException(jni)) {
- is_h264_hw_supported = false;
- }
- if (is_h264_hw_supported) {
- ALOGD << "H264 HW Decoder supported.";
- supported_codec_types_.push_back(kVideoCodecH264);
- }
-}
-
-MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {
- ALOGD << "MediaCodecVideoDecoderFactory dtor";
-}
-
-void MediaCodecVideoDecoderFactory::SetEGLContext(
- JNIEnv* jni, jobject render_egl_context) {
- ALOGD << "MediaCodecVideoDecoderFactory::SetEGLContext";
- if (!egl_.CreateEglBase(jni, render_egl_context)) {
- ALOGW << "Invalid EGL context - HW surface decoding is disabled.";
- }
-}
-
-webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
- VideoCodecType type) {
- if (supported_codec_types_.empty()) {
- ALOGW << "No HW video decoder for type " << (int)type;
- return nullptr;
- }
- for (VideoCodecType codec_type : supported_codec_types_) {
- if (codec_type == type) {
- ALOGD << "Create HW video decoder for type " << (int)type;
- return new MediaCodecVideoDecoder(AttachCurrentThreadIfNeeded(), type,
- egl_.egl_base_context());
- }
- }
- ALOGW << "Can not find HW video decoder for type " << (int)type;
- return nullptr;
-}
-
-void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
- webrtc::VideoDecoder* decoder) {
- ALOGD << "Destroy video decoder.";
- delete decoder;
-}
-
-const char* MediaCodecVideoDecoder::ImplementationName() const {
- return "MediaCodec";
-}
-
-} // namespace webrtc_jni
-
« no previous file with comments | « talk/app/webrtc/java/jni/androidmediadecoder_jni.h ('k') | talk/app/webrtc/java/jni/androidmediaencoder_jni.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698