OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/common_video/include/incoming_video_stream.h" | 11 #include "webrtc/common_video/include/incoming_video_stream.h" |
12 | 12 |
13 #include <memory> | |
14 | |
15 #include "webrtc/base/timeutils.h" | 13 #include "webrtc/base/timeutils.h" |
16 #include "webrtc/common_video/video_render_frames.h" | 14 #include "webrtc/common_video/video_render_frames.h" |
17 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | 15 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" |
18 #include "webrtc/system_wrappers/include/event_wrapper.h" | 16 #include "webrtc/system_wrappers/include/event_wrapper.h" |
19 | 17 |
20 namespace webrtc { | 18 namespace webrtc { |
21 namespace { | 19 namespace { |
22 const char kIncomingQueueName[] = "IncomingVideoStream"; | 20 const int kEventStartupTimeMs = 10; |
23 } | 21 const int kEventMaxWaitTimeMs = 100; |
24 | 22 } // namespace |
25 // Capture by moving (std::move) into a lambda isn't possible in C++11 | |
26 // (supported in C++14). This class provides the functionality of what would be | |
27 // something like (inside OnFrame): | |
28 // VideoFrame frame(video_frame); | |
29 // incoming_render_queue_.PostTask([this, frame = std::move(frame)](){ | |
30 // if (render_buffers_.AddFrame(std::move(frame)) == 1) | |
31 // Dequeue(); | |
32 // }); | |
33 class IncomingVideoStream::NewFrameTask : public rtc::QueuedTask { | |
34 public: | |
35 NewFrameTask(IncomingVideoStream* stream, VideoFrame frame) | |
36 : stream_(stream), frame_(std::move(frame)) {} | |
37 | |
38 private: | |
39 bool Run() override { | |
40 RTC_DCHECK(rtc::TaskQueue::IsCurrent(kIncomingQueueName)); | |
41 if (stream_->render_buffers_.AddFrame(std::move(frame_)) == 1) | |
42 stream_->Dequeue(); | |
43 return true; | |
44 } | |
45 | |
46 IncomingVideoStream* stream_; | |
47 VideoFrame frame_; | |
48 }; | |
49 | 23 |
50 IncomingVideoStream::IncomingVideoStream( | 24 IncomingVideoStream::IncomingVideoStream( |
51 int32_t delay_ms, | 25 int32_t delay_ms, |
52 rtc::VideoSinkInterface<VideoFrame>* callback) | 26 rtc::VideoSinkInterface<VideoFrame>* callback) |
53 : render_buffers_(delay_ms), | 27 : incoming_render_thread_(&IncomingVideoStreamThreadFun, |
54 callback_(callback), | 28 this, |
55 incoming_render_queue_(kIncomingQueueName, | 29 "IncomingVideoStreamThread", |
56 rtc::TaskQueue::Priority::HIGH) {} | 30 rtc::kRealtimePriority), |
| 31 deliver_buffer_event_(EventTimerWrapper::Create()), |
| 32 external_callback_(callback), |
| 33 render_buffers_(new VideoRenderFrames(delay_ms)) { |
| 34 RTC_DCHECK(external_callback_); |
| 35 |
| 36 render_thread_checker_.DetachFromThread(); |
| 37 |
| 38 deliver_buffer_event_->StartTimer(false, kEventStartupTimeMs); |
| 39 incoming_render_thread_.Start(); |
| 40 } |
57 | 41 |
58 IncomingVideoStream::~IncomingVideoStream() { | 42 IncomingVideoStream::~IncomingVideoStream() { |
59 RTC_DCHECK(main_thread_checker_.CalledOnValidThread()); | 43 RTC_DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 44 |
| 45 { |
| 46 rtc::CritScope cs(&buffer_critsect_); |
| 47 render_buffers_.reset(); |
| 48 } |
| 49 |
| 50 deliver_buffer_event_->Set(); |
| 51 incoming_render_thread_.Stop(); |
| 52 deliver_buffer_event_->StopTimer(); |
60 } | 53 } |
61 | 54 |
62 void IncomingVideoStream::OnFrame(const VideoFrame& video_frame) { | 55 void IncomingVideoStream::OnFrame(const VideoFrame& video_frame) { |
63 RTC_CHECK_RUNS_SERIALIZED(&decoder_race_checker_); | 56 RTC_CHECK_RUNS_SERIALIZED(&decoder_race_checker_); |
64 RTC_DCHECK(!incoming_render_queue_.IsCurrent()); | 57 // Hand over or insert frame. |
65 incoming_render_queue_.PostTask( | 58 rtc::CritScope csB(&buffer_critsect_); |
66 std::unique_ptr<rtc::QueuedTask>(new NewFrameTask(this, video_frame))); | 59 if (render_buffers_->AddFrame(video_frame) == 1) { |
67 } | 60 deliver_buffer_event_->Set(); |
68 | |
69 void IncomingVideoStream::Dequeue() { | |
70 RTC_DCHECK(incoming_render_queue_.IsCurrent()); | |
71 rtc::Optional<VideoFrame> frame_to_render = render_buffers_.FrameToRender(); | |
72 if (frame_to_render) | |
73 callback_->OnFrame(*frame_to_render); | |
74 | |
75 if (render_buffers_.HasPendingFrames()) { | |
76 uint32_t wait_time = render_buffers_.TimeToNextFrameRelease(); | |
77 incoming_render_queue_.PostDelayedTask([this]() { Dequeue(); }, wait_time); | |
78 } | 61 } |
79 } | 62 } |
80 | 63 |
| 64 // static |
| 65 void IncomingVideoStream::IncomingVideoStreamThreadFun(void* obj) { |
| 66 static_cast<IncomingVideoStream*>(obj)->IncomingVideoStreamProcess(); |
| 67 } |
| 68 |
| 69 void IncomingVideoStream::IncomingVideoStreamProcess() { |
| 70 RTC_DCHECK_RUN_ON(&render_thread_checker_); |
| 71 |
| 72 while (true) { |
| 73 if (kEventError != deliver_buffer_event_->Wait(kEventMaxWaitTimeMs)) { |
| 74 // Get a new frame to render and the time for the frame after this one. |
| 75 rtc::Optional<VideoFrame> frame_to_render; |
| 76 uint32_t wait_time; |
| 77 { |
| 78 rtc::CritScope cs(&buffer_critsect_); |
| 79 if (!render_buffers_.get()) { |
| 80 // Terminating |
| 81 return; |
| 82 } |
| 83 |
| 84 frame_to_render = render_buffers_->FrameToRender(); |
| 85 wait_time = render_buffers_->TimeToNextFrameRelease(); |
| 86 } |
| 87 |
| 88 // Set timer for next frame to render. |
| 89 if (wait_time > kEventMaxWaitTimeMs) { |
| 90 wait_time = kEventMaxWaitTimeMs; |
| 91 } |
| 92 |
| 93 deliver_buffer_event_->StartTimer(false, wait_time); |
| 94 |
| 95 if (frame_to_render) { |
| 96 external_callback_->OnFrame(*frame_to_render); |
| 97 } |
| 98 } else { |
| 99 RTC_NOTREACHED(); |
| 100 } |
| 101 } |
| 102 } |
| 103 |
81 } // namespace webrtc | 104 } // namespace webrtc |
OLD | NEW |