Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / renderer / pepper / video_encoder_shim.cc
bloba89f18c719965061fcf6f5b98ea87bf1693642f8
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"
7 #include <inttypes.h>
9 #include <deque>
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"
22 namespace content {
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
27 // software encoding.
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 {
38 public:
39 explicit EncoderImpl(const base::WeakPtr<VideoEncoderShim>& shim);
40 ~EncoderImpl();
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,
47 bool force_keyframe);
48 void UseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer,
49 uint8_t* mem);
50 void RequestEncodingParametersChange(uint32 bitrate, uint32 framerate);
51 void Stop();
53 private:
54 struct PendingEncode {
55 PendingEncode(const scoped_refptr<media::VideoFrame>& frame,
56 bool force_keyframe)
57 : frame(frame), force_keyframe(force_keyframe) {}
58 ~PendingEncode() {}
60 scoped_refptr<media::VideoFrame> frame;
61 bool force_keyframe;
64 struct BitstreamBuffer {
65 BitstreamBuffer(const media::BitstreamBuffer buffer, uint8_t* mem)
66 : buffer(buffer), mem(mem) {}
67 ~BitstreamBuffer() {}
69 media::BitstreamBuffer buffer;
70 uint8_t* mem;
73 void DoEncode();
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));
114 DoEncode();
117 void VideoEncoderShim::EncoderImpl::UseOutputBitstreamBuffer(
118 const media::BitstreamBuffer& buffer,
119 uint8_t* mem) {
120 buffers_.push_back(BitstreamBuffer(buffer, mem));
121 DoEncode();
124 void VideoEncoderShim::EncoderImpl::RequestEncodingParametersChange(
125 uint32 bitrate,
126 uint32 framerate) {
127 encoder_->UpdateRates(bitrate);
130 void VideoEncoderShim::EncoderImpl::Stop() {
131 frames_.clear();
132 buffers_.clear();
133 encoder_.reset();
136 void VideoEncoderShim::EncoderImpl::DoEncode() {
137 while (!frames_.empty() && !buffers_.empty()) {
138 PendingEncode frame = frames_.front();
139 frames_.pop_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(
157 FROM_HERE,
158 base::Bind(
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)
166 : host_(host),
167 media_task_runner_(
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);
190 return profiles;
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)
203 return false;
205 media_task_runner_->PostTask(
206 FROM_HERE,
207 base::Bind(&VideoEncoderShim::EncoderImpl::Initialize,
208 base::Unretained(encoder_impl_.get()), input_format,
209 input_visible_size, output_profile, initial_bitrate));
211 return true;
214 void VideoEncoderShim::Encode(const scoped_refptr<media::VideoFrame>& frame,
215 bool force_keyframe) {
216 DCHECK(RenderThreadImpl::current());
218 media_task_runner_->PostTask(
219 FROM_HERE,
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(
229 FROM_HERE,
230 base::Bind(&VideoEncoderShim::EncoderImpl::UseOutputBitstreamBuffer,
231 base::Unretained(encoder_impl_.get()), buffer,
232 host_->ShmHandleToAddress(buffer.id())));
235 void VideoEncoderShim::RequestEncodingParametersChange(uint32 bitrate,
236 uint32 framerate) {
237 DCHECK(RenderThreadImpl::current());
239 media_task_runner_->PostTask(
240 FROM_HERE,
241 base::Bind(
242 &VideoEncoderShim::EncoderImpl::RequestEncodingParametersChange,
243 base::Unretained(encoder_impl_.get()), bitrate, framerate));
246 void VideoEncoderShim::Destroy() {
247 DCHECK(RenderThreadImpl::current());
249 delete this;
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,
259 output_buffer_size);
262 void VideoEncoderShim::OnBitstreamBufferReady(
263 scoped_refptr<media::VideoFrame> frame,
264 int32 bitstream_buffer_id,
265 size_t payload_size,
266 bool key_frame) {
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