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; |
} |