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 |
20 const int kEventStartupTimeMs = 10; | 22 // Capture by moving (std::move) into a lambda isn't possible in C++11 |
21 const int kEventMaxWaitTimeMs = 100; | 23 // (supported in C++14). This class provides the functionality of what would be |
22 } // namespace | 24 // something like (inside OnFrame): |
25 // VideoFrame frame(video_frame); | |
26 // incoming_render_queue_.PostTask([this, frame = std::move(frame)](){ | |
27 // if (render_buffers_.AddFrame(std::move(frame)) == 1) | |
28 // Dequeue(); | |
29 // }); | |
30 class IncomingVideoStream::NewFrameTask : public rtc::QueuedTask { | |
31 public: | |
32 NewFrameTask(IncomingVideoStream* stream, VideoFrame frame) | |
33 : stream_(stream), frame_(std::move(frame)) {} | |
34 | |
35 private: | |
36 bool Run() override { | |
37 if (stream_->render_buffers_.AddFrame(std::move(frame_)) == 1) | |
mflodman
2017/02/23 15:23:25
There is no check that this happens on the right t
tommi
2017/02/23 19:00:08
Check added. Dequeue would have caught it, but on
mflodman
2017/02/24 15:29:58
If render_buffers_ were empty yes, but not otherwi
| |
38 stream_->Dequeue(); | |
39 return true; | |
40 } | |
41 | |
42 IncomingVideoStream* stream_; | |
43 VideoFrame frame_; | |
44 }; | |
23 | 45 |
24 IncomingVideoStream::IncomingVideoStream( | 46 IncomingVideoStream::IncomingVideoStream( |
25 int32_t delay_ms, | 47 int32_t delay_ms, |
26 rtc::VideoSinkInterface<VideoFrame>* callback) | 48 rtc::VideoSinkInterface<VideoFrame>* callback) |
27 : incoming_render_thread_(&IncomingVideoStreamThreadFun, | 49 : render_buffers_(delay_ms), |
28 this, | 50 callback_(callback), |
29 "IncomingVideoStreamThread", | 51 incoming_render_queue_("IncomingVideoStream", rtc::TaskQueue::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 } | |
41 | 52 |
42 IncomingVideoStream::~IncomingVideoStream() { | 53 IncomingVideoStream::~IncomingVideoStream() { |
43 RTC_DCHECK(main_thread_checker_.CalledOnValidThread()); | 54 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 } | 55 } |
54 | 56 |
55 void IncomingVideoStream::OnFrame(const VideoFrame& video_frame) { | 57 void IncomingVideoStream::OnFrame(const VideoFrame& video_frame) { |
56 RTC_CHECK_RUNS_SERIALIZED(&decoder_race_checker_); | 58 RTC_CHECK_RUNS_SERIALIZED(&decoder_race_checker_); |
57 // Hand over or insert frame. | 59 RTC_DCHECK(!incoming_render_queue_.IsCurrent()); |
58 rtc::CritScope csB(&buffer_critsect_); | 60 incoming_render_queue_.PostTask( |
59 if (render_buffers_->AddFrame(video_frame) == 1) { | 61 std::unique_ptr<rtc::QueuedTask>(new NewFrameTask(this, video_frame))); |
60 deliver_buffer_event_->Set(); | 62 } |
63 | |
64 void IncomingVideoStream::Dequeue() { | |
65 RTC_DCHECK(incoming_render_queue_.IsCurrent()); | |
66 rtc::Optional<VideoFrame> frame_to_render = render_buffers_.FrameToRender(); | |
67 if (frame_to_render) | |
68 callback_->OnFrame(*frame_to_render); | |
69 | |
70 if (render_buffers_.HasPendingFrames()) { | |
71 uint32_t wait_time = render_buffers_.TimeToNextFrameRelease(); | |
72 incoming_render_queue_.PostDelayedTask([this]() { Dequeue(); }, wait_time); | |
mflodman
2017/02/23 15:23:25
'wait_time' can in theory be '0, e.g. if 'OnFrame'
tommi
2017/02/23 19:00:08
That's ok. Also added test for TaskQueue.
mflodman
2017/02/24 15:29:58
Thanks
| |
61 } | 73 } |
62 } | 74 } |
63 | 75 |
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 | 76 } // namespace webrtc |
OLD | NEW |