1a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
2a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// found in the LICENSE file.
4a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
5a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "content/renderer/media/webrtc/media_stream_remote_video_source.h"
6a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
7a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "base/bind.h"
8010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/callback_helpers.h"
9a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "base/location.h"
100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/message_loop/message_loop_proxy.h"
11a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "content/renderer/media/native_handle_impl.h"
12010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "media/base/bind_to_current_loop.h"
13a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "media/base/video_frame.h"
14010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "media/base/video_frame_pool.h"
15a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "media/base/video_util.h"
16a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "third_party/libjingle/source/talk/media/base/videoframe.h"
17a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
18a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochnamespace content {
19a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
20010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Internal class used for receiving frames from the webrtc track on a
21010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// libjingle thread and forward it to the IO-thread.
22010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)class MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate
23010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    : public base::RefCountedThreadSafe<RemoteVideoSourceDelegate>,
24010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      public webrtc::VideoRendererInterface {
25010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) public:
26010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  RemoteVideoSourceDelegate(
27010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      const scoped_refptr<base::MessageLoopProxy>& io_message_loop,
28010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      const VideoCaptureDeliverFrameCB& new_frame_callback);
29010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
30010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) protected:
31010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  friend class base::RefCountedThreadSafe<RemoteVideoSourceDelegate>;
32010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  virtual ~RemoteVideoSourceDelegate();
33010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
34010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Implements webrtc::VideoRendererInterface used for receiving video frames
35010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // from the PeerConnection video track. May be called on a libjingle internal
36010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // thread.
37010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  virtual void SetSize(int width, int height) OVERRIDE;
38010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE;
39010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
40010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  void DoRenderFrameOnIOThread(scoped_refptr<media::VideoFrame> video_frame,
41010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                               const media::VideoCaptureFormat& format);
42010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) private:
43010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Bound to the render thread.
44010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  base::ThreadChecker thread_checker_;
45010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
46010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  scoped_refptr<base::MessageLoopProxy> io_message_loop_;
47010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // |frame_pool_| is only accessed on whatever
48010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // thread webrtc::VideoRendererInterface::RenderFrame is called on.
49010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  media::VideoFramePool frame_pool_;
50010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
51010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // |frame_callback_| is accessed on the IO thread.
52010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  VideoCaptureDeliverFrameCB frame_callback_;
53010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)};
54010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
55010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)MediaStreamRemoteVideoSource::
56010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)RemoteVideoSourceDelegate::RemoteVideoSourceDelegate(
57010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const scoped_refptr<base::MessageLoopProxy>& io_message_loop,
58010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const VideoCaptureDeliverFrameCB& new_frame_callback)
59010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    : io_message_loop_(io_message_loop),
60010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      frame_callback_(new_frame_callback) {
61a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
62a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
63010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)MediaStreamRemoteVideoSource::
64010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)RemoteVideoSourceDelegate::~RemoteVideoSourceDelegate() {
65a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
66a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
67010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void MediaStreamRemoteVideoSource::
68010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)RemoteVideoSourceDelegate::SetSize(int width, int height) {
69a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
70a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
71010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void MediaStreamRemoteVideoSource::
72010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)RemoteVideoSourceDelegate::RenderFrame(
73a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const cricket::VideoFrame* frame) {
74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds(
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      frame->GetElapsedTime() / rtc::kNumNanosecsPerMicrosec);
76a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
77a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  scoped_refptr<media::VideoFrame> video_frame;
78a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (frame->GetNativeHandle() != NULL) {
79a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    NativeHandleImpl* handle =
80a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        static_cast<NativeHandleImpl*>(frame->GetNativeHandle());
81a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    video_frame = static_cast<media::VideoFrame*>(handle->GetHandle());
82a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    video_frame->set_timestamp(timestamp);
83a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  } else {
84a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    gfx::Size size(frame->GetWidth(), frame->GetHeight());
85a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    video_frame = frame_pool_.CreateFrame(
86a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        media::VideoFrame::YV12, size, gfx::Rect(size), size, timestamp);
87a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
88a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    // Non-square pixels are unsupported.
89a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    DCHECK_EQ(frame->GetPixelWidth(), 1u);
90a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    DCHECK_EQ(frame->GetPixelHeight(), 1u);
91a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
92a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    int y_rows = frame->GetHeight();
93a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    int uv_rows = frame->GetChromaHeight();
94a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    CopyYPlane(
95a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        frame->GetYPlane(), frame->GetYPitch(), y_rows, video_frame.get());
96a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    CopyUPlane(
97a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        frame->GetUPlane(), frame->GetUPitch(), uv_rows, video_frame.get());
98a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    CopyVPlane(
99a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        frame->GetVPlane(), frame->GetVPitch(), uv_rows, video_frame.get());
100a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  }
101a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
102010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  media::VideoPixelFormat pixel_format =
103010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      (video_frame->format() == media::VideoFrame::YV12) ?
104010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)          media::PIXEL_FORMAT_YV12 : media::PIXEL_FORMAT_TEXTURE;
105010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
106010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  media::VideoCaptureFormat format(
107010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      gfx::Size(video_frame->natural_size().width(),
108010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                video_frame->natural_size().height()),
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                MediaStreamVideoSource::kUnknownFrameRate,
110010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                pixel_format);
111a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
112010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  io_message_loop_->PostTask(
113a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      FROM_HERE,
114010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      base::Bind(&RemoteVideoSourceDelegate::DoRenderFrameOnIOThread,
115010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                 this, video_frame, format));
116010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
117010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
118010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void MediaStreamRemoteVideoSource::
119010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)RemoteVideoSourceDelegate::DoRenderFrameOnIOThread(
120010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    scoped_refptr<media::VideoFrame> video_frame,
121010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const media::VideoCaptureFormat& format) {
122010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(io_message_loop_->BelongsToCurrentThread());
12346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // TODO(hclam): Give the estimated capture time.
12446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  frame_callback_.Run(video_frame, format, base::TimeTicks());
125010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
126010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
127010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)MediaStreamRemoteVideoSource::MediaStreamRemoteVideoSource(
128010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    webrtc::VideoTrackInterface* remote_track)
129010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    : remote_track_(remote_track),
130010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      last_state_(remote_track->state()) {
131010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  remote_track_->RegisterObserver(this);
132010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
133010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
134010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)MediaStreamRemoteVideoSource::~MediaStreamRemoteVideoSource() {
135010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  remote_track_->UnregisterObserver(this);
136010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
137010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
138010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void MediaStreamRemoteVideoSource::GetCurrentSupportedFormats(
139010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    int max_requested_width,
140010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    int max_requested_height,
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    double max_requested_frame_rate,
142010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const VideoCaptureDeviceFormatsCB& callback) {
143010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
144010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  media::VideoCaptureFormats formats;
145010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Since the remote end is free to change the resolution at any point in time
146010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // the supported formats are unknown.
147010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  callback.Run(formats);
148010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
149010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
150010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void MediaStreamRemoteVideoSource::StartSourceImpl(
1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const media::VideoCaptureFormat& format,
152010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const VideoCaptureDeliverFrameCB& frame_callback) {
153010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(!delegate_.get());
155010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  delegate_ = new RemoteVideoSourceDelegate(io_message_loop(), frame_callback);
1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  remote_track_->AddRenderer(delegate_.get());
1576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  OnStartDone(MEDIA_DEVICE_OK);
158010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
159010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
160010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void MediaStreamRemoteVideoSource::StopSourceImpl() {
161010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
162010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(state() != MediaStreamVideoSource::ENDED);
1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  remote_track_->RemoveRenderer(delegate_.get());
164010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
165010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
166010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)webrtc::VideoRendererInterface*
167010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)MediaStreamRemoteVideoSource::RenderInterfaceForTest() {
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return delegate_.get();
169a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
170a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
171a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid MediaStreamRemoteVideoSource::OnChanged() {
172010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
173a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  webrtc::MediaStreamTrackInterface::TrackState state = remote_track_->state();
174a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (state != last_state_) {
175a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    last_state_ = state;
176a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    switch (state) {
177a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      case webrtc::MediaStreamTrackInterface::kInitializing:
178a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        // Ignore the kInitializing state since there is no match in
179a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        // WebMediaStreamSource::ReadyState.
180a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        break;
181a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      case webrtc::MediaStreamTrackInterface::kLive:
182a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        SetReadyState(blink::WebMediaStreamSource::ReadyStateLive);
183a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        break;
184a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      case webrtc::MediaStreamTrackInterface::kEnded:
185a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        SetReadyState(blink::WebMediaStreamSource::ReadyStateEnded);
186a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        break;
187a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      default:
188a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        NOTREACHED();
189a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        break;
190a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    }
191a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  }
192a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
193a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
194a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}  // namespace content
195