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"
10 #include "third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h"
15 void ResetCallback(scoped_ptr
<VideoCaptureDeliverFrameCB
> callback
) {
16 // |callback| will be deleted when this exits.
20 // MediaStreamVideoTrack::FrameDeliverer is a helper class used for registering
21 // VideoCaptureDeliverFrameCB on the main render thread to receive video frames
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
26 class MediaStreamVideoTrack::FrameDeliverer
27 : public base::RefCountedThreadSafe
<FrameDeliverer
> {
29 typedef MediaStreamVideoSink
* VideoSinkId
;
32 const scoped_refptr
<base::MessageLoopProxy
>& io_message_loop
,
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
);
53 friend class base::RefCountedThreadSafe
<FrameDeliverer
>;
54 virtual ~FrameDeliverer();
55 void AddCallbackOnIO(VideoSinkId id
,
56 const VideoCaptureDeliverFrameCB
& callback
);
57 void RemoveCallbackOnIO(
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
69 base::ThreadChecker main_render_thread_checker_
;
70 const scoped_refptr
<base::MessageLoopProxy
> io_message_loop_
;
73 scoped_refptr
<media::VideoFrame
> black_frame_
;
75 typedef std::pair
<VideoSinkId
, VideoCaptureDeliverFrameCB
>
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
),
86 DCHECK(io_message_loop_
.get());
89 MediaStreamVideoTrack::FrameDeliverer::~FrameDeliverer() {
90 DCHECK(callbacks_
.empty());
93 void MediaStreamVideoTrack::FrameDeliverer::AddCallback(
95 const VideoCaptureDeliverFrameCB
& callback
) {
96 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
97 io_message_loop_
->PostTask(
99 base::Bind(&FrameDeliverer::AddCallbackOnIO
,
100 this, id
, callback
));
103 void MediaStreamVideoTrack::FrameDeliverer::AddCallbackOnIO(
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(
114 base::Bind(&FrameDeliverer::RemoveCallbackOnIO
,
115 this, id
, base::MessageLoopProxy::current()));
118 void MediaStreamVideoTrack::FrameDeliverer::RemoveCallbackOnIO(
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
)));
136 void MediaStreamVideoTrack::FrameDeliverer::SetEnabled(bool enabled
) {
137 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
138 io_message_loop_
->PostTask(
140 base::Bind(&FrameDeliverer::SetEnabledOnIO
,
144 void MediaStreamVideoTrack::FrameDeliverer::SetEnabledOnIO(bool enabled
) {
145 DCHECK(io_message_loop_
->BelongsToCurrentThread());
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())
168 media::VideoFrame::CreateBlackFrame(reference_frame
->natural_size());
170 black_frame_
->set_timestamp(reference_frame
->timestamp());
175 blink::WebMediaStreamTrack
MediaStreamVideoTrack::CreateVideoTrack(
176 MediaStreamVideoSource
* source
,
177 const blink::WebMediaConstraints
& constraints
,
178 const MediaStreamVideoSource::ConstraintsCallback
& callback
,
180 blink::WebMediaStreamTrack track
;
181 track
.initialize(source
->owner());
182 track
.setExtraData(new MediaStreamVideoTrack(source
,
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
,
200 : MediaStreamTrack(true),
202 new MediaStreamVideoTrack::FrameDeliverer(source
->io_message_loop(),
204 constraints_(constraints
),
206 DCHECK(!constraints
.isNull());
207 source
->AddTrack(this,
209 &MediaStreamVideoTrack::FrameDeliverer::DeliverFrameOnIO
,
211 constraints
, callback
);
214 MediaStreamVideoTrack::~MediaStreamVideoTrack() {
215 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
216 DCHECK(sinks_
.empty());
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());
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());
248 source_
->RemoveTrack(this);
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