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 "webrtc/base/atomicops.h" | 13 #include <assert.h> |
| 14 |
14 #include "webrtc/base/platform_thread.h" | 15 #include "webrtc/base/platform_thread.h" |
15 #include "webrtc/base/timeutils.h" | 16 #include "webrtc/base/timeutils.h" |
16 #include "webrtc/common_video/video_render_frames.h" | 17 #include "webrtc/common_video/video_render_frames.h" |
17 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | 18 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" |
18 #include "webrtc/system_wrappers/include/event_wrapper.h" | 19 #include "webrtc/system_wrappers/include/event_wrapper.h" |
19 | 20 |
20 namespace webrtc { | 21 namespace webrtc { |
21 | 22 |
22 IncomingVideoStream::IncomingVideoStream( | 23 IncomingVideoStream::IncomingVideoStream(bool disable_prerenderer_smoothing) |
23 int32_t delay_ms, | 24 : disable_prerenderer_smoothing_(disable_prerenderer_smoothing), |
24 rtc::VideoSinkInterface<VideoFrame>* callback) | 25 incoming_render_thread_(), |
25 : incoming_render_thread_(&IncomingVideoStreamThreadFun, | |
26 this, | |
27 "IncomingVideoStreamThread"), | |
28 deliver_buffer_event_(EventTimerWrapper::Create()), | 26 deliver_buffer_event_(EventTimerWrapper::Create()), |
29 external_callback_(callback), | 27 running_(false), |
30 render_buffers_(new VideoRenderFrames(delay_ms)) { | 28 external_callback_(nullptr), |
31 RTC_DCHECK(external_callback_); | 29 render_buffers_(new VideoRenderFrames()) {} |
32 | |
33 render_thread_checker_.DetachFromThread(); | |
34 decoder_thread_checker_.DetachFromThread(); | |
35 | |
36 incoming_render_thread_.Start(); | |
37 incoming_render_thread_.SetPriority(rtc::kRealtimePriority); | |
38 deliver_buffer_event_->StartTimer(false, kEventStartupTimeMs); | |
39 } | |
40 | 30 |
41 IncomingVideoStream::~IncomingVideoStream() { | 31 IncomingVideoStream::~IncomingVideoStream() { |
42 RTC_DCHECK(main_thread_checker_.CalledOnValidThread()); | 32 Stop(); |
43 | |
44 { | |
45 rtc::CritScope cs(&buffer_critsect_); | |
46 render_buffers_.reset(); | |
47 } | |
48 | |
49 deliver_buffer_event_->Set(); | |
50 incoming_render_thread_.Stop(); | |
51 deliver_buffer_event_->StopTimer(); | |
52 } | 33 } |
53 | 34 |
54 void IncomingVideoStream::OnFrame(const VideoFrame& video_frame) { | 35 void IncomingVideoStream::OnFrame(const VideoFrame& video_frame) { |
55 RTC_DCHECK_RUN_ON(&decoder_thread_checker_); | 36 rtc::CritScope csS(&stream_critsect_); |
| 37 |
| 38 if (!running_) { |
| 39 return; |
| 40 } |
56 | 41 |
57 // Hand over or insert frame. | 42 // Hand over or insert frame. |
58 rtc::CritScope csB(&buffer_critsect_); | 43 if (disable_prerenderer_smoothing_) { |
59 if (render_buffers_->AddFrame(video_frame) == 1) { | 44 DeliverFrame(video_frame); |
60 deliver_buffer_event_->Set(); | 45 } else { |
| 46 rtc::CritScope csB(&buffer_critsect_); |
| 47 if (render_buffers_->AddFrame(video_frame) == 1) { |
| 48 deliver_buffer_event_->Set(); |
| 49 } |
61 } | 50 } |
62 } | 51 } |
63 | 52 |
| 53 int32_t IncomingVideoStream::SetExpectedRenderDelay( |
| 54 int32_t delay_ms) { |
| 55 rtc::CritScope csS(&stream_critsect_); |
| 56 if (running_) { |
| 57 return -1; |
| 58 } |
| 59 rtc::CritScope cs(&buffer_critsect_); |
| 60 return render_buffers_->SetRenderDelay(delay_ms); |
| 61 } |
| 62 |
| 63 void IncomingVideoStream::SetExternalCallback( |
| 64 rtc::VideoSinkInterface<VideoFrame>* external_callback) { |
| 65 rtc::CritScope cs(&thread_critsect_); |
| 66 external_callback_ = external_callback; |
| 67 } |
| 68 |
| 69 int32_t IncomingVideoStream::Start() { |
| 70 rtc::CritScope csS(&stream_critsect_); |
| 71 if (running_) { |
| 72 return 0; |
| 73 } |
| 74 |
| 75 if (!disable_prerenderer_smoothing_) { |
| 76 rtc::CritScope csT(&thread_critsect_); |
| 77 assert(incoming_render_thread_ == NULL); |
| 78 |
| 79 incoming_render_thread_.reset(new rtc::PlatformThread( |
| 80 IncomingVideoStreamThreadFun, this, "IncomingVideoStreamThread")); |
| 81 if (!incoming_render_thread_) { |
| 82 return -1; |
| 83 } |
| 84 |
| 85 incoming_render_thread_->Start(); |
| 86 incoming_render_thread_->SetPriority(rtc::kRealtimePriority); |
| 87 deliver_buffer_event_->StartTimer(false, kEventStartupTimeMs); |
| 88 } |
| 89 |
| 90 running_ = true; |
| 91 return 0; |
| 92 } |
| 93 |
| 94 int32_t IncomingVideoStream::Stop() { |
| 95 rtc::CritScope cs_stream(&stream_critsect_); |
| 96 |
| 97 if (!running_) { |
| 98 return 0; |
| 99 } |
| 100 |
| 101 rtc::PlatformThread* thread = NULL; |
| 102 { |
| 103 rtc::CritScope cs_thread(&thread_critsect_); |
| 104 if (incoming_render_thread_) { |
| 105 // Setting the incoming render thread to NULL marks that we're performing |
| 106 // a shutdown and will make IncomingVideoStreamProcess abort after wakeup. |
| 107 thread = incoming_render_thread_.release(); |
| 108 deliver_buffer_event_->StopTimer(); |
| 109 // Set the event to allow the thread to wake up and shut down without |
| 110 // waiting for a timeout. |
| 111 deliver_buffer_event_->Set(); |
| 112 } |
| 113 } |
| 114 if (thread) { |
| 115 thread->Stop(); |
| 116 delete thread; |
| 117 } |
| 118 running_ = false; |
| 119 return 0; |
| 120 } |
| 121 |
64 bool IncomingVideoStream::IncomingVideoStreamThreadFun(void* obj) { | 122 bool IncomingVideoStream::IncomingVideoStreamThreadFun(void* obj) { |
65 return static_cast<IncomingVideoStream*>(obj)->IncomingVideoStreamProcess(); | 123 return static_cast<IncomingVideoStream*>(obj)->IncomingVideoStreamProcess(); |
66 } | 124 } |
67 | 125 |
68 bool IncomingVideoStream::IncomingVideoStreamProcess() { | 126 bool IncomingVideoStream::IncomingVideoStreamProcess() { |
69 RTC_DCHECK_RUN_ON(&render_thread_checker_); | 127 if (kEventError != deliver_buffer_event_->Wait(kEventMaxWaitTimeMs)) { |
| 128 rtc::CritScope cs(&thread_critsect_); |
| 129 if (incoming_render_thread_ == NULL) { |
| 130 // Terminating |
| 131 return false; |
| 132 } |
70 | 133 |
71 if (kEventError != deliver_buffer_event_->Wait(kEventMaxWaitTimeMs)) { | |
72 // Get a new frame to render and the time for the frame after this one. | 134 // Get a new frame to render and the time for the frame after this one. |
73 rtc::Optional<VideoFrame> frame_to_render; | 135 rtc::Optional<VideoFrame> frame_to_render; |
74 uint32_t wait_time; | 136 uint32_t wait_time; |
75 { | 137 { |
76 rtc::CritScope cs(&buffer_critsect_); | 138 rtc::CritScope cs(&buffer_critsect_); |
77 if (!render_buffers_.get()) { | |
78 // Terminating | |
79 return false; | |
80 } | |
81 frame_to_render = render_buffers_->FrameToRender(); | 139 frame_to_render = render_buffers_->FrameToRender(); |
82 wait_time = render_buffers_->TimeToNextFrameRelease(); | 140 wait_time = render_buffers_->TimeToNextFrameRelease(); |
83 } | 141 } |
84 | 142 |
85 // Set timer for next frame to render. | 143 // Set timer for next frame to render. |
86 if (wait_time > kEventMaxWaitTimeMs) { | 144 if (wait_time > kEventMaxWaitTimeMs) { |
87 wait_time = kEventMaxWaitTimeMs; | 145 wait_time = kEventMaxWaitTimeMs; |
88 } | 146 } |
89 | |
90 deliver_buffer_event_->StartTimer(false, wait_time); | 147 deliver_buffer_event_->StartTimer(false, wait_time); |
91 | 148 |
92 if (frame_to_render) { | 149 if (frame_to_render) |
93 external_callback_->OnFrame(*frame_to_render); | 150 DeliverFrame(*frame_to_render); |
94 } | |
95 } | 151 } |
96 return true; | 152 return true; |
97 } | 153 } |
98 | 154 |
99 //////////////////////////////////////////////////////////////////////////////// | 155 void IncomingVideoStream::DeliverFrame(const VideoFrame& video_frame) { |
100 IncomingVideoStreamNoSmoothing::IncomingVideoStreamNoSmoothing( | 156 rtc::CritScope cs(&thread_critsect_); |
101 rtc::VideoSinkInterface<VideoFrame>* callback) | |
102 : callback_(callback), queue_("InVideoStream") { | |
103 decoder_thread_checker_.DetachFromThread(); | |
104 } | |
105 | 157 |
106 void IncomingVideoStreamNoSmoothing::OnFrame(const VideoFrame& video_frame) { | 158 // Send frame for rendering. |
107 RTC_DCHECK_RUN_ON(&decoder_thread_checker_); | 159 if (external_callback_) { |
108 queue_.PostTask([video_frame, this]() { callback_->OnFrame(video_frame); }); | 160 external_callback_->OnFrame(video_frame); |
| 161 } |
109 } | 162 } |
110 | 163 |
111 } // namespace webrtc | 164 } // namespace webrtc |
OLD | NEW |