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 267