• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "content/renderer/media/media_stream_video_track.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h"
11 
12 namespace content {
13 
14 namespace {
ResetCallback(scoped_ptr<VideoCaptureDeliverFrameCB> callback)15 void ResetCallback(scoped_ptr<VideoCaptureDeliverFrameCB> callback) {
16   // |callback| will be deleted when this exits.
17 }
18 }  // namespace
19 
20 // MediaStreamVideoTrack::FrameDeliverer is a helper class used for registering
21 // VideoCaptureDeliverFrameCB on the main render thread to receive video frames
22 // on the IO-thread.
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
25 // frame rate.
26 class MediaStreamVideoTrack::FrameDeliverer
27     : public base::RefCountedThreadSafe<FrameDeliverer> {
28  public:
29   FrameDeliverer(
30       const scoped_refptr<base::MessageLoopProxy>& io_message_loop,
31       bool enabled);
32 
33   void SetEnabled(bool enabled);
34 
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);
38 
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);
44 
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);
50 
51  private:
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);
57 
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);
63 
64   // Used to DCHECK that AddCallback and RemoveCallback are called on the main
65   // render thread.
66   base::ThreadChecker thread_checker_;
67   scoped_refptr<base::MessageLoopProxy> io_message_loop_;
68 
69   bool enabled_;
70   scoped_refptr<media::VideoFrame> black_frame_;
71 
72   typedef std::pair<void*, VideoCaptureDeliverFrameCB> VideoIdCallbackPair;
73   std::vector<VideoIdCallbackPair> callbacks_;
74 
75   DISALLOW_COPY_AND_ASSIGN(FrameDeliverer);
76 };
77 
FrameDeliverer(const scoped_refptr<base::MessageLoopProxy> & io_message_loop,bool enabled)78 MediaStreamVideoTrack::FrameDeliverer::FrameDeliverer(
79     const scoped_refptr<base::MessageLoopProxy>& io_message_loop, bool enabled)
80     : io_message_loop_(io_message_loop),
81       enabled_(enabled) {
82   DCHECK(io_message_loop_.get());
83 }
84 
~FrameDeliverer()85 MediaStreamVideoTrack::FrameDeliverer::~FrameDeliverer() {
86   DCHECK(callbacks_.empty());
87 }
88 
AddCallback(void * id,const VideoCaptureDeliverFrameCB & callback)89 void MediaStreamVideoTrack::FrameDeliverer::AddCallback(
90     void* id,
91     const VideoCaptureDeliverFrameCB& callback) {
92   DCHECK(thread_checker_.CalledOnValidThread());
93   io_message_loop_->PostTask(
94       FROM_HERE,
95       base::Bind(&FrameDeliverer::AddCallbackOnIO,
96                  this, id, callback));
97 }
98 
AddCallbackOnIO(void * id,const VideoCaptureDeliverFrameCB & callback)99 void MediaStreamVideoTrack::FrameDeliverer::AddCallbackOnIO(
100     void* id,
101     const VideoCaptureDeliverFrameCB& callback) {
102   DCHECK(io_message_loop_->BelongsToCurrentThread());
103   callbacks_.push_back(std::make_pair(id, callback));
104 }
105 
RemoveCallback(void * id)106 void MediaStreamVideoTrack::FrameDeliverer::RemoveCallback(void* id) {
107   DCHECK(thread_checker_.CalledOnValidThread());
108   io_message_loop_->PostTask(
109       FROM_HERE,
110       base::Bind(&FrameDeliverer::RemoveCallbackOnIO,
111                  this, id, base::MessageLoopProxy::current()));
112 }
113 
RemoveCallbackOnIO(void * id,const scoped_refptr<base::MessageLoopProxy> & message_loop)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)));
126       return;
127     }
128   }
129 }
130 
SetEnabled(bool enabled)131 void MediaStreamVideoTrack::FrameDeliverer::SetEnabled(bool enabled) {
132   DCHECK(thread_checker_.CalledOnValidThread());
133   io_message_loop_->PostTask(
134       FROM_HERE,
135       base::Bind(&FrameDeliverer::SetEnabledOnIO,
136                  this, enabled));
137 }
138 
SetEnabledOnIO(bool enabled)139 void MediaStreamVideoTrack::FrameDeliverer::SetEnabledOnIO(bool enabled) {
140   DCHECK(io_message_loop_->BelongsToCurrentThread());
141   enabled_ = enabled;
142   if (enabled_)
143     black_frame_ = NULL;
144 }
145 
DeliverFrameOnIO(const scoped_refptr<media::VideoFrame> & frame,const media::VideoCaptureFormat & format,const base::TimeTicks & estimated_capture_time)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);
153 
154   for (std::vector<VideoIdCallbackPair>::iterator it = callbacks_.begin();
155        it != callbacks_.end(); ++it) {
156     it->second.Run(video_frame, format, estimated_capture_time);
157   }
158 }
159 
160 const scoped_refptr<media::VideoFrame>&
GetBlackFrame(const scoped_refptr<media::VideoFrame> & reference_frame)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())
166     black_frame_ =
167         media::VideoFrame::CreateBlackFrame(reference_frame->natural_size());
168 
169   black_frame_->set_timestamp(reference_frame->timestamp());
170   return black_frame_;
171 }
172 
173 // static
CreateVideoTrack(MediaStreamVideoSource * source,const blink::WebMediaConstraints & constraints,const MediaStreamVideoSource::ConstraintsCallback & callback,bool enabled)174 blink::WebMediaStreamTrack MediaStreamVideoTrack::CreateVideoTrack(
175     MediaStreamVideoSource* source,
176     const blink::WebMediaConstraints& constraints,
177     const MediaStreamVideoSource::ConstraintsCallback& callback,
178     bool enabled) {
179   blink::WebMediaStreamTrack track;
180   track.initialize(source->owner());
181   track.setExtraData(new MediaStreamVideoTrack(source,
182                                                constraints,
183                                                callback,
184                                                enabled));
185   return track;
186 }
187 
188 // static
GetVideoTrack(const blink::WebMediaStreamTrack & track)189 MediaStreamVideoTrack* MediaStreamVideoTrack::GetVideoTrack(
190      const blink::WebMediaStreamTrack& track) {
191   return static_cast<MediaStreamVideoTrack*>(track.extraData());
192 }
193 
MediaStreamVideoTrack(MediaStreamVideoSource * source,const blink::WebMediaConstraints & constraints,const MediaStreamVideoSource::ConstraintsCallback & callback,bool enabled)194 MediaStreamVideoTrack::MediaStreamVideoTrack(
195     MediaStreamVideoSource* source,
196     const blink::WebMediaConstraints& constraints,
197     const MediaStreamVideoSource::ConstraintsCallback& callback,
198     bool enabled)
199     : MediaStreamTrack(NULL, true),
200       frame_deliverer_(
201           new MediaStreamVideoTrack::FrameDeliverer(source->io_message_loop(),
202                                                     enabled)),
203       constraints_(constraints),
204       source_(source) {
205   DCHECK(!constraints.isNull());
206   source->AddTrack(this,
207                    base::Bind(
208                        &MediaStreamVideoTrack::FrameDeliverer::DeliverFrameOnIO,
209                        frame_deliverer_),
210                    constraints, callback);
211 }
212 
~MediaStreamVideoTrack()213 MediaStreamVideoTrack::~MediaStreamVideoTrack() {
214   DCHECK(thread_checker_.CalledOnValidThread());
215   DCHECK(sinks_.empty());
216   Stop();
217   DVLOG(3) << "~MediaStreamVideoTrack()";
218 }
219 
AddSink(MediaStreamVideoSink * sink,const VideoCaptureDeliverFrameCB & callback)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);
226 }
227 
RemoveSink(MediaStreamVideoSink * sink)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());
233   sinks_.erase(it);
234   frame_deliverer_->RemoveCallback(sink);
235 }
236 
SetEnabled(bool enabled)237 void MediaStreamVideoTrack::SetEnabled(bool enabled) {
238   DCHECK(thread_checker_.CalledOnValidThread());
239   MediaStreamTrack::SetEnabled(enabled);
240 
241   frame_deliverer_->SetEnabled(enabled);
242   for (std::vector<MediaStreamVideoSink*>::const_iterator it = sinks_.begin();
243        it != sinks_.end(); ++it) {
244     (*it)->OnEnabledChanged(enabled);
245   }
246 }
247 
Stop()248 void MediaStreamVideoTrack::Stop() {
249   DCHECK(thread_checker_.CalledOnValidThread());
250   if (source_) {
251     source_->RemoveTrack(this);
252     source_ = NULL;
253   }
254   OnReadyStateChanged(blink::WebMediaStreamSource::ReadyStateEnded);
255 }
256 
OnReadyStateChanged(blink::WebMediaStreamSource::ReadyState state)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);
263   }
264 }
265 
266 }  // namespace content
267