OLD | NEW |
---|---|
(Empty) | |
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. | |
4 | |
5 #include "content/renderer/pepper/video_encoder_shim.h" | |
6 | |
7 #include <deque> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/bind_helpers.h" | |
11 #include "base/memory/scoped_vector.h" | |
12 #include "base/memory/shared_memory.h" | |
13 #include "base/message_loop/message_loop.h" | |
14 #include "content/renderer/pepper/pepper_video_encoder_host.h" | |
15 #include "content/renderer/render_thread_impl.h" | |
16 #include "media/cast/cast_config.h" | |
17 #include "media/cast/sender/vp8_encoder.h" | |
18 #include "ui/gfx/geometry/size.h" | |
19 | |
20 namespace content { | |
21 | |
22 const int32_t kMaxWidth = 1920; | |
23 const int32_t kMaxHeight = 1080; | |
bbudge
2015/03/02 20:01:06
Needs a comment explaining these constants.
llandwerlin-old
2015/03/03 15:23:28
Done.
| |
24 | |
25 class VideoEncoderShim::EncoderImpl { | |
26 public: | |
27 explicit EncoderImpl(const base::WeakPtr<VideoEncoderShim>& proxy); | |
28 ~EncoderImpl(); | |
29 | |
30 void Initialize(media::VideoFrame::Format input_format, | |
31 const gfx::Size& input_visible_size, | |
32 media::VideoCodecProfile output_profile, | |
33 uint32 initial_bitrate); | |
34 void Encode(const scoped_refptr<media::VideoFrame>& frame, | |
35 bool force_keyframe); | |
36 void UseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer, | |
37 uint8_t* mem); | |
38 void RequestEncodingParametersChange(uint32 bitrate, uint32 framerate); | |
39 void Stop(); | |
40 | |
41 private: | |
42 struct Frame { | |
bbudge
2015/03/02 20:01:06
Suggestion: s/Frame/PendingEncode
So you don't hav
llandwerlin-old
2015/03/03 15:23:28
Done.
| |
43 Frame(const scoped_refptr<media::VideoFrame>& frame, bool force_keyframe) | |
44 : frame(frame), force_keyframe(force_keyframe) {} | |
45 ~Frame() {} | |
46 | |
47 scoped_refptr<media::VideoFrame> frame; | |
48 bool force_keyframe; | |
49 }; | |
50 | |
51 struct BitstreamBuffer { | |
52 BitstreamBuffer(const media::BitstreamBuffer buffer, uint8_t* mem) | |
53 : buffer(buffer), mem(mem) {} | |
54 ~BitstreamBuffer() {} | |
55 | |
56 media::BitstreamBuffer buffer; | |
57 uint8_t* mem; | |
58 }; | |
59 | |
60 void DoEncode(); | |
61 | |
62 base::WeakPtr<VideoEncoderShim> shim_; | |
63 scoped_refptr<base::SingleThreadTaskRunner> shim_task_runner_; | |
bbudge
2015/03/02 20:01:06
Name suggestion: task_runner_ or media_task_runner
llandwerlin-old
2015/03/03 15:23:28
Done.
| |
64 | |
65 scoped_ptr<media::cast::SoftwareVideoEncoder> encoder_; | |
66 std::deque<Frame> frames_; | |
67 std::deque<BitstreamBuffer> buffers_; | |
68 }; | |
69 | |
70 VideoEncoderShim::EncoderImpl::EncoderImpl( | |
71 const base::WeakPtr<VideoEncoderShim>& proxy) | |
bbudge
2015/03/02 20:01:06
s/proxy/shim
And above in class decl.
llandwerlin-old
2015/03/03 15:23:28
Done.
| |
72 : shim_(proxy), shim_task_runner_(base::MessageLoopProxy::current()) { | |
73 } | |
74 | |
75 VideoEncoderShim::EncoderImpl::~EncoderImpl() { | |
76 } | |
77 | |
78 void VideoEncoderShim::EncoderImpl::Initialize( | |
79 media::VideoFrame::Format input_format, | |
80 const gfx::Size& input_visible_size, | |
81 media::VideoCodecProfile output_profile, | |
82 uint32 initial_bitrate) { | |
83 media::cast::VideoSenderConfig config; | |
84 | |
85 config.max_number_of_video_buffers_used = | |
86 3; // media::cast::Vp8Encoder::kNumberOfVp8VideoBuffers; | |
bbudge
2015/03/02 20:01:06
This comment confused me, since it refers to a pri
llandwerlin-old
2015/03/03 15:23:28
Done.
| |
87 config.number_of_encode_threads = 1; | |
88 encoder_.reset(new media::cast::Vp8Encoder(config)); | |
89 | |
90 encoder_->UpdateRates(initial_bitrate); | |
91 | |
92 shim_task_runner_->PostTask( | |
93 FROM_HERE, base::Bind(&VideoEncoderShim::OnRequireBitstreamBuffers, shim_, | |
94 3, input_visible_size, 4 * 1000000)); | |
bbudge
2015/03/02 20:01:06
4 * 1000000 should be a constant with a comment.
llandwerlin-old
2015/03/03 15:23:28
Done.
| |
95 } | |
96 | |
97 void VideoEncoderShim::EncoderImpl::Encode( | |
98 const scoped_refptr<media::VideoFrame>& frame, | |
99 bool force_keyframe) { | |
100 frames_.push_back(Frame(frame, force_keyframe)); | |
101 DoEncode(); | |
102 } | |
103 | |
104 void VideoEncoderShim::EncoderImpl::UseOutputBitstreamBuffer( | |
105 const media::BitstreamBuffer& buffer, | |
106 uint8_t* mem) { | |
107 buffers_.push_back(BitstreamBuffer(buffer, mem)); | |
108 DoEncode(); | |
109 } | |
110 | |
111 void VideoEncoderShim::EncoderImpl::RequestEncodingParametersChange( | |
112 uint32 bitrate, | |
113 uint32 framerate) { | |
114 encoder_->UpdateRates(bitrate); | |
115 } | |
116 | |
117 void VideoEncoderShim::EncoderImpl::Stop() { | |
118 frames_.clear(); | |
119 buffers_.clear(); | |
120 encoder_.reset(); | |
121 } | |
122 | |
123 void VideoEncoderShim::EncoderImpl::DoEncode() { | |
124 if (frames_.empty() || buffers_.empty()) | |
125 return; | |
bbudge
2015/03/02 20:01:06
I don't think you need this 'if' - the 'while' han
llandwerlin-old
2015/03/03 15:23:28
Done.
| |
126 | |
127 while (!frames_.empty() && !buffers_.empty()) { | |
128 Frame frame = frames_.front(); | |
129 frames_.pop_front(); | |
130 | |
131 if (frame.force_keyframe) | |
132 encoder_->GenerateKeyFrame(); | |
133 | |
134 scoped_ptr<media::cast::EncodedFrame> encoded_frame( | |
135 new media::cast::EncodedFrame()); | |
136 encoder_->Encode(frame.frame, base::TimeTicks::Now(), encoded_frame.get()); | |
bbudge
2015/03/02 20:01:06
nit: .get() isn't necessary.
llandwerlin-old
2015/03/03 15:23:27
That doesn't compile on GCC : no known conversion
| |
137 | |
138 BitstreamBuffer buffer = buffers_.front(); | |
139 buffers_.pop_front(); | |
140 | |
141 CHECK(buffer.buffer.size() >= encoded_frame->data.size()); | |
142 memcpy(buffer.mem, encoded_frame->bytes(), encoded_frame->data.size()); | |
143 | |
144 shim_task_runner_->PostTask( | |
145 FROM_HERE, | |
146 base::Bind( | |
147 &VideoEncoderShim::OnBitstreamBufferReady, shim_, | |
148 // Pass the media::VideoFrame back | |
149 // to the renderer thread so it's | |
150 // freed on the right thread. | |
bbudge
2015/03/02 20:01:06
comment formatting is a little weird. Maybe put it
llandwerlin-old
2015/03/03 15:23:27
Done.
| |
151 frame.frame, buffer.buffer.id(), encoded_frame->data.size(), | |
152 encoded_frame->dependency == media::cast::EncodedFrame::KEY)); | |
153 } | |
154 } | |
155 | |
156 // VideoEncoderShim : | |
bbudge
2015/03/02 20:01:06
nit: remove
llandwerlin-old
2015/03/03 15:23:27
Done.
| |
157 | |
158 VideoEncoderShim::VideoEncoderShim(PepperVideoEncoderHost* host) | |
159 : host_(host), | |
160 media_task_runner_( | |
161 RenderThreadImpl::current()->GetMediaThreadTaskRunner()), | |
162 weak_ptr_factory_(this) { | |
163 encoder_impl_.reset(new EncoderImpl(weak_ptr_factory_.GetWeakPtr())); | |
164 } | |
165 | |
166 VideoEncoderShim::~VideoEncoderShim() { | |
167 DCHECK(RenderThreadImpl::current()); | |
168 | |
169 media_task_runner_->PostTask( | |
170 FROM_HERE, base::Bind(&VideoEncoderShim::EncoderImpl::Stop, | |
171 base::Owned(encoder_impl_.release()))); | |
172 } | |
173 | |
174 std::vector<media::VideoEncodeAccelerator::SupportedProfile> | |
175 VideoEncoderShim::GetSupportedProfiles() { | |
176 media::VideoEncodeAccelerator::SupportedProfile profile = { | |
177 media::VP8PROFILE_ANY, | |
178 // TODO(llandwerlin): find correct values from libvpx. | |
bbudge
2015/03/02 20:01:06
Move TODO to definitions at top of file.
llandwerlin-old
2015/03/03 15:23:28
Done.
| |
179 gfx::Size(kMaxWidth, kMaxHeight), | |
180 media::cast::kDefaultMaxFrameRate, | |
181 1}; | |
182 std::vector<media::VideoEncodeAccelerator::SupportedProfile> profiles; | |
183 profiles.push_back(profile); | |
184 return profiles; | |
185 } | |
186 | |
187 bool VideoEncoderShim::Initialize( | |
188 media::VideoFrame::Format input_format, | |
189 const gfx::Size& input_visible_size, | |
190 media::VideoCodecProfile output_profile, | |
191 uint32 initial_bitrate, | |
192 media::VideoEncodeAccelerator::Client* client) { | |
193 DCHECK(RenderThreadImpl::current()); | |
194 DCHECK_EQ(client, host_); | |
195 | |
196 if (input_format != media::VideoFrame::I420) | |
197 return false; | |
bbudge
2015/03/02 20:01:06
Is it possible that other formats could work? I se
llandwerlin-old
2015/03/03 15:23:28
Looking at the VPX code, it depends on the codec a
bbudge
2015/03/05 01:43:59
It would be nice to have more profiles. I don't kn
| |
198 if (output_profile != media::VP8PROFILE_ANY) | |
199 return false; | |
200 if (input_visible_size.width() > kMaxWidth || | |
201 input_visible_size.height() > kMaxHeight) | |
202 return false; | |
bbudge
2015/03/02 20:01:06
Is this input validation needed? Doesn't the host
llandwerlin-old
2015/03/03 15:23:27
Fair, removing.
| |
203 | |
204 media_task_runner_->PostTask( | |
205 FROM_HERE, | |
206 base::Bind(&VideoEncoderShim::EncoderImpl::Initialize, | |
207 base::Unretained(encoder_impl_.get()), input_format, | |
208 input_visible_size, output_profile, initial_bitrate)); | |
209 | |
210 return true; | |
211 } | |
212 | |
213 void VideoEncoderShim::Encode(const scoped_refptr<media::VideoFrame>& frame, | |
214 bool force_keyframe) { | |
215 DCHECK(RenderThreadImpl::current()); | |
216 | |
217 media_task_runner_->PostTask( | |
218 FROM_HERE, | |
219 base::Bind(&VideoEncoderShim::EncoderImpl::Encode, | |
220 base::Unretained(encoder_impl_.get()), frame, force_keyframe)); | |
221 } | |
222 | |
223 void VideoEncoderShim::UseOutputBitstreamBuffer( | |
224 const media::BitstreamBuffer& buffer) { | |
225 DCHECK(RenderThreadImpl::current()); | |
226 | |
227 media_task_runner_->PostTask( | |
228 FROM_HERE, | |
229 base::Bind(&VideoEncoderShim::EncoderImpl::UseOutputBitstreamBuffer, | |
230 base::Unretained(encoder_impl_.get()), buffer, | |
231 host_->ShmHandleToAddress(buffer.id()))); | |
232 } | |
233 | |
234 void VideoEncoderShim::RequestEncodingParametersChange(uint32 bitrate, | |
235 uint32 framerate) { | |
236 DCHECK(RenderThreadImpl::current()); | |
237 | |
238 media_task_runner_->PostTask( | |
239 FROM_HERE, | |
240 base::Bind( | |
241 &VideoEncoderShim::EncoderImpl::RequestEncodingParametersChange, | |
242 base::Unretained(encoder_impl_.get()), bitrate, framerate)); | |
243 } | |
244 | |
245 void VideoEncoderShim::Destroy() { | |
246 DCHECK(RenderThreadImpl::current()); | |
247 | |
248 delete this; | |
249 } | |
250 | |
251 void VideoEncoderShim::OnRequireBitstreamBuffers( | |
252 unsigned int input_count, | |
253 const gfx::Size& input_coded_size, | |
254 size_t output_buffer_size) { | |
255 DCHECK(RenderThreadImpl::current()); | |
256 | |
257 host_->RequireBitstreamBuffers(input_count, input_coded_size, | |
258 output_buffer_size); | |
259 } | |
260 | |
261 void VideoEncoderShim::OnBitstreamBufferReady( | |
262 scoped_refptr<media::VideoFrame> frame, | |
263 int32 bitstream_buffer_id, | |
264 size_t payload_size, | |
265 bool key_frame) { | |
266 DCHECK(RenderThreadImpl::current()); | |
267 | |
268 host_->BitstreamBufferReady(bitstream_buffer_id, payload_size, key_frame); | |
269 } | |
270 | |
271 void VideoEncoderShim::OnNotifyError( | |
272 media::VideoEncodeAccelerator::Error error) { | |
273 DCHECK(RenderThreadImpl::current()); | |
274 | |
275 host_->NotifyError(error); | |
276 } | |
277 | |
278 } // namespace content | |
OLD | NEW |