| 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 |