Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / renderer / media / media_stream_video_track.cc
blob248e44d6cae6405dc2843a6eb44c492c46035d6a
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/media/media_stream_video_track.h"
7 #include <utility>
9 #include "base/bind.h"
10 #include "third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h"
12 namespace content {
14 namespace {
15 void ResetCallback(scoped_ptr<VideoCaptureDeliverFrameCB> callback) {
16 // |callback| will be deleted when this exits.
18 } // namespace
20 // MediaStreamVideoTrack::FrameDeliverer is a helper class used for registering
21 // VideoCaptureDeliverFrameCB on the main render thread to receive video frames
22 // on the IO-thread.
23 // Frames are only delivered to the sinks if the track is enabled. If the track
24 // is disabled, a black frame is instead forwarded to the sinks at the same
25 // frame rate.
26 class MediaStreamVideoTrack::FrameDeliverer
27 : public base::RefCountedThreadSafe<FrameDeliverer> {
28 public:
29 typedef MediaStreamVideoSink* VideoSinkId;
31 FrameDeliverer(
32 const scoped_refptr<base::MessageLoopProxy>& io_message_loop,
33 bool enabled);
35 void SetEnabled(bool enabled);
37 // Add |callback| to receive video frames on the IO-thread.
38 // Must be called on the main render thread.
39 void AddCallback(VideoSinkId id, const VideoCaptureDeliverFrameCB& callback);
41 // Removes |callback| associated with |id| from receiving video frames if |id|
42 // has been added. It is ok to call RemoveCallback even if the |id| has not
43 // been added. Note that the added callback will be reset on the main thread.
44 // Must be called on the main render thread.
45 void RemoveCallback(VideoSinkId id);
47 // Triggers all registered callbacks with |frame|, |format| and
48 // |estimated_capture_time| as parameters. Must be called on the IO-thread.
49 void DeliverFrameOnIO(const scoped_refptr<media::VideoFrame>& frame,
50 const base::TimeTicks& estimated_capture_time);
52 private:
53 friend class base::RefCountedThreadSafe<FrameDeliverer>;
54 virtual ~FrameDeliverer();
55 void AddCallbackOnIO(VideoSinkId id,
56 const VideoCaptureDeliverFrameCB& callback);
57 void RemoveCallbackOnIO(
58 VideoSinkId id,
59 const scoped_refptr<base::MessageLoopProxy>& message_loop);
61 void SetEnabledOnIO(bool enabled);
62 // Returns |black_frame_| where the size and time stamp is set to the same as
63 // as in |reference_frame|.
64 const scoped_refptr<media::VideoFrame>& GetBlackFrame(
65 const scoped_refptr<media::VideoFrame>& reference_frame);
67 // Used to DCHECK that AddCallback and RemoveCallback are called on the main
68 // Render Thread.
69 base::ThreadChecker main_render_thread_checker_;
70 const scoped_refptr<base::MessageLoopProxy> io_message_loop_;
72 bool enabled_;
73 scoped_refptr<media::VideoFrame> black_frame_;
75 typedef std::pair<VideoSinkId, VideoCaptureDeliverFrameCB>
76 VideoIdCallbackPair;
77 std::vector<VideoIdCallbackPair> callbacks_;
79 DISALLOW_COPY_AND_ASSIGN(FrameDeliverer);
82 MediaStreamVideoTrack::FrameDeliverer::FrameDeliverer(
83 const scoped_refptr<base::MessageLoopProxy>& io_message_loop, bool enabled)
84 : io_message_loop_(io_message_loop),
85 enabled_(enabled) {
86 DCHECK(io_message_loop_.get());
89 MediaStreamVideoTrack::FrameDeliverer::~FrameDeliverer() {
90 DCHECK(callbacks_.empty());
93 void MediaStreamVideoTrack::FrameDeliverer::AddCallback(
94 VideoSinkId id,
95 const VideoCaptureDeliverFrameCB& callback) {
96 DCHECK(main_render_thread_checker_.CalledOnValidThread());
97 io_message_loop_->PostTask(
98 FROM_HERE,
99 base::Bind(&FrameDeliverer::AddCallbackOnIO,
100 this, id, callback));
103 void MediaStreamVideoTrack::FrameDeliverer::AddCallbackOnIO(
104 VideoSinkId id,
105 const VideoCaptureDeliverFrameCB& callback) {
106 DCHECK(io_message_loop_->BelongsToCurrentThread());
107 callbacks_.push_back(std::make_pair(id, callback));
110 void MediaStreamVideoTrack::FrameDeliverer::RemoveCallback(VideoSinkId id) {
111 DCHECK(main_render_thread_checker_.CalledOnValidThread());
112 io_message_loop_->PostTask(
113 FROM_HERE,
114 base::Bind(&FrameDeliverer::RemoveCallbackOnIO,
115 this, id, base::MessageLoopProxy::current()));
118 void MediaStreamVideoTrack::FrameDeliverer::RemoveCallbackOnIO(
119 VideoSinkId id,
120 const scoped_refptr<base::MessageLoopProxy>& message_loop) {
121 DCHECK(io_message_loop_->BelongsToCurrentThread());
122 std::vector<VideoIdCallbackPair>::iterator it = callbacks_.begin();
123 for (; it != callbacks_.end(); ++it) {
124 if (it->first == id) {
125 // Callback is copied to heap and then deleted on the target thread.
126 scoped_ptr<VideoCaptureDeliverFrameCB> callback;
127 callback.reset(new VideoCaptureDeliverFrameCB(it->second));
128 callbacks_.erase(it);
129 message_loop->PostTask(
130 FROM_HERE, base::Bind(&ResetCallback, base::Passed(&callback)));
131 return;
136 void MediaStreamVideoTrack::FrameDeliverer::SetEnabled(bool enabled) {
137 DCHECK(main_render_thread_checker_.CalledOnValidThread());
138 io_message_loop_->PostTask(
139 FROM_HERE,
140 base::Bind(&FrameDeliverer::SetEnabledOnIO,
141 this, enabled));
144 void MediaStreamVideoTrack::FrameDeliverer::SetEnabledOnIO(bool enabled) {
145 DCHECK(io_message_loop_->BelongsToCurrentThread());
146 enabled_ = enabled;
147 if (enabled_)
148 black_frame_ = NULL;
151 void MediaStreamVideoTrack::FrameDeliverer::DeliverFrameOnIO(
152 const scoped_refptr<media::VideoFrame>& frame,
153 const base::TimeTicks& estimated_capture_time) {
154 DCHECK(io_message_loop_->BelongsToCurrentThread());
155 const scoped_refptr<media::VideoFrame>& video_frame =
156 enabled_ ? frame : GetBlackFrame(frame);
157 for (const auto& entry : callbacks_)
158 entry.second.Run(video_frame, estimated_capture_time);
161 const scoped_refptr<media::VideoFrame>&
162 MediaStreamVideoTrack::FrameDeliverer::GetBlackFrame(
163 const scoped_refptr<media::VideoFrame>& reference_frame) {
164 DCHECK(io_message_loop_->BelongsToCurrentThread());
165 if (!black_frame_.get() ||
166 black_frame_->natural_size() != reference_frame->natural_size())
167 black_frame_ =
168 media::VideoFrame::CreateBlackFrame(reference_frame->natural_size());
170 black_frame_->set_timestamp(reference_frame->timestamp());
171 return black_frame_;
174 // static
175 blink::WebMediaStreamTrack MediaStreamVideoTrack::CreateVideoTrack(
176 MediaStreamVideoSource* source,
177 const blink::WebMediaConstraints& constraints,
178 const MediaStreamVideoSource::ConstraintsCallback& callback,
179 bool enabled) {
180 blink::WebMediaStreamTrack track;
181 track.initialize(source->owner());
182 track.setExtraData(new MediaStreamVideoTrack(source,
183 constraints,
184 callback,
185 enabled));
186 return track;
189 // static
190 MediaStreamVideoTrack* MediaStreamVideoTrack::GetVideoTrack(
191 const blink::WebMediaStreamTrack& track) {
192 return static_cast<MediaStreamVideoTrack*>(track.extraData());
195 MediaStreamVideoTrack::MediaStreamVideoTrack(
196 MediaStreamVideoSource* source,
197 const blink::WebMediaConstraints& constraints,
198 const MediaStreamVideoSource::ConstraintsCallback& callback,
199 bool enabled)
200 : MediaStreamTrack(true),
201 frame_deliverer_(
202 new MediaStreamVideoTrack::FrameDeliverer(source->io_message_loop(),
203 enabled)),
204 constraints_(constraints),
205 source_(source) {
206 DCHECK(!constraints.isNull());
207 source->AddTrack(this,
208 base::Bind(
209 &MediaStreamVideoTrack::FrameDeliverer::DeliverFrameOnIO,
210 frame_deliverer_),
211 constraints, callback);
214 MediaStreamVideoTrack::~MediaStreamVideoTrack() {
215 DCHECK(main_render_thread_checker_.CalledOnValidThread());
216 DCHECK(sinks_.empty());
217 Stop();
218 DVLOG(3) << "~MediaStreamVideoTrack()";
221 void MediaStreamVideoTrack::AddSink(
222 MediaStreamVideoSink* sink, const VideoCaptureDeliverFrameCB& callback) {
223 DCHECK(main_render_thread_checker_.CalledOnValidThread());
224 DCHECK(std::find(sinks_.begin(), sinks_.end(), sink) == sinks_.end());
225 sinks_.push_back(sink);
226 frame_deliverer_->AddCallback(sink, callback);
229 void MediaStreamVideoTrack::RemoveSink(MediaStreamVideoSink* sink) {
230 DCHECK(main_render_thread_checker_.CalledOnValidThread());
231 std::vector<MediaStreamVideoSink*>::iterator it =
232 std::find(sinks_.begin(), sinks_.end(), sink);
233 DCHECK(it != sinks_.end());
234 sinks_.erase(it);
235 frame_deliverer_->RemoveCallback(sink);
238 void MediaStreamVideoTrack::SetEnabled(bool enabled) {
239 DCHECK(main_render_thread_checker_.CalledOnValidThread());
240 frame_deliverer_->SetEnabled(enabled);
241 for (auto* sink : sinks_)
242 sink->OnEnabledChanged(enabled);
245 void MediaStreamVideoTrack::Stop() {
246 DCHECK(main_render_thread_checker_.CalledOnValidThread());
247 if (source_) {
248 source_->RemoveTrack(this);
249 source_ = NULL;
251 OnReadyStateChanged(blink::WebMediaStreamSource::ReadyStateEnded);
254 void MediaStreamVideoTrack::OnReadyStateChanged(
255 blink::WebMediaStreamSource::ReadyState state) {
256 DCHECK(main_render_thread_checker_.CalledOnValidThread());
257 for (auto* sink : sinks_)
258 sink->OnReadyStateChanged(state);
261 } // namespace content