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 <assert.h> |
| 14 |
| 15 #include "webrtc/base/platform_thread.h" |
13 #include "webrtc/base/timeutils.h" | 16 #include "webrtc/base/timeutils.h" |
14 #include "webrtc/common_video/video_render_frames.h" | 17 #include "webrtc/common_video/video_render_frames.h" |
15 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | 18 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" |
16 #include "webrtc/system_wrappers/include/event_wrapper.h" | 19 #include "webrtc/system_wrappers/include/event_wrapper.h" |
17 | 20 |
18 namespace webrtc { | 21 namespace webrtc { |
19 | 22 |
20 IncomingVideoStream::IncomingVideoStream( | 23 IncomingVideoStream::IncomingVideoStream(bool disable_prerenderer_smoothing) |
21 int32_t delay_ms, | 24 : disable_prerenderer_smoothing_(disable_prerenderer_smoothing), |
22 rtc::VideoSinkInterface<VideoFrame>* callback) | 25 incoming_render_thread_(), |
23 : incoming_render_thread_(&IncomingVideoStreamThreadFun, | |
24 this, | |
25 "IncomingVideoStreamThread"), | |
26 deliver_buffer_event_(EventTimerWrapper::Create()), | 26 deliver_buffer_event_(EventTimerWrapper::Create()), |
27 external_callback_(callback), | 27 running_(false), |
28 render_buffers_(new VideoRenderFrames(delay_ms)) { | 28 external_callback_(nullptr), |
29 RTC_DCHECK(external_callback_); | 29 render_buffers_(new VideoRenderFrames()) {} |
30 | |
31 render_thread_checker_.DetachFromThread(); | |
32 decoder_thread_checker_.DetachFromThread(); | |
33 | |
34 incoming_render_thread_.Start(); | |
35 incoming_render_thread_.SetPriority(rtc::kRealtimePriority); | |
36 deliver_buffer_event_->StartTimer(false, kEventStartupTimeMs); | |
37 } | |
38 | 30 |
39 IncomingVideoStream::~IncomingVideoStream() { | 31 IncomingVideoStream::~IncomingVideoStream() { |
40 RTC_DCHECK(main_thread_checker_.CalledOnValidThread()); | 32 Stop(); |
41 | |
42 { | |
43 rtc::CritScope cs(&buffer_critsect_); | |
44 render_buffers_.reset(); | |
45 } | |
46 | |
47 deliver_buffer_event_->Set(); | |
48 incoming_render_thread_.Stop(); | |
49 deliver_buffer_event_->StopTimer(); | |
50 } | 33 } |
51 | 34 |
52 void IncomingVideoStream::OnFrame(const VideoFrame& video_frame) { | 35 void IncomingVideoStream::OnFrame(const VideoFrame& video_frame) { |
53 RTC_DCHECK_RUN_ON(&decoder_thread_checker_); | 36 rtc::CritScope csS(&stream_critsect_); |
| 37 |
| 38 if (!running_) { |
| 39 return; |
| 40 } |
54 | 41 |
55 // Hand over or insert frame. | 42 // Hand over or insert frame. |
56 rtc::CritScope csB(&buffer_critsect_); | 43 if (disable_prerenderer_smoothing_) { |
57 if (render_buffers_->AddFrame(video_frame) == 1) { | 44 DeliverFrame(video_frame); |
58 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 } |
59 } | 50 } |
60 } | 51 } |
61 | 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 |
62 bool IncomingVideoStream::IncomingVideoStreamThreadFun(void* obj) { | 122 bool IncomingVideoStream::IncomingVideoStreamThreadFun(void* obj) { |
63 return static_cast<IncomingVideoStream*>(obj)->IncomingVideoStreamProcess(); | 123 return static_cast<IncomingVideoStream*>(obj)->IncomingVideoStreamProcess(); |
64 } | 124 } |
65 | 125 |
66 bool IncomingVideoStream::IncomingVideoStreamProcess() { | 126 bool IncomingVideoStream::IncomingVideoStreamProcess() { |
67 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 } |
68 | 133 |
69 if (kEventError != deliver_buffer_event_->Wait(kEventMaxWaitTimeMs)) { | |
70 // 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. |
71 rtc::Optional<VideoFrame> frame_to_render; | 135 rtc::Optional<VideoFrame> frame_to_render; |
72 uint32_t wait_time; | 136 uint32_t wait_time; |
73 { | 137 { |
74 rtc::CritScope cs(&buffer_critsect_); | 138 rtc::CritScope cs(&buffer_critsect_); |
75 if (!render_buffers_.get()) { | |
76 // Terminating | |
77 return false; | |
78 } | |
79 frame_to_render = render_buffers_->FrameToRender(); | 139 frame_to_render = render_buffers_->FrameToRender(); |
80 wait_time = render_buffers_->TimeToNextFrameRelease(); | 140 wait_time = render_buffers_->TimeToNextFrameRelease(); |
81 } | 141 } |
82 | 142 |
83 // Set timer for next frame to render. | 143 // Set timer for next frame to render. |
84 if (wait_time > kEventMaxWaitTimeMs) { | 144 if (wait_time > kEventMaxWaitTimeMs) { |
85 wait_time = kEventMaxWaitTimeMs; | 145 wait_time = kEventMaxWaitTimeMs; |
86 } | 146 } |
87 | |
88 deliver_buffer_event_->StartTimer(false, wait_time); | 147 deliver_buffer_event_->StartTimer(false, wait_time); |
89 | 148 |
90 if (frame_to_render) { | 149 if (frame_to_render) |
91 external_callback_->OnFrame(*frame_to_render); | 150 DeliverFrame(*frame_to_render); |
92 } | |
93 } | 151 } |
94 return true; | 152 return true; |
95 } | 153 } |
96 | 154 |
| 155 void IncomingVideoStream::DeliverFrame(const VideoFrame& video_frame) { |
| 156 rtc::CritScope cs(&thread_critsect_); |
| 157 |
| 158 // Send frame for rendering. |
| 159 if (external_callback_) { |
| 160 external_callback_->OnFrame(video_frame); |
| 161 } |
| 162 } |
| 163 |
97 } // namespace webrtc | 164 } // namespace webrtc |
OLD | NEW |