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"
14 void ResetCallback(scoped_ptr
<VideoCaptureDeliverFrameCB
> callback
) {
15 // |callback| will be deleted when this exits.
19 // MediaStreamVideoTrack::FrameDeliverer is a helper class used for registering
20 // VideoCaptureDeliverFrameCB on the main render thread to receive video frames
22 // Frames are only delivered to the sinks if the track is enabled. If the track
23 // is disabled, a black frame is instead forwarded to the sinks at the same
25 class MediaStreamVideoTrack::FrameDeliverer
26 : public base::RefCountedThreadSafe
<FrameDeliverer
> {
29 const scoped_refptr
<base::MessageLoopProxy
>& io_message_loop
,
32 void SetEnabled(bool enabled
);
34 // Add |callback| to receive video frames on the IO-thread.
35 // Must be called on the main render thread.
36 void AddCallback(void* id
, const VideoCaptureDeliverFrameCB
& callback
);
38 // Removes |callback| associated with |id| from receiving video frames if |id|
39 // has been added. It is ok to call RemoveCallback even if the |id| has not
40 // been added. Note that the added callback will be reset on the main thread.
41 // Must be called on the main render thread.
42 void RemoveCallback(void* id
);
44 // Triggers all registered callbacks with |frame|, |format| and
45 // |estimated_capture_time| as parameters. Must be called on the IO-thread.
46 void DeliverFrameOnIO(const scoped_refptr
<media::VideoFrame
>& frame
,
47 const media::VideoCaptureFormat
& format
,
48 const base::TimeTicks
& estimated_capture_time
);
51 friend class base::RefCountedThreadSafe
<FrameDeliverer
>;
52 virtual ~FrameDeliverer();
53 void AddCallbackOnIO(void* id
, const VideoCaptureDeliverFrameCB
& callback
);
54 void RemoveCallbackOnIO(
55 void* id
, const scoped_refptr
<base::MessageLoopProxy
>& message_loop
);
57 void SetEnabledOnIO(bool enabled
);
58 // Returns |black_frame_| where the size and time stamp is set to the same as
59 // as in |reference_frame|.
60 const scoped_refptr
<media::VideoFrame
>& GetBlackFrame(
61 const scoped_refptr
<media::VideoFrame
>& reference_frame
);
63 // Used to DCHECK that AddCallback and RemoveCallback are called on the main
65 base::ThreadChecker thread_checker_
;
66 scoped_refptr
<base::MessageLoopProxy
> io_message_loop_
;
69 scoped_refptr
<media::VideoFrame
> black_frame_
;
71 typedef std::pair
<void*, VideoCaptureDeliverFrameCB
> VideoIdCallbackPair
;
72 std::vector
<VideoIdCallbackPair
> callbacks_
;
74 DISALLOW_COPY_AND_ASSIGN(FrameDeliverer
);
77 MediaStreamVideoTrack::FrameDeliverer::FrameDeliverer(
78 const scoped_refptr
<base::MessageLoopProxy
>& io_message_loop
, bool enabled
)
79 : io_message_loop_(io_message_loop
),
81 DCHECK(io_message_loop_
.get());
84 MediaStreamVideoTrack::FrameDeliverer::~FrameDeliverer() {
85 DCHECK(callbacks_
.empty());
88 void MediaStreamVideoTrack::FrameDeliverer::AddCallback(
90 const VideoCaptureDeliverFrameCB
& callback
) {
91 DCHECK(thread_checker_
.CalledOnValidThread());
92 io_message_loop_
->PostTask(
94 base::Bind(&FrameDeliverer::AddCallbackOnIO
,
98 void MediaStreamVideoTrack::FrameDeliverer::AddCallbackOnIO(
100 const VideoCaptureDeliverFrameCB
& callback
) {
101 DCHECK(io_message_loop_
->BelongsToCurrentThread());
102 callbacks_
.push_back(std::make_pair(id
, callback
));
105 void MediaStreamVideoTrack::FrameDeliverer::RemoveCallback(void* id
) {
106 DCHECK(thread_checker_
.CalledOnValidThread());
107 io_message_loop_
->PostTask(
109 base::Bind(&FrameDeliverer::RemoveCallbackOnIO
,
110 this, id
, base::MessageLoopProxy::current()));
113 void MediaStreamVideoTrack::FrameDeliverer::RemoveCallbackOnIO(
114 void* id
, const scoped_refptr
<base::MessageLoopProxy
>& message_loop
) {
115 DCHECK(io_message_loop_
->BelongsToCurrentThread());
116 std::vector
<VideoIdCallbackPair
>::iterator it
= callbacks_
.begin();
117 for (; it
!= callbacks_
.end(); ++it
) {
118 if (it
->first
== id
) {
119 // Callback is copied to heap and then deleted on the target thread.
120 scoped_ptr
<VideoCaptureDeliverFrameCB
> callback
;
121 callback
.reset(new VideoCaptureDeliverFrameCB(it
->second
));
122 callbacks_
.erase(it
);
123 message_loop
->PostTask(
124 FROM_HERE
, base::Bind(&ResetCallback
, base::Passed(&callback
)));
130 void MediaStreamVideoTrack::FrameDeliverer::SetEnabled(bool enabled
) {
131 DCHECK(thread_checker_
.CalledOnValidThread());
132 io_message_loop_
->PostTask(
134 base::Bind(&FrameDeliverer::SetEnabledOnIO
,
138 void MediaStreamVideoTrack::FrameDeliverer::SetEnabledOnIO(bool enabled
) {
139 DCHECK(io_message_loop_
->BelongsToCurrentThread());
145 void MediaStreamVideoTrack::FrameDeliverer::DeliverFrameOnIO(
146 const scoped_refptr
<media::VideoFrame
>& frame
,
147 const media::VideoCaptureFormat
& format
,
148 const base::TimeTicks
& estimated_capture_time
) {
149 DCHECK(io_message_loop_
->BelongsToCurrentThread());
150 const scoped_refptr
<media::VideoFrame
>& video_frame
=
151 enabled_
? frame
: GetBlackFrame(frame
);
153 for (std::vector
<VideoIdCallbackPair
>::iterator it
= callbacks_
.begin();
154 it
!= callbacks_
.end(); ++it
) {
155 it
->second
.Run(video_frame
, format
, estimated_capture_time
);
159 const scoped_refptr
<media::VideoFrame
>&
160 MediaStreamVideoTrack::FrameDeliverer::GetBlackFrame(
161 const scoped_refptr
<media::VideoFrame
>& reference_frame
) {
162 DCHECK(io_message_loop_
->BelongsToCurrentThread());
163 if (!black_frame_
.get() ||
164 black_frame_
->natural_size() != reference_frame
->natural_size())
166 media::VideoFrame::CreateBlackFrame(reference_frame
->natural_size());
168 black_frame_
->set_timestamp(reference_frame
->timestamp());
173 blink::WebMediaStreamTrack
MediaStreamVideoTrack::CreateVideoTrack(
174 MediaStreamVideoSource
* source
,
175 const blink::WebMediaConstraints
& constraints
,
176 const MediaStreamVideoSource::ConstraintsCallback
& callback
,
178 blink::WebMediaStreamTrack track
;
179 track
.initialize(source
->owner());
180 track
.setExtraData(new MediaStreamVideoTrack(source
,
188 MediaStreamVideoTrack
* MediaStreamVideoTrack::GetVideoTrack(
189 const blink::WebMediaStreamTrack
& track
) {
190 return static_cast<MediaStreamVideoTrack
*>(track
.extraData());
193 MediaStreamVideoTrack::MediaStreamVideoTrack(
194 MediaStreamVideoSource
* source
,
195 const blink::WebMediaConstraints
& constraints
,
196 const MediaStreamVideoSource::ConstraintsCallback
& callback
,
198 : MediaStreamTrack(NULL
, true),
200 new MediaStreamVideoTrack::FrameDeliverer(source
->io_message_loop(),
202 constraints_(constraints
),
204 DCHECK(!constraints
.isNull());
205 source
->AddTrack(this,
207 &MediaStreamVideoTrack::FrameDeliverer::DeliverFrameOnIO
,
209 constraints
, callback
);
212 MediaStreamVideoTrack::~MediaStreamVideoTrack() {
213 DCHECK(thread_checker_
.CalledOnValidThread());
214 DCHECK(sinks_
.empty());
216 DVLOG(3) << "~MediaStreamVideoTrack()";
219 void MediaStreamVideoTrack::AddSink(
220 MediaStreamVideoSink
* sink
, const VideoCaptureDeliverFrameCB
& callback
) {
221 DCHECK(thread_checker_
.CalledOnValidThread());
222 DCHECK(std::find(sinks_
.begin(), sinks_
.end(), sink
) == sinks_
.end());
223 sinks_
.push_back(sink
);
224 frame_deliverer_
->AddCallback(sink
, callback
);
227 void MediaStreamVideoTrack::RemoveSink(MediaStreamVideoSink
* sink
) {
228 DCHECK(thread_checker_
.CalledOnValidThread());
229 std::vector
<MediaStreamVideoSink
*>::iterator it
=
230 std::find(sinks_
.begin(), sinks_
.end(), sink
);
231 DCHECK(it
!= sinks_
.end());
233 frame_deliverer_
->RemoveCallback(sink
);
236 void MediaStreamVideoTrack::SetEnabled(bool enabled
) {
237 DCHECK(thread_checker_
.CalledOnValidThread());
238 MediaStreamTrack::SetEnabled(enabled
);
240 frame_deliverer_
->SetEnabled(enabled
);
241 for (std::vector
<MediaStreamVideoSink
*>::const_iterator it
= sinks_
.begin();
242 it
!= sinks_
.end(); ++it
) {
243 (*it
)->OnEnabledChanged(enabled
);
247 void MediaStreamVideoTrack::Stop() {
248 DCHECK(thread_checker_
.CalledOnValidThread());
250 source_
->RemoveTrack(this);
253 OnReadyStateChanged(blink::WebMediaStreamSource::ReadyStateEnded
);
256 void MediaStreamVideoTrack::OnReadyStateChanged(
257 blink::WebMediaStreamSource::ReadyState state
) {
258 DCHECK(thread_checker_
.CalledOnValidThread());
259 for (std::vector
<MediaStreamVideoSink
*>::const_iterator it
= sinks_
.begin();
260 it
!= sinks_
.end(); ++it
) {
261 (*it
)->OnReadyStateChanged(state
);
265 void MediaStreamVideoTrack::SetMutedState(bool muted_state
) {
266 DCHECK(thread_checker_
.CalledOnValidThread());
267 muted_state_
= muted_state
;
270 bool MediaStreamVideoTrack::GetMutedState(void) const {
271 DCHECK(thread_checker_
.CalledOnValidThread());
275 } // namespace content