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
LogFrameEncodedEvent(const scoped_refptr<media::cast::CastEnvironment> & cast_environment,base::TimeTicks event_time,media::cast::RtpTimestamp rtp_timestamp,uint32 frame_id)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.
ProxyCreateVideoEncodeAccelerator(const scoped_refptr<media::cast::CastEnvironment> & cast_environment,const base::WeakPtr<media::cast::ExternalVideoEncoder> & weak_ptr,const media::cast::CreateVideoEncodeMemoryCallback & create_video_encode_mem_cb,scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner,scoped_ptr<media::VideoEncodeAccelerator> vea)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 {
EncodedFrameReturnDatamedia::cast::EncodedFrameReturnData63 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:
LocalVideoEncodeAcceleratorClient(scoped_refptr<CastEnvironment> cast_environment,scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner,scoped_ptr<media::VideoEncodeAccelerator> vea,const CreateVideoEncodeMemoryCallback & create_video_encode_mem_cb,const base::WeakPtr<ExternalVideoEncoder> & weak_owner)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.
Initialize(const VideoSenderConfig & video_config)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::kVp8:
103 output_profile = media::VP8PROFILE_MAIN;
104 break;
105 case transport::kH264:
106 output_profile = media::H264PROFILE_MAIN;
107 break;
108 case transport::kFakeSoftwareVideo:
109 NOTREACHED() << "Fake software video encoder cannot be external";
110 break;
111 case transport::kUnknownVideoCodec:
112 NOTREACHED() << "Video codec not specified";
113 break;
114 }
115 codec_ = video_config.codec;
116 max_frame_rate_ = video_config.max_frame_rate;
117
118 if (!video_encode_accelerator_->Initialize(
119 media::VideoFrame::I420,
120 gfx::Size(video_config.width, video_config.height),
121 output_profile,
122 video_config.start_bitrate,
123 this)) {
124 NotifyError(VideoEncodeAccelerator::kInvalidArgumentError);
125 return;
126 }
127
128 // Wait until shared memory is allocated to indicate that encoder is
129 // initialized.
130 }
131
132 // Free the HW.
Destroy()133 void Destroy() {
134 DCHECK(encoder_task_runner_);
135 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
136
137 video_encode_accelerator_.reset();
138 }
139
SetBitRate(uint32 bit_rate)140 void SetBitRate(uint32 bit_rate) {
141 DCHECK(encoder_task_runner_);
142 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
143
144 video_encode_accelerator_->RequestEncodingParametersChange(bit_rate,
145 max_frame_rate_);
146 }
147
EncodeVideoFrame(const scoped_refptr<media::VideoFrame> & video_frame,const base::TimeTicks & capture_time,bool key_frame_requested,const VideoEncoder::FrameEncodedCallback & frame_encoded_callback)148 void EncodeVideoFrame(
149 const scoped_refptr<media::VideoFrame>& video_frame,
150 const base::TimeTicks& capture_time,
151 bool key_frame_requested,
152 const VideoEncoder::FrameEncodedCallback& frame_encoded_callback) {
153 DCHECK(encoder_task_runner_);
154 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
155
156 encoded_frame_data_storage_.push_back(
157 EncodedFrameReturnData(capture_time, frame_encoded_callback));
158
159 // BitstreamBufferReady will be called once the encoder is done.
160 video_encode_accelerator_->Encode(video_frame, key_frame_requested);
161 }
162
163 protected:
NotifyError(VideoEncodeAccelerator::Error error)164 virtual void NotifyError(VideoEncodeAccelerator::Error error) OVERRIDE {
165 DCHECK(encoder_task_runner_);
166 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
167 VLOG(1) << "ExternalVideoEncoder NotifyError: " << error;
168
169 video_encode_accelerator_.reset();
170 cast_environment_->PostTask(
171 CastEnvironment::MAIN,
172 FROM_HERE,
173 base::Bind(&ExternalVideoEncoder::EncoderError, weak_owner_));
174 }
175
176 // Called to allocate the input and output buffers.
RequireBitstreamBuffers(unsigned int input_count,const gfx::Size & input_coded_size,size_t output_buffer_size)177 virtual void RequireBitstreamBuffers(unsigned int input_count,
178 const gfx::Size& input_coded_size,
179 size_t output_buffer_size) OVERRIDE {
180 DCHECK(encoder_task_runner_);
181 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
182 DCHECK(video_encode_accelerator_);
183
184 for (size_t j = 0; j < kOutputBufferCount; ++j) {
185 create_video_encode_memory_cb_.Run(
186 output_buffer_size,
187 base::Bind(&LocalVideoEncodeAcceleratorClient::OnCreateSharedMemory,
188 this));
189 }
190 }
191
192 // Encoder has encoded a frame and it's available in one of out output
193 // buffers.
BitstreamBufferReady(int32 bitstream_buffer_id,size_t payload_size,bool key_frame)194 virtual void BitstreamBufferReady(int32 bitstream_buffer_id,
195 size_t payload_size,
196 bool key_frame) OVERRIDE {
197 DCHECK(encoder_task_runner_);
198 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
199 if (bitstream_buffer_id < 0 ||
200 bitstream_buffer_id >= static_cast<int32>(output_buffers_.size())) {
201 NOTREACHED();
202 VLOG(1) << "BitstreamBufferReady(): invalid bitstream_buffer_id="
203 << bitstream_buffer_id;
204 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
205 return;
206 }
207 base::SharedMemory* output_buffer = output_buffers_[bitstream_buffer_id];
208 if (payload_size > output_buffer->mapped_size()) {
209 NOTREACHED();
210 VLOG(1) << "BitstreamBufferReady(): invalid payload_size = "
211 << payload_size;
212 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
213 return;
214 }
215 if (key_frame)
216 key_frame_encountered_ = true;
217 if (!key_frame_encountered_) {
218 // Do not send video until we have encountered the first key frame.
219 // Save the bitstream buffer in |stream_header_| to be sent later along
220 // with the first key frame.
221 stream_header_.append(static_cast<const char*>(output_buffer->memory()),
222 payload_size);
223 } else if (!encoded_frame_data_storage_.empty()) {
224 scoped_ptr<transport::EncodedFrame> encoded_frame(
225 new transport::EncodedFrame());
226 encoded_frame->dependency = key_frame ? transport::EncodedFrame::KEY :
227 transport::EncodedFrame::DEPENDENT;
228 encoded_frame->frame_id = ++last_encoded_frame_id_;
229 if (key_frame)
230 encoded_frame->referenced_frame_id = encoded_frame->frame_id;
231 else
232 encoded_frame->referenced_frame_id = encoded_frame->frame_id - 1;
233 encoded_frame->reference_time =
234 encoded_frame_data_storage_.front().capture_time;
235 encoded_frame->rtp_timestamp =
236 GetVideoRtpTimestamp(encoded_frame->reference_time);
237 if (!stream_header_.empty()) {
238 encoded_frame->data = stream_header_;
239 stream_header_.clear();
240 }
241 encoded_frame->data.append(
242 static_cast<const char*>(output_buffer->memory()), payload_size);
243
244 cast_environment_->PostTask(
245 CastEnvironment::MAIN,
246 FROM_HERE,
247 base::Bind(&LogFrameEncodedEvent,
248 cast_environment_,
249 cast_environment_->Clock()->NowTicks(),
250 encoded_frame->rtp_timestamp,
251 encoded_frame->frame_id));
252
253 cast_environment_->PostTask(
254 CastEnvironment::MAIN,
255 FROM_HERE,
256 base::Bind(encoded_frame_data_storage_.front().frame_encoded_callback,
257 base::Passed(&encoded_frame)));
258
259 encoded_frame_data_storage_.pop_front();
260 } else {
261 VLOG(1) << "BitstreamBufferReady(): no encoded frame data available";
262 }
263
264 // We need to re-add the output buffer to the encoder after we are done
265 // with it.
266 video_encode_accelerator_->UseOutputBitstreamBuffer(media::BitstreamBuffer(
267 bitstream_buffer_id,
268 output_buffers_[bitstream_buffer_id]->handle(),
269 output_buffers_[bitstream_buffer_id]->mapped_size()));
270 }
271
272 private:
273 // Note: This method can be called on any thread.
OnCreateSharedMemory(scoped_ptr<base::SharedMemory> memory)274 void OnCreateSharedMemory(scoped_ptr<base::SharedMemory> memory) {
275 encoder_task_runner_->PostTask(
276 FROM_HERE,
277 base::Bind(&LocalVideoEncodeAcceleratorClient::ReceivedSharedMemory,
278 this,
279 base::Passed(&memory)));
280 }
281
ReceivedSharedMemory(scoped_ptr<base::SharedMemory> memory)282 void ReceivedSharedMemory(scoped_ptr<base::SharedMemory> memory) {
283 DCHECK(encoder_task_runner_);
284 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
285
286 output_buffers_.push_back(memory.release());
287
288 // Wait until all requested buffers are received.
289 if (output_buffers_.size() < kOutputBufferCount)
290 return;
291
292 // Immediately provide all output buffers to the VEA.
293 for (size_t i = 0; i < output_buffers_.size(); ++i) {
294 video_encode_accelerator_->UseOutputBitstreamBuffer(
295 media::BitstreamBuffer(static_cast<int32>(i),
296 output_buffers_[i]->handle(),
297 output_buffers_[i]->mapped_size()));
298 }
299
300 cast_environment_->PostTask(
301 CastEnvironment::MAIN,
302 FROM_HERE,
303 base::Bind(&ExternalVideoEncoder::EncoderInitialized, weak_owner_));
304 }
305
306 friend class base::RefCountedThreadSafe<LocalVideoEncodeAcceleratorClient>;
307
~LocalVideoEncodeAcceleratorClient()308 virtual ~LocalVideoEncodeAcceleratorClient() {}
309
310 const scoped_refptr<CastEnvironment> cast_environment_;
311 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner_;
312 scoped_ptr<media::VideoEncodeAccelerator> video_encode_accelerator_;
313 const CreateVideoEncodeMemoryCallback create_video_encode_memory_cb_;
314 const base::WeakPtr<ExternalVideoEncoder> weak_owner_;
315 int max_frame_rate_;
316 transport::VideoCodec codec_;
317 uint32 last_encoded_frame_id_;
318 bool key_frame_encountered_;
319 std::string stream_header_;
320
321 // Shared memory buffers for output with the VideoAccelerator.
322 ScopedVector<base::SharedMemory> output_buffers_;
323
324 // FIFO list.
325 std::list<EncodedFrameReturnData> encoded_frame_data_storage_;
326
327 DISALLOW_COPY_AND_ASSIGN(LocalVideoEncodeAcceleratorClient);
328 };
329
ExternalVideoEncoder(scoped_refptr<CastEnvironment> cast_environment,const VideoSenderConfig & video_config,const CreateVideoEncodeAcceleratorCallback & create_vea_cb,const CreateVideoEncodeMemoryCallback & create_video_encode_mem_cb)330 ExternalVideoEncoder::ExternalVideoEncoder(
331 scoped_refptr<CastEnvironment> cast_environment,
332 const VideoSenderConfig& video_config,
333 const CreateVideoEncodeAcceleratorCallback& create_vea_cb,
334 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb)
335 : video_config_(video_config),
336 cast_environment_(cast_environment),
337 encoder_active_(false),
338 key_frame_requested_(false),
339 weak_factory_(this) {
340 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
341
342 create_vea_cb.Run(base::Bind(&ProxyCreateVideoEncodeAccelerator,
343 cast_environment,
344 weak_factory_.GetWeakPtr(),
345 create_video_encode_mem_cb));
346 }
347
~ExternalVideoEncoder()348 ExternalVideoEncoder::~ExternalVideoEncoder() {
349 encoder_task_runner_->PostTask(
350 FROM_HERE,
351 base::Bind(&LocalVideoEncodeAcceleratorClient::Destroy,
352 video_accelerator_client_));
353 }
354
EncoderInitialized()355 void ExternalVideoEncoder::EncoderInitialized() {
356 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
357 encoder_active_ = true;
358 }
359
EncoderError()360 void ExternalVideoEncoder::EncoderError() {
361 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
362 encoder_active_ = false;
363 }
364
OnCreateVideoEncodeAccelerator(const CreateVideoEncodeMemoryCallback & create_video_encode_mem_cb,scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner,scoped_ptr<media::VideoEncodeAccelerator> vea)365 void ExternalVideoEncoder::OnCreateVideoEncodeAccelerator(
366 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb,
367 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner,
368 scoped_ptr<media::VideoEncodeAccelerator> vea) {
369 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
370 encoder_task_runner_ = encoder_task_runner;
371
372 video_accelerator_client_ =
373 new LocalVideoEncodeAcceleratorClient(cast_environment_,
374 encoder_task_runner,
375 vea.Pass(),
376 create_video_encode_mem_cb,
377 weak_factory_.GetWeakPtr());
378 encoder_task_runner_->PostTask(
379 FROM_HERE,
380 base::Bind(&LocalVideoEncodeAcceleratorClient::Initialize,
381 video_accelerator_client_,
382 video_config_));
383 }
384
EncodeVideoFrame(const scoped_refptr<media::VideoFrame> & video_frame,const base::TimeTicks & capture_time,const FrameEncodedCallback & frame_encoded_callback)385 bool ExternalVideoEncoder::EncodeVideoFrame(
386 const scoped_refptr<media::VideoFrame>& video_frame,
387 const base::TimeTicks& capture_time,
388 const FrameEncodedCallback& frame_encoded_callback) {
389 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
390
391 if (!encoder_active_)
392 return false;
393
394 encoder_task_runner_->PostTask(
395 FROM_HERE,
396 base::Bind(&LocalVideoEncodeAcceleratorClient::EncodeVideoFrame,
397 video_accelerator_client_,
398 video_frame,
399 capture_time,
400 key_frame_requested_,
401 frame_encoded_callback));
402
403 key_frame_requested_ = false;
404 return true;
405 }
406
407 // Inform the encoder about the new target bit rate.
SetBitRate(int new_bit_rate)408 void ExternalVideoEncoder::SetBitRate(int new_bit_rate) {
409 if (!encoder_active_) {
410 // If we receive SetBitRate() before VEA creation callback is invoked,
411 // cache the new bit rate in the encoder config and use the new settings
412 // to initialize VEA.
413 video_config_.start_bitrate = new_bit_rate;
414 return;
415 }
416
417 encoder_task_runner_->PostTask(
418 FROM_HERE,
419 base::Bind(&LocalVideoEncodeAcceleratorClient::SetBitRate,
420 video_accelerator_client_,
421 new_bit_rate));
422 }
423
424 // Inform the encoder to encode the next frame as a key frame.
GenerateKeyFrame()425 void ExternalVideoEncoder::GenerateKeyFrame() {
426 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
427 key_frame_requested_ = true;
428 }
429
430 // Inform the encoder to only reference frames older or equal to frame_id;
LatestFrameIdToReference(uint32)431 void ExternalVideoEncoder::LatestFrameIdToReference(uint32 /*frame_id*/) {
432 // Do nothing not supported.
433 }
434
435 } // namespace cast
436 } // namespace media
437