VideoStreamDecoderImpl implementation, part 3.
This CL implements the functions related to decoding.
Bug: webrtc:8909
Change-Id: Iefa3c1565a9b9ae93f14992b4a1cca141b7c5193
Reviewed-on: https://webrtc-review.googlesource.com/66403
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Commit-Queue: Philip Eliasson <philipel@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22747}diff --git a/video/video_stream_decoder_impl.cc b/video/video_stream_decoder_impl.cc
index 3a9751e..7b4a1ba 100644
--- a/video/video_stream_decoder_impl.cc
+++ b/video/video_stream_decoder_impl.cc
@@ -11,6 +11,7 @@
#include "video/video_stream_decoder_impl.h"
#include "rtc_base/logging.h"
+#include "rtc_base/numerics/mod_ops.h"
#include "rtc_base/ptr_util.h"
namespace webrtc {
@@ -23,15 +24,24 @@
decoder_factory_(decoder_factory),
decoder_settings_(std::move(decoder_settings)),
bookkeeping_queue_("video_stream_decoder_bookkeeping_queue"),
+ decode_thread_(&DecodeLoop,
+ this,
+ "video_stream_decoder_decode_thread",
+ rtc::kHighestPriority),
jitter_estimator_(Clock::GetRealTimeClock()),
timing_(Clock::GetRealTimeClock()),
frame_buffer_(Clock::GetRealTimeClock(),
&jitter_estimator_,
&timing_,
- nullptr) {}
+ nullptr),
+ next_start_time_index_(0) {
+ decode_start_time_.fill({-1, 0});
+ decode_thread_.Start();
+}
VideoStreamDecoderImpl::~VideoStreamDecoderImpl() {
frame_buffer_.Stop();
+ decode_thread_.Stop();
}
void VideoStreamDecoderImpl::OnFrame(
@@ -111,4 +121,94 @@
return decoder_.get();
}
+// static
+void VideoStreamDecoderImpl::DecodeLoop(void* ptr) {
+ // TODO(philipel): Remove this and use rtc::Event::kForever when it's
+ // supported by the |frame_buffer_|.
+ static constexpr int kForever = 100000000;
+
+ int max_wait_time_ms = kForever;
+ bool keyframe_required = true;
+ auto* vs_decoder = static_cast<VideoStreamDecoderImpl*>(ptr);
+ while (true) {
+ DecodeResult decode_result =
+ vs_decoder->DecodeNextFrame(max_wait_time_ms, keyframe_required);
+
+ switch (decode_result) {
+ case kOk: {
+ max_wait_time_ms = kForever;
+ keyframe_required = false;
+ break;
+ }
+ case kDecodeFailure: {
+ max_wait_time_ms = 0;
+ keyframe_required = true;
+ break;
+ }
+ case kNoFrame: {
+ max_wait_time_ms = kForever;
+ // If we end up here it means that we got a decoding error and there is
+ // no keyframe available in the |frame_buffer_|.
+ vs_decoder->bookkeeping_queue_.PostTask([vs_decoder]() {
+ RTC_DCHECK_RUN_ON(&vs_decoder->bookkeeping_queue_);
+ vs_decoder->callbacks_->OnNonDecodableState();
+ });
+ break;
+ }
+ case kNoDecoder: {
+ max_wait_time_ms = kForever;
+ break;
+ }
+ case kShutdown: {
+ return;
+ }
+ }
+ }
+}
+
+VideoStreamDecoderImpl::DecodeResult VideoStreamDecoderImpl::DecodeNextFrame(
+ int max_wait_time_ms,
+ bool keyframe_required) {
+ std::unique_ptr<video_coding::EncodedFrame> frame;
+ video_coding::FrameBuffer::ReturnReason res =
+ frame_buffer_.NextFrame(max_wait_time_ms, &frame, keyframe_required);
+
+ if (res == video_coding::FrameBuffer::ReturnReason::kStopped)
+ return kShutdown;
+
+ if (frame) {
+ VideoDecoder* decoder = GetDecoder(frame->PayloadType());
+ if (!decoder) {
+ RTC_LOG(LS_WARNING) << "Failed to get decoder, dropping frame ("
+ << frame->id.picture_id << ":"
+ << frame->id.spatial_layer << ").";
+ return kNoDecoder;
+ }
+
+ int64_t decode_start_time_ms = rtc::TimeMillis();
+ uint32_t frame_timestamp = frame->timestamp;
+ bookkeeping_queue_.PostTask(
+ [this, decode_start_time_ms, frame_timestamp]() {
+ RTC_DCHECK_RUN_ON(&bookkeeping_queue_);
+ // Saving decode start time this way wont work if we decode spatial
+ // layers sequentially.
+ decode_start_time_[next_start_time_index_] = {frame_timestamp,
+ decode_start_time_ms};
+ next_start_time_index_ =
+ Add<kDecodeTimeMemory>(next_start_time_index_, 1);
+ });
+
+ int32_t decode_result =
+ decoder->Decode(frame->EncodedImage(),
+ false, // missing_frame
+ nullptr, // rtp fragmentation header
+ nullptr, // codec specific info
+ frame->RenderTimeMs());
+
+ return decode_result == WEBRTC_VIDEO_CODEC_OK ? kOk : kDecodeFailure;
+ }
+
+ return kNoFrame;
+}
+
} // namespace webrtc
diff --git a/video/video_stream_decoder_impl.h b/video/video_stream_decoder_impl.h
index 5575176..42c1b94 100644
--- a/video/video_stream_decoder_impl.h
+++ b/video/video_stream_decoder_impl.h
@@ -20,6 +20,7 @@
#include "modules/video_coding/frame_buffer2.h"
#include "modules/video_coding/jitter_estimator.h"
#include "modules/video_coding/timing.h"
+#include "rtc_base/platform_thread.h"
#include "rtc_base/task_queue.h"
#include "rtc_base/thread_checker.h"
#include "system_wrappers/include/clock.h"
@@ -39,7 +40,17 @@
void OnFrame(std::unique_ptr<video_coding::EncodedFrame> frame) override;
private:
+ enum DecodeResult {
+ kOk,
+ kDecodeFailure,
+ kNoFrame,
+ kNoDecoder,
+ kShutdown,
+ };
+
VideoDecoder* GetDecoder(int payload_type);
+ static void DecodeLoop(void* ptr);
+ DecodeResult DecodeNextFrame(int max_wait_time_ms, bool keyframe_required);
// Implements DecodedImageCallback interface
int32_t Decoded(VideoFrame& decodedImage) override;
@@ -59,12 +70,21 @@
// - Synchronize with whatever thread that makes the Decoded callback.
rtc::TaskQueue bookkeeping_queue_;
+ rtc::PlatformThread decode_thread_;
VCMJitterEstimator jitter_estimator_;
VCMTiming timing_;
video_coding::FrameBuffer frame_buffer_;
video_coding::VideoLayerFrameId last_continuous_id_;
rtc::Optional<int> current_payload_type_;
std::unique_ptr<VideoDecoder> decoder_;
+
+ // Keep track of the |decode_start_time_| of the last |kDecodeTimeMemory|
+ // number of frames. The |decode_start_time_| array contain
+ // <frame timestamp> --> <decode start time> pairs.
+ static constexpr int kDecodeTimeMemory = 8;
+ std::array<std::pair<int64_t, int64_t>, kDecodeTimeMemory> decode_start_time_
+ RTC_GUARDED_BY(bookkeeping_queue_);
+ int next_start_time_index_ RTC_GUARDED_BY(bookkeeping_queue_);
};
} // namespace webrtc