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 |
13 #include "webrtc/base/timeutils.h" | 15 #include "webrtc/base/timeutils.h" |
14 #include "webrtc/common_video/video_render_frames.h" | 16 #include "webrtc/common_video/video_render_frames.h" |
15 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | 17 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" |
16 #include "webrtc/system_wrappers/include/event_wrapper.h" | 18 #include "webrtc/system_wrappers/include/event_wrapper.h" |
17 | 19 |
18 namespace webrtc { | 20 namespace webrtc { |
19 namespace { | 21 namespace { |
20 const int kEventStartupTimeMs = 10; | 22 const char kIncomingQueueName[] = "IncomingVideoStream"; |
21 const int kEventMaxWaitTimeMs = 100; | 23 } |
22 } // namespace | 24 |
| 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 }; |
23 | 49 |
24 IncomingVideoStream::IncomingVideoStream( | 50 IncomingVideoStream::IncomingVideoStream( |
25 int32_t delay_ms, | 51 int32_t delay_ms, |
26 rtc::VideoSinkInterface<VideoFrame>* callback) | 52 rtc::VideoSinkInterface<VideoFrame>* callback) |
27 : incoming_render_thread_(&IncomingVideoStreamThreadFun, | 53 : render_buffers_(delay_ms), |
28 this, | 54 callback_(callback), |
29 "IncomingVideoStreamThread", | 55 incoming_render_queue_(kIncomingQueueName, |
30 rtc::kRealtimePriority), | 56 rtc::TaskQueue::Priority::HIGH) {} |
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 } | |
41 | 57 |
42 IncomingVideoStream::~IncomingVideoStream() { | 58 IncomingVideoStream::~IncomingVideoStream() { |
43 RTC_DCHECK(main_thread_checker_.CalledOnValidThread()); | 59 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(); | |
53 } | 60 } |
54 | 61 |
55 void IncomingVideoStream::OnFrame(const VideoFrame& video_frame) { | 62 void IncomingVideoStream::OnFrame(const VideoFrame& video_frame) { |
56 RTC_CHECK_RUNS_SERIALIZED(&decoder_race_checker_); | 63 RTC_CHECK_RUNS_SERIALIZED(&decoder_race_checker_); |
57 // Hand over or insert frame. | 64 RTC_DCHECK(!incoming_render_queue_.IsCurrent()); |
58 rtc::CritScope csB(&buffer_critsect_); | 65 incoming_render_queue_.PostTask( |
59 if (render_buffers_->AddFrame(video_frame) == 1) { | 66 std::unique_ptr<rtc::QueuedTask>(new NewFrameTask(this, video_frame))); |
60 deliver_buffer_event_->Set(); | 67 } |
| 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); |
61 } | 78 } |
62 } | 79 } |
63 | 80 |
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 | |
104 } // namespace webrtc | 81 } // namespace webrtc |
OLD | NEW |