Upstream version 9.38.198.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
11 namespace content {
12
13 namespace {
14 void ResetCallback(scoped_ptr<VideoCaptureDeliverFrameCB> callback) {
15   // |callback| will be deleted when this exits.
16 }
17 }  // namespace
18
19 // MediaStreamVideoTrack::FrameDeliverer is a helper class used for registering
20 // VideoCaptureDeliverFrameCB on the main render thread to receive video frames
21 // on the IO-thread.
22 // Frames are only delivered to the sinks if the track is enabled. If the track
23 // is disabled, a black frame is instead forwarded to the sinks at the same
24 // frame rate.
25 class MediaStreamVideoTrack::FrameDeliverer
26     : public base::RefCountedThreadSafe<FrameDeliverer> {
27  public:
28   FrameDeliverer(
29       const scoped_refptr<base::MessageLoopProxy>& io_message_loop,
30       bool enabled);
31
32   void SetEnabled(bool enabled);
33
34   // Add |callback| to receive video frames on the IO-thread.
35   // Must be called on the main render thread.
36   void AddCallback(void* id, const VideoCaptureDeliverFrameCB& callback);
37
38   // Removes |callback| associated with |id| from receiving video frames if |id|
39   // has been added. It is ok to call RemoveCallback even if the |id| has not
40   // been added. Note that the added callback will be reset on the main thread.
41   // Must be called on the main render thread.
42   void RemoveCallback(void* id);
43
44   // Triggers all registered callbacks with |frame|, |format| and
45   // |estimated_capture_time| as parameters. Must be called on the IO-thread.
46   void DeliverFrameOnIO(const scoped_refptr<media::VideoFrame>& frame,
47                         const media::VideoCaptureFormat& format,
48                         const base::TimeTicks& estimated_capture_time);
49
50  private:
51   friend class base::RefCountedThreadSafe<FrameDeliverer>;
52   virtual ~FrameDeliverer();
53   void AddCallbackOnIO(void* id, const VideoCaptureDeliverFrameCB& callback);
54   void RemoveCallbackOnIO(
55       void* id, const scoped_refptr<base::MessageLoopProxy>& message_loop);
56
57   void SetEnabledOnIO(bool enabled);
58   // Returns |black_frame_| where the size and time stamp is set to the same as
59   // as in |reference_frame|.
60   const scoped_refptr<media::VideoFrame>& GetBlackFrame(
61       const scoped_refptr<media::VideoFrame>& reference_frame);
62
63   // Used to DCHECK that AddCallback and RemoveCallback are called on the main
64   // render thread.
65   base::ThreadChecker thread_checker_;
66   scoped_refptr<base::MessageLoopProxy> io_message_loop_;
67
68   bool enabled_;
69   scoped_refptr<media::VideoFrame> black_frame_;
70
71   typedef std::pair<void*, VideoCaptureDeliverFrameCB> VideoIdCallbackPair;
72   std::vector<VideoIdCallbackPair> callbacks_;
73
74   DISALLOW_COPY_AND_ASSIGN(FrameDeliverer);
75 };
76
77 MediaStreamVideoTrack::FrameDeliverer::FrameDeliverer(
78     const scoped_refptr<base::MessageLoopProxy>& io_message_loop, bool enabled)
79     : io_message_loop_(io_message_loop),
80       enabled_(enabled) {
81   DCHECK(io_message_loop_);
82 }
83
84 MediaStreamVideoTrack::FrameDeliverer::~FrameDeliverer() {
85   DCHECK(callbacks_.empty());
86 }
87
88 void MediaStreamVideoTrack::FrameDeliverer::AddCallback(
89     void* id,
90     const VideoCaptureDeliverFrameCB& callback) {
91   DCHECK(thread_checker_.CalledOnValidThread());
92   io_message_loop_->PostTask(
93       FROM_HERE,
94       base::Bind(&FrameDeliverer::AddCallbackOnIO,
95                  this, id, callback));
96 }
97
98 void MediaStreamVideoTrack::FrameDeliverer::AddCallbackOnIO(
99     void* id,
100     const VideoCaptureDeliverFrameCB& callback) {
101   DCHECK(io_message_loop_->BelongsToCurrentThread());
102   callbacks_.push_back(std::make_pair(id, callback));
103 }
104
105 void MediaStreamVideoTrack::FrameDeliverer::RemoveCallback(void* id) {
106   DCHECK(thread_checker_.CalledOnValidThread());
107   io_message_loop_->PostTask(
108       FROM_HERE,
109       base::Bind(&FrameDeliverer::RemoveCallbackOnIO,
110                  this, id, base::MessageLoopProxy::current()));
111 }
112
113 void MediaStreamVideoTrack::FrameDeliverer::RemoveCallbackOnIO(
114     void* id, const scoped_refptr<base::MessageLoopProxy>& message_loop) {
115   DCHECK(io_message_loop_->BelongsToCurrentThread());
116   std::vector<VideoIdCallbackPair>::iterator it = callbacks_.begin();
117   for (; it != callbacks_.end(); ++it) {
118     if (it->first == id) {
119       // Callback is copied to heap and then deleted on the target thread.
120       scoped_ptr<VideoCaptureDeliverFrameCB> callback;
121       callback.reset(new VideoCaptureDeliverFrameCB(it->second));
122       callbacks_.erase(it);
123       message_loop->PostTask(
124           FROM_HERE, base::Bind(&ResetCallback, base::Passed(&callback)));
125       return;
126     }
127   }
128 }
129
130 void MediaStreamVideoTrack::FrameDeliverer::SetEnabled(bool enabled) {
131   DCHECK(thread_checker_.CalledOnValidThread());
132   io_message_loop_->PostTask(
133       FROM_HERE,
134       base::Bind(&FrameDeliverer::SetEnabledOnIO,
135                  this, enabled));
136 }
137
138 void MediaStreamVideoTrack::FrameDeliverer::SetEnabledOnIO(bool enabled) {
139   DCHECK(io_message_loop_->BelongsToCurrentThread());
140   enabled_ = enabled;
141   if (enabled_)
142     black_frame_ = NULL;
143 }
144
145 void MediaStreamVideoTrack::FrameDeliverer::DeliverFrameOnIO(
146     const scoped_refptr<media::VideoFrame>& frame,
147     const media::VideoCaptureFormat& format,
148     const base::TimeTicks& estimated_capture_time) {
149   DCHECK(io_message_loop_->BelongsToCurrentThread());
150   const scoped_refptr<media::VideoFrame>& video_frame =
151       enabled_ ? frame : GetBlackFrame(frame);
152
153   for (std::vector<VideoIdCallbackPair>::iterator it = callbacks_.begin();
154        it != callbacks_.end(); ++it) {
155     it->second.Run(video_frame, format, estimated_capture_time);
156   }
157 }
158
159 const scoped_refptr<media::VideoFrame>&
160 MediaStreamVideoTrack::FrameDeliverer::GetBlackFrame(
161     const scoped_refptr<media::VideoFrame>& reference_frame) {
162   DCHECK(io_message_loop_->BelongsToCurrentThread());
163   if (!black_frame_ ||
164       black_frame_->natural_size() != reference_frame->natural_size())
165     black_frame_ =
166         media::VideoFrame::CreateBlackFrame(reference_frame->natural_size());
167
168   black_frame_->set_timestamp(reference_frame->timestamp());
169   return black_frame_;
170 }
171
172 // static
173 blink::WebMediaStreamTrack MediaStreamVideoTrack::CreateVideoTrack(
174     MediaStreamVideoSource* source,
175     const blink::WebMediaConstraints& constraints,
176     const MediaStreamVideoSource::ConstraintsCallback& callback,
177     bool enabled) {
178   blink::WebMediaStreamTrack track;
179   track.initialize(source->owner());
180   track.setExtraData(new MediaStreamVideoTrack(source,
181                                                constraints,
182                                                callback,
183                                                enabled));
184   return track;
185 }
186
187 // static
188 MediaStreamVideoTrack* MediaStreamVideoTrack::GetVideoTrack(
189      const blink::WebMediaStreamTrack& track) {
190   return static_cast<MediaStreamVideoTrack*>(track.extraData());
191 }
192
193 MediaStreamVideoTrack::MediaStreamVideoTrack(
194     MediaStreamVideoSource* source,
195     const blink::WebMediaConstraints& constraints,
196     const MediaStreamVideoSource::ConstraintsCallback& callback,
197     bool enabled)
198     : MediaStreamTrack(NULL, true),
199       frame_deliverer_(
200           new MediaStreamVideoTrack::FrameDeliverer(source->io_message_loop(),
201                                                     enabled)),
202       constraints_(constraints),
203       source_(source) {
204   DCHECK(!constraints.isNull());
205   source->AddTrack(this,
206                    base::Bind(
207                        &MediaStreamVideoTrack::FrameDeliverer::DeliverFrameOnIO,
208                        frame_deliverer_),
209                    constraints, callback);
210 }
211
212 MediaStreamVideoTrack::~MediaStreamVideoTrack() {
213   DCHECK(thread_checker_.CalledOnValidThread());
214   DCHECK(sinks_.empty());
215   Stop();
216   DVLOG(3) << "~MediaStreamVideoTrack()";
217 }
218
219 void MediaStreamVideoTrack::AddSink(
220     MediaStreamVideoSink* sink, const VideoCaptureDeliverFrameCB& callback) {
221   DCHECK(thread_checker_.CalledOnValidThread());
222   DCHECK(std::find(sinks_.begin(), sinks_.end(), sink) == sinks_.end());
223   sinks_.push_back(sink);
224   frame_deliverer_->AddCallback(sink, callback);
225 }
226
227 void MediaStreamVideoTrack::RemoveSink(MediaStreamVideoSink* sink) {
228   DCHECK(thread_checker_.CalledOnValidThread());
229   std::vector<MediaStreamVideoSink*>::iterator it =
230       std::find(sinks_.begin(), sinks_.end(), sink);
231   DCHECK(it != sinks_.end());
232   sinks_.erase(it);
233   frame_deliverer_->RemoveCallback(sink);
234 }
235
236 void MediaStreamVideoTrack::SetEnabled(bool enabled) {
237   DCHECK(thread_checker_.CalledOnValidThread());
238   MediaStreamTrack::SetEnabled(enabled);
239
240   frame_deliverer_->SetEnabled(enabled);
241   for (std::vector<MediaStreamVideoSink*>::const_iterator it = sinks_.begin();
242        it != sinks_.end(); ++it) {
243     (*it)->OnEnabledChanged(enabled);
244   }
245 }
246
247 void MediaStreamVideoTrack::Stop() {
248   DCHECK(thread_checker_.CalledOnValidThread());
249   if (source_) {
250     source_->RemoveTrack(this);
251     source_ = NULL;
252   }
253   OnReadyStateChanged(blink::WebMediaStreamSource::ReadyStateEnded);
254 }
255
256 void MediaStreamVideoTrack::OnReadyStateChanged(
257     blink::WebMediaStreamSource::ReadyState state) {
258   DCHECK(thread_checker_.CalledOnValidThread());
259   for (std::vector<MediaStreamVideoSink*>::const_iterator it = sinks_.begin();
260        it != sinks_.end(); ++it) {
261     (*it)->OnReadyStateChanged(state);
262   }
263 }
264
265 void MediaStreamVideoTrack::SetMutedState(bool muted_state) {
266   DCHECK(thread_checker_.CalledOnValidThread());
267   muted_state_ = muted_state;
268 }
269
270 bool MediaStreamVideoTrack::GetMutedState(void) const {
271   DCHECK(thread_checker_.CalledOnValidThread());
272   return muted_state_;
273 }
274
275 }  // namespace content