Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / renderer / media / media_stream_video_track.cc
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 {
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
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
85 MediaStreamVideoTrack::FrameDeliverer::~FrameDeliverer() {
86   DCHECK(callbacks_.empty());
87 }
88
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
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
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
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
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
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
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>&
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
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
189 MediaStreamVideoTrack* MediaStreamVideoTrack::GetVideoTrack(
190      const blink::WebMediaStreamTrack& track) {
191   return static_cast<MediaStreamVideoTrack*>(track.extraData());
192 }
193
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
213 MediaStreamVideoTrack::~MediaStreamVideoTrack() {
214   DCHECK(thread_checker_.CalledOnValidThread());
215   DCHECK(sinks_.empty());
216   Stop();
217   DVLOG(3) << "~MediaStreamVideoTrack()";
218 }
219
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
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
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
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
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