| Index: webrtc/sdk/android/src/jni/androidmediadecoder_jni.cc
|
| diff --git a/webrtc/sdk/android/src/jni/androidmediadecoder_jni.cc b/webrtc/sdk/android/src/jni/androidmediadecoder_jni.cc
|
| index 6bd749a3bccdf22b281904f66664c9222e6be818..bcca86a917352ef09575088aa31800f5ae2623b2 100644
|
| --- a/webrtc/sdk/android/src/jni/androidmediadecoder_jni.cc
|
| +++ b/webrtc/sdk/android/src/jni/androidmediadecoder_jni.cc
|
| @@ -24,7 +24,7 @@
|
| #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/thread_checker.h"
|
| #include "webrtc/base/timeutils.h"
|
| #include "webrtc/common_video/h264/h264_bitstream_parser.h"
|
| #include "webrtc/common_video/include/i420_buffer_pool.h"
|
| @@ -65,6 +65,8 @@ using webrtc::kVideoCodecVP9;
|
|
|
| namespace webrtc_jni {
|
|
|
| +// All calls should be made on the decoding thread expect for release which can
|
| +// be called after the decoder thread has been stopped.
|
| class MediaCodecVideoDecoder : public webrtc::VideoDecoder {
|
| public:
|
| explicit MediaCodecVideoDecoder(
|
| @@ -92,39 +94,12 @@ class MediaCodecVideoDecoder : public webrtc::VideoDecoder {
|
| const char* ImplementationName() const override;
|
|
|
| private:
|
| - struct DecodedFrame {
|
| - DecodedFrame(VideoFrame frame,
|
| - int decode_time_ms,
|
| - int64_t timestamp,
|
| - int64_t ntp_timestamp,
|
| - rtc::Optional<uint8_t> qp)
|
| - : frame(std::move(frame)),
|
| - decode_time_ms(decode_time_ms),
|
| - qp(std::move(qp)) {
|
| - frame.set_timestamp(timestamp);
|
| - frame.set_ntp_time_ms(ntp_timestamp);
|
| - }
|
| -
|
| - VideoFrame frame;
|
| - int decode_time_ms;
|
| - rtc::Optional<uint8_t> qp;
|
| - };
|
| -
|
| - // Returns true if running on |codec_thread_|. Used for DCHECKing.
|
| - bool IsOnCodecThread();
|
| -
|
| - int32_t InitDecodeOnCodecThread();
|
| - int32_t ResetDecodeOnCodecThread();
|
| - int32_t ReleaseOnCodecThread();
|
| - int32_t DecodeOnCodecThread(const EncodedImage& inputImage,
|
| - std::vector<DecodedFrame>* frames);
|
| - void PollDecodedFramesOnCodecThread(std::vector<DecodedFrame>* frames);
|
| + int32_t InitDecodeInternal();
|
| + int32_t ResetDecode();
|
| // Deliver any outputs pending in the MediaCodec to our |callback_| and return
|
| // true on success.
|
| - bool DeliverPendingOutputs(JNIEnv* jni,
|
| - int dequeue_timeout_us,
|
| - std::vector<DecodedFrame>* frames);
|
| - int32_t ProcessHWErrorOnCodecThread();
|
| + bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us);
|
| + int32_t ProcessHWError();
|
| void EnableFrameLogOnWarning();
|
| void ResetVariables();
|
|
|
| @@ -158,8 +133,7 @@ class MediaCodecVideoDecoder : public webrtc::VideoDecoder {
|
|
|
| // State that is constant for the lifetime of this object once the ctor
|
| // returns.
|
| - std::unique_ptr<Thread>
|
| - codec_thread_; // Thread on which to operate MediaCodec.
|
| + rtc::ThreadChecker decode_thread_checker_;
|
| ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_;
|
| ScopedGlobalRef<jobject> j_media_codec_video_decoder_;
|
| jmethodID j_init_decode_method_;
|
| @@ -197,9 +171,6 @@ class MediaCodecVideoDecoder : public webrtc::VideoDecoder {
|
|
|
| // Global references; must be deleted in Release().
|
| std::vector<jobject> input_buffers_;
|
| -
|
| - // Added to on the codec thread, frames are delivered on the decoder thread.
|
| - std::vector<DecodedFrame> decoded_frames_;
|
| };
|
|
|
| MediaCodecVideoDecoder::MediaCodecVideoDecoder(
|
| @@ -209,7 +180,6 @@ MediaCodecVideoDecoder::MediaCodecVideoDecoder(
|
| 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")),
|
| @@ -220,8 +190,7 @@ MediaCodecVideoDecoder::MediaCodecVideoDecoder(
|
| *j_media_codec_video_decoder_class_,
|
| "<init>",
|
| "()V"))) {
|
| - codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
|
| - RTC_CHECK(codec_thread_->Start());
|
| + decode_thread_checker_.DetachFromThread();
|
|
|
| j_init_decode_method_ = GetMethodID(
|
| jni, *j_media_codec_video_decoder_class_, "initDecode",
|
| @@ -310,6 +279,7 @@ MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
|
|
|
| int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
|
| int32_t numberOfCores) {
|
| + RTC_DCHECK(decode_thread_checker_.CalledOnValidThread());
|
| ALOGD << "InitDecode.";
|
| if (inst == NULL) {
|
| ALOGE << "NULL VideoCodec instance";
|
| @@ -331,13 +301,11 @@ int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
|
| codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 30;
|
|
|
| // Call Java init.
|
| - return codec_thread_->Invoke<int32_t>(
|
| - RTC_FROM_HERE,
|
| - Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
|
| + return InitDecodeInternal();
|
| }
|
|
|
| void MediaCodecVideoDecoder::ResetVariables() {
|
| - RTC_DCHECK(IsOnCodecThread());
|
| + RTC_DCHECK(decode_thread_checker_.CalledOnValidThread());
|
|
|
| key_frame_required_ = true;
|
| frames_received_ = 0;
|
| @@ -351,16 +319,16 @@ void MediaCodecVideoDecoder::ResetVariables() {
|
| pending_frame_qps_.clear();
|
| }
|
|
|
| -int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
|
| - RTC_DCHECK(IsOnCodecThread());
|
| +int32_t MediaCodecVideoDecoder::InitDecodeInternal() {
|
| + RTC_DCHECK(decode_thread_checker_.CalledOnValidThread());
|
| JNIEnv* jni = AttachCurrentThreadIfNeeded();
|
| ScopedLocalRefFrame local_ref_frame(jni);
|
| - ALOGD << "InitDecodeOnCodecThread Type: " << (int)codecType_ << ". "
|
| - << codec_.width << " x " << codec_.height << ". Fps: " <<
|
| - (int)codec_.maxFramerate;
|
| + ALOGD << "InitDecodeInternal 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();
|
| + int ret_val = Release();
|
| if (ret_val < 0) {
|
| ALOGE << "Release failure: " << ret_val << " - fallback to SW codec";
|
| sw_fallback_required_ = true;
|
| @@ -429,12 +397,12 @@ int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
|
| return WEBRTC_VIDEO_CODEC_OK;
|
| }
|
|
|
| -int32_t MediaCodecVideoDecoder::ResetDecodeOnCodecThread() {
|
| - RTC_DCHECK(IsOnCodecThread());
|
| +int32_t MediaCodecVideoDecoder::ResetDecode() {
|
| + RTC_DCHECK(decode_thread_checker_.CalledOnValidThread());
|
| JNIEnv* jni = AttachCurrentThreadIfNeeded();
|
| ScopedLocalRefFrame local_ref_frame(jni);
|
| - ALOGD << "ResetDecodeOnCodecThread Type: " << (int)codecType_ << ". "
|
| - << codec_.width << " x " << codec_.height;
|
| + ALOGD << "ResetDecode Type: " << (int)codecType_ << ". " << codec_.width
|
| + << " x " << codec_.height;
|
| ALOGD << " Frames received: " << frames_received_ <<
|
| ". Frames decoded: " << frames_decoded_;
|
|
|
| @@ -459,18 +427,12 @@ int32_t MediaCodecVideoDecoder::ResetDecodeOnCodecThread() {
|
|
|
| int32_t MediaCodecVideoDecoder::Release() {
|
| ALOGD << "DecoderRelease request";
|
| - return codec_thread_->Invoke<int32_t>(
|
| - RTC_FROM_HERE, Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
|
| -}
|
| -
|
| -int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
|
| - RTC_DCHECK(IsOnCodecThread());
|
| if (!inited_) {
|
| return WEBRTC_VIDEO_CODEC_OK;
|
| }
|
| JNIEnv* jni = AttachCurrentThreadIfNeeded();
|
| - ALOGD << "DecoderReleaseOnCodecThread: Frames received: " <<
|
| - frames_received_ << ". Frames decoded: " << frames_decoded_;
|
| + ALOGD << "DecoderRelease: 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]);
|
| @@ -483,14 +445,10 @@ int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
|
| ALOGE << "Decoder release exception";
|
| return WEBRTC_VIDEO_CODEC_ERROR;
|
| }
|
| - ALOGD << "DecoderReleaseOnCodecThread done";
|
| + ALOGD << "DecoderRelease done";
|
| return WEBRTC_VIDEO_CODEC_OK;
|
| }
|
|
|
| -bool MediaCodecVideoDecoder::IsOnCodecThread() {
|
| - return codec_thread_.get() == ThreadManager::Instance()->CurrentThread();
|
| -}
|
| -
|
| void MediaCodecVideoDecoder::EnableFrameLogOnWarning() {
|
| // Log next 2 output frames.
|
| static const int kMaxWarningLogFrames = 2;
|
| @@ -498,16 +456,16 @@ void MediaCodecVideoDecoder::EnableFrameLogOnWarning() {
|
| frames_decoded_logged_, frames_decoded_ + kMaxWarningLogFrames);
|
| }
|
|
|
| -int32_t MediaCodecVideoDecoder::ProcessHWErrorOnCodecThread() {
|
| - RTC_DCHECK(IsOnCodecThread());
|
| - int ret_val = ReleaseOnCodecThread();
|
| +int32_t MediaCodecVideoDecoder::ProcessHWError() {
|
| + RTC_DCHECK(decode_thread_checker_.CalledOnValidThread());
|
| + int ret_val = Release();
|
| 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();
|
| + ret_val = InitDecodeInternal();
|
| 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.
|
| @@ -530,6 +488,7 @@ int32_t MediaCodecVideoDecoder::Decode(
|
| const RTPFragmentationHeader* fragmentation,
|
| const CodecSpecificInfo* codecSpecificInfo,
|
| int64_t renderTimeMs) {
|
| + RTC_DCHECK(decode_thread_checker_.CalledOnValidThread());
|
| RTC_DCHECK(callback_);
|
| RTC_DCHECK(inited_);
|
|
|
| @@ -555,9 +514,7 @@ int32_t MediaCodecVideoDecoder::Decode(
|
| if (use_surface_ &&
|
| (codecType_ == kVideoCodecVP8 || codecType_ == kVideoCodecH264)) {
|
| // Soft codec reset - only for surface decoding.
|
| - ret = codec_thread_->Invoke<int32_t>(
|
| - RTC_FROM_HERE,
|
| - Bind(&MediaCodecVideoDecoder::ResetDecodeOnCodecThread, this));
|
| + ret = ResetDecode();
|
| } else {
|
| // Hard codec reset.
|
| ret = InitDecode(&codec_, 1);
|
| @@ -585,32 +542,7 @@ int32_t MediaCodecVideoDecoder::Decode(
|
| return WEBRTC_VIDEO_CODEC_ERROR;
|
| }
|
|
|
| - std::vector<DecodedFrame> frames;
|
| - int32_t ret = codec_thread_->Invoke<int32_t>(
|
| - RTC_FROM_HERE, Bind(&MediaCodecVideoDecoder::DecodeOnCodecThread, this,
|
| - inputImage, &frames));
|
| - for (auto& f : frames)
|
| - callback_->Decoded(f.frame, rtc::Optional<int32_t>(f.decode_time_ms), f.qp);
|
| - return ret;
|
| -}
|
| -
|
| -void MediaCodecVideoDecoder::PollDecodedFrames() {
|
| - RTC_DCHECK(callback_);
|
| -
|
| - std::vector<DecodedFrame> frames;
|
| - codec_thread_->Invoke<void>(
|
| - RTC_FROM_HERE,
|
| - Bind(&MediaCodecVideoDecoder::PollDecodedFramesOnCodecThread, this,
|
| - &frames));
|
| -
|
| - for (auto& f : frames)
|
| - callback_->Decoded(f.frame, rtc::Optional<int32_t>(f.decode_time_ms), f.qp);
|
| -}
|
| -
|
| -int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
|
| - const EncodedImage& inputImage,
|
| - std::vector<DecodedFrame>* frames) {
|
| - RTC_DCHECK(IsOnCodecThread());
|
| + RTC_DCHECK(decode_thread_checker_.CalledOnValidThread());
|
| JNIEnv* jni = AttachCurrentThreadIfNeeded();
|
| ScopedLocalRefFrame local_ref_frame(jni);
|
|
|
| @@ -626,16 +558,16 @@ int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
|
| const int64 drain_start = rtc::TimeMillis();
|
| while ((frames_received_ > frames_decoded_ + max_pending_frames_) &&
|
| (rtc::TimeMillis() - drain_start) < kMediaCodecTimeoutMs) {
|
| - if (!DeliverPendingOutputs(jni, kMediaCodecPollMs, frames)) {
|
| + if (!DeliverPendingOutputs(jni, kMediaCodecPollMs)) {
|
| ALOGE << "DeliverPendingOutputs error. Frames received: " <<
|
| frames_received_ << ". Frames decoded: " << frames_decoded_;
|
| - return ProcessHWErrorOnCodecThread();
|
| + return ProcessHWError();
|
| }
|
| }
|
| if (frames_received_ > frames_decoded_ + max_pending_frames_) {
|
| ALOGE << "Output buffer dequeue timeout. Frames received: " <<
|
| frames_received_ << ". Frames decoded: " << frames_decoded_;
|
| - return ProcessHWErrorOnCodecThread();
|
| + return ProcessHWError();
|
| }
|
|
|
| // Get input buffer.
|
| @@ -646,17 +578,17 @@ int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
|
| ". Retry DeliverPendingOutputs.";
|
| EnableFrameLogOnWarning();
|
| // Try to drain the decoder.
|
| - if (!DeliverPendingOutputs(jni, kMediaCodecPollMs, frames)) {
|
| + if (!DeliverPendingOutputs(jni, kMediaCodecPollMs)) {
|
| ALOGE << "DeliverPendingOutputs error. Frames received: " <<
|
| frames_received_ << ". Frames decoded: " << frames_decoded_;
|
| - return ProcessHWErrorOnCodecThread();
|
| + return ProcessHWError();
|
| }
|
| // 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();
|
| + return ProcessHWError();
|
| }
|
| }
|
|
|
| @@ -669,7 +601,7 @@ int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
|
| if (CheckException(jni) || buffer_capacity < inputImage._length) {
|
| ALOGE << "Input frame size "<< inputImage._length <<
|
| " is bigger than buffer size " << buffer_capacity;
|
| - return ProcessHWErrorOnCodecThread();
|
| + return ProcessHWError();
|
| }
|
| jlong presentation_timestamp_us = static_cast<jlong>(
|
| static_cast<int64_t>(frames_received_) * 1000000 / codec_.maxFramerate);
|
| @@ -713,37 +645,33 @@ int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
|
| inputImage.ntp_time_ms_);
|
| if (CheckException(jni) || !success) {
|
| ALOGE << "queueInputBuffer error";
|
| - return ProcessHWErrorOnCodecThread();
|
| + return ProcessHWError();
|
| }
|
|
|
| // Try to drain the decoder
|
| - if (!DeliverPendingOutputs(jni, 0, frames)) {
|
| + if (!DeliverPendingOutputs(jni, 0)) {
|
| ALOGE << "DeliverPendingOutputs error";
|
| - return ProcessHWErrorOnCodecThread();
|
| + return ProcessHWError();
|
| }
|
|
|
| return WEBRTC_VIDEO_CODEC_OK;
|
| }
|
|
|
| -void MediaCodecVideoDecoder::PollDecodedFramesOnCodecThread(
|
| - std::vector<DecodedFrame>* frames) {
|
| - RTC_DCHECK(IsOnCodecThread());
|
| +void MediaCodecVideoDecoder::PollDecodedFrames() {
|
| + RTC_DCHECK(decode_thread_checker_.CalledOnValidThread());
|
|
|
| JNIEnv* jni = AttachCurrentThreadIfNeeded();
|
| ScopedLocalRefFrame local_ref_frame(jni);
|
|
|
| - if (!DeliverPendingOutputs(jni, 0, frames)) {
|
| - ALOGE << "PollDecodedFramesOnCodecThread: DeliverPendingOutputs error";
|
| - ProcessHWErrorOnCodecThread();
|
| + if (!DeliverPendingOutputs(jni, 0)) {
|
| + ALOGE << "PollDecodedFrames: DeliverPendingOutputs error";
|
| + ProcessHWError();
|
| }
|
| }
|
|
|
| -bool MediaCodecVideoDecoder::DeliverPendingOutputs(
|
| - JNIEnv* jni,
|
| - int dequeue_timeout_ms,
|
| - std::vector<DecodedFrame>* frames) {
|
| - RTC_DCHECK(IsOnCodecThread());
|
| - RTC_DCHECK(frames);
|
| +bool MediaCodecVideoDecoder::DeliverPendingOutputs(JNIEnv* jni,
|
| + int dequeue_timeout_ms) {
|
| + RTC_DCHECK(decode_thread_checker_.CalledOnValidThread());
|
|
|
| if (frames_received_ <= frames_decoded_) {
|
| // No need to query for output buffers - decoder is drained.
|
| @@ -954,16 +882,10 @@ bool MediaCodecVideoDecoder::DeliverPendingOutputs(
|
|
|
| rtc::Optional<uint8_t> qp = pending_frame_qps_.front();
|
| pending_frame_qps_.pop_front();
|
| - decoded_frames_.push_back(DecodedFrame(std::move(decoded_frame),
|
| - decode_time_ms, output_timestamps_ms,
|
| - output_ntp_timestamps_ms, qp));
|
| + callback_->Decoded(decoded_frame, rtc::Optional<int32_t>(decode_time_ms),
|
| + qp);
|
| }
|
|
|
| - frames->reserve(frames->size() + decoded_frames_.size());
|
| - std::move(decoded_frames_.begin(), decoded_frames_.end(),
|
| - std::back_inserter(*frames));
|
| - decoded_frames_.clear();
|
| -
|
| return true;
|
| }
|
|
|
|
|