Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/renderer/media/rtc_video_renderer.h" | 5 #include "content/renderer/media/rtc_video_renderer.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | |
| 8 #include "base/debug/trace_event.h" | 7 #include "base/debug/trace_event.h" |
| 9 #include "base/location.h" | |
| 10 #include "base/logging.h" | |
| 11 #include "base/message_loop/message_loop_proxy.h" | 8 #include "base/message_loop/message_loop_proxy.h" |
| 12 #include "content/renderer/media/native_handle_impl.h" | |
| 13 #include "media/base/video_frame.h" | 9 #include "media/base/video_frame.h" |
| 14 #include "media/base/video_util.h" | 10 #include "media/base/video_util.h" |
| 15 #include "third_party/libjingle/source/talk/media/base/videoframe.h" | |
| 16 | |
| 17 using media::CopyYPlane; | |
| 18 using media::CopyUPlane; | |
| 19 using media::CopyVPlane; | |
| 20 | 11 |
| 21 namespace content { | 12 namespace content { |
| 22 | 13 |
| 23 RTCVideoRenderer::RTCVideoRenderer( | 14 RTCVideoRenderer::RTCVideoRenderer( |
| 24 webrtc::VideoTrackInterface* video_track, | 15 const blink::WebMediaStreamTrack& video_track, |
| 25 const base::Closure& error_cb, | 16 const base::Closure& error_cb, |
| 26 const RepaintCB& repaint_cb) | 17 const RepaintCB& repaint_cb) |
| 27 : error_cb_(error_cb), | 18 : error_cb_(error_cb), |
| 28 repaint_cb_(repaint_cb), | 19 repaint_cb_(repaint_cb), |
| 29 message_loop_proxy_(base::MessageLoopProxy::current()), | 20 message_loop_proxy_(base::MessageLoopProxy::current()), |
| 30 state_(kStopped), | 21 state_(kStopped), |
| 31 video_track_(video_track) { | 22 video_track_(video_track) { |
| 23 MaybeRenderSignalingFrame(GetSourceState(video_track_)); | |
| 32 } | 24 } |
| 33 | 25 |
| 34 RTCVideoRenderer::~RTCVideoRenderer() { | 26 RTCVideoRenderer::~RTCVideoRenderer() { |
| 35 } | 27 } |
| 36 | 28 |
| 37 void RTCVideoRenderer::Start() { | 29 void RTCVideoRenderer::Start() { |
| 38 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | 30 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
| 39 DCHECK_EQ(state_, kStopped); | 31 DCHECK_EQ(state_, kStopped); |
| 40 | 32 |
| 41 if (video_track_.get()) { | 33 Register(video_track_); |
| 42 video_track_->AddRenderer(this); | |
| 43 video_track_->RegisterObserver(this); | |
| 44 } | |
| 45 state_ = kStarted; | 34 state_ = kStarted; |
| 46 MaybeRenderSignalingFrame(); | |
| 47 } | 35 } |
| 48 | 36 |
| 49 void RTCVideoRenderer::Stop() { | 37 void RTCVideoRenderer::Stop() { |
| 50 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | 38 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
| 51 if (video_track_.get()) { | 39 UnRegister(video_track_); |
| 52 state_ = kStopped; | |
| 53 video_track_->RemoveRenderer(this); | |
| 54 video_track_->UnregisterObserver(this); | |
| 55 video_track_ = NULL; | |
| 56 } | |
| 57 } | 40 } |
| 58 | 41 |
| 59 void RTCVideoRenderer::Play() { | 42 void RTCVideoRenderer::Play() { |
| 60 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | 43 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
| 61 if (video_track_.get() && state_ == kPaused) { | 44 if (state_ == kPaused) { |
| 62 state_ = kStarted; | 45 state_ = kStarted; |
| 63 } | 46 } |
| 64 } | 47 } |
| 65 | 48 |
| 66 void RTCVideoRenderer::Pause() { | 49 void RTCVideoRenderer::Pause() { |
| 67 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | 50 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
| 68 if (video_track_.get() && state_ == kStarted) { | 51 if (state_ == kStarted) { |
| 69 state_ = kPaused; | 52 state_ = kPaused; |
| 70 } | 53 } |
| 71 } | 54 } |
| 72 | 55 |
| 73 void RTCVideoRenderer::SetSize(int width, int height) { | 56 void RTCVideoRenderer::OnSourceChangedState(ReadyState state) { |
| 57 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | |
| 58 MaybeRenderSignalingFrame(state); | |
| 74 } | 59 } |
| 75 | 60 |
| 76 void RTCVideoRenderer::RenderFrame(const cricket::VideoFrame* frame) { | 61 void RTCVideoRenderer::OnVideoFrame( |
| 77 base::TimeDelta timestamp = base::TimeDelta::FromMilliseconds( | 62 const scoped_refptr<media::VideoFrame>& frame) { |
| 78 frame->GetTimeStamp() / talk_base::kNumNanosecsPerMillisec); | 63 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
| 79 | 64 if (state_ != kStarted) { |
| 80 TRACE_EVENT_INSTANT2("rtc_video_renderer", | 65 return; |
|
Alpha Left Google
2013/11/26 04:59:32
Please keep this event in some form.
Alpha Left Google
2013/11/26 10:00:47
Ignore this and just remove the events please.
| |
| 81 "RenderFrame", | |
| 82 TRACE_EVENT_SCOPE_THREAD, | |
| 83 "elapsed time", | |
| 84 frame->GetElapsedTime(), | |
| 85 "timestamp_ms", | |
| 86 timestamp.InMilliseconds()); | |
| 87 | |
| 88 scoped_refptr<media::VideoFrame> video_frame; | |
| 89 if (frame->GetNativeHandle() != NULL) { | |
| 90 NativeHandleImpl* handle = | |
| 91 static_cast<NativeHandleImpl*>(frame->GetNativeHandle()); | |
| 92 video_frame = static_cast<media::VideoFrame*>(handle->GetHandle()); | |
| 93 video_frame->SetTimestamp(timestamp); | |
| 94 } else { | |
| 95 gfx::Size size(frame->GetWidth(), frame->GetHeight()); | |
| 96 video_frame = media::VideoFrame::CreateFrame( | |
| 97 media::VideoFrame::YV12, size, gfx::Rect(size), size, timestamp); | |
| 98 | |
| 99 // Aspect ratio unsupported; DCHECK when there are non-square pixels. | |
| 100 DCHECK_EQ(frame->GetPixelWidth(), 1u); | |
| 101 DCHECK_EQ(frame->GetPixelHeight(), 1u); | |
| 102 | |
| 103 int y_rows = frame->GetHeight(); | |
| 104 int uv_rows = frame->GetHeight() / 2; // YV12 format. | |
| 105 CopyYPlane( | |
| 106 frame->GetYPlane(), frame->GetYPitch(), y_rows, video_frame.get()); | |
| 107 CopyUPlane( | |
| 108 frame->GetUPlane(), frame->GetUPitch(), uv_rows, video_frame.get()); | |
| 109 CopyVPlane( | |
| 110 frame->GetVPlane(), frame->GetVPitch(), uv_rows, video_frame.get()); | |
| 111 } | 66 } |
| 112 | 67 |
| 113 message_loop_proxy_->PostTask( | 68 // TODO(perkj): How does tracing work? |
| 114 FROM_HERE, base::Bind(&RTCVideoRenderer::DoRenderFrameOnMainThread, | 69 /* |
| 115 this, video_frame)); | 70 TRACE_EVENT_INSTANT1("rtc_video_renderer", |
| 71 "OnVideoFrame", | |
| 72 TRACE_EVENT_SCOPE_THREAD, | |
| 73 "timestamp", | |
| 74 frame->GetTimestamp());*/ | |
| 75 repaint_cb_.Run(frame); | |
|
Alpha Left Google
2013/11/26 04:59:32
Great! Love this!
| |
| 116 } | 76 } |
| 117 | 77 |
| 118 void RTCVideoRenderer::OnChanged() { | 78 void RTCVideoRenderer::MaybeRenderSignalingFrame(ReadyState state) { |
| 119 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | |
| 120 MaybeRenderSignalingFrame(); | |
| 121 } | |
| 122 | |
| 123 void RTCVideoRenderer::MaybeRenderSignalingFrame() { | |
| 124 // Render a small black frame if the track transition to ended. | 79 // Render a small black frame if the track transition to ended. |
| 125 // This is necessary to make sure audio can play if the video tag src is | 80 // This is necessary to make sure audio can play if the video tag src is |
| 126 // a MediaStream video track that has been rejected or ended. | 81 // a MediaStream video track that has been rejected or ended. |
| 127 if (video_track_->state() == webrtc::MediaStreamTrackInterface::kEnded) { | 82 if (state == VideoTrackSink::kEnded) { |
| 128 const int kMinFrameSize = 2; | 83 const int kMinFrameSize = 2; |
| 129 const gfx::Size size(kMinFrameSize, kMinFrameSize); | 84 const gfx::Size size(kMinFrameSize, kMinFrameSize); |
| 130 scoped_refptr<media::VideoFrame> video_frame = | 85 scoped_refptr<media::VideoFrame> video_frame = |
| 131 media::VideoFrame::CreateBlackFrame(size); | 86 media::VideoFrame::CreateBlackFrame(size); |
| 132 DoRenderFrameOnMainThread(video_frame); | 87 OnVideoFrame(video_frame); |
| 133 } | 88 } |
| 134 } | 89 } |
| 135 | 90 |
| 136 void RTCVideoRenderer::DoRenderFrameOnMainThread( | |
| 137 scoped_refptr<media::VideoFrame> video_frame) { | |
| 138 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | |
| 139 | |
| 140 if (state_ != kStarted) { | |
| 141 return; | |
| 142 } | |
| 143 | |
| 144 TRACE_EVENT0("video", "DoRenderFrameOnMainThread"); | |
|
Alpha Left Google
2013/11/26 04:59:32
Please keep this event. We depend on it to for som
perkj_chrome
2013/11/26 09:16:38
This does seem to make sense with this change. Can
Alpha Left Google
2013/11/26 10:00:47
Okay. Just remove the trace then, we'll handle tha
| |
| 145 repaint_cb_.Run(video_frame); | |
| 146 } | |
| 147 | |
| 148 } // namespace content | 91 } // namespace content |
| OLD | NEW |