Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/cast/sender/external_video_encoder.h" | 5 #include "media/cast/sender/external_video_encoder.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/memory/scoped_vector.h" | 9 #include "base/memory/scoped_vector.h" |
| 10 #include "base/memory/shared_memory.h" | 10 #include "base/memory/shared_memory.h" |
| 11 #include "base/message_loop/message_loop.h" | 11 #include "base/message_loop/message_loop.h" |
| 12 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
| 13 #include "media/base/video_frame.h" | 13 #include "media/base/video_frame.h" |
| 14 #include "media/base/video_util.h" | 14 #include "media/base/video_util.h" |
| 15 #include "media/cast/cast_defines.h" | 15 #include "media/cast/cast_defines.h" |
| 16 #include "media/cast/logging/logging_defines.h" | 16 #include "media/cast/logging/logging_defines.h" |
| 17 #include "media/cast/net/cast_transport_config.h" | 17 #include "media/cast/net/cast_transport_config.h" |
| 18 #include "media/video/video_encode_accelerator.h" | 18 #include "media/video/video_encode_accelerator.h" |
| 19 | 19 |
| 20 namespace media { | 20 namespace { |
| 21 namespace cast { | |
| 22 class LocalVideoEncodeAcceleratorClient; | |
| 23 } // namespace cast | |
| 24 } // namespace media | |
| 25 | 21 |
| 26 namespace { | |
| 27 static const size_t kOutputBufferCount = 3; | 22 static const size_t kOutputBufferCount = 3; |
| 28 | 23 |
| 29 void LogFrameEncodedEvent( | 24 void LogFrameEncodedEvent( |
| 30 const scoped_refptr<media::cast::CastEnvironment>& cast_environment, | 25 const scoped_refptr<media::cast::CastEnvironment>& cast_environment, |
| 31 base::TimeTicks event_time, | 26 base::TimeTicks event_time, |
| 32 media::cast::RtpTimestamp rtp_timestamp, | 27 media::cast::RtpTimestamp rtp_timestamp, |
| 33 uint32 frame_id) { | 28 uint32 frame_id) { |
| 34 cast_environment->Logging()->InsertFrameEvent( | 29 cast_environment->Logging()->InsertFrameEvent( |
| 35 event_time, media::cast::FRAME_ENCODED, media::cast::VIDEO_EVENT, | 30 event_time, media::cast::FRAME_ENCODED, media::cast::VIDEO_EVENT, |
| 36 rtp_timestamp, frame_id); | 31 rtp_timestamp, frame_id); |
| 37 } | 32 } |
| 33 | |
| 38 } // namespace | 34 } // namespace |
| 39 | 35 |
| 40 namespace media { | 36 namespace media { |
| 41 namespace cast { | 37 namespace cast { |
| 42 | 38 |
| 43 // Container for the associated data of a video frame being processed. | 39 // Container for the associated data of a video frame being processed. |
| 44 struct InProgressFrameEncode { | 40 struct InProgressFrameEncode { |
| 45 const RtpTimestamp rtp_timestamp; | 41 const RtpTimestamp rtp_timestamp; |
| 46 const base::TimeTicks reference_time; | 42 const base::TimeTicks reference_time; |
| 47 const VideoEncoder::FrameEncodedCallback frame_encoded_callback; | 43 const VideoEncoder::FrameEncodedCallback frame_encoded_callback; |
| 48 | 44 |
| 49 InProgressFrameEncode(RtpTimestamp rtp, | 45 InProgressFrameEncode(RtpTimestamp rtp, |
| 50 base::TimeTicks r_time, | 46 base::TimeTicks r_time, |
| 51 VideoEncoder::FrameEncodedCallback callback) | 47 VideoEncoder::FrameEncodedCallback callback) |
| 52 : rtp_timestamp(rtp), | 48 : rtp_timestamp(rtp), |
| 53 reference_time(r_time), | 49 reference_time(r_time), |
| 54 frame_encoded_callback(callback) {} | 50 frame_encoded_callback(callback) {} |
| 55 }; | 51 }; |
| 56 | 52 |
| 57 // The ExternalVideoEncoder class can be deleted directly by cast, while | 53 // Owns a VideoEncoderAccelerator instance and provides the necessary adapters |
| 58 // LocalVideoEncodeAcceleratorClient stays around long enough to properly shut | 54 // to encode media::VideoFrames and emit media::cast::EncodedFrames. All |
| 59 // down the VideoEncodeAccelerator. | 55 // methods must be called on the thread associated with the given |
| 60 class LocalVideoEncodeAcceleratorClient | 56 // SingleThreadTaskRunner, except for the task_runner() accessor. |
| 57 class ExternalVideoEncoder::VEAClientImpl | |
| 61 : public VideoEncodeAccelerator::Client, | 58 : public VideoEncodeAccelerator::Client, |
| 62 public base::RefCountedThreadSafe<LocalVideoEncodeAcceleratorClient> { | 59 public base::RefCountedThreadSafe<VEAClientImpl> { |
| 63 public: | 60 public: |
| 64 // Create an instance of this class and post a task to create | 61 VEAClientImpl( |
| 65 // video_encode_accelerator_. A ref to |this| will be kept, awaiting reply | 62 const scoped_refptr<CastEnvironment>& cast_environment, |
| 66 // via ProxyCreateVideoEncodeAccelerator, which will provide us with the | 63 const scoped_refptr<base::SingleThreadTaskRunner>& encoder_task_runner, |
| 67 // encoder task runner and vea instance. We cannot be destroyed until we | 64 scoped_ptr<media::VideoEncodeAccelerator> vea, |
| 68 // receive the reply, otherwise the VEA object created may leak. | 65 int max_frame_rate, |
| 69 static scoped_refptr<LocalVideoEncodeAcceleratorClient> Create( | 66 const CreateVideoEncodeMemoryCallback& create_video_encode_memory_cb) |
| 70 scoped_refptr<CastEnvironment> cast_environment, | 67 : cast_environment_(cast_environment), |
| 71 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, | 68 task_runner_(encoder_task_runner), |
| 72 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb, | 69 max_frame_rate_(max_frame_rate), |
| 73 const base::WeakPtr<ExternalVideoEncoder>& weak_owner) { | 70 create_video_encode_memory_cb_(create_video_encode_memory_cb), |
| 74 scoped_refptr<LocalVideoEncodeAcceleratorClient> client( | 71 video_encode_accelerator_(vea.Pass()), |
| 75 new LocalVideoEncodeAcceleratorClient( | 72 encoder_active_(false), |
| 76 cast_environment, create_video_encode_mem_cb, weak_owner)); | 73 last_encoded_frame_id_(kStartFrameId), |
| 77 | 74 key_frame_encountered_(false) { |
| 78 // This will keep a ref to |client|, if weak_owner is destroyed before | |
| 79 // ProxyCreateVideoEncodeAccelerator is called, we will stay alive until | |
| 80 // we can properly destroy the VEA. | |
| 81 create_vea_cb.Run(base::Bind( | |
| 82 &LocalVideoEncodeAcceleratorClient::OnCreateVideoEncodeAcceleratorProxy, | |
| 83 client)); | |
| 84 | |
| 85 return client; | |
| 86 } | 75 } |
| 87 | 76 |
| 88 // Initialize the real HW encoder. | 77 base::SingleThreadTaskRunner* task_runner() const { |
| 89 void Initialize(const VideoSenderConfig& video_config) { | 78 return task_runner_.get(); |
| 90 DCHECK(encoder_task_runner_.get()); | 79 } |
| 91 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread()); | |
| 92 | 80 |
| 93 VideoCodecProfile output_profile = media::VIDEO_CODEC_PROFILE_UNKNOWN; | 81 void Initialize(const gfx::Size& frame_size, |
| 94 switch (video_config.codec) { | 82 VideoCodecProfile codec_profile, |
| 95 case CODEC_VIDEO_VP8: | 83 int start_bit_rate, |
| 96 output_profile = media::VP8PROFILE_ANY; | 84 const CastInitializationCallback& initialization_cb) { |
| 97 break; | 85 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| 98 case CODEC_VIDEO_H264: | 86 DCHECK(!frame_size.IsEmpty()); |
| 99 output_profile = media::H264PROFILE_MAIN; | |
| 100 break; | |
| 101 case CODEC_VIDEO_FAKE: | |
| 102 NOTREACHED() << "Fake software video encoder cannot be external"; | |
| 103 break; | |
| 104 default: | |
| 105 NOTREACHED() << "Video codec not specified or not supported"; | |
| 106 break; | |
| 107 } | |
| 108 max_frame_rate_ = video_config.max_frame_rate; | |
| 109 | 87 |
| 110 bool result = video_encode_accelerator_->Initialize( | 88 encoder_active_ = video_encode_accelerator_->Initialize( |
| 111 media::VideoFrame::I420, | 89 media::VideoFrame::I420, |
| 112 gfx::Size(video_config.width, video_config.height), | 90 frame_size, |
| 113 output_profile, | 91 codec_profile, |
| 114 video_config.start_bitrate, | 92 start_bit_rate, |
| 115 this); | 93 this); |
| 116 | 94 |
| 117 UMA_HISTOGRAM_BOOLEAN("Cast.Sender.VideoEncodeAcceleratorInitializeSuccess", | 95 UMA_HISTOGRAM_BOOLEAN("Cast.Sender.VideoEncodeAcceleratorInitializeSuccess", |
| 118 result); | 96 encoder_active_); |
| 119 if (!result) { | 97 |
| 98 if (!initialization_cb.is_null()) { | |
| 120 cast_environment_->PostTask( | 99 cast_environment_->PostTask( |
| 121 CastEnvironment::MAIN, | 100 CastEnvironment::MAIN, |
| 122 FROM_HERE, | 101 FROM_HERE, |
| 123 base::Bind(&ExternalVideoEncoder::EncoderInitialized, weak_owner_, | 102 base::Bind(initialization_cb, |
|
hubbe
2015/01/29 23:29:15
Looks like there is a change in behavior when the
miu
2015/01/30 00:20:47
I looked at the code. It's safe, since the impl w
| |
| 124 false)); | 103 encoder_active_ ? STATUS_VIDEO_INITIALIZED : |
| 125 return; | 104 STATUS_HW_VIDEO_ENCODER_NOT_SUPPORTED)); |
| 126 } | |
| 127 | |
| 128 // Wait until shared memory is allocated to indicate that encoder is | |
| 129 // initialized. | |
| 130 } | |
| 131 | |
| 132 // Destroy the VEA on the correct thread. | |
| 133 void Destroy() { | |
| 134 DCHECK(encoder_task_runner_.get()); | |
| 135 if (!video_encode_accelerator_) | |
| 136 return; | |
| 137 | |
| 138 if (encoder_task_runner_->RunsTasksOnCurrentThread()) { | |
| 139 video_encode_accelerator_.reset(); | |
| 140 } else { | |
| 141 // We do this instead of just reposting to encoder_task_runner_, because | |
| 142 // we are called from the destructor. | |
| 143 encoder_task_runner_->PostTask( | |
| 144 FROM_HERE, | |
| 145 base::Bind(&DestroyVideoEncodeAcceleratorOnEncoderThread, | |
| 146 base::Passed(&video_encode_accelerator_))); | |
| 147 } | 105 } |
| 148 } | 106 } |
| 149 | 107 |
| 150 void SetBitRate(uint32 bit_rate) { | 108 void SetBitRate(int bit_rate) { |
| 151 DCHECK(encoder_task_runner_.get()); | 109 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| 152 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread()); | |
| 153 | 110 |
| 154 video_encode_accelerator_->RequestEncodingParametersChange(bit_rate, | 111 video_encode_accelerator_->RequestEncodingParametersChange(bit_rate, |
| 155 max_frame_rate_); | 112 max_frame_rate_); |
| 156 } | 113 } |
| 157 | 114 |
| 158 void EncodeVideoFrame( | 115 void EncodeVideoFrame( |
| 159 const scoped_refptr<media::VideoFrame>& video_frame, | 116 const scoped_refptr<media::VideoFrame>& video_frame, |
| 160 const base::TimeTicks& reference_time, | 117 const base::TimeTicks& reference_time, |
| 161 bool key_frame_requested, | 118 bool key_frame_requested, |
| 162 const VideoEncoder::FrameEncodedCallback& frame_encoded_callback) { | 119 const VideoEncoder::FrameEncodedCallback& frame_encoded_callback) { |
| 163 DCHECK(encoder_task_runner_.get()); | 120 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| 164 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread()); | 121 |
| 122 if (!encoder_active_) | |
| 123 return; | |
| 165 | 124 |
| 166 in_progress_frame_encodes_.push_back(InProgressFrameEncode( | 125 in_progress_frame_encodes_.push_back(InProgressFrameEncode( |
| 167 TimeDeltaToRtpDelta(video_frame->timestamp(), kVideoFrequency), | 126 TimeDeltaToRtpDelta(video_frame->timestamp(), kVideoFrequency), |
| 168 reference_time, | 127 reference_time, |
| 169 frame_encoded_callback)); | 128 frame_encoded_callback)); |
| 170 | 129 |
| 171 // BitstreamBufferReady will be called once the encoder is done. | 130 // BitstreamBufferReady will be called once the encoder is done. |
| 172 video_encode_accelerator_->Encode(video_frame, key_frame_requested); | 131 video_encode_accelerator_->Encode(video_frame, key_frame_requested); |
| 173 } | 132 } |
| 174 | 133 |
| 175 protected: | 134 protected: |
| 176 void NotifyError(VideoEncodeAccelerator::Error error) override { | 135 void NotifyError(VideoEncodeAccelerator::Error error) override { |
| 177 DCHECK(encoder_task_runner_.get()); | 136 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| 178 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread()); | |
| 179 VLOG(1) << "ExternalVideoEncoder NotifyError: " << error; | 137 VLOG(1) << "ExternalVideoEncoder NotifyError: " << error; |
| 180 | 138 |
| 181 cast_environment_->PostTask( | 139 encoder_active_ = false; |
| 182 CastEnvironment::MAIN, | 140 // TODO(miu): Plumbing is required to bubble this up to the CastSession and |
| 183 FROM_HERE, | 141 // beyond. |
| 184 base::Bind(&ExternalVideoEncoder::EncoderError, weak_owner_)); | |
| 185 } | 142 } |
| 186 | 143 |
| 187 // Called to allocate the input and output buffers. | 144 // Called to allocate the input and output buffers. |
| 188 void RequireBitstreamBuffers(unsigned int input_count, | 145 void RequireBitstreamBuffers(unsigned int input_count, |
| 189 const gfx::Size& input_coded_size, | 146 const gfx::Size& input_coded_size, |
| 190 size_t output_buffer_size) override { | 147 size_t output_buffer_size) override { |
| 191 DCHECK(encoder_task_runner_.get()); | 148 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| 192 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread()); | |
| 193 DCHECK(video_encode_accelerator_); | |
| 194 | 149 |
| 195 for (size_t j = 0; j < kOutputBufferCount; ++j) { | 150 for (size_t j = 0; j < kOutputBufferCount; ++j) { |
| 196 create_video_encode_memory_cb_.Run( | 151 create_video_encode_memory_cb_.Run( |
| 197 output_buffer_size, | 152 output_buffer_size, |
| 198 base::Bind(&LocalVideoEncodeAcceleratorClient::OnCreateSharedMemory, | 153 base::Bind(&VEAClientImpl::OnCreateSharedMemory, this)); |
| 199 this)); | |
| 200 } | 154 } |
| 201 } | 155 } |
| 202 | 156 |
| 203 // Encoder has encoded a frame and it's available in one of out output | 157 // Encoder has encoded a frame and it's available in one of the output |
| 204 // buffers. | 158 // buffers. Package the result in a media::cast::EncodedFrame and post it |
| 159 // to the Cast MAIN thread via the supplied callback. | |
| 205 void BitstreamBufferReady(int32 bitstream_buffer_id, | 160 void BitstreamBufferReady(int32 bitstream_buffer_id, |
| 206 size_t payload_size, | 161 size_t payload_size, |
| 207 bool key_frame) override { | 162 bool key_frame) override { |
| 208 DCHECK(encoder_task_runner_.get()); | 163 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| 209 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread()); | |
| 210 if (bitstream_buffer_id < 0 || | 164 if (bitstream_buffer_id < 0 || |
| 211 bitstream_buffer_id >= static_cast<int32>(output_buffers_.size())) { | 165 bitstream_buffer_id >= static_cast<int32>(output_buffers_.size())) { |
| 212 NOTREACHED(); | 166 NOTREACHED(); |
| 213 VLOG(1) << "BitstreamBufferReady(): invalid bitstream_buffer_id=" | 167 VLOG(1) << "BitstreamBufferReady(): invalid bitstream_buffer_id=" |
| 214 << bitstream_buffer_id; | 168 << bitstream_buffer_id; |
| 215 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | 169 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); |
| 216 return; | 170 return; |
| 217 } | 171 } |
| 218 base::SharedMemory* output_buffer = output_buffers_[bitstream_buffer_id]; | 172 base::SharedMemory* output_buffer = output_buffers_[bitstream_buffer_id]; |
| 219 if (payload_size > output_buffer->mapped_size()) { | 173 if (payload_size > output_buffer->mapped_size()) { |
| 220 NOTREACHED(); | 174 NOTREACHED(); |
| 221 VLOG(1) << "BitstreamBufferReady(): invalid payload_size = " | 175 VLOG(1) << "BitstreamBufferReady(): invalid payload_size = " |
| 222 << payload_size; | 176 << payload_size; |
| 223 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | 177 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); |
| 224 return; | 178 return; |
| 225 } | 179 } |
| 226 if (key_frame) | 180 if (key_frame) |
| 227 key_frame_encountered_ = true; | 181 key_frame_encountered_ = true; |
| 228 if (!key_frame_encountered_) { | 182 if (!key_frame_encountered_) { |
| 229 // Do not send video until we have encountered the first key frame. | 183 // Do not send video until we have encountered the first key frame. |
| 230 // Save the bitstream buffer in |stream_header_| to be sent later along | 184 // Save the bitstream buffer in |stream_header_| to be sent later along |
| 231 // with the first key frame. | 185 // with the first key frame. |
| 186 // | |
| 187 // TODO(miu): Should |stream_header_| be an std::ostringstream for | |
| 188 // performance reasons? | |
| 232 stream_header_.append(static_cast<const char*>(output_buffer->memory()), | 189 stream_header_.append(static_cast<const char*>(output_buffer->memory()), |
| 233 payload_size); | 190 payload_size); |
| 234 } else if (!in_progress_frame_encodes_.empty()) { | 191 } else if (!in_progress_frame_encodes_.empty()) { |
| 235 const InProgressFrameEncode& request = in_progress_frame_encodes_.front(); | 192 const InProgressFrameEncode& request = in_progress_frame_encodes_.front(); |
| 236 | 193 |
| 237 scoped_ptr<EncodedFrame> encoded_frame(new EncodedFrame()); | 194 scoped_ptr<EncodedFrame> encoded_frame(new EncodedFrame()); |
| 238 encoded_frame->dependency = key_frame ? EncodedFrame::KEY : | 195 encoded_frame->dependency = key_frame ? EncodedFrame::KEY : |
| 239 EncodedFrame::DEPENDENT; | 196 EncodedFrame::DEPENDENT; |
| 240 encoded_frame->frame_id = ++last_encoded_frame_id_; | 197 encoded_frame->frame_id = ++last_encoded_frame_id_; |
| 241 if (key_frame) | 198 if (key_frame) |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 273 | 230 |
| 274 // We need to re-add the output buffer to the encoder after we are done | 231 // We need to re-add the output buffer to the encoder after we are done |
| 275 // with it. | 232 // with it. |
| 276 video_encode_accelerator_->UseOutputBitstreamBuffer(media::BitstreamBuffer( | 233 video_encode_accelerator_->UseOutputBitstreamBuffer(media::BitstreamBuffer( |
| 277 bitstream_buffer_id, | 234 bitstream_buffer_id, |
| 278 output_buffers_[bitstream_buffer_id]->handle(), | 235 output_buffers_[bitstream_buffer_id]->handle(), |
| 279 output_buffers_[bitstream_buffer_id]->mapped_size())); | 236 output_buffers_[bitstream_buffer_id]->mapped_size())); |
| 280 } | 237 } |
| 281 | 238 |
| 282 private: | 239 private: |
| 283 LocalVideoEncodeAcceleratorClient( | 240 friend class base::RefCountedThreadSafe<VEAClientImpl>; |
| 284 scoped_refptr<CastEnvironment> cast_environment, | |
| 285 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb, | |
| 286 const base::WeakPtr<ExternalVideoEncoder>& weak_owner) | |
| 287 : cast_environment_(cast_environment), | |
| 288 create_video_encode_memory_cb_(create_video_encode_mem_cb), | |
| 289 weak_owner_(weak_owner), | |
| 290 last_encoded_frame_id_(kStartFrameId), | |
| 291 key_frame_encountered_(false) {} | |
| 292 | 241 |
| 293 // Trampoline VEA creation callback to OnCreateVideoEncodeAccelerator() | 242 ~VEAClientImpl() override { |
| 294 // on encoder_task_runner. Normally we would just repost the same method to | 243 // According to the media::VideoEncodeAccelerator interface, Destroy() |
| 295 // it, and would not need a separate proxy method, but we can't | 244 // should be called instead of invoking its private destructor. |
| 296 // ThreadTaskRunnerHandle::Get() in unittests just yet. | 245 task_runner_->PostTask( |
| 297 void OnCreateVideoEncodeAcceleratorProxy( | |
| 298 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner, | |
| 299 scoped_ptr<media::VideoEncodeAccelerator> vea) { | |
| 300 encoder_task_runner->PostTask( | |
| 301 FROM_HERE, | 246 FROM_HERE, |
| 302 base::Bind(&media::cast::LocalVideoEncodeAcceleratorClient:: | 247 base::Bind(&media::VideoEncodeAccelerator::Destroy, |
| 303 OnCreateVideoEncodeAccelerator, | 248 base::Unretained(video_encode_accelerator_.release()))); |
| 304 this, | |
| 305 encoder_task_runner, | |
| 306 base::Passed(&vea))); | |
| 307 } | |
| 308 | |
| 309 void OnCreateVideoEncodeAccelerator( | |
| 310 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner, | |
| 311 scoped_ptr<media::VideoEncodeAccelerator> vea) { | |
| 312 encoder_task_runner_ = encoder_task_runner; | |
| 313 video_encode_accelerator_.reset(vea.release()); | |
| 314 | |
| 315 cast_environment_->PostTask( | |
| 316 CastEnvironment::MAIN, | |
| 317 FROM_HERE, | |
| 318 base::Bind(&ExternalVideoEncoder::OnCreateVideoEncodeAccelerator, | |
| 319 weak_owner_, | |
| 320 encoder_task_runner_)); | |
| 321 } | 249 } |
| 322 | 250 |
| 323 // Note: This method can be called on any thread. | 251 // Note: This method can be called on any thread. |
| 324 void OnCreateSharedMemory(scoped_ptr<base::SharedMemory> memory) { | 252 void OnCreateSharedMemory(scoped_ptr<base::SharedMemory> memory) { |
| 325 encoder_task_runner_->PostTask( | 253 task_runner_->PostTask(FROM_HERE, |
| 326 FROM_HERE, | 254 base::Bind(&VEAClientImpl::OnReceivedSharedMemory, |
| 327 base::Bind(&LocalVideoEncodeAcceleratorClient::ReceivedSharedMemory, | 255 this, |
| 328 this, | 256 base::Passed(&memory))); |
| 329 base::Passed(&memory))); | |
| 330 } | 257 } |
| 331 | 258 |
| 332 void ReceivedSharedMemory(scoped_ptr<base::SharedMemory> memory) { | 259 void OnReceivedSharedMemory(scoped_ptr<base::SharedMemory> memory) { |
| 333 DCHECK(encoder_task_runner_.get()); | 260 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| 334 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread()); | |
| 335 | 261 |
| 336 output_buffers_.push_back(memory.release()); | 262 output_buffers_.push_back(memory.release()); |
| 337 | 263 |
| 338 // Wait until all requested buffers are received. | 264 // Wait until all requested buffers are received. |
| 339 if (output_buffers_.size() < kOutputBufferCount) | 265 if (output_buffers_.size() < kOutputBufferCount) |
| 340 return; | 266 return; |
| 341 | 267 |
| 342 // Immediately provide all output buffers to the VEA. | 268 // Immediately provide all output buffers to the VEA. |
| 343 for (size_t i = 0; i < output_buffers_.size(); ++i) { | 269 for (size_t i = 0; i < output_buffers_.size(); ++i) { |
| 344 video_encode_accelerator_->UseOutputBitstreamBuffer( | 270 video_encode_accelerator_->UseOutputBitstreamBuffer( |
| 345 media::BitstreamBuffer(static_cast<int32>(i), | 271 media::BitstreamBuffer(static_cast<int32>(i), |
| 346 output_buffers_[i]->handle(), | 272 output_buffers_[i]->handle(), |
| 347 output_buffers_[i]->mapped_size())); | 273 output_buffers_[i]->mapped_size())); |
| 348 } | 274 } |
| 349 | |
| 350 cast_environment_->PostTask( | |
| 351 CastEnvironment::MAIN, | |
| 352 FROM_HERE, | |
| 353 base::Bind(&ExternalVideoEncoder::EncoderInitialized, weak_owner_, | |
| 354 true)); | |
| 355 } | |
| 356 | |
| 357 static void DestroyVideoEncodeAcceleratorOnEncoderThread( | |
| 358 scoped_ptr<media::VideoEncodeAccelerator> vea) { | |
| 359 // VEA::~VEA specialization takes care of calling Destroy() on the VEA impl. | |
| 360 } | |
| 361 | |
| 362 friend class base::RefCountedThreadSafe<LocalVideoEncodeAcceleratorClient>; | |
| 363 | |
| 364 ~LocalVideoEncodeAcceleratorClient() override { | |
| 365 Destroy(); | |
| 366 DCHECK(!video_encode_accelerator_); | |
| 367 } | 275 } |
| 368 | 276 |
| 369 const scoped_refptr<CastEnvironment> cast_environment_; | 277 const scoped_refptr<CastEnvironment> cast_environment_; |
| 370 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner_; | 278 const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
| 279 const int max_frame_rate_; | |
| 280 const CreateVideoEncodeMemoryCallback create_video_encode_memory_cb_; | |
| 371 scoped_ptr<media::VideoEncodeAccelerator> video_encode_accelerator_; | 281 scoped_ptr<media::VideoEncodeAccelerator> video_encode_accelerator_; |
| 372 const CreateVideoEncodeMemoryCallback create_video_encode_memory_cb_; | 282 bool encoder_active_; |
| 373 const base::WeakPtr<ExternalVideoEncoder> weak_owner_; | |
| 374 int max_frame_rate_; | |
| 375 uint32 last_encoded_frame_id_; | 283 uint32 last_encoded_frame_id_; |
| 376 bool key_frame_encountered_; | 284 bool key_frame_encountered_; |
| 377 std::string stream_header_; | 285 std::string stream_header_; |
| 378 | 286 |
| 379 // Shared memory buffers for output with the VideoAccelerator. | 287 // Shared memory buffers for output with the VideoAccelerator. |
| 380 ScopedVector<base::SharedMemory> output_buffers_; | 288 ScopedVector<base::SharedMemory> output_buffers_; |
| 381 | 289 |
| 382 // FIFO list. | 290 // FIFO list. |
| 383 std::list<InProgressFrameEncode> in_progress_frame_encodes_; | 291 std::list<InProgressFrameEncode> in_progress_frame_encodes_; |
| 384 | 292 |
| 385 DISALLOW_COPY_AND_ASSIGN(LocalVideoEncodeAcceleratorClient); | 293 DISALLOW_COPY_AND_ASSIGN(VEAClientImpl); |
| 386 }; | 294 }; |
| 387 | 295 |
| 388 ExternalVideoEncoder::ExternalVideoEncoder( | 296 ExternalVideoEncoder::ExternalVideoEncoder( |
| 389 scoped_refptr<CastEnvironment> cast_environment, | 297 const scoped_refptr<CastEnvironment>& cast_environment, |
| 390 const VideoSenderConfig& video_config, | 298 const VideoSenderConfig& video_config, |
| 299 const gfx::Size& frame_size, | |
| 391 const CastInitializationCallback& initialization_cb, | 300 const CastInitializationCallback& initialization_cb, |
| 392 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, | 301 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, |
| 393 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb) | 302 const CreateVideoEncodeMemoryCallback& create_video_encode_memory_cb) |
| 394 : video_config_(video_config), | 303 : cast_environment_(cast_environment), |
| 395 cast_environment_(cast_environment), | 304 create_video_encode_memory_cb_(create_video_encode_memory_cb), |
| 396 encoder_active_(false), | 305 bit_rate_(video_config.start_bitrate), |
| 397 key_frame_requested_(false), | 306 key_frame_requested_(false), |
| 398 initialization_cb_(initialization_cb), | |
| 399 weak_factory_(this) { | 307 weak_factory_(this) { |
| 400 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 308 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 309 DCHECK_GT(video_config.max_frame_rate, 0); | |
| 310 DCHECK(!frame_size.IsEmpty()); | |
| 311 DCHECK(!create_vea_cb.is_null()); | |
| 312 DCHECK(!create_video_encode_memory_cb_.is_null()); | |
| 313 DCHECK_GT(bit_rate_, 0); | |
| 401 | 314 |
| 402 video_accelerator_client_ = | 315 VideoCodecProfile codec_profile; |
| 403 LocalVideoEncodeAcceleratorClient::Create(cast_environment_, | 316 switch (video_config.codec) { |
| 404 create_vea_cb, | 317 case CODEC_VIDEO_VP8: |
| 405 create_video_encode_mem_cb, | 318 codec_profile = media::VP8PROFILE_ANY; |
| 406 weak_factory_.GetWeakPtr()); | 319 break; |
| 407 DCHECK(video_accelerator_client_.get()); | 320 case CODEC_VIDEO_H264: |
| 321 codec_profile = media::H264PROFILE_MAIN; | |
| 322 break; | |
| 323 case CODEC_VIDEO_FAKE: | |
| 324 NOTREACHED() << "Fake software video encoder cannot be external"; | |
| 325 // ...flow through to next case... | |
| 326 default: | |
| 327 cast_environment_->PostTask( | |
| 328 CastEnvironment::MAIN, | |
| 329 FROM_HERE, | |
| 330 base::Bind(initialization_cb, STATUS_HW_VIDEO_ENCODER_NOT_SUPPORTED)); | |
| 331 return; | |
| 332 } | |
| 333 | |
| 334 create_vea_cb.Run( | |
| 335 base::Bind(&ExternalVideoEncoder::OnCreateVideoEncodeAccelerator, | |
| 336 weak_factory_.GetWeakPtr(), | |
| 337 frame_size, | |
| 338 codec_profile, | |
| 339 video_config.max_frame_rate, | |
| 340 initialization_cb)); | |
| 408 } | 341 } |
| 409 | 342 |
| 410 ExternalVideoEncoder::~ExternalVideoEncoder() { | 343 ExternalVideoEncoder::~ExternalVideoEncoder() { |
| 411 } | 344 } |
| 412 | 345 |
| 413 void ExternalVideoEncoder::EncoderInitialized(bool success) { | |
| 414 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
| 415 encoder_active_ = success; | |
| 416 DCHECK(!initialization_cb_.is_null()); | |
| 417 initialization_cb_.Run( | |
| 418 success ? | |
| 419 STATUS_VIDEO_INITIALIZED : STATUS_HW_VIDEO_ENCODER_NOT_SUPPORTED); | |
| 420 initialization_cb_.Reset(); | |
| 421 } | |
| 422 | |
| 423 void ExternalVideoEncoder::EncoderError() { | |
| 424 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
| 425 encoder_active_ = false; | |
| 426 } | |
| 427 | |
| 428 void ExternalVideoEncoder::OnCreateVideoEncodeAccelerator( | |
| 429 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner) { | |
| 430 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
| 431 encoder_task_runner_ = encoder_task_runner; | |
| 432 | |
| 433 encoder_task_runner_->PostTask( | |
| 434 FROM_HERE, | |
| 435 base::Bind(&LocalVideoEncodeAcceleratorClient::Initialize, | |
| 436 video_accelerator_client_, | |
| 437 video_config_)); | |
| 438 } | |
| 439 | |
| 440 bool ExternalVideoEncoder::EncodeVideoFrame( | 346 bool ExternalVideoEncoder::EncodeVideoFrame( |
| 441 const scoped_refptr<media::VideoFrame>& video_frame, | 347 const scoped_refptr<media::VideoFrame>& video_frame, |
| 442 const base::TimeTicks& reference_time, | 348 const base::TimeTicks& reference_time, |
| 443 const FrameEncodedCallback& frame_encoded_callback) { | 349 const FrameEncodedCallback& frame_encoded_callback) { |
| 444 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 350 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 351 DCHECK(!video_frame->visible_rect().IsEmpty()); | |
| 352 DCHECK(!frame_encoded_callback.is_null()); | |
| 445 | 353 |
| 446 if (!encoder_active_) | 354 if (!client_) |
| 447 return false; | 355 return false; // Not ready. |
| 448 | 356 |
| 449 encoder_task_runner_->PostTask( | 357 client_->task_runner()->PostTask(FROM_HERE, |
| 450 FROM_HERE, | 358 base::Bind(&VEAClientImpl::EncodeVideoFrame, |
| 451 base::Bind(&LocalVideoEncodeAcceleratorClient::EncodeVideoFrame, | 359 client_, |
| 452 video_accelerator_client_, | 360 video_frame, |
| 453 video_frame, | 361 reference_time, |
| 454 reference_time, | 362 key_frame_requested_, |
| 455 key_frame_requested_, | 363 frame_encoded_callback)); |
| 456 frame_encoded_callback)); | |
| 457 | |
| 458 key_frame_requested_ = false; | 364 key_frame_requested_ = false; |
| 459 return true; | 365 return true; |
| 460 } | 366 } |
| 461 | 367 |
| 462 // Inform the encoder about the new target bit rate. | |
| 463 void ExternalVideoEncoder::SetBitRate(int new_bit_rate) { | 368 void ExternalVideoEncoder::SetBitRate(int new_bit_rate) { |
| 464 if (!encoder_active_) { | 369 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 465 // If we receive SetBitRate() before VEA creation callback is invoked, | 370 DCHECK_GT(new_bit_rate, 0); |
| 466 // cache the new bit rate in the encoder config and use the new settings | 371 |
| 467 // to initialize VEA. | 372 bit_rate_ = new_bit_rate; |
| 468 video_config_.start_bitrate = new_bit_rate; | 373 if (!client_) |
| 469 return; | 374 return; |
| 470 } | 375 client_->task_runner()->PostTask( |
| 471 | 376 FROM_HERE, base::Bind(&VEAClientImpl::SetBitRate, client_, bit_rate_)); |
| 472 encoder_task_runner_->PostTask( | |
| 473 FROM_HERE, | |
| 474 base::Bind(&LocalVideoEncodeAcceleratorClient::SetBitRate, | |
| 475 video_accelerator_client_, | |
| 476 new_bit_rate)); | |
| 477 } | 377 } |
| 478 | 378 |
| 479 // Inform the encoder to encode the next frame as a key frame. | |
| 480 void ExternalVideoEncoder::GenerateKeyFrame() { | 379 void ExternalVideoEncoder::GenerateKeyFrame() { |
| 481 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 380 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 482 key_frame_requested_ = true; | 381 key_frame_requested_ = true; |
| 483 } | 382 } |
| 484 | 383 |
| 485 // Inform the encoder to only reference frames older or equal to frame_id; | |
| 486 void ExternalVideoEncoder::LatestFrameIdToReference(uint32 /*frame_id*/) { | 384 void ExternalVideoEncoder::LatestFrameIdToReference(uint32 /*frame_id*/) { |
| 487 // Do nothing not supported. | 385 // Do nothing. Not supported. |
| 488 } | 386 } |
| 387 | |
| 388 void ExternalVideoEncoder::OnCreateVideoEncodeAccelerator( | |
| 389 const gfx::Size& frame_size, | |
| 390 VideoCodecProfile codec_profile, | |
| 391 int max_frame_rate, | |
| 392 const CastInitializationCallback& initialization_cb, | |
| 393 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner, | |
| 394 scoped_ptr<media::VideoEncodeAccelerator> vea) { | |
| 395 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
| 396 | |
| 397 if (!encoder_task_runner || !vea) { | |
|
hubbe
2015/01/29 23:29:15
Seems like these should be CHECK/DCHECKs?
(At leas
miu
2015/01/30 00:20:47
The implementation can return nulls when support i
| |
| 398 if (!initialization_cb.is_null()) { | |
| 399 cast_environment_->PostTask( | |
| 400 CastEnvironment::MAIN, | |
| 401 FROM_HERE, | |
| 402 base::Bind(initialization_cb, STATUS_INVALID_VIDEO_CONFIGURATION)); | |
| 403 } | |
| 404 return; | |
| 405 } | |
| 406 | |
| 407 DCHECK(!client_); | |
| 408 client_ = new VEAClientImpl(cast_environment_, | |
| 409 encoder_task_runner, | |
| 410 vea.Pass(), | |
| 411 max_frame_rate, | |
| 412 create_video_encode_memory_cb_); | |
| 413 client_->task_runner()->PostTask(FROM_HERE, | |
| 414 base::Bind(&VEAClientImpl::Initialize, | |
| 415 client_, | |
| 416 frame_size, | |
| 417 codec_profile, | |
| 418 bit_rate_, | |
| 419 initialization_cb)); | |
| 420 } | |
| 421 | |
| 489 } // namespace cast | 422 } // namespace cast |
| 490 } // namespace media | 423 } // namespace media |
| OLD | NEW |