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.
5 #include "content/renderer/media/webrtc/media_stream_remote_video_source.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"
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 {
26 RemoteVideoSourceDelegate(
27 const scoped_refptr<base::MessageLoopProxy>& io_message_loop,
28 const VideoCaptureDeliverFrameCB& new_frame_callback);
31 friend class base::RefCountedThreadSafe<RemoteVideoSourceDelegate>;
32 virtual ~RemoteVideoSourceDelegate();
34 // Implements webrtc::VideoRendererInterface used for receiving video frames
35 // from the PeerConnection video track. May be called on a libjingle internal
37 virtual void SetSize(int width, int height) OVERRIDE;
38 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE;
40 void DoRenderFrameOnIOThread(scoped_refptr<media::VideoFrame> video_frame,
41 const media::VideoCaptureFormat& format);
43 // Bound to the render thread.
44 base::ThreadChecker thread_checker_;
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_;
51 // |frame_callback_| is accessed on the IO thread.
52 VideoCaptureDeliverFrameCB frame_callback_;
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) {
63 MediaStreamRemoteVideoSource::
64 RemoteVideoSourceDelegate::~RemoteVideoSourceDelegate() {
67 void MediaStreamRemoteVideoSource::
68 RemoteVideoSourceDelegate::SetSize(int width, int height) {
71 void MediaStreamRemoteVideoSource::
72 RemoteVideoSourceDelegate::RenderFrame(
73 const cricket::VideoFrame* frame) {
74 base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds(
75 frame->GetElapsedTime() / rtc::kNumNanosecsPerMicrosec);
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);
84 gfx::Size size(frame->GetWidth(), frame->GetHeight());
85 video_frame = frame_pool_.CreateFrame(
86 media::VideoFrame::YV12, size, gfx::Rect(size), size, timestamp);
88 // Non-square pixels are unsupported.
89 DCHECK_EQ(frame->GetPixelWidth(), 1u);
90 DCHECK_EQ(frame->GetPixelHeight(), 1u);
92 int y_rows = frame->GetHeight();
93 int uv_rows = frame->GetChromaHeight();
95 frame->GetYPlane(), frame->GetYPitch(), y_rows, video_frame.get());
97 frame->GetUPlane(), frame->GetUPitch(), uv_rows, video_frame.get());
99 frame->GetVPlane(), frame->GetVPitch(), uv_rows, video_frame.get());
102 media::VideoPixelFormat pixel_format =
103 (video_frame->format() == media::VideoFrame::YV12) ?
104 media::PIXEL_FORMAT_YV12 : media::PIXEL_FORMAT_TEXTURE;
106 media::VideoCaptureFormat format(
107 gfx::Size(video_frame->natural_size().width(),
108 video_frame->natural_size().height()),
109 MediaStreamVideoSource::kUnknownFrameRate,
112 io_message_loop_->PostTask(
114 base::Bind(&RemoteVideoSourceDelegate::DoRenderFrameOnIOThread,
115 this, video_frame, format));
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());
127 MediaStreamRemoteVideoSource::MediaStreamRemoteVideoSource(
128 webrtc::VideoTrackInterface* remote_track)
129 : remote_track_(remote_track),
130 last_state_(remote_track->state()) {
131 remote_track_->RegisterObserver(this);
134 MediaStreamRemoteVideoSource::~MediaStreamRemoteVideoSource() {
135 remote_track_->UnregisterObserver(this);
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);
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);
160 void MediaStreamRemoteVideoSource::StopSourceImpl() {
161 DCHECK(thread_checker_.CalledOnValidThread());
162 DCHECK(state() != MediaStreamVideoSource::ENDED);
163 remote_track_->RemoveRenderer(delegate_.get());
166 webrtc::VideoRendererInterface*
167 MediaStreamRemoteVideoSource::RenderInterfaceForTest() {
168 return delegate_.get();
171 void MediaStreamRemoteVideoSource::OnChanged() {
172 DCHECK(thread_checker_.CalledOnValidThread());
173 webrtc::MediaStreamTrackInterface::TrackState state = remote_track_->state();
174 if (state != last_state_) {
177 case webrtc::MediaStreamTrackInterface::kInitializing:
178 // Ignore the kInitializing state since there is no match in
179 // WebMediaStreamSource::ReadyState.
181 case webrtc::MediaStreamTrackInterface::kLive:
182 SetReadyState(blink::WebMediaStreamSource::ReadyStateLive);
184 case webrtc::MediaStreamTrackInterface::kEnded:
185 SetReadyState(blink::WebMediaStreamSource::ReadyStateEnded);
194 } // namespace content