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.
5 #include "media/cast/video_sender/external_video_encoder.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/transport/cast_transport_config.h"
16 #include "media/video/video_encode_accelerator.h"
19 // We allocate more input buffers than what is asked for by
20 // RequireBitstreamBuffers() due to potential threading timing.
21 static const int kInputBufferExtraCount = 1;
22 static const int kOutputBufferCount = 3;
24 void LogFrameEncodedEvent(media::cast::CastEnvironment* const cast_environment,
25 const base::TimeTicks& capture_time) {
26 cast_environment->Logging()->InsertFrameEvent(
27 cast_environment->Clock()->NowTicks(),
28 media::cast::kVideoFrameEncoded,
29 media::cast::GetVideoRtpTimestamp(capture_time),
30 media::cast::kFrameIdUnknown);
37 // Container for the associated data of a video frame being processed.
38 struct EncodedFrameReturnData {
39 EncodedFrameReturnData(base::TimeTicks c_time,
40 VideoEncoder::FrameEncodedCallback callback) {
41 capture_time = c_time;
42 frame_encoded_callback = callback;
44 base::TimeTicks capture_time;
45 VideoEncoder::FrameEncodedCallback frame_encoded_callback;
48 // The ExternalVideoEncoder class can be deleted directly by cast, while
49 // LocalVideoEncodeAcceleratorClient stays around long enough to properly shut
50 // down the VideoEncodeAccelerator.
51 class LocalVideoEncodeAcceleratorClient
52 : public VideoEncodeAccelerator::Client,
53 public base::RefCountedThreadSafe<LocalVideoEncodeAcceleratorClient> {
55 LocalVideoEncodeAcceleratorClient(
56 scoped_refptr<CastEnvironment> cast_environment,
57 scoped_refptr<GpuVideoAcceleratorFactories> gpu_factories,
58 const base::WeakPtr<ExternalVideoEncoder>& weak_owner)
59 : cast_environment_(cast_environment),
60 gpu_factories_(gpu_factories),
61 encoder_task_runner_(gpu_factories->GetTaskRunner()),
62 weak_owner_(weak_owner),
63 last_encoded_frame_id_(kStartFrameId) {
64 DCHECK(encoder_task_runner_);
67 // Initialize the real HW encoder.
68 void Initialize(const VideoSenderConfig& video_config) {
69 DCHECK(gpu_factories_);
70 DCHECK(encoder_task_runner_);
72 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
74 video_encode_accelerator_ =
75 gpu_factories_->CreateVideoEncodeAccelerator(this).Pass();
76 if (!video_encode_accelerator_)
79 VideoCodecProfile output_profile = media::VIDEO_CODEC_PROFILE_UNKNOWN;
80 switch (video_config.codec) {
82 output_profile = media::VP8PROFILE_MAIN;
84 case transport::kH264:
85 output_profile = media::H264PROFILE_MAIN;
88 codec_ = video_config.codec;
89 max_frame_rate_ = video_config.max_frame_rate;
91 // Asynchronous initialization call; NotifyInitializeDone or NotifyError
92 // will be called once the HW is initialized.
93 video_encode_accelerator_->Initialize(
94 media::VideoFrame::I420,
95 gfx::Size(video_config.width, video_config.height),
97 video_config.start_bitrate);
102 DCHECK(encoder_task_runner_);
103 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
105 if (video_encode_accelerator_) {
106 video_encode_accelerator_.release()->Destroy();
110 void SetBitRate(uint32 bit_rate) {
111 DCHECK(encoder_task_runner_);
112 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
114 video_encode_accelerator_->RequestEncodingParametersChange(bit_rate,
118 void EncodeVideoFrame(
119 const scoped_refptr<media::VideoFrame>& video_frame,
120 const base::TimeTicks& capture_time,
121 bool key_frame_requested,
122 const VideoEncoder::FrameEncodedCallback& frame_encoded_callback) {
123 DCHECK(encoder_task_runner_);
124 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
126 if (input_buffers_free_.empty()) {
128 VLOG(2) << "EncodeVideoFrame(): drop frame due to no hw buffers";
131 const int index = input_buffers_free_.back();
132 base::SharedMemory* input_buffer = input_buffers_[index];
134 // TODO(pwestin): this allocation and copy can be removed once we don't
135 // pass the video frame through liblingle.
137 scoped_refptr<media::VideoFrame> frame =
138 media::VideoFrame::WrapExternalPackedMemory(
139 video_frame->format(),
140 video_frame->coded_size(),
141 video_frame->visible_rect(),
142 video_frame->natural_size(),
143 reinterpret_cast<uint8*>(input_buffer->memory()),
144 input_buffer->mapped_size(),
145 input_buffer->handle(),
146 video_frame->GetTimestamp(),
147 base::Bind(&LocalVideoEncodeAcceleratorClient::FinishedWithInBuffer,
152 VLOG(1) << "EncodeVideoFrame(): failed to create frame";
153 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
156 // Do a stride copy of the input frame to match the input requirements.
157 media::CopyYPlane(video_frame->data(VideoFrame::kYPlane),
158 video_frame->stride(VideoFrame::kYPlane),
159 video_frame->natural_size().height(),
161 media::CopyUPlane(video_frame->data(VideoFrame::kUPlane),
162 video_frame->stride(VideoFrame::kUPlane),
163 video_frame->natural_size().height(),
165 media::CopyVPlane(video_frame->data(VideoFrame::kVPlane),
166 video_frame->stride(VideoFrame::kVPlane),
167 video_frame->natural_size().height(),
170 encoded_frame_data_storage_.push_back(
171 EncodedFrameReturnData(capture_time, frame_encoded_callback));
173 // BitstreamBufferReady will be called once the encoder is done.
174 video_encode_accelerator_->Encode(frame, key_frame_requested);
178 virtual void NotifyInitializeDone() OVERRIDE {
179 DCHECK(encoder_task_runner_);
180 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
182 cast_environment_->PostTask(
183 CastEnvironment::MAIN,
185 base::Bind(&ExternalVideoEncoder::EncoderInitialized, weak_owner_));
188 virtual void NotifyError(VideoEncodeAccelerator::Error error) OVERRIDE {
189 DCHECK(encoder_task_runner_);
190 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
191 VLOG(1) << "ExternalVideoEncoder NotifyError: " << error;
193 if (video_encode_accelerator_) {
194 video_encode_accelerator_.release()->Destroy();
196 cast_environment_->PostTask(
197 CastEnvironment::MAIN,
199 base::Bind(&ExternalVideoEncoder::EncoderError, weak_owner_));
202 // Called to allocate the input and output buffers.
203 virtual void RequireBitstreamBuffers(unsigned int input_count,
204 const gfx::Size& input_coded_size,
205 size_t output_buffer_size) OVERRIDE {
206 DCHECK(encoder_task_runner_);
207 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
208 DCHECK(video_encode_accelerator_);
210 for (unsigned int i = 0; i < input_count + kInputBufferExtraCount; ++i) {
211 base::SharedMemory* shm =
212 gpu_factories_->CreateSharedMemory(media::VideoFrame::AllocationSize(
213 media::VideoFrame::I420, input_coded_size));
215 VLOG(1) << "RequireBitstreamBuffers(): failed to create input buffer ";
218 input_buffers_.push_back(shm);
219 input_buffers_free_.push_back(i);
222 for (int j = 0; j < kOutputBufferCount; ++j) {
223 base::SharedMemory* shm =
224 gpu_factories_->CreateSharedMemory(output_buffer_size);
226 VLOG(1) << "RequireBitstreamBuffers(): failed to create input buffer ";
229 output_buffers_.push_back(shm);
231 // Immediately provide all output buffers to the VEA.
232 for (size_t i = 0; i < output_buffers_.size(); ++i) {
233 video_encode_accelerator_->UseOutputBitstreamBuffer(
234 media::BitstreamBuffer(static_cast<int32>(i),
235 output_buffers_[i]->handle(),
236 output_buffers_[i]->mapped_size()));
240 // Encoder has encoded a frame and it's available in one of out output
242 virtual void BitstreamBufferReady(int32 bitstream_buffer_id,
244 bool key_frame) OVERRIDE {
245 DCHECK(encoder_task_runner_);
246 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
247 if (bitstream_buffer_id < 0 ||
248 bitstream_buffer_id >= static_cast<int32>(output_buffers_.size())) {
250 VLOG(1) << "BitstreamBufferReady(): invalid bitstream_buffer_id="
251 << bitstream_buffer_id;
252 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
255 base::SharedMemory* output_buffer = output_buffers_[bitstream_buffer_id];
256 if (payload_size > output_buffer->mapped_size()) {
258 VLOG(1) << "BitstreamBufferReady(): invalid payload_size = "
260 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
263 if (encoded_frame_data_storage_.empty()) {
265 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
268 scoped_ptr<transport::EncodedVideoFrame> encoded_frame(
269 new transport::EncodedVideoFrame());
271 encoded_frame->codec = codec_;
272 encoded_frame->key_frame = key_frame;
273 encoded_frame->last_referenced_frame_id = last_encoded_frame_id_;
274 last_encoded_frame_id_++;
275 encoded_frame->frame_id = last_encoded_frame_id_;
276 encoded_frame->rtp_timestamp =
277 GetVideoRtpTimestamp(encoded_frame_data_storage_.front().capture_time);
280 encoded_frame->last_referenced_frame_id = encoded_frame->frame_id;
283 encoded_frame->data.insert(
284 0, static_cast<const char*>(output_buffer->memory()), payload_size);
286 cast_environment_->PostTask(
287 CastEnvironment::MAIN,
289 base::Bind(LogFrameEncodedEvent,
291 encoded_frame_data_storage_.front().capture_time));
293 cast_environment_->PostTask(
294 CastEnvironment::MAIN,
296 base::Bind(encoded_frame_data_storage_.front().frame_encoded_callback,
297 base::Passed(&encoded_frame),
298 encoded_frame_data_storage_.front().capture_time));
300 encoded_frame_data_storage_.pop_front();
302 // We need to re-add the output buffer to the encoder after we are done
304 video_encode_accelerator_->UseOutputBitstreamBuffer(media::BitstreamBuffer(
306 output_buffers_[bitstream_buffer_id]->handle(),
307 output_buffers_[bitstream_buffer_id]->mapped_size()));
311 // Encoder is done with the provided input buffer.
312 void FinishedWithInBuffer(int input_index) {
313 DCHECK(encoder_task_runner_);
314 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
315 DCHECK_GE(input_index, 0);
316 DCHECK_LT(input_index, static_cast<int>(input_buffers_.size()));
317 VLOG(2) << "EncodeFrameFinished(): index=" << input_index;
318 input_buffers_free_.push_back(input_index);
321 friend class base::RefCountedThreadSafe<LocalVideoEncodeAcceleratorClient>;
323 virtual ~LocalVideoEncodeAcceleratorClient() {}
325 const scoped_refptr<CastEnvironment> cast_environment_;
326 scoped_refptr<GpuVideoAcceleratorFactories> gpu_factories_;
327 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner_;
328 const base::WeakPtr<ExternalVideoEncoder> weak_owner_;
330 scoped_ptr<media::VideoEncodeAccelerator> video_encode_accelerator_;
332 transport::VideoCodec codec_;
333 uint32 last_encoded_frame_id_;
335 // Shared memory buffers for input/output with the VideoAccelerator.
336 ScopedVector<base::SharedMemory> input_buffers_;
337 ScopedVector<base::SharedMemory> output_buffers_;
339 // Input buffers ready to be filled with input from Encode(). As a LIFO since
340 // we don't care about ordering.
341 std::vector<int> input_buffers_free_;
344 std::list<EncodedFrameReturnData> encoded_frame_data_storage_;
346 DISALLOW_COPY_AND_ASSIGN(LocalVideoEncodeAcceleratorClient);
349 ExternalVideoEncoder::ExternalVideoEncoder(
350 scoped_refptr<CastEnvironment> cast_environment,
351 const VideoSenderConfig& video_config,
352 scoped_refptr<GpuVideoAcceleratorFactories> gpu_factories)
353 : video_config_(video_config),
354 cast_environment_(cast_environment),
355 encoder_active_(false),
356 key_frame_requested_(false),
357 skip_next_frame_(false),
359 encoder_task_runner_(gpu_factories->GetTaskRunner()),
360 weak_factory_(this) {
361 DCHECK(gpu_factories);
362 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
363 video_accelerator_client_ = new LocalVideoEncodeAcceleratorClient(
364 cast_environment, gpu_factories, weak_factory_.GetWeakPtr());
366 encoder_task_runner_->PostTask(
368 base::Bind(&LocalVideoEncodeAcceleratorClient::Initialize,
369 video_accelerator_client_,
373 ExternalVideoEncoder::~ExternalVideoEncoder() {
374 encoder_task_runner_->PostTask(
376 base::Bind(&LocalVideoEncodeAcceleratorClient::Destroy,
377 video_accelerator_client_));
380 void ExternalVideoEncoder::EncoderInitialized() {
381 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
382 encoder_active_ = true;
385 void ExternalVideoEncoder::EncoderError() {
386 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
387 encoder_active_ = false;
390 bool ExternalVideoEncoder::EncodeVideoFrame(
391 const scoped_refptr<media::VideoFrame>& video_frame,
392 const base::TimeTicks& capture_time,
393 const FrameEncodedCallback& frame_encoded_callback) {
394 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
396 if (!encoder_active_)
399 if (skip_next_frame_) {
400 VLOG(1) << "Skip encoding frame";
402 skip_next_frame_ = false;
405 base::TimeTicks now = cast_environment_->Clock()->NowTicks();
406 cast_environment_->Logging()->InsertFrameEvent(
408 kVideoFrameSentToEncoder,
409 GetVideoRtpTimestamp(capture_time),
412 encoder_task_runner_->PostTask(
414 base::Bind(&LocalVideoEncodeAcceleratorClient::EncodeVideoFrame,
415 video_accelerator_client_,
418 key_frame_requested_,
419 frame_encoded_callback));
421 key_frame_requested_ = false;
425 // Inform the encoder about the new target bit rate.
426 void ExternalVideoEncoder::SetBitRate(int new_bit_rate) {
427 encoder_task_runner_->PostTask(
429 base::Bind(&LocalVideoEncodeAcceleratorClient::SetBitRate,
430 video_accelerator_client_,
434 // Inform the encoder to not encode the next frame.
435 void ExternalVideoEncoder::SkipNextFrame(bool skip_next_frame) {
436 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
437 skip_next_frame_ = skip_next_frame;
440 // Inform the encoder to encode the next frame as a key frame.
441 void ExternalVideoEncoder::GenerateKeyFrame() {
442 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
443 key_frame_requested_ = true;
446 // Inform the encoder to only reference frames older or equal to frame_id;
447 void ExternalVideoEncoder::LatestFrameIdToReference(uint32 /*frame_id*/) {
448 // Do nothing not supported.
451 int ExternalVideoEncoder::NumberOfSkippedFrames() const {
452 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));