OLD | NEW |
| (Empty) |
1 // Copyright 2014 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 "media/cast/video_sender/external_video_encoder.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/logging.h" | |
9 #include "base/memory/scoped_vector.h" | |
10 #include "base/memory/shared_memory.h" | |
11 #include "base/message_loop/message_loop.h" | |
12 #include "media/base/video_frame.h" | |
13 #include "media/base/video_util.h" | |
14 #include "media/cast/cast_defines.h" | |
15 #include "media/cast/logging/logging_defines.h" | |
16 #include "media/cast/transport/cast_transport_config.h" | |
17 #include "media/video/video_encode_accelerator.h" | |
18 | |
19 namespace media { | |
20 namespace cast { | |
21 class LocalVideoEncodeAcceleratorClient; | |
22 } // namespace cast | |
23 } // namespace media | |
24 | |
25 namespace { | |
26 static const size_t kOutputBufferCount = 3; | |
27 | |
28 void LogFrameEncodedEvent( | |
29 const scoped_refptr<media::cast::CastEnvironment>& cast_environment, | |
30 base::TimeTicks event_time, | |
31 media::cast::RtpTimestamp rtp_timestamp, | |
32 uint32 frame_id) { | |
33 cast_environment->Logging()->InsertFrameEvent( | |
34 event_time, media::cast::FRAME_ENCODED, media::cast::VIDEO_EVENT, | |
35 rtp_timestamp, frame_id); | |
36 } | |
37 | |
38 // Proxy this call to ExternalVideoEncoder on the cast main thread. | |
39 void ProxyCreateVideoEncodeAccelerator( | |
40 const scoped_refptr<media::cast::CastEnvironment>& cast_environment, | |
41 const base::WeakPtr<media::cast::ExternalVideoEncoder>& weak_ptr, | |
42 const media::cast::CreateVideoEncodeMemoryCallback& | |
43 create_video_encode_mem_cb, | |
44 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner, | |
45 scoped_ptr<media::VideoEncodeAccelerator> vea) { | |
46 cast_environment->PostTask( | |
47 media::cast::CastEnvironment::MAIN, | |
48 FROM_HERE, | |
49 base::Bind( | |
50 &media::cast::ExternalVideoEncoder::OnCreateVideoEncodeAccelerator, | |
51 weak_ptr, | |
52 create_video_encode_mem_cb, | |
53 encoder_task_runner, | |
54 base::Passed(&vea))); | |
55 } | |
56 } // namespace | |
57 | |
58 namespace media { | |
59 namespace cast { | |
60 | |
61 // Container for the associated data of a video frame being processed. | |
62 struct EncodedFrameReturnData { | |
63 EncodedFrameReturnData(base::TimeTicks c_time, | |
64 VideoEncoder::FrameEncodedCallback callback) { | |
65 capture_time = c_time; | |
66 frame_encoded_callback = callback; | |
67 } | |
68 base::TimeTicks capture_time; | |
69 VideoEncoder::FrameEncodedCallback frame_encoded_callback; | |
70 }; | |
71 | |
72 // The ExternalVideoEncoder class can be deleted directly by cast, while | |
73 // LocalVideoEncodeAcceleratorClient stays around long enough to properly shut | |
74 // down the VideoEncodeAccelerator. | |
75 class LocalVideoEncodeAcceleratorClient | |
76 : public VideoEncodeAccelerator::Client, | |
77 public base::RefCountedThreadSafe<LocalVideoEncodeAcceleratorClient> { | |
78 public: | |
79 LocalVideoEncodeAcceleratorClient( | |
80 scoped_refptr<CastEnvironment> cast_environment, | |
81 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner, | |
82 scoped_ptr<media::VideoEncodeAccelerator> vea, | |
83 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb, | |
84 const base::WeakPtr<ExternalVideoEncoder>& weak_owner) | |
85 : cast_environment_(cast_environment), | |
86 encoder_task_runner_(encoder_task_runner), | |
87 video_encode_accelerator_(vea.Pass()), | |
88 create_video_encode_memory_cb_(create_video_encode_mem_cb), | |
89 weak_owner_(weak_owner), | |
90 last_encoded_frame_id_(kStartFrameId), | |
91 key_frame_encountered_(false) { | |
92 DCHECK(encoder_task_runner_); | |
93 } | |
94 | |
95 // Initialize the real HW encoder. | |
96 void Initialize(const VideoSenderConfig& video_config) { | |
97 DCHECK(encoder_task_runner_); | |
98 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread()); | |
99 | |
100 VideoCodecProfile output_profile = media::VIDEO_CODEC_PROFILE_UNKNOWN; | |
101 switch (video_config.codec) { | |
102 case transport::CODEC_VIDEO_VP8: | |
103 output_profile = media::VP8PROFILE_MAIN; | |
104 break; | |
105 case transport::CODEC_VIDEO_H264: | |
106 output_profile = media::H264PROFILE_MAIN; | |
107 break; | |
108 case transport::CODEC_VIDEO_FAKE: | |
109 NOTREACHED() << "Fake software video encoder cannot be external"; | |
110 break; | |
111 default: | |
112 NOTREACHED() << "Video codec not specified or not supported"; | |
113 break; | |
114 } | |
115 max_frame_rate_ = video_config.max_frame_rate; | |
116 | |
117 if (!video_encode_accelerator_->Initialize( | |
118 media::VideoFrame::I420, | |
119 gfx::Size(video_config.width, video_config.height), | |
120 output_profile, | |
121 video_config.start_bitrate, | |
122 this)) { | |
123 NotifyError(VideoEncodeAccelerator::kInvalidArgumentError); | |
124 return; | |
125 } | |
126 | |
127 // Wait until shared memory is allocated to indicate that encoder is | |
128 // initialized. | |
129 } | |
130 | |
131 // Free the HW. | |
132 void Destroy() { | |
133 DCHECK(encoder_task_runner_); | |
134 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread()); | |
135 | |
136 video_encode_accelerator_.reset(); | |
137 } | |
138 | |
139 void SetBitRate(uint32 bit_rate) { | |
140 DCHECK(encoder_task_runner_); | |
141 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread()); | |
142 | |
143 video_encode_accelerator_->RequestEncodingParametersChange(bit_rate, | |
144 max_frame_rate_); | |
145 } | |
146 | |
147 void EncodeVideoFrame( | |
148 const scoped_refptr<media::VideoFrame>& video_frame, | |
149 const base::TimeTicks& capture_time, | |
150 bool key_frame_requested, | |
151 const VideoEncoder::FrameEncodedCallback& frame_encoded_callback) { | |
152 DCHECK(encoder_task_runner_); | |
153 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread()); | |
154 | |
155 encoded_frame_data_storage_.push_back( | |
156 EncodedFrameReturnData(capture_time, frame_encoded_callback)); | |
157 | |
158 // BitstreamBufferReady will be called once the encoder is done. | |
159 video_encode_accelerator_->Encode(video_frame, key_frame_requested); | |
160 } | |
161 | |
162 protected: | |
163 virtual void NotifyError(VideoEncodeAccelerator::Error error) OVERRIDE { | |
164 DCHECK(encoder_task_runner_); | |
165 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread()); | |
166 VLOG(1) << "ExternalVideoEncoder NotifyError: " << error; | |
167 | |
168 video_encode_accelerator_.reset(); | |
169 cast_environment_->PostTask( | |
170 CastEnvironment::MAIN, | |
171 FROM_HERE, | |
172 base::Bind(&ExternalVideoEncoder::EncoderError, weak_owner_)); | |
173 } | |
174 | |
175 // Called to allocate the input and output buffers. | |
176 virtual void RequireBitstreamBuffers(unsigned int input_count, | |
177 const gfx::Size& input_coded_size, | |
178 size_t output_buffer_size) OVERRIDE { | |
179 DCHECK(encoder_task_runner_); | |
180 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread()); | |
181 DCHECK(video_encode_accelerator_); | |
182 | |
183 for (size_t j = 0; j < kOutputBufferCount; ++j) { | |
184 create_video_encode_memory_cb_.Run( | |
185 output_buffer_size, | |
186 base::Bind(&LocalVideoEncodeAcceleratorClient::OnCreateSharedMemory, | |
187 this)); | |
188 } | |
189 } | |
190 | |
191 // Encoder has encoded a frame and it's available in one of out output | |
192 // buffers. | |
193 virtual void BitstreamBufferReady(int32 bitstream_buffer_id, | |
194 size_t payload_size, | |
195 bool key_frame) OVERRIDE { | |
196 DCHECK(encoder_task_runner_); | |
197 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread()); | |
198 if (bitstream_buffer_id < 0 || | |
199 bitstream_buffer_id >= static_cast<int32>(output_buffers_.size())) { | |
200 NOTREACHED(); | |
201 VLOG(1) << "BitstreamBufferReady(): invalid bitstream_buffer_id=" | |
202 << bitstream_buffer_id; | |
203 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | |
204 return; | |
205 } | |
206 base::SharedMemory* output_buffer = output_buffers_[bitstream_buffer_id]; | |
207 if (payload_size > output_buffer->mapped_size()) { | |
208 NOTREACHED(); | |
209 VLOG(1) << "BitstreamBufferReady(): invalid payload_size = " | |
210 << payload_size; | |
211 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | |
212 return; | |
213 } | |
214 if (key_frame) | |
215 key_frame_encountered_ = true; | |
216 if (!key_frame_encountered_) { | |
217 // Do not send video until we have encountered the first key frame. | |
218 // Save the bitstream buffer in |stream_header_| to be sent later along | |
219 // with the first key frame. | |
220 stream_header_.append(static_cast<const char*>(output_buffer->memory()), | |
221 payload_size); | |
222 } else if (!encoded_frame_data_storage_.empty()) { | |
223 scoped_ptr<transport::EncodedFrame> encoded_frame( | |
224 new transport::EncodedFrame()); | |
225 encoded_frame->dependency = key_frame ? transport::EncodedFrame::KEY : | |
226 transport::EncodedFrame::DEPENDENT; | |
227 encoded_frame->frame_id = ++last_encoded_frame_id_; | |
228 if (key_frame) | |
229 encoded_frame->referenced_frame_id = encoded_frame->frame_id; | |
230 else | |
231 encoded_frame->referenced_frame_id = encoded_frame->frame_id - 1; | |
232 encoded_frame->reference_time = | |
233 encoded_frame_data_storage_.front().capture_time; | |
234 encoded_frame->rtp_timestamp = | |
235 GetVideoRtpTimestamp(encoded_frame->reference_time); | |
236 if (!stream_header_.empty()) { | |
237 encoded_frame->data = stream_header_; | |
238 stream_header_.clear(); | |
239 } | |
240 encoded_frame->data.append( | |
241 static_cast<const char*>(output_buffer->memory()), payload_size); | |
242 | |
243 cast_environment_->PostTask( | |
244 CastEnvironment::MAIN, | |
245 FROM_HERE, | |
246 base::Bind(&LogFrameEncodedEvent, | |
247 cast_environment_, | |
248 cast_environment_->Clock()->NowTicks(), | |
249 encoded_frame->rtp_timestamp, | |
250 encoded_frame->frame_id)); | |
251 | |
252 cast_environment_->PostTask( | |
253 CastEnvironment::MAIN, | |
254 FROM_HERE, | |
255 base::Bind(encoded_frame_data_storage_.front().frame_encoded_callback, | |
256 base::Passed(&encoded_frame))); | |
257 | |
258 encoded_frame_data_storage_.pop_front(); | |
259 } else { | |
260 VLOG(1) << "BitstreamBufferReady(): no encoded frame data available"; | |
261 } | |
262 | |
263 // We need to re-add the output buffer to the encoder after we are done | |
264 // with it. | |
265 video_encode_accelerator_->UseOutputBitstreamBuffer(media::BitstreamBuffer( | |
266 bitstream_buffer_id, | |
267 output_buffers_[bitstream_buffer_id]->handle(), | |
268 output_buffers_[bitstream_buffer_id]->mapped_size())); | |
269 } | |
270 | |
271 private: | |
272 // Note: This method can be called on any thread. | |
273 void OnCreateSharedMemory(scoped_ptr<base::SharedMemory> memory) { | |
274 encoder_task_runner_->PostTask( | |
275 FROM_HERE, | |
276 base::Bind(&LocalVideoEncodeAcceleratorClient::ReceivedSharedMemory, | |
277 this, | |
278 base::Passed(&memory))); | |
279 } | |
280 | |
281 void ReceivedSharedMemory(scoped_ptr<base::SharedMemory> memory) { | |
282 DCHECK(encoder_task_runner_); | |
283 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread()); | |
284 | |
285 output_buffers_.push_back(memory.release()); | |
286 | |
287 // Wait until all requested buffers are received. | |
288 if (output_buffers_.size() < kOutputBufferCount) | |
289 return; | |
290 | |
291 // Immediately provide all output buffers to the VEA. | |
292 for (size_t i = 0; i < output_buffers_.size(); ++i) { | |
293 video_encode_accelerator_->UseOutputBitstreamBuffer( | |
294 media::BitstreamBuffer(static_cast<int32>(i), | |
295 output_buffers_[i]->handle(), | |
296 output_buffers_[i]->mapped_size())); | |
297 } | |
298 | |
299 cast_environment_->PostTask( | |
300 CastEnvironment::MAIN, | |
301 FROM_HERE, | |
302 base::Bind(&ExternalVideoEncoder::EncoderInitialized, weak_owner_)); | |
303 } | |
304 | |
305 friend class base::RefCountedThreadSafe<LocalVideoEncodeAcceleratorClient>; | |
306 | |
307 virtual ~LocalVideoEncodeAcceleratorClient() {} | |
308 | |
309 const scoped_refptr<CastEnvironment> cast_environment_; | |
310 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner_; | |
311 scoped_ptr<media::VideoEncodeAccelerator> video_encode_accelerator_; | |
312 const CreateVideoEncodeMemoryCallback create_video_encode_memory_cb_; | |
313 const base::WeakPtr<ExternalVideoEncoder> weak_owner_; | |
314 int max_frame_rate_; | |
315 uint32 last_encoded_frame_id_; | |
316 bool key_frame_encountered_; | |
317 std::string stream_header_; | |
318 | |
319 // Shared memory buffers for output with the VideoAccelerator. | |
320 ScopedVector<base::SharedMemory> output_buffers_; | |
321 | |
322 // FIFO list. | |
323 std::list<EncodedFrameReturnData> encoded_frame_data_storage_; | |
324 | |
325 DISALLOW_COPY_AND_ASSIGN(LocalVideoEncodeAcceleratorClient); | |
326 }; | |
327 | |
328 ExternalVideoEncoder::ExternalVideoEncoder( | |
329 scoped_refptr<CastEnvironment> cast_environment, | |
330 const VideoSenderConfig& video_config, | |
331 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, | |
332 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb) | |
333 : video_config_(video_config), | |
334 cast_environment_(cast_environment), | |
335 encoder_active_(false), | |
336 key_frame_requested_(false), | |
337 weak_factory_(this) { | |
338 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
339 | |
340 create_vea_cb.Run(base::Bind(&ProxyCreateVideoEncodeAccelerator, | |
341 cast_environment, | |
342 weak_factory_.GetWeakPtr(), | |
343 create_video_encode_mem_cb)); | |
344 } | |
345 | |
346 ExternalVideoEncoder::~ExternalVideoEncoder() { | |
347 encoder_task_runner_->PostTask( | |
348 FROM_HERE, | |
349 base::Bind(&LocalVideoEncodeAcceleratorClient::Destroy, | |
350 video_accelerator_client_)); | |
351 } | |
352 | |
353 void ExternalVideoEncoder::EncoderInitialized() { | |
354 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
355 encoder_active_ = true; | |
356 } | |
357 | |
358 void ExternalVideoEncoder::EncoderError() { | |
359 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
360 encoder_active_ = false; | |
361 } | |
362 | |
363 void ExternalVideoEncoder::OnCreateVideoEncodeAccelerator( | |
364 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb, | |
365 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner, | |
366 scoped_ptr<media::VideoEncodeAccelerator> vea) { | |
367 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
368 encoder_task_runner_ = encoder_task_runner; | |
369 | |
370 video_accelerator_client_ = | |
371 new LocalVideoEncodeAcceleratorClient(cast_environment_, | |
372 encoder_task_runner, | |
373 vea.Pass(), | |
374 create_video_encode_mem_cb, | |
375 weak_factory_.GetWeakPtr()); | |
376 encoder_task_runner_->PostTask( | |
377 FROM_HERE, | |
378 base::Bind(&LocalVideoEncodeAcceleratorClient::Initialize, | |
379 video_accelerator_client_, | |
380 video_config_)); | |
381 } | |
382 | |
383 bool ExternalVideoEncoder::EncodeVideoFrame( | |
384 const scoped_refptr<media::VideoFrame>& video_frame, | |
385 const base::TimeTicks& capture_time, | |
386 const FrameEncodedCallback& frame_encoded_callback) { | |
387 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
388 | |
389 if (!encoder_active_) | |
390 return false; | |
391 | |
392 encoder_task_runner_->PostTask( | |
393 FROM_HERE, | |
394 base::Bind(&LocalVideoEncodeAcceleratorClient::EncodeVideoFrame, | |
395 video_accelerator_client_, | |
396 video_frame, | |
397 capture_time, | |
398 key_frame_requested_, | |
399 frame_encoded_callback)); | |
400 | |
401 key_frame_requested_ = false; | |
402 return true; | |
403 } | |
404 | |
405 // Inform the encoder about the new target bit rate. | |
406 void ExternalVideoEncoder::SetBitRate(int new_bit_rate) { | |
407 if (!encoder_active_) { | |
408 // If we receive SetBitRate() before VEA creation callback is invoked, | |
409 // cache the new bit rate in the encoder config and use the new settings | |
410 // to initialize VEA. | |
411 video_config_.start_bitrate = new_bit_rate; | |
412 return; | |
413 } | |
414 | |
415 encoder_task_runner_->PostTask( | |
416 FROM_HERE, | |
417 base::Bind(&LocalVideoEncodeAcceleratorClient::SetBitRate, | |
418 video_accelerator_client_, | |
419 new_bit_rate)); | |
420 } | |
421 | |
422 // Inform the encoder to encode the next frame as a key frame. | |
423 void ExternalVideoEncoder::GenerateKeyFrame() { | |
424 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
425 key_frame_requested_ = true; | |
426 } | |
427 | |
428 // Inform the encoder to only reference frames older or equal to frame_id; | |
429 void ExternalVideoEncoder::LatestFrameIdToReference(uint32 /*frame_id*/) { | |
430 // Do nothing not supported. | |
431 } | |
432 | |
433 } // namespace cast | |
434 } // namespace media | |
OLD | NEW |