Index: webrtc/common_video/incoming_video_stream.cc |
diff --git a/webrtc/common_video/incoming_video_stream.cc b/webrtc/common_video/incoming_video_stream.cc |
index b88892d9672ddfa18ad675b6f02d9383af8e54c0..c1f61d1cfb87c94b55f57246a4ceaf684f98526d 100644 |
--- a/webrtc/common_video/incoming_video_stream.cc |
+++ b/webrtc/common_video/incoming_video_stream.cc |
@@ -10,8 +10,6 @@ |
#include "webrtc/common_video/include/incoming_video_stream.h" |
-#include <memory> |
- |
#include "webrtc/base/timeutils.h" |
#include "webrtc/common_video/video_render_frames.h" |
#include "webrtc/system_wrappers/include/critical_section_wrapper.h" |
@@ -19,62 +17,87 @@ |
namespace webrtc { |
namespace { |
-const char kIncomingQueueName[] = "IncomingVideoStream"; |
-} |
- |
-// Capture by moving (std::move) into a lambda isn't possible in C++11 |
-// (supported in C++14). This class provides the functionality of what would be |
-// something like (inside OnFrame): |
-// VideoFrame frame(video_frame); |
-// incoming_render_queue_.PostTask([this, frame = std::move(frame)](){ |
-// if (render_buffers_.AddFrame(std::move(frame)) == 1) |
-// Dequeue(); |
-// }); |
-class IncomingVideoStream::NewFrameTask : public rtc::QueuedTask { |
- public: |
- NewFrameTask(IncomingVideoStream* stream, VideoFrame frame) |
- : stream_(stream), frame_(std::move(frame)) {} |
- |
- private: |
- bool Run() override { |
- RTC_DCHECK(rtc::TaskQueue::IsCurrent(kIncomingQueueName)); |
- if (stream_->render_buffers_.AddFrame(std::move(frame_)) == 1) |
- stream_->Dequeue(); |
- return true; |
- } |
- |
- IncomingVideoStream* stream_; |
- VideoFrame frame_; |
-}; |
+const int kEventStartupTimeMs = 10; |
+const int kEventMaxWaitTimeMs = 100; |
+} // namespace |
IncomingVideoStream::IncomingVideoStream( |
int32_t delay_ms, |
rtc::VideoSinkInterface<VideoFrame>* callback) |
- : render_buffers_(delay_ms), |
- callback_(callback), |
- incoming_render_queue_(kIncomingQueueName, |
- rtc::TaskQueue::Priority::HIGH) {} |
+ : incoming_render_thread_(&IncomingVideoStreamThreadFun, |
+ this, |
+ "IncomingVideoStreamThread", |
+ rtc::kRealtimePriority), |
+ deliver_buffer_event_(EventTimerWrapper::Create()), |
+ external_callback_(callback), |
+ render_buffers_(new VideoRenderFrames(delay_ms)) { |
+ RTC_DCHECK(external_callback_); |
+ |
+ render_thread_checker_.DetachFromThread(); |
+ |
+ deliver_buffer_event_->StartTimer(false, kEventStartupTimeMs); |
+ incoming_render_thread_.Start(); |
+} |
IncomingVideoStream::~IncomingVideoStream() { |
RTC_DCHECK(main_thread_checker_.CalledOnValidThread()); |
+ |
+ { |
+ rtc::CritScope cs(&buffer_critsect_); |
+ render_buffers_.reset(); |
+ } |
+ |
+ deliver_buffer_event_->Set(); |
+ incoming_render_thread_.Stop(); |
+ deliver_buffer_event_->StopTimer(); |
} |
void IncomingVideoStream::OnFrame(const VideoFrame& video_frame) { |
RTC_CHECK_RUNS_SERIALIZED(&decoder_race_checker_); |
- RTC_DCHECK(!incoming_render_queue_.IsCurrent()); |
- incoming_render_queue_.PostTask( |
- std::unique_ptr<rtc::QueuedTask>(new NewFrameTask(this, video_frame))); |
+ // Hand over or insert frame. |
+ rtc::CritScope csB(&buffer_critsect_); |
+ if (render_buffers_->AddFrame(video_frame) == 1) { |
+ deliver_buffer_event_->Set(); |
+ } |
} |
-void IncomingVideoStream::Dequeue() { |
- RTC_DCHECK(incoming_render_queue_.IsCurrent()); |
- rtc::Optional<VideoFrame> frame_to_render = render_buffers_.FrameToRender(); |
- if (frame_to_render) |
- callback_->OnFrame(*frame_to_render); |
+// static |
+void IncomingVideoStream::IncomingVideoStreamThreadFun(void* obj) { |
+ static_cast<IncomingVideoStream*>(obj)->IncomingVideoStreamProcess(); |
+} |
- if (render_buffers_.HasPendingFrames()) { |
- uint32_t wait_time = render_buffers_.TimeToNextFrameRelease(); |
- incoming_render_queue_.PostDelayedTask([this]() { Dequeue(); }, wait_time); |
+void IncomingVideoStream::IncomingVideoStreamProcess() { |
+ RTC_DCHECK_RUN_ON(&render_thread_checker_); |
+ |
+ while (true) { |
+ if (kEventError != deliver_buffer_event_->Wait(kEventMaxWaitTimeMs)) { |
+ // Get a new frame to render and the time for the frame after this one. |
+ rtc::Optional<VideoFrame> frame_to_render; |
+ uint32_t wait_time; |
+ { |
+ rtc::CritScope cs(&buffer_critsect_); |
+ if (!render_buffers_.get()) { |
+ // Terminating |
+ return; |
+ } |
+ |
+ frame_to_render = render_buffers_->FrameToRender(); |
+ wait_time = render_buffers_->TimeToNextFrameRelease(); |
+ } |
+ |
+ // Set timer for next frame to render. |
+ if (wait_time > kEventMaxWaitTimeMs) { |
+ wait_time = kEventMaxWaitTimeMs; |
+ } |
+ |
+ deliver_buffer_event_->StartTimer(false, wait_time); |
+ |
+ if (frame_to_render) { |
+ external_callback_->OnFrame(*frame_to_render); |
+ } |
+ } else { |
+ RTC_NOTREACHED(); |
+ } |
} |
} |