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 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 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());
175 // Wrap |black_frame_| so we get a fresh timestamp we can modify. Frames
176 // returned from this function may still be in use.
177 scoped_refptr
<media::VideoFrame
> wrapped_black_frame
=
178 media::VideoFrame::WrapVideoFrame(
179 black_frame_
, black_frame_
->visible_rect(),
180 black_frame_
->natural_size());
181 wrapped_black_frame
->AddDestructionObserver(
182 base::Bind(&ReleaseOriginalFrame
, black_frame_
));
184 wrapped_black_frame
->set_timestamp(reference_frame
->timestamp());
185 return wrapped_black_frame
;
189 blink::WebMediaStreamTrack
MediaStreamVideoTrack::CreateVideoTrack(
190 MediaStreamVideoSource
* source
,
191 const blink::WebMediaConstraints
& constraints
,
192 const MediaStreamVideoSource::ConstraintsCallback
& callback
,
194 blink::WebMediaStreamTrack track
;
195 track
.initialize(source
->owner());
196 track
.setExtraData(new MediaStreamVideoTrack(source
,
204 MediaStreamVideoTrack
* MediaStreamVideoTrack::GetVideoTrack(
205 const blink::WebMediaStreamTrack
& track
) {
206 return static_cast<MediaStreamVideoTrack
*>(track
.extraData());
209 MediaStreamVideoTrack::MediaStreamVideoTrack(
210 MediaStreamVideoSource
* source
,
211 const blink::WebMediaConstraints
& constraints
,
212 const MediaStreamVideoSource::ConstraintsCallback
& callback
,
214 : MediaStreamTrack(true),
216 new MediaStreamVideoTrack::FrameDeliverer(source
->io_task_runner(),
218 constraints_(constraints
),
220 DCHECK(!constraints
.isNull());
221 source
->AddTrack(this,
223 &MediaStreamVideoTrack::FrameDeliverer::DeliverFrameOnIO
,
225 constraints
, callback
);
228 MediaStreamVideoTrack::~MediaStreamVideoTrack() {
229 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
230 DCHECK(sinks_
.empty());
232 DVLOG(3) << "~MediaStreamVideoTrack()";
235 void MediaStreamVideoTrack::AddSink(
236 MediaStreamVideoSink
* sink
, const VideoCaptureDeliverFrameCB
& callback
) {
237 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
238 DCHECK(std::find(sinks_
.begin(), sinks_
.end(), sink
) == sinks_
.end());
239 sinks_
.push_back(sink
);
240 frame_deliverer_
->AddCallback(sink
, callback
);
243 void MediaStreamVideoTrack::RemoveSink(MediaStreamVideoSink
* sink
) {
244 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
245 std::vector
<MediaStreamVideoSink
*>::iterator it
=
246 std::find(sinks_
.begin(), sinks_
.end(), sink
);
247 DCHECK(it
!= sinks_
.end());
249 frame_deliverer_
->RemoveCallback(sink
);
252 void MediaStreamVideoTrack::SetEnabled(bool enabled
) {
253 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
254 frame_deliverer_
->SetEnabled(enabled
);
255 for (auto* sink
: sinks_
)
256 sink
->OnEnabledChanged(enabled
);
259 void MediaStreamVideoTrack::Stop() {
260 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
262 source_
->RemoveTrack(this);
265 OnReadyStateChanged(blink::WebMediaStreamSource::ReadyStateEnded
);
268 void MediaStreamVideoTrack::OnReadyStateChanged(
269 blink::WebMediaStreamSource::ReadyState state
) {
270 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
271 for (auto* sink
: sinks_
)
272 sink
->OnReadyStateChanged(state
);
275 } // namespace content