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
> {
30 const scoped_refptr
<base::MessageLoopProxy
>& io_message_loop
,
33 void SetEnabled(bool enabled
);
35 // Add |callback| to receive video frames on the IO-thread.
36 // Must be called on the main render thread.
37 void AddCallback(void* id
, const VideoCaptureDeliverFrameCB
& callback
);
39 // Removes |callback| associated with |id| from receiving video frames if |id|
40 // has been added. It is ok to call RemoveCallback even if the |id| has not
41 // been added. Note that the added callback will be reset on the main thread.
42 // Must be called on the main render thread.
43 void RemoveCallback(void* id
);
45 // Triggers all registered callbacks with |frame|, |format| and
46 // |estimated_capture_time| as parameters. Must be called on the IO-thread.
47 void DeliverFrameOnIO(const scoped_refptr
<media::VideoFrame
>& frame
,
48 const media::VideoCaptureFormat
& format
,
49 const base::TimeTicks
& estimated_capture_time
);
52 friend class base::RefCountedThreadSafe
<FrameDeliverer
>;
53 virtual ~FrameDeliverer();
54 void AddCallbackOnIO(void* id
, const VideoCaptureDeliverFrameCB
& callback
);
55 void RemoveCallbackOnIO(
56 void* id
, const scoped_refptr
<base::MessageLoopProxy
>& message_loop
);
58 void SetEnabledOnIO(bool enabled
);
59 // Returns |black_frame_| where the size and time stamp is set to the same as
60 // as in |reference_frame|.
61 const scoped_refptr
<media::VideoFrame
>& GetBlackFrame(
62 const scoped_refptr
<media::VideoFrame
>& reference_frame
);
64 // Used to DCHECK that AddCallback and RemoveCallback are called on the main
66 base::ThreadChecker thread_checker_
;
67 scoped_refptr
<base::MessageLoopProxy
> io_message_loop_
;
70 scoped_refptr
<media::VideoFrame
> black_frame_
;
72 typedef std::pair
<void*, VideoCaptureDeliverFrameCB
> VideoIdCallbackPair
;
73 std::vector
<VideoIdCallbackPair
> callbacks_
;
75 DISALLOW_COPY_AND_ASSIGN(FrameDeliverer
);
78 MediaStreamVideoTrack::FrameDeliverer::FrameDeliverer(
79 const scoped_refptr
<base::MessageLoopProxy
>& io_message_loop
, bool enabled
)
80 : io_message_loop_(io_message_loop
),
82 DCHECK(io_message_loop_
.get());
85 MediaStreamVideoTrack::FrameDeliverer::~FrameDeliverer() {
86 DCHECK(callbacks_
.empty());
89 void MediaStreamVideoTrack::FrameDeliverer::AddCallback(
91 const VideoCaptureDeliverFrameCB
& callback
) {
92 DCHECK(thread_checker_
.CalledOnValidThread());
93 io_message_loop_
->PostTask(
95 base::Bind(&FrameDeliverer::AddCallbackOnIO
,
99 void MediaStreamVideoTrack::FrameDeliverer::AddCallbackOnIO(
101 const VideoCaptureDeliverFrameCB
& callback
) {
102 DCHECK(io_message_loop_
->BelongsToCurrentThread());
103 callbacks_
.push_back(std::make_pair(id
, callback
));
106 void MediaStreamVideoTrack::FrameDeliverer::RemoveCallback(void* id
) {
107 DCHECK(thread_checker_
.CalledOnValidThread());
108 io_message_loop_
->PostTask(
110 base::Bind(&FrameDeliverer::RemoveCallbackOnIO
,
111 this, id
, base::MessageLoopProxy::current()));
114 void MediaStreamVideoTrack::FrameDeliverer::RemoveCallbackOnIO(
115 void* id
, const scoped_refptr
<base::MessageLoopProxy
>& message_loop
) {
116 DCHECK(io_message_loop_
->BelongsToCurrentThread());
117 std::vector
<VideoIdCallbackPair
>::iterator it
= callbacks_
.begin();
118 for (; it
!= callbacks_
.end(); ++it
) {
119 if (it
->first
== id
) {
120 // Callback is copied to heap and then deleted on the target thread.
121 scoped_ptr
<VideoCaptureDeliverFrameCB
> callback
;
122 callback
.reset(new VideoCaptureDeliverFrameCB(it
->second
));
123 callbacks_
.erase(it
);
124 message_loop
->PostTask(
125 FROM_HERE
, base::Bind(&ResetCallback
, base::Passed(&callback
)));
131 void MediaStreamVideoTrack::FrameDeliverer::SetEnabled(bool enabled
) {
132 DCHECK(thread_checker_
.CalledOnValidThread());
133 io_message_loop_
->PostTask(
135 base::Bind(&FrameDeliverer::SetEnabledOnIO
,
139 void MediaStreamVideoTrack::FrameDeliverer::SetEnabledOnIO(bool enabled
) {
140 DCHECK(io_message_loop_
->BelongsToCurrentThread());
146 void MediaStreamVideoTrack::FrameDeliverer::DeliverFrameOnIO(
147 const scoped_refptr
<media::VideoFrame
>& frame
,
148 const media::VideoCaptureFormat
& format
,
149 const base::TimeTicks
& estimated_capture_time
) {
150 DCHECK(io_message_loop_
->BelongsToCurrentThread());
151 const scoped_refptr
<media::VideoFrame
>& video_frame
=
152 enabled_
? frame
: GetBlackFrame(frame
);
154 for (std::vector
<VideoIdCallbackPair
>::iterator it
= callbacks_
.begin();
155 it
!= callbacks_
.end(); ++it
) {
156 it
->second
.Run(video_frame
, format
, estimated_capture_time
);
160 const scoped_refptr
<media::VideoFrame
>&
161 MediaStreamVideoTrack::FrameDeliverer::GetBlackFrame(
162 const scoped_refptr
<media::VideoFrame
>& reference_frame
) {
163 DCHECK(io_message_loop_
->BelongsToCurrentThread());
164 if (!black_frame_
.get() ||
165 black_frame_
->natural_size() != reference_frame
->natural_size())
167 media::VideoFrame::CreateBlackFrame(reference_frame
->natural_size());
169 black_frame_
->set_timestamp(reference_frame
->timestamp());
174 blink::WebMediaStreamTrack
MediaStreamVideoTrack::CreateVideoTrack(
175 MediaStreamVideoSource
* source
,
176 const blink::WebMediaConstraints
& constraints
,
177 const MediaStreamVideoSource::ConstraintsCallback
& callback
,
179 blink::WebMediaStreamTrack track
;
180 track
.initialize(source
->owner());
181 track
.setExtraData(new MediaStreamVideoTrack(source
,
189 MediaStreamVideoTrack
* MediaStreamVideoTrack::GetVideoTrack(
190 const blink::WebMediaStreamTrack
& track
) {
191 return static_cast<MediaStreamVideoTrack
*>(track
.extraData());
194 MediaStreamVideoTrack::MediaStreamVideoTrack(
195 MediaStreamVideoSource
* source
,
196 const blink::WebMediaConstraints
& constraints
,
197 const MediaStreamVideoSource::ConstraintsCallback
& callback
,
199 : MediaStreamTrack(NULL
, true),
201 new MediaStreamVideoTrack::FrameDeliverer(source
->io_message_loop(),
203 constraints_(constraints
),
205 DCHECK(!constraints
.isNull());
206 source
->AddTrack(this,
208 &MediaStreamVideoTrack::FrameDeliverer::DeliverFrameOnIO
,
210 constraints
, callback
);
213 MediaStreamVideoTrack::~MediaStreamVideoTrack() {
214 DCHECK(thread_checker_
.CalledOnValidThread());
215 DCHECK(sinks_
.empty());
217 DVLOG(3) << "~MediaStreamVideoTrack()";
220 void MediaStreamVideoTrack::AddSink(
221 MediaStreamVideoSink
* sink
, const VideoCaptureDeliverFrameCB
& callback
) {
222 DCHECK(thread_checker_
.CalledOnValidThread());
223 DCHECK(std::find(sinks_
.begin(), sinks_
.end(), sink
) == sinks_
.end());
224 sinks_
.push_back(sink
);
225 frame_deliverer_
->AddCallback(sink
, callback
);
228 void MediaStreamVideoTrack::RemoveSink(MediaStreamVideoSink
* sink
) {
229 DCHECK(thread_checker_
.CalledOnValidThread());
230 std::vector
<MediaStreamVideoSink
*>::iterator it
=
231 std::find(sinks_
.begin(), sinks_
.end(), sink
);
232 DCHECK(it
!= sinks_
.end());
234 frame_deliverer_
->RemoveCallback(sink
);
237 void MediaStreamVideoTrack::SetEnabled(bool enabled
) {
238 DCHECK(thread_checker_
.CalledOnValidThread());
239 MediaStreamTrack::SetEnabled(enabled
);
241 frame_deliverer_
->SetEnabled(enabled
);
242 for (std::vector
<MediaStreamVideoSink
*>::const_iterator it
= sinks_
.begin();
243 it
!= sinks_
.end(); ++it
) {
244 (*it
)->OnEnabledChanged(enabled
);
248 void MediaStreamVideoTrack::Stop() {
249 DCHECK(thread_checker_
.CalledOnValidThread());
251 source_
->RemoveTrack(this);
254 OnReadyStateChanged(blink::WebMediaStreamSource::ReadyStateEnded
);
257 void MediaStreamVideoTrack::OnReadyStateChanged(
258 blink::WebMediaStreamSource::ReadyState state
) {
259 DCHECK(thread_checker_
.CalledOnValidThread());
260 for (std::vector
<MediaStreamVideoSink
*>::const_iterator it
= sinks_
.begin();
261 it
!= sinks_
.end(); ++it
) {
262 (*it
)->OnReadyStateChanged(state
);
266 } // namespace content