1 // Copyright 2014 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/webrtc/media_stream_remote_video_source.h" 6 7 #include "base/bind.h" 8 #include "base/callback_helpers.h" 9 #include "base/location.h" 10 #include "base/message_loop/message_loop_proxy.h" 11 #include "content/renderer/media/native_handle_impl.h" 12 #include "media/base/bind_to_current_loop.h" 13 #include "media/base/video_frame.h" 14 #include "media/base/video_frame_pool.h" 15 #include "media/base/video_util.h" 16 #include "third_party/libjingle/source/talk/media/base/videoframe.h" 17 18 namespace content { 19 20 // Internal class used for receiving frames from the webrtc track on a 21 // libjingle thread and forward it to the IO-thread. 22 class MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate 23 : public base::RefCountedThreadSafe<RemoteVideoSourceDelegate>, 24 public webrtc::VideoRendererInterface { 25 public: 26 RemoteVideoSourceDelegate( 27 const scoped_refptr<base::MessageLoopProxy>& io_message_loop, 28 const VideoCaptureDeliverFrameCB& new_frame_callback); 29 30 protected: 31 friend class base::RefCountedThreadSafe<RemoteVideoSourceDelegate>; 32 virtual ~RemoteVideoSourceDelegate(); 33 34 // Implements webrtc::VideoRendererInterface used for receiving video frames 35 // from the PeerConnection video track. May be called on a libjingle internal 36 // thread. 37 virtual void SetSize(int width, int height) OVERRIDE; 38 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE; 39 40 void DoRenderFrameOnIOThread(scoped_refptr<media::VideoFrame> video_frame, 41 const media::VideoCaptureFormat& format); 42 private: 43 // Bound to the render thread. 44 base::ThreadChecker thread_checker_; 45 46 scoped_refptr<base::MessageLoopProxy> io_message_loop_; 47 // |frame_pool_| is only accessed on whatever 48 // thread webrtc::VideoRendererInterface::RenderFrame is called on. 49 media::VideoFramePool frame_pool_; 50 51 // |frame_callback_| is accessed on the IO thread. 52 VideoCaptureDeliverFrameCB frame_callback_; 53 }; 54 55 MediaStreamRemoteVideoSource:: 56 RemoteVideoSourceDelegate::RemoteVideoSourceDelegate( 57 const scoped_refptr<base::MessageLoopProxy>& io_message_loop, 58 const VideoCaptureDeliverFrameCB& new_frame_callback) 59 : io_message_loop_(io_message_loop), 60 frame_callback_(new_frame_callback) { 61 } 62 63 MediaStreamRemoteVideoSource:: 64 RemoteVideoSourceDelegate::~RemoteVideoSourceDelegate() { 65 } 66 67 void MediaStreamRemoteVideoSource:: 68 RemoteVideoSourceDelegate::SetSize(int width, int height) { 69 } 70 71 void MediaStreamRemoteVideoSource:: 72 RemoteVideoSourceDelegate::RenderFrame( 73 const cricket::VideoFrame* frame) { 74 base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds( 75 frame->GetElapsedTime() / rtc::kNumNanosecsPerMicrosec); 76 77 scoped_refptr<media::VideoFrame> video_frame; 78 if (frame->GetNativeHandle() != NULL) { 79 NativeHandleImpl* handle = 80 static_cast<NativeHandleImpl*>(frame->GetNativeHandle()); 81 video_frame = static_cast<media::VideoFrame*>(handle->GetHandle()); 82 video_frame->set_timestamp(timestamp); 83 } else { 84 gfx::Size size(frame->GetWidth(), frame->GetHeight()); 85 video_frame = frame_pool_.CreateFrame( 86 media::VideoFrame::YV12, size, gfx::Rect(size), size, timestamp); 87 88 // Non-square pixels are unsupported. 89 DCHECK_EQ(frame->GetPixelWidth(), 1u); 90 DCHECK_EQ(frame->GetPixelHeight(), 1u); 91 92 int y_rows = frame->GetHeight(); 93 int uv_rows = frame->GetChromaHeight(); 94 CopyYPlane( 95 frame->GetYPlane(), frame->GetYPitch(), y_rows, video_frame.get()); 96 CopyUPlane( 97 frame->GetUPlane(), frame->GetUPitch(), uv_rows, video_frame.get()); 98 CopyVPlane( 99 frame->GetVPlane(), frame->GetVPitch(), uv_rows, video_frame.get()); 100 } 101 102 media::VideoPixelFormat pixel_format = 103 (video_frame->format() == media::VideoFrame::YV12) ? 104 media::PIXEL_FORMAT_YV12 : media::PIXEL_FORMAT_TEXTURE; 105 106 media::VideoCaptureFormat format( 107 gfx::Size(video_frame->natural_size().width(), 108 video_frame->natural_size().height()), 109 MediaStreamVideoSource::kUnknownFrameRate, 110 pixel_format); 111 112 io_message_loop_->PostTask( 113 FROM_HERE, 114 base::Bind(&RemoteVideoSourceDelegate::DoRenderFrameOnIOThread, 115 this, video_frame, format)); 116 } 117 118 void MediaStreamRemoteVideoSource:: 119 RemoteVideoSourceDelegate::DoRenderFrameOnIOThread( 120 scoped_refptr<media::VideoFrame> video_frame, 121 const media::VideoCaptureFormat& format) { 122 DCHECK(io_message_loop_->BelongsToCurrentThread()); 123 // TODO(hclam): Give the estimated capture time. 124 frame_callback_.Run(video_frame, format, base::TimeTicks()); 125 } 126 127 MediaStreamRemoteVideoSource::MediaStreamRemoteVideoSource( 128 webrtc::VideoTrackInterface* remote_track) 129 : remote_track_(remote_track), 130 last_state_(remote_track->state()) { 131 remote_track_->RegisterObserver(this); 132 } 133 134 MediaStreamRemoteVideoSource::~MediaStreamRemoteVideoSource() { 135 remote_track_->UnregisterObserver(this); 136 } 137 138 void MediaStreamRemoteVideoSource::GetCurrentSupportedFormats( 139 int max_requested_width, 140 int max_requested_height, 141 double max_requested_frame_rate, 142 const VideoCaptureDeviceFormatsCB& callback) { 143 DCHECK(thread_checker_.CalledOnValidThread()); 144 media::VideoCaptureFormats formats; 145 // Since the remote end is free to change the resolution at any point in time 146 // the supported formats are unknown. 147 callback.Run(formats); 148 } 149 150 void MediaStreamRemoteVideoSource::StartSourceImpl( 151 const media::VideoCaptureFormat& format, 152 const VideoCaptureDeliverFrameCB& frame_callback) { 153 DCHECK(thread_checker_.CalledOnValidThread()); 154 DCHECK(!delegate_.get()); 155 delegate_ = new RemoteVideoSourceDelegate(io_message_loop(), frame_callback); 156 remote_track_->AddRenderer(delegate_.get()); 157 OnStartDone(MEDIA_DEVICE_OK); 158 } 159 160 void MediaStreamRemoteVideoSource::StopSourceImpl() { 161 DCHECK(thread_checker_.CalledOnValidThread()); 162 DCHECK(state() != MediaStreamVideoSource::ENDED); 163 remote_track_->RemoveRenderer(delegate_.get()); 164 } 165 166 webrtc::VideoRendererInterface* 167 MediaStreamRemoteVideoSource::RenderInterfaceForTest() { 168 return delegate_.get(); 169 } 170 171 void MediaStreamRemoteVideoSource::OnChanged() { 172 DCHECK(thread_checker_.CalledOnValidThread()); 173 webrtc::MediaStreamTrackInterface::TrackState state = remote_track_->state(); 174 if (state != last_state_) { 175 last_state_ = state; 176 switch (state) { 177 case webrtc::MediaStreamTrackInterface::kInitializing: 178 // Ignore the kInitializing state since there is no match in 179 // WebMediaStreamSource::ReadyState. 180 break; 181 case webrtc::MediaStreamTrackInterface::kLive: 182 SetReadyState(blink::WebMediaStreamSource::ReadyStateLive); 183 break; 184 case webrtc::MediaStreamTrackInterface::kEnded: 185 SetReadyState(blink::WebMediaStreamSource::ReadyStateEnded); 186 break; 187 default: 188 NOTREACHED(); 189 break; 190 } 191 } 192 } 193 194 } // namespace content 195