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, |
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_)); | 142 // TODO(miu): Force-flush all |in_progress_frame_encodes_| immediately so |
| 143 // pending frames do not become stuck, freezing VideoSender. |
185 } | 144 } |
186 | 145 |
187 // Called to allocate the input and output buffers. | 146 // Called to allocate the input and output buffers. |
188 void RequireBitstreamBuffers(unsigned int input_count, | 147 void RequireBitstreamBuffers(unsigned int input_count, |
189 const gfx::Size& input_coded_size, | 148 const gfx::Size& input_coded_size, |
190 size_t output_buffer_size) override { | 149 size_t output_buffer_size) override { |
191 DCHECK(encoder_task_runner_.get()); | 150 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
192 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread()); | |
193 DCHECK(video_encode_accelerator_); | |
194 | 151 |
| 152 // TODO(miu): Investigate why we are ignoring |input_count| (4) and instead |
| 153 // using |kOutputBufferCount| (3) here. |
195 for (size_t j = 0; j < kOutputBufferCount; ++j) { | 154 for (size_t j = 0; j < kOutputBufferCount; ++j) { |
196 create_video_encode_memory_cb_.Run( | 155 create_video_encode_memory_cb_.Run( |
197 output_buffer_size, | 156 output_buffer_size, |
198 base::Bind(&LocalVideoEncodeAcceleratorClient::OnCreateSharedMemory, | 157 base::Bind(&VEAClientImpl::OnCreateSharedMemory, this)); |
199 this)); | |
200 } | 158 } |
201 } | 159 } |
202 | 160 |
203 // Encoder has encoded a frame and it's available in one of out output | 161 // Encoder has encoded a frame and it's available in one of the output |
204 // buffers. | 162 // buffers. Package the result in a media::cast::EncodedFrame and post it |
| 163 // to the Cast MAIN thread via the supplied callback. |
205 void BitstreamBufferReady(int32 bitstream_buffer_id, | 164 void BitstreamBufferReady(int32 bitstream_buffer_id, |
206 size_t payload_size, | 165 size_t payload_size, |
207 bool key_frame) override { | 166 bool key_frame) override { |
208 DCHECK(encoder_task_runner_.get()); | 167 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
209 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread()); | |
210 if (bitstream_buffer_id < 0 || | 168 if (bitstream_buffer_id < 0 || |
211 bitstream_buffer_id >= static_cast<int32>(output_buffers_.size())) { | 169 bitstream_buffer_id >= static_cast<int32>(output_buffers_.size())) { |
212 NOTREACHED(); | 170 NOTREACHED(); |
213 VLOG(1) << "BitstreamBufferReady(): invalid bitstream_buffer_id=" | 171 VLOG(1) << "BitstreamBufferReady(): invalid bitstream_buffer_id=" |
214 << bitstream_buffer_id; | 172 << bitstream_buffer_id; |
215 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | 173 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); |
216 return; | 174 return; |
217 } | 175 } |
218 base::SharedMemory* output_buffer = output_buffers_[bitstream_buffer_id]; | 176 base::SharedMemory* output_buffer = output_buffers_[bitstream_buffer_id]; |
219 if (payload_size > output_buffer->mapped_size()) { | 177 if (payload_size > output_buffer->mapped_size()) { |
220 NOTREACHED(); | 178 NOTREACHED(); |
221 VLOG(1) << "BitstreamBufferReady(): invalid payload_size = " | 179 VLOG(1) << "BitstreamBufferReady(): invalid payload_size = " |
222 << payload_size; | 180 << payload_size; |
223 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | 181 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); |
224 return; | 182 return; |
225 } | 183 } |
226 if (key_frame) | 184 if (key_frame) |
227 key_frame_encountered_ = true; | 185 key_frame_encountered_ = true; |
228 if (!key_frame_encountered_) { | 186 if (!key_frame_encountered_) { |
229 // Do not send video until we have encountered the first key frame. | 187 // 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 | 188 // Save the bitstream buffer in |stream_header_| to be sent later along |
231 // with the first key frame. | 189 // with the first key frame. |
| 190 // |
| 191 // TODO(miu): Should |stream_header_| be an std::ostringstream for |
| 192 // performance reasons? |
232 stream_header_.append(static_cast<const char*>(output_buffer->memory()), | 193 stream_header_.append(static_cast<const char*>(output_buffer->memory()), |
233 payload_size); | 194 payload_size); |
234 } else if (!in_progress_frame_encodes_.empty()) { | 195 } else if (!in_progress_frame_encodes_.empty()) { |
235 const InProgressFrameEncode& request = in_progress_frame_encodes_.front(); | 196 const InProgressFrameEncode& request = in_progress_frame_encodes_.front(); |
236 | 197 |
237 scoped_ptr<EncodedFrame> encoded_frame(new EncodedFrame()); | 198 scoped_ptr<EncodedFrame> encoded_frame(new EncodedFrame()); |
238 encoded_frame->dependency = key_frame ? EncodedFrame::KEY : | 199 encoded_frame->dependency = key_frame ? EncodedFrame::KEY : |
239 EncodedFrame::DEPENDENT; | 200 EncodedFrame::DEPENDENT; |
240 encoded_frame->frame_id = ++last_encoded_frame_id_; | 201 encoded_frame->frame_id = ++last_encoded_frame_id_; |
241 if (key_frame) | 202 if (key_frame) |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
273 | 234 |
274 // We need to re-add the output buffer to the encoder after we are done | 235 // We need to re-add the output buffer to the encoder after we are done |
275 // with it. | 236 // with it. |
276 video_encode_accelerator_->UseOutputBitstreamBuffer(media::BitstreamBuffer( | 237 video_encode_accelerator_->UseOutputBitstreamBuffer(media::BitstreamBuffer( |
277 bitstream_buffer_id, | 238 bitstream_buffer_id, |
278 output_buffers_[bitstream_buffer_id]->handle(), | 239 output_buffers_[bitstream_buffer_id]->handle(), |
279 output_buffers_[bitstream_buffer_id]->mapped_size())); | 240 output_buffers_[bitstream_buffer_id]->mapped_size())); |
280 } | 241 } |
281 | 242 |
282 private: | 243 private: |
283 LocalVideoEncodeAcceleratorClient( | 244 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 | 245 |
293 // Trampoline VEA creation callback to OnCreateVideoEncodeAccelerator() | 246 ~VEAClientImpl() override { |
294 // on encoder_task_runner. Normally we would just repost the same method to | 247 // According to the media::VideoEncodeAccelerator interface, Destroy() |
295 // it, and would not need a separate proxy method, but we can't | 248 // should be called instead of invoking its private destructor. |
296 // ThreadTaskRunnerHandle::Get() in unittests just yet. | 249 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, | 250 FROM_HERE, |
302 base::Bind(&media::cast::LocalVideoEncodeAcceleratorClient:: | 251 base::Bind(&media::VideoEncodeAccelerator::Destroy, |
303 OnCreateVideoEncodeAccelerator, | 252 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 } | 253 } |
322 | 254 |
323 // Note: This method can be called on any thread. | 255 // Note: This method can be called on any thread. |
324 void OnCreateSharedMemory(scoped_ptr<base::SharedMemory> memory) { | 256 void OnCreateSharedMemory(scoped_ptr<base::SharedMemory> memory) { |
325 encoder_task_runner_->PostTask( | 257 task_runner_->PostTask(FROM_HERE, |
326 FROM_HERE, | 258 base::Bind(&VEAClientImpl::OnReceivedSharedMemory, |
327 base::Bind(&LocalVideoEncodeAcceleratorClient::ReceivedSharedMemory, | 259 this, |
328 this, | 260 base::Passed(&memory))); |
329 base::Passed(&memory))); | |
330 } | 261 } |
331 | 262 |
332 void ReceivedSharedMemory(scoped_ptr<base::SharedMemory> memory) { | 263 void OnReceivedSharedMemory(scoped_ptr<base::SharedMemory> memory) { |
333 DCHECK(encoder_task_runner_.get()); | 264 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
334 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread()); | |
335 | 265 |
336 output_buffers_.push_back(memory.release()); | 266 output_buffers_.push_back(memory.release()); |
337 | 267 |
338 // Wait until all requested buffers are received. | 268 // Wait until all requested buffers are received. |
339 if (output_buffers_.size() < kOutputBufferCount) | 269 if (output_buffers_.size() < kOutputBufferCount) |
340 return; | 270 return; |
341 | 271 |
342 // Immediately provide all output buffers to the VEA. | 272 // Immediately provide all output buffers to the VEA. |
343 for (size_t i = 0; i < output_buffers_.size(); ++i) { | 273 for (size_t i = 0; i < output_buffers_.size(); ++i) { |
344 video_encode_accelerator_->UseOutputBitstreamBuffer( | 274 video_encode_accelerator_->UseOutputBitstreamBuffer( |
345 media::BitstreamBuffer(static_cast<int32>(i), | 275 media::BitstreamBuffer(static_cast<int32>(i), |
346 output_buffers_[i]->handle(), | 276 output_buffers_[i]->handle(), |
347 output_buffers_[i]->mapped_size())); | 277 output_buffers_[i]->mapped_size())); |
348 } | 278 } |
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 } | 279 } |
368 | 280 |
369 const scoped_refptr<CastEnvironment> cast_environment_; | 281 const scoped_refptr<CastEnvironment> cast_environment_; |
370 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner_; | 282 const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
| 283 const int max_frame_rate_; |
| 284 const CreateVideoEncodeMemoryCallback create_video_encode_memory_cb_; |
371 scoped_ptr<media::VideoEncodeAccelerator> video_encode_accelerator_; | 285 scoped_ptr<media::VideoEncodeAccelerator> video_encode_accelerator_; |
372 const CreateVideoEncodeMemoryCallback create_video_encode_memory_cb_; | 286 bool encoder_active_; |
373 const base::WeakPtr<ExternalVideoEncoder> weak_owner_; | |
374 int max_frame_rate_; | |
375 uint32 last_encoded_frame_id_; | 287 uint32 last_encoded_frame_id_; |
376 bool key_frame_encountered_; | 288 bool key_frame_encountered_; |
377 std::string stream_header_; | 289 std::string stream_header_; |
378 | 290 |
379 // Shared memory buffers for output with the VideoAccelerator. | 291 // Shared memory buffers for output with the VideoAccelerator. |
380 ScopedVector<base::SharedMemory> output_buffers_; | 292 ScopedVector<base::SharedMemory> output_buffers_; |
381 | 293 |
382 // FIFO list. | 294 // FIFO list. |
383 std::list<InProgressFrameEncode> in_progress_frame_encodes_; | 295 std::list<InProgressFrameEncode> in_progress_frame_encodes_; |
384 | 296 |
385 DISALLOW_COPY_AND_ASSIGN(LocalVideoEncodeAcceleratorClient); | 297 DISALLOW_COPY_AND_ASSIGN(VEAClientImpl); |
386 }; | 298 }; |
387 | 299 |
388 ExternalVideoEncoder::ExternalVideoEncoder( | 300 ExternalVideoEncoder::ExternalVideoEncoder( |
389 scoped_refptr<CastEnvironment> cast_environment, | 301 const scoped_refptr<CastEnvironment>& cast_environment, |
390 const VideoSenderConfig& video_config, | 302 const VideoSenderConfig& video_config, |
| 303 const gfx::Size& frame_size, |
391 const CastInitializationCallback& initialization_cb, | 304 const CastInitializationCallback& initialization_cb, |
392 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, | 305 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, |
393 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb) | 306 const CreateVideoEncodeMemoryCallback& create_video_encode_memory_cb) |
394 : video_config_(video_config), | 307 : cast_environment_(cast_environment), |
395 cast_environment_(cast_environment), | 308 create_video_encode_memory_cb_(create_video_encode_memory_cb), |
396 encoder_active_(false), | 309 bit_rate_(video_config.start_bitrate), |
397 key_frame_requested_(false), | 310 key_frame_requested_(false), |
398 initialization_cb_(initialization_cb), | |
399 weak_factory_(this) { | 311 weak_factory_(this) { |
400 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 312 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 313 DCHECK_GT(video_config.max_frame_rate, 0); |
| 314 DCHECK(!frame_size.IsEmpty()); |
| 315 DCHECK(!create_vea_cb.is_null()); |
| 316 DCHECK(!create_video_encode_memory_cb_.is_null()); |
| 317 DCHECK_GT(bit_rate_, 0); |
401 | 318 |
402 video_accelerator_client_ = | 319 VideoCodecProfile codec_profile; |
403 LocalVideoEncodeAcceleratorClient::Create(cast_environment_, | 320 switch (video_config.codec) { |
404 create_vea_cb, | 321 case CODEC_VIDEO_VP8: |
405 create_video_encode_mem_cb, | 322 codec_profile = media::VP8PROFILE_ANY; |
406 weak_factory_.GetWeakPtr()); | 323 break; |
407 DCHECK(video_accelerator_client_.get()); | 324 case CODEC_VIDEO_H264: |
| 325 codec_profile = media::H264PROFILE_MAIN; |
| 326 break; |
| 327 case CODEC_VIDEO_FAKE: |
| 328 NOTREACHED() << "Fake software video encoder cannot be external"; |
| 329 // ...flow through to next case... |
| 330 default: |
| 331 cast_environment_->PostTask( |
| 332 CastEnvironment::MAIN, |
| 333 FROM_HERE, |
| 334 base::Bind(initialization_cb, STATUS_HW_VIDEO_ENCODER_NOT_SUPPORTED)); |
| 335 return; |
| 336 } |
| 337 |
| 338 create_vea_cb.Run( |
| 339 base::Bind(&ExternalVideoEncoder::OnCreateVideoEncodeAccelerator, |
| 340 weak_factory_.GetWeakPtr(), |
| 341 frame_size, |
| 342 codec_profile, |
| 343 video_config.max_frame_rate, |
| 344 initialization_cb)); |
408 } | 345 } |
409 | 346 |
410 ExternalVideoEncoder::~ExternalVideoEncoder() { | 347 ExternalVideoEncoder::~ExternalVideoEncoder() { |
411 } | 348 } |
412 | 349 |
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( | 350 bool ExternalVideoEncoder::EncodeVideoFrame( |
441 const scoped_refptr<media::VideoFrame>& video_frame, | 351 const scoped_refptr<media::VideoFrame>& video_frame, |
442 const base::TimeTicks& reference_time, | 352 const base::TimeTicks& reference_time, |
443 const FrameEncodedCallback& frame_encoded_callback) { | 353 const FrameEncodedCallback& frame_encoded_callback) { |
444 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 354 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 355 DCHECK(!video_frame->visible_rect().IsEmpty()); |
| 356 DCHECK(!frame_encoded_callback.is_null()); |
445 | 357 |
446 if (!encoder_active_) | 358 if (!client_) |
447 return false; | 359 return false; // Not ready. |
448 | 360 |
449 encoder_task_runner_->PostTask( | 361 client_->task_runner()->PostTask(FROM_HERE, |
450 FROM_HERE, | 362 base::Bind(&VEAClientImpl::EncodeVideoFrame, |
451 base::Bind(&LocalVideoEncodeAcceleratorClient::EncodeVideoFrame, | 363 client_, |
452 video_accelerator_client_, | 364 video_frame, |
453 video_frame, | 365 reference_time, |
454 reference_time, | 366 key_frame_requested_, |
455 key_frame_requested_, | 367 frame_encoded_callback)); |
456 frame_encoded_callback)); | |
457 | |
458 key_frame_requested_ = false; | 368 key_frame_requested_ = false; |
459 return true; | 369 return true; |
460 } | 370 } |
461 | 371 |
462 // Inform the encoder about the new target bit rate. | |
463 void ExternalVideoEncoder::SetBitRate(int new_bit_rate) { | 372 void ExternalVideoEncoder::SetBitRate(int new_bit_rate) { |
464 if (!encoder_active_) { | 373 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
465 // If we receive SetBitRate() before VEA creation callback is invoked, | 374 DCHECK_GT(new_bit_rate, 0); |
466 // cache the new bit rate in the encoder config and use the new settings | 375 |
467 // to initialize VEA. | 376 bit_rate_ = new_bit_rate; |
468 video_config_.start_bitrate = new_bit_rate; | 377 if (!client_) |
469 return; | 378 return; |
470 } | 379 client_->task_runner()->PostTask( |
471 | 380 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 } | 381 } |
478 | 382 |
479 // Inform the encoder to encode the next frame as a key frame. | |
480 void ExternalVideoEncoder::GenerateKeyFrame() { | 383 void ExternalVideoEncoder::GenerateKeyFrame() { |
481 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 384 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
482 key_frame_requested_ = true; | 385 key_frame_requested_ = true; |
483 } | 386 } |
484 | 387 |
485 // Inform the encoder to only reference frames older or equal to frame_id; | |
486 void ExternalVideoEncoder::LatestFrameIdToReference(uint32 /*frame_id*/) { | 388 void ExternalVideoEncoder::LatestFrameIdToReference(uint32 /*frame_id*/) { |
487 // Do nothing not supported. | 389 // Do nothing. Not supported. |
488 } | 390 } |
| 391 |
| 392 void ExternalVideoEncoder::OnCreateVideoEncodeAccelerator( |
| 393 const gfx::Size& frame_size, |
| 394 VideoCodecProfile codec_profile, |
| 395 int max_frame_rate, |
| 396 const CastInitializationCallback& initialization_cb, |
| 397 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner, |
| 398 scoped_ptr<media::VideoEncodeAccelerator> vea) { |
| 399 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 400 |
| 401 // The callback will be invoked with null pointers in the case where the |
| 402 // system does not support or lacks the resources to provide GPU-accelerated |
| 403 // video encoding. |
| 404 if (!encoder_task_runner || !vea) { |
| 405 if (!initialization_cb.is_null()) { |
| 406 cast_environment_->PostTask( |
| 407 CastEnvironment::MAIN, |
| 408 FROM_HERE, |
| 409 base::Bind(initialization_cb, STATUS_INVALID_VIDEO_CONFIGURATION)); |
| 410 } |
| 411 return; |
| 412 } |
| 413 |
| 414 DCHECK(!client_); |
| 415 client_ = new VEAClientImpl(cast_environment_, |
| 416 encoder_task_runner, |
| 417 vea.Pass(), |
| 418 max_frame_rate, |
| 419 create_video_encode_memory_cb_); |
| 420 client_->task_runner()->PostTask(FROM_HERE, |
| 421 base::Bind(&VEAClientImpl::Initialize, |
| 422 client_, |
| 423 frame_size, |
| 424 codec_profile, |
| 425 bit_rate_, |
| 426 initialization_cb)); |
| 427 } |
| 428 |
489 } // namespace cast | 429 } // namespace cast |
490 } // namespace media | 430 } // namespace media |
OLD | NEW |