1 // Copyright 2015 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/pepper/video_encoder_shim.h"
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/memory/scoped_vector.h"
14 #include "base/memory/shared_memory.h"
15 #include "base/message_loop/message_loop.h"
16 #include "content/renderer/pepper/pepper_video_encoder_host.h"
17 #include "content/renderer/render_thread_impl.h"
18 #include "media/cast/cast_config.h"
19 #include "media/cast/sender/vp8_encoder.h"
20 #include "ui/gfx/geometry/size.h"
24 // TODO(llandwerlin): Libvpx doesn't seem to have a maximum frame size
25 // limitation. We currently limit the size of the frames to encode at
26 // 1080p (%64 pixels blocks), this seems like a reasonable limit for
28 const int32_t kMaxWidth
= 1920;
29 const int32_t kMaxHeight
= 1088;
31 // Bitstream buffer size.
32 const uint32_t kBitstreamBufferSize
= 2 * 1024 * 1024;
34 // Number of frames needs at any given time.
35 const uint32_t kInputFrameCount
= 1;
37 class VideoEncoderShim::EncoderImpl
{
39 explicit EncoderImpl(const base::WeakPtr
<VideoEncoderShim
>& shim
);
42 void Initialize(media::VideoFrame::Format input_format
,
43 const gfx::Size
& input_visible_size
,
44 media::VideoCodecProfile output_profile
,
45 uint32 initial_bitrate
);
46 void Encode(const scoped_refptr
<media::VideoFrame
>& frame
,
48 void UseOutputBitstreamBuffer(const media::BitstreamBuffer
& buffer
,
50 void RequestEncodingParametersChange(uint32 bitrate
, uint32 framerate
);
54 struct PendingEncode
{
55 PendingEncode(const scoped_refptr
<media::VideoFrame
>& frame
,
57 : frame(frame
), force_keyframe(force_keyframe
) {}
60 scoped_refptr
<media::VideoFrame
> frame
;
64 struct BitstreamBuffer
{
65 BitstreamBuffer(const media::BitstreamBuffer buffer
, uint8_t* mem
)
66 : buffer(buffer
), mem(mem
) {}
69 media::BitstreamBuffer buffer
;
75 base::WeakPtr
<VideoEncoderShim
> shim_
;
76 scoped_refptr
<base::SingleThreadTaskRunner
> media_task_runner_
;
78 scoped_ptr
<media::cast::SoftwareVideoEncoder
> encoder_
;
79 std::deque
<PendingEncode
> frames_
;
80 std::deque
<BitstreamBuffer
> buffers_
;
83 VideoEncoderShim::EncoderImpl::EncoderImpl(
84 const base::WeakPtr
<VideoEncoderShim
>& shim
)
85 : shim_(shim
), media_task_runner_(base::MessageLoopProxy::current()) {
88 VideoEncoderShim::EncoderImpl::~EncoderImpl() {
91 void VideoEncoderShim::EncoderImpl::Initialize(
92 media::VideoFrame::Format input_format
,
93 const gfx::Size
& input_visible_size
,
94 media::VideoCodecProfile output_profile
,
95 uint32 initial_bitrate
) {
96 media::cast::VideoSenderConfig config
;
98 config
.max_number_of_video_buffers_used
= kInputFrameCount
;
99 config
.number_of_encode_threads
= 1;
100 encoder_
.reset(new media::cast::Vp8Encoder(config
));
102 encoder_
->UpdateRates(initial_bitrate
);
104 media_task_runner_
->PostTask(
105 FROM_HERE
, base::Bind(&VideoEncoderShim::OnRequireBitstreamBuffers
, shim_
,
106 kInputFrameCount
, input_visible_size
,
107 kBitstreamBufferSize
));
110 void VideoEncoderShim::EncoderImpl::Encode(
111 const scoped_refptr
<media::VideoFrame
>& frame
,
112 bool force_keyframe
) {
113 frames_
.push_back(PendingEncode(frame
, force_keyframe
));
117 void VideoEncoderShim::EncoderImpl::UseOutputBitstreamBuffer(
118 const media::BitstreamBuffer
& buffer
,
120 buffers_
.push_back(BitstreamBuffer(buffer
, mem
));
124 void VideoEncoderShim::EncoderImpl::RequestEncodingParametersChange(
127 encoder_
->UpdateRates(bitrate
);
130 void VideoEncoderShim::EncoderImpl::Stop() {
136 void VideoEncoderShim::EncoderImpl::DoEncode() {
137 while (!frames_
.empty() && !buffers_
.empty()) {
138 PendingEncode frame
= frames_
.front();
141 if (frame
.force_keyframe
)
142 encoder_
->GenerateKeyFrame();
144 scoped_ptr
<media::cast::EncodedFrame
> encoded_frame(
145 new media::cast::EncodedFrame());
146 encoder_
->Encode(frame
.frame
, base::TimeTicks::Now(), encoded_frame
.get());
148 BitstreamBuffer buffer
= buffers_
.front();
149 buffers_
.pop_front();
151 CHECK(buffer
.buffer
.size() >= encoded_frame
->data
.size());
152 memcpy(buffer
.mem
, encoded_frame
->bytes(), encoded_frame
->data
.size());
154 // Pass the media::VideoFrame back to the renderer thread so it's
155 // freed on the right thread.
156 media_task_runner_
->PostTask(
159 &VideoEncoderShim::OnBitstreamBufferReady
, shim_
,
160 frame
.frame
, buffer
.buffer
.id(), encoded_frame
->data
.size(),
161 encoded_frame
->dependency
== media::cast::EncodedFrame::KEY
));
165 VideoEncoderShim::VideoEncoderShim(PepperVideoEncoderHost
* host
)
168 RenderThreadImpl::current()->GetMediaThreadTaskRunner()),
169 weak_ptr_factory_(this) {
170 encoder_impl_
.reset(new EncoderImpl(weak_ptr_factory_
.GetWeakPtr()));
173 VideoEncoderShim::~VideoEncoderShim() {
174 DCHECK(RenderThreadImpl::current());
176 media_task_runner_
->PostTask(
177 FROM_HERE
, base::Bind(&VideoEncoderShim::EncoderImpl::Stop
,
178 base::Owned(encoder_impl_
.release())));
181 std::vector
<media::VideoEncodeAccelerator::SupportedProfile
>
182 VideoEncoderShim::GetSupportedProfiles() {
183 media::VideoEncodeAccelerator::SupportedProfile profile
= {
184 media::VP8PROFILE_ANY
,
185 gfx::Size(kMaxWidth
, kMaxHeight
),
186 media::cast::kDefaultMaxFrameRate
,
188 std::vector
<media::VideoEncodeAccelerator::SupportedProfile
> profiles
;
189 profiles
.push_back(profile
);
193 bool VideoEncoderShim::Initialize(
194 media::VideoFrame::Format input_format
,
195 const gfx::Size
& input_visible_size
,
196 media::VideoCodecProfile output_profile
,
197 uint32 initial_bitrate
,
198 media::VideoEncodeAccelerator::Client
* client
) {
199 DCHECK(RenderThreadImpl::current());
200 DCHECK_EQ(client
, host_
);
202 if (input_format
!= media::VideoFrame::I420
)
205 media_task_runner_
->PostTask(
207 base::Bind(&VideoEncoderShim::EncoderImpl::Initialize
,
208 base::Unretained(encoder_impl_
.get()), input_format
,
209 input_visible_size
, output_profile
, initial_bitrate
));
214 void VideoEncoderShim::Encode(const scoped_refptr
<media::VideoFrame
>& frame
,
215 bool force_keyframe
) {
216 DCHECK(RenderThreadImpl::current());
218 media_task_runner_
->PostTask(
220 base::Bind(&VideoEncoderShim::EncoderImpl::Encode
,
221 base::Unretained(encoder_impl_
.get()), frame
, force_keyframe
));
224 void VideoEncoderShim::UseOutputBitstreamBuffer(
225 const media::BitstreamBuffer
& buffer
) {
226 DCHECK(RenderThreadImpl::current());
228 media_task_runner_
->PostTask(
230 base::Bind(&VideoEncoderShim::EncoderImpl::UseOutputBitstreamBuffer
,
231 base::Unretained(encoder_impl_
.get()), buffer
,
232 host_
->ShmHandleToAddress(buffer
.id())));
235 void VideoEncoderShim::RequestEncodingParametersChange(uint32 bitrate
,
237 DCHECK(RenderThreadImpl::current());
239 media_task_runner_
->PostTask(
242 &VideoEncoderShim::EncoderImpl::RequestEncodingParametersChange
,
243 base::Unretained(encoder_impl_
.get()), bitrate
, framerate
));
246 void VideoEncoderShim::Destroy() {
247 DCHECK(RenderThreadImpl::current());
252 void VideoEncoderShim::OnRequireBitstreamBuffers(
253 unsigned int input_count
,
254 const gfx::Size
& input_coded_size
,
255 size_t output_buffer_size
) {
256 DCHECK(RenderThreadImpl::current());
258 host_
->RequireBitstreamBuffers(input_count
, input_coded_size
,
262 void VideoEncoderShim::OnBitstreamBufferReady(
263 scoped_refptr
<media::VideoFrame
> frame
,
264 int32 bitstream_buffer_id
,
267 DCHECK(RenderThreadImpl::current());
269 host_
->BitstreamBufferReady(bitstream_buffer_id
, payload_size
, key_frame
);
272 void VideoEncoderShim::OnNotifyError(
273 media::VideoEncodeAccelerator::Error error
) {
274 DCHECK(RenderThreadImpl::current());
276 host_
->NotifyError(error
);
279 } // namespace content