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 "base/location.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h"
18 void ResetCallback(scoped_ptr
<VideoCaptureDeliverFrameCB
> callback
) {
19 // |callback| will be deleted when this exits.
22 // Empty method used for keeping a reference to the original media::VideoFrame.
23 // The reference to |frame| is kept in the closure that calls this method.
24 void ReleaseOriginalFrame(const scoped_refptr
<media::VideoFrame
>& frame
) {
29 // MediaStreamVideoTrack::FrameDeliverer is a helper class used for registering
30 // VideoCaptureDeliverFrameCB on the main render thread to receive video frames
32 // Frames are only delivered to the sinks if the track is enabled. If the track
33 // is disabled, a black frame is instead forwarded to the sinks at the same
35 class MediaStreamVideoTrack::FrameDeliverer
36 : public base::RefCountedThreadSafe
<FrameDeliverer
> {
38 typedef MediaStreamVideoSink
* VideoSinkId
;
40 FrameDeliverer(scoped_refptr
<base::SingleThreadTaskRunner
> io_task_runner
,
43 void SetEnabled(bool enabled
);
45 // Add |callback| to receive video frames on the IO-thread.
46 // Must be called on the main render thread.
47 void AddCallback(VideoSinkId id
, const VideoCaptureDeliverFrameCB
& callback
);
49 // Removes |callback| associated with |id| from receiving video frames if |id|
50 // has been added. It is ok to call RemoveCallback even if the |id| has not
51 // been added. Note that the added callback will be reset on the main thread.
52 // Must be called on the main render thread.
53 void RemoveCallback(VideoSinkId id
);
55 // Triggers all registered callbacks with |frame|, |format| and
56 // |estimated_capture_time| as parameters. Must be called on the IO-thread.
57 void DeliverFrameOnIO(const scoped_refptr
<media::VideoFrame
>& frame
,
58 const base::TimeTicks
& estimated_capture_time
);
61 friend class base::RefCountedThreadSafe
<FrameDeliverer
>;
62 virtual ~FrameDeliverer();
63 void AddCallbackOnIO(VideoSinkId id
,
64 const VideoCaptureDeliverFrameCB
& callback
);
65 void RemoveCallbackOnIO(
67 const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
);
69 void SetEnabledOnIO(bool enabled
);
70 // Returns a black frame where the size and time stamp is set to the same as
71 // as in |reference_frame|.
72 scoped_refptr
<media::VideoFrame
> GetBlackFrame(
73 const scoped_refptr
<media::VideoFrame
>& reference_frame
);
75 // Used to DCHECK that AddCallback and RemoveCallback are called on the main
77 base::ThreadChecker main_render_thread_checker_
;
78 const scoped_refptr
<base::SingleThreadTaskRunner
> io_task_runner_
;
81 scoped_refptr
<media::VideoFrame
> black_frame_
;
83 typedef std::pair
<VideoSinkId
, VideoCaptureDeliverFrameCB
>
85 std::vector
<VideoIdCallbackPair
> callbacks_
;
87 DISALLOW_COPY_AND_ASSIGN(FrameDeliverer
);
90 MediaStreamVideoTrack::FrameDeliverer::FrameDeliverer(
91 scoped_refptr
<base::SingleThreadTaskRunner
> io_task_runner
,
93 : io_task_runner_(io_task_runner
), enabled_(enabled
) {
94 DCHECK(io_task_runner_
.get());
97 MediaStreamVideoTrack::FrameDeliverer::~FrameDeliverer() {
98 DCHECK(callbacks_
.empty());
101 void MediaStreamVideoTrack::FrameDeliverer::AddCallback(
103 const VideoCaptureDeliverFrameCB
& callback
) {
104 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
105 io_task_runner_
->PostTask(
107 base::Bind(&FrameDeliverer::AddCallbackOnIO
, this, id
, callback
));
110 void MediaStreamVideoTrack::FrameDeliverer::AddCallbackOnIO(
112 const VideoCaptureDeliverFrameCB
& callback
) {
113 DCHECK(io_task_runner_
->BelongsToCurrentThread());
114 callbacks_
.push_back(std::make_pair(id
, callback
));
117 void MediaStreamVideoTrack::FrameDeliverer::RemoveCallback(VideoSinkId id
) {
118 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
119 io_task_runner_
->PostTask(
120 FROM_HERE
, base::Bind(&FrameDeliverer::RemoveCallbackOnIO
, this, id
,
121 base::ThreadTaskRunnerHandle::Get()));
124 void MediaStreamVideoTrack::FrameDeliverer::RemoveCallbackOnIO(
126 const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
) {
127 DCHECK(io_task_runner_
->BelongsToCurrentThread());
128 std::vector
<VideoIdCallbackPair
>::iterator it
= callbacks_
.begin();
129 for (; it
!= callbacks_
.end(); ++it
) {
130 if (it
->first
== id
) {
131 // Callback is copied to heap and then deleted on the target thread.
132 scoped_ptr
<VideoCaptureDeliverFrameCB
> callback
;
133 callback
.reset(new VideoCaptureDeliverFrameCB(it
->second
));
134 callbacks_
.erase(it
);
135 task_runner
->PostTask(
136 FROM_HERE
, base::Bind(&ResetCallback
, base::Passed(&callback
)));
142 void MediaStreamVideoTrack::FrameDeliverer::SetEnabled(bool enabled
) {
143 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
144 io_task_runner_
->PostTask(
145 FROM_HERE
, base::Bind(&FrameDeliverer::SetEnabledOnIO
, this, enabled
));
148 void MediaStreamVideoTrack::FrameDeliverer::SetEnabledOnIO(bool enabled
) {
149 DCHECK(io_task_runner_
->BelongsToCurrentThread());
155 void MediaStreamVideoTrack::FrameDeliverer::DeliverFrameOnIO(
156 const scoped_refptr
<media::VideoFrame
>& frame
,
157 const base::TimeTicks
& estimated_capture_time
) {
158 DCHECK(io_task_runner_
->BelongsToCurrentThread());
159 const scoped_refptr
<media::VideoFrame
>& video_frame
=
160 enabled_
? frame
: GetBlackFrame(frame
);
161 for (const auto& entry
: callbacks_
)
162 entry
.second
.Run(video_frame
, estimated_capture_time
);
165 scoped_refptr
<media::VideoFrame
>
166 MediaStreamVideoTrack::FrameDeliverer::GetBlackFrame(
167 const scoped_refptr
<media::VideoFrame
>& reference_frame
) {
168 DCHECK(io_task_runner_
->BelongsToCurrentThread());
169 if (!black_frame_
.get() ||
170 black_frame_
->natural_size() != reference_frame
->natural_size())
172 media::VideoFrame::CreateBlackFrame(reference_frame
->natural_size());
174 // Wrap |black_frame_| so we get a fresh timestamp we can modify. Frames
175 // returned from this function may still be in use.
176 scoped_refptr
<media::VideoFrame
> wrapped_black_frame
=
177 media::VideoFrame::WrapVideoFrame(
178 black_frame_
, black_frame_
->visible_rect(),
179 black_frame_
->natural_size());
180 wrapped_black_frame
->AddDestructionObserver(
181 base::Bind(&ReleaseOriginalFrame
, black_frame_
));
183 wrapped_black_frame
->set_timestamp(reference_frame
->timestamp());
184 return wrapped_black_frame
;
188 blink::WebMediaStreamTrack
MediaStreamVideoTrack::CreateVideoTrack(
189 MediaStreamVideoSource
* source
,
190 const blink::WebMediaConstraints
& constraints
,
191 const MediaStreamVideoSource::ConstraintsCallback
& callback
,
193 blink::WebMediaStreamTrack track
;
194 track
.initialize(source
->owner());
195 track
.setExtraData(new MediaStreamVideoTrack(source
,
203 MediaStreamVideoTrack
* MediaStreamVideoTrack::GetVideoTrack(
204 const blink::WebMediaStreamTrack
& track
) {
205 return static_cast<MediaStreamVideoTrack
*>(track
.extraData());
208 MediaStreamVideoTrack::MediaStreamVideoTrack(
209 MediaStreamVideoSource
* source
,
210 const blink::WebMediaConstraints
& constraints
,
211 const MediaStreamVideoSource::ConstraintsCallback
& callback
,
213 : MediaStreamTrack(true),
215 new MediaStreamVideoTrack::FrameDeliverer(source
->io_task_runner(),
217 constraints_(constraints
),
219 DCHECK(!constraints
.isNull());
220 source
->AddTrack(this,
222 &MediaStreamVideoTrack::FrameDeliverer::DeliverFrameOnIO
,
224 constraints
, callback
);
227 MediaStreamVideoTrack::~MediaStreamVideoTrack() {
228 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
229 DCHECK(sinks_
.empty());
231 DVLOG(3) << "~MediaStreamVideoTrack()";
234 void MediaStreamVideoTrack::AddSink(
235 MediaStreamVideoSink
* sink
, const VideoCaptureDeliverFrameCB
& callback
) {
236 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
237 DCHECK(std::find(sinks_
.begin(), sinks_
.end(), sink
) == sinks_
.end());
238 sinks_
.push_back(sink
);
239 frame_deliverer_
->AddCallback(sink
, callback
);
242 void MediaStreamVideoTrack::RemoveSink(MediaStreamVideoSink
* sink
) {
243 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
244 std::vector
<MediaStreamVideoSink
*>::iterator it
=
245 std::find(sinks_
.begin(), sinks_
.end(), sink
);
246 DCHECK(it
!= sinks_
.end());
248 frame_deliverer_
->RemoveCallback(sink
);
251 void MediaStreamVideoTrack::SetEnabled(bool enabled
) {
252 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
253 frame_deliverer_
->SetEnabled(enabled
);
254 for (auto* sink
: sinks_
)
255 sink
->OnEnabledChanged(enabled
);
258 void MediaStreamVideoTrack::Stop() {
259 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
261 source_
->RemoveTrack(this);
264 OnReadyStateChanged(blink::WebMediaStreamSource::ReadyStateEnded
);
267 void MediaStreamVideoTrack::OnReadyStateChanged(
268 blink::WebMediaStreamSource::ReadyState state
) {
269 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
270 for (auto* sink
: sinks_
)
271 sink
->OnReadyStateChanged(state
);
274 } // namespace content