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 "base/threading/thread_checker.h"
12 #include "base/trace_event/trace_event.h"
13 #include "content/renderer/media/native_handle_impl.h"
14 #include "content/renderer/media/webrtc/track_observer.h"
15 #include "media/base/bind_to_current_loop.h"
16 #include "media/base/video_frame.h"
17 #include "media/base/video_frame_pool.h"
18 #include "media/base/video_util.h"
19 #include "third_party/libjingle/source/talk/media/base/videoframe.h"
23 // Internal class used for receiving frames from the webrtc track on a
24 // libjingle thread and forward it to the IO-thread.
25 class MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate
26 : public base::RefCountedThreadSafe
<RemoteVideoSourceDelegate
>,
27 public webrtc::VideoRendererInterface
{
29 RemoteVideoSourceDelegate(
30 const scoped_refptr
<base::MessageLoopProxy
>& io_message_loop
,
31 const VideoCaptureDeliverFrameCB
& new_frame_callback
);
34 friend class base::RefCountedThreadSafe
<RemoteVideoSourceDelegate
>;
35 ~RemoteVideoSourceDelegate() override
;
37 // Implements webrtc::VideoRendererInterface used for receiving video frames
38 // from the PeerConnection video track. May be called on a libjingle internal
40 void SetSize(int width
, int height
) override
;
41 void RenderFrame(const cricket::VideoFrame
* frame
) override
;
43 void DoRenderFrameOnIOThread(scoped_refptr
<media::VideoFrame
> video_frame
,
44 const media::VideoCaptureFormat
& format
);
46 // Bound to the render thread.
47 base::ThreadChecker thread_checker_
;
49 scoped_refptr
<base::MessageLoopProxy
> io_message_loop_
;
50 // |frame_pool_| is only accessed on whatever
51 // thread webrtc::VideoRendererInterface::RenderFrame is called on.
52 media::VideoFramePool frame_pool_
;
54 // |frame_callback_| is accessed on the IO thread.
55 VideoCaptureDeliverFrameCB frame_callback_
;
58 MediaStreamRemoteVideoSource::
59 RemoteVideoSourceDelegate::RemoteVideoSourceDelegate(
60 const scoped_refptr
<base::MessageLoopProxy
>& io_message_loop
,
61 const VideoCaptureDeliverFrameCB
& new_frame_callback
)
62 : io_message_loop_(io_message_loop
),
63 frame_callback_(new_frame_callback
) {
66 MediaStreamRemoteVideoSource::
67 RemoteVideoSourceDelegate::~RemoteVideoSourceDelegate() {
70 void MediaStreamRemoteVideoSource::
71 RemoteVideoSourceDelegate::SetSize(int width
, int height
) {
74 void MediaStreamRemoteVideoSource::
75 RemoteVideoSourceDelegate::RenderFrame(
76 const cricket::VideoFrame
* frame
) {
77 TRACE_EVENT0("webrtc", "RemoteVideoSourceDelegate::RenderFrame");
78 base::TimeDelta timestamp
= base::TimeDelta::FromMicroseconds(
79 frame
->GetElapsedTime() / rtc::kNumNanosecsPerMicrosec
);
81 scoped_refptr
<media::VideoFrame
> video_frame
;
82 if (frame
->GetNativeHandle() != NULL
) {
83 NativeHandleImpl
* handle
=
84 static_cast<NativeHandleImpl
*>(frame
->GetNativeHandle());
85 video_frame
= static_cast<media::VideoFrame
*>(handle
->GetHandle());
86 video_frame
->set_timestamp(timestamp
);
88 gfx::Size
size(frame
->GetWidth(), frame
->GetHeight());
89 video_frame
= frame_pool_
.CreateFrame(
90 media::VideoFrame::YV12
, size
, gfx::Rect(size
), size
, timestamp
);
92 // Non-square pixels are unsupported.
93 DCHECK_EQ(frame
->GetPixelWidth(), 1u);
94 DCHECK_EQ(frame
->GetPixelHeight(), 1u);
96 int y_rows
= frame
->GetHeight();
97 int uv_rows
= frame
->GetChromaHeight();
99 frame
->GetYPlane(), frame
->GetYPitch(), y_rows
, video_frame
.get());
101 frame
->GetUPlane(), frame
->GetUPitch(), uv_rows
, video_frame
.get());
103 frame
->GetVPlane(), frame
->GetVPitch(), uv_rows
, video_frame
.get());
106 media::VideoPixelFormat pixel_format
=
107 (video_frame
->format() == media::VideoFrame::YV12
) ?
108 media::PIXEL_FORMAT_YV12
: media::PIXEL_FORMAT_TEXTURE
;
110 media::VideoCaptureFormat
format(
111 gfx::Size(video_frame
->natural_size().width(),
112 video_frame
->natural_size().height()),
113 MediaStreamVideoSource::kUnknownFrameRate
,
116 io_message_loop_
->PostTask(
118 base::Bind(&RemoteVideoSourceDelegate::DoRenderFrameOnIOThread
,
119 this, video_frame
, format
));
122 void MediaStreamRemoteVideoSource::
123 RemoteVideoSourceDelegate::DoRenderFrameOnIOThread(
124 scoped_refptr
<media::VideoFrame
> video_frame
,
125 const media::VideoCaptureFormat
& format
) {
126 DCHECK(io_message_loop_
->BelongsToCurrentThread());
127 TRACE_EVENT0("webrtc", "RemoteVideoSourceDelegate::DoRenderFrameOnIOThread");
128 // TODO(hclam): Give the estimated capture time.
129 frame_callback_
.Run(video_frame
, format
, base::TimeTicks());
132 MediaStreamRemoteVideoSource::MediaStreamRemoteVideoSource(
133 scoped_ptr
<TrackObserver
> observer
)
134 : observer_(observer
.Pass()) {
135 // The callback will be automatically cleared when 'observer_' goes out of
136 // scope and no further callbacks will occur.
137 observer_
->SetCallback(base::Bind(&MediaStreamRemoteVideoSource::OnChanged
,
138 base::Unretained(this)));
141 MediaStreamRemoteVideoSource::~MediaStreamRemoteVideoSource() {
142 DCHECK(CalledOnValidThread());
145 void MediaStreamRemoteVideoSource::GetCurrentSupportedFormats(
146 int max_requested_width
,
147 int max_requested_height
,
148 double max_requested_frame_rate
,
149 const VideoCaptureDeviceFormatsCB
& callback
) {
150 DCHECK(CalledOnValidThread());
151 media::VideoCaptureFormats formats
;
152 // Since the remote end is free to change the resolution at any point in time
153 // the supported formats are unknown.
154 callback
.Run(formats
);
157 void MediaStreamRemoteVideoSource::StartSourceImpl(
158 const media::VideoCaptureFormat
& format
,
159 const VideoCaptureDeliverFrameCB
& frame_callback
) {
160 DCHECK(CalledOnValidThread());
161 DCHECK(!delegate_
.get());
162 delegate_
= new RemoteVideoSourceDelegate(io_message_loop(), frame_callback
);
163 scoped_refptr
<webrtc::VideoTrackInterface
> video_track(
164 static_cast<webrtc::VideoTrackInterface
*>(observer_
->track().get()));
165 video_track
->AddRenderer(delegate_
.get());
166 OnStartDone(MEDIA_DEVICE_OK
);
169 void MediaStreamRemoteVideoSource::StopSourceImpl() {
170 DCHECK(CalledOnValidThread());
171 DCHECK(state() != MediaStreamVideoSource::ENDED
);
172 scoped_refptr
<webrtc::VideoTrackInterface
> video_track(
173 static_cast<webrtc::VideoTrackInterface
*>(observer_
->track().get()));
174 video_track
->RemoveRenderer(delegate_
.get());
177 webrtc::VideoRendererInterface
*
178 MediaStreamRemoteVideoSource::RenderInterfaceForTest() {
179 return delegate_
.get();
182 void MediaStreamRemoteVideoSource::OnChanged(
183 webrtc::MediaStreamTrackInterface::TrackState state
) {
184 DCHECK(CalledOnValidThread());
186 case webrtc::MediaStreamTrackInterface::kInitializing
:
187 // Ignore the kInitializing state since there is no match in
188 // WebMediaStreamSource::ReadyState.
190 case webrtc::MediaStreamTrackInterface::kLive
:
191 SetReadyState(blink::WebMediaStreamSource::ReadyStateLive
);
193 case webrtc::MediaStreamTrackInterface::kEnded
:
194 SetReadyState(blink::WebMediaStreamSource::ReadyStateEnded
);
202 } // namespace content