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
3 // found in the LICENSE file.
5 #include "content/renderer/media/rtc_video_renderer.h"
7 #include "base/debug/trace_event.h"
8 #include "base/message_loop/message_loop_proxy.h"
9 #include "media/base/bind_to_current_loop.h"
10 #include "media/base/video_frame.h"
11 #include "media/base/video_util.h"
13 const int kMinFrameSize
= 2;
17 RTCVideoRenderer::RTCVideoRenderer(
18 const blink::WebMediaStreamTrack
& video_track
,
19 const base::Closure
& error_cb
,
20 const RepaintCB
& repaint_cb
)
21 : error_cb_(error_cb
),
22 repaint_cb_(repaint_cb
),
23 message_loop_proxy_(base::MessageLoopProxy::current()),
25 frame_size_(kMinFrameSize
, kMinFrameSize
),
26 video_track_(video_track
),
30 RTCVideoRenderer::~RTCVideoRenderer() {
33 void RTCVideoRenderer::Start() {
34 DCHECK(message_loop_proxy_
->BelongsToCurrentThread());
35 DCHECK_EQ(state_
, STOPPED
);
39 media::BindToCurrentLoop(
41 &RTCVideoRenderer::OnVideoFrame
,
42 weak_factory_
.GetWeakPtr())),
46 if (video_track_
.source().readyState() ==
47 blink::WebMediaStreamSource::ReadyStateEnded
||
48 !video_track_
.isEnabled()) {
49 RenderSignalingFrame();
53 void RTCVideoRenderer::Stop() {
54 DCHECK(message_loop_proxy_
->BelongsToCurrentThread());
55 DCHECK(state_
== STARTED
|| state_
== PAUSED
);
56 RemoveFromVideoTrack(this, video_track_
);
57 weak_factory_
.InvalidateWeakPtrs();
59 frame_size_
.set_width(kMinFrameSize
);
60 frame_size_
.set_height(kMinFrameSize
);
63 void RTCVideoRenderer::Play() {
64 DCHECK(message_loop_proxy_
->BelongsToCurrentThread());
65 if (state_
== PAUSED
) {
70 void RTCVideoRenderer::Pause() {
71 DCHECK(message_loop_proxy_
->BelongsToCurrentThread());
72 if (state_
== STARTED
) {
77 void RTCVideoRenderer::OnReadyStateChanged(
78 blink::WebMediaStreamSource::ReadyState state
) {
79 DCHECK(message_loop_proxy_
->BelongsToCurrentThread());
80 if (state
== blink::WebMediaStreamSource::ReadyStateEnded
)
81 RenderSignalingFrame();
84 void RTCVideoRenderer::OnEnabledChanged(bool enabled
) {
85 DCHECK(message_loop_proxy_
->BelongsToCurrentThread());
87 RenderSignalingFrame();
90 void RTCVideoRenderer::OnVideoFrame(
91 const scoped_refptr
<media::VideoFrame
>& frame
,
92 const media::VideoCaptureFormat
& format
,
93 const base::TimeTicks
& estimated_capture_time
) {
94 DCHECK(message_loop_proxy_
->BelongsToCurrentThread());
95 if (state_
!= STARTED
) {
99 frame_size_
= frame
->natural_size();
101 TRACE_EVENT_INSTANT1("rtc_video_renderer",
103 TRACE_EVENT_SCOPE_THREAD
,
105 frame
->timestamp().InMilliseconds());
106 repaint_cb_
.Run(frame
);
109 void RTCVideoRenderer::RenderSignalingFrame() {
110 // This is necessary to make sure audio can play if the video tag src is
111 // a MediaStream video track that has been rejected, ended or disabled.
112 // It also ensure that the renderer don't hold a reference to a real video
113 // frame if no more frames are provided. This is since there might be a
114 // finite number of available buffers. E.g, video that
115 // originates from a video camera.
116 scoped_refptr
<media::VideoFrame
> video_frame
=
117 media::VideoFrame::CreateBlackFrame(frame_size_
);
118 OnVideoFrame(video_frame
, media::VideoCaptureFormat(), base::TimeTicks());
121 } // namespace content