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