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(video_track_.source().readyState()); | |
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 AddToVideoTrack(this, video_track_); |
Alpha Left Google
2013/12/02 17:44:37
I don't think you can stash a WebMediaStreamTrack
perkj_chrome
2013/12/03 16:14:17
See my comment in the header file.
We added the ex
| |
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 RemoveFromVideoTrack(this, 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::OnReadyStateChanged( |
57 blink::WebMediaStreamSource::ReadyState state) { | |
58 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | |
59 MaybeRenderSignalingFrame(state); | |
74 } | 60 } |
75 | 61 |
76 void RTCVideoRenderer::RenderFrame(const cricket::VideoFrame* frame) { | 62 void RTCVideoRenderer::OnVideoFrame( |
77 base::TimeDelta timestamp = base::TimeDelta::FromMilliseconds( | 63 const scoped_refptr<media::VideoFrame>& frame) { |
78 frame->GetTimeStamp() / talk_base::kNumNanosecsPerMillisec); | 64 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
79 | 65 if (state_ != kStarted) { |
80 TRACE_EVENT_INSTANT2("rtc_video_renderer", | 66 return; |
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 } | 67 } |
112 | 68 |
113 message_loop_proxy_->PostTask( | 69 TRACE_EVENT_INSTANT1("rtc_video_renderer", |
114 FROM_HERE, base::Bind(&RTCVideoRenderer::DoRenderFrameOnMainThread, | 70 "OnVideoFrame", |
115 this, video_frame)); | 71 TRACE_EVENT_SCOPE_THREAD, |
72 "timestamp", | |
73 frame->GetTimestamp().InMilliseconds()); | |
74 repaint_cb_.Run(frame); | |
116 } | 75 } |
117 | 76 |
118 void RTCVideoRenderer::OnChanged() { | 77 void RTCVideoRenderer::MaybeRenderSignalingFrame( |
119 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | 78 blink::WebMediaStreamSource::ReadyState state) { |
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 == blink::WebMediaStreamSource::ReadyStateEnded) { |
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"); | |
145 repaint_cb_.Run(video_frame); | |
146 } | |
147 | |
148 } // namespace content | 91 } // namespace content |
OLD | NEW |