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/h264_vt_encoder.h" | 5 #include "media/cast/sender/h264_vt_encoder.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <string> | 9 #include <string> |
10 #include <vector> | 10 #include <vector> |
11 | 11 |
12 #include "base/big_endian.h" | 12 #include "base/big_endian.h" |
13 #include "base/bind.h" | 13 #include "base/bind.h" |
14 #include "base/bind_helpers.h" | 14 #include "base/bind_helpers.h" |
15 #include "base/location.h" | 15 #include "base/location.h" |
16 #include "base/logging.h" | 16 #include "base/logging.h" |
17 #include "base/macros.h" | 17 #include "base/macros.h" |
18 #include "base/power_monitor/power_monitor.h" | 18 #include "base/power_monitor/power_monitor.h" |
19 #include "base/synchronization/lock.h" | 19 #include "base/synchronization/lock.h" |
20 #include "build/build_config.h" | 20 #include "build/build_config.h" |
21 #include "media/base/mac/corevideo_glue.h" | |
22 #include "media/base/mac/video_frame_mac.h" | 21 #include "media/base/mac/video_frame_mac.h" |
23 #include "media/cast/common/rtp_time.h" | 22 #include "media/cast/common/rtp_time.h" |
24 #include "media/cast/constants.h" | 23 #include "media/cast/constants.h" |
25 #include "media/cast/sender/video_frame_factory.h" | 24 #include "media/cast/sender/video_frame_factory.h" |
26 | 25 |
27 namespace media { | 26 namespace media { |
28 namespace cast { | 27 namespace cast { |
29 | 28 |
30 namespace { | 29 namespace { |
31 | 30 |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
141 ~Proxy() final {} | 140 ~Proxy() final {} |
142 | 141 |
143 const scoped_refptr<VideoFrameFactoryImpl> video_frame_factory_; | 142 const scoped_refptr<VideoFrameFactoryImpl> video_frame_factory_; |
144 | 143 |
145 DISALLOW_COPY_AND_ASSIGN(Proxy); | 144 DISALLOW_COPY_AND_ASSIGN(Proxy); |
146 }; | 145 }; |
147 | 146 |
148 // static | 147 // static |
149 bool H264VideoToolboxEncoder::IsSupported( | 148 bool H264VideoToolboxEncoder::IsSupported( |
150 const FrameSenderConfig& video_config) { | 149 const FrameSenderConfig& video_config) { |
151 return video_config.codec == CODEC_VIDEO_H264 && VideoToolboxGlue::Get(); | 150 return video_config.codec == CODEC_VIDEO_H264; |
152 } | 151 } |
153 | 152 |
154 H264VideoToolboxEncoder::H264VideoToolboxEncoder( | 153 H264VideoToolboxEncoder::H264VideoToolboxEncoder( |
155 const scoped_refptr<CastEnvironment>& cast_environment, | 154 const scoped_refptr<CastEnvironment>& cast_environment, |
156 const FrameSenderConfig& video_config, | 155 const FrameSenderConfig& video_config, |
157 const StatusChangeCallback& status_change_cb) | 156 const StatusChangeCallback& status_change_cb) |
158 : cast_environment_(cast_environment), | 157 : cast_environment_(cast_environment), |
159 videotoolbox_glue_(VideoToolboxGlue::Get()), | |
160 video_config_(video_config), | 158 video_config_(video_config), |
161 status_change_cb_(status_change_cb), | 159 status_change_cb_(status_change_cb), |
162 next_frame_id_(FrameId::first()), | 160 next_frame_id_(FrameId::first()), |
163 encode_next_frame_as_keyframe_(false), | 161 encode_next_frame_as_keyframe_(false), |
164 power_suspended_(false), | 162 power_suspended_(false), |
165 weak_factory_(this) { | 163 weak_factory_(this) { |
166 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 164 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
167 DCHECK(!status_change_cb_.is_null()); | 165 DCHECK(!status_change_cb_.is_null()); |
168 | 166 |
169 OperationalStatus operational_status = | 167 OperationalStatus operational_status = |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
219 base::Bind(status_change_cb_, STATUS_CODEC_REINIT_PENDING)); | 217 base::Bind(status_change_cb_, STATUS_CODEC_REINIT_PENDING)); |
220 | 218 |
221 // Destroy the current session, if any. | 219 // Destroy the current session, if any. |
222 DestroyCompressionSession(); | 220 DestroyCompressionSession(); |
223 | 221 |
224 // On OS X, allow the hardware encoder. Don't require it, it does not support | 222 // On OS X, allow the hardware encoder. Don't require it, it does not support |
225 // all configurations (some of which are used for testing). | 223 // all configurations (some of which are used for testing). |
226 base::ScopedCFTypeRef<CFDictionaryRef> encoder_spec; | 224 base::ScopedCFTypeRef<CFDictionaryRef> encoder_spec; |
227 #if !defined(OS_IOS) | 225 #if !defined(OS_IOS) |
228 encoder_spec = video_toolbox::DictionaryWithKeyValue( | 226 encoder_spec = video_toolbox::DictionaryWithKeyValue( |
229 videotoolbox_glue_ | 227 kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder, |
230 ->kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder()
, | |
231 kCFBooleanTrue); | 228 kCFBooleanTrue); |
232 #endif | 229 #endif |
233 | 230 |
234 // Force 420v so that clients can easily use these buffers as GPU textures. | 231 // Force 420v so that clients can easily use these buffers as GPU textures. |
235 const int format[] = { | 232 const int format[] = {kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange}; |
236 CoreVideoGlue::kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange}; | |
237 | 233 |
238 // Keep these attachment settings in-sync with those in ConfigureSession(). | 234 // Keep these attachment settings in-sync with those in ConfigureSession(). |
239 CFTypeRef attachments_keys[] = {kCVImageBufferColorPrimariesKey, | 235 CFTypeRef attachments_keys[] = {kCVImageBufferColorPrimariesKey, |
240 kCVImageBufferTransferFunctionKey, | 236 kCVImageBufferTransferFunctionKey, |
241 kCVImageBufferYCbCrMatrixKey}; | 237 kCVImageBufferYCbCrMatrixKey}; |
242 CFTypeRef attachments_values[] = {kCVImageBufferColorPrimaries_ITU_R_709_2, | 238 CFTypeRef attachments_values[] = {kCVImageBufferColorPrimaries_ITU_R_709_2, |
243 kCVImageBufferTransferFunction_ITU_R_709_2, | 239 kCVImageBufferTransferFunction_ITU_R_709_2, |
244 kCVImageBufferYCbCrMatrix_ITU_R_709_2}; | 240 kCVImageBufferYCbCrMatrix_ITU_R_709_2}; |
245 CFTypeRef buffer_attributes_keys[] = {kCVPixelBufferPixelFormatTypeKey, | 241 CFTypeRef buffer_attributes_keys[] = {kCVPixelBufferPixelFormatTypeKey, |
246 kCVBufferPropagatedAttachmentsKey}; | 242 kCVBufferPropagatedAttachmentsKey}; |
(...skipping 12 matching lines...) Expand all Loading... |
259 // Create the compression session. | 255 // Create the compression session. |
260 | 256 |
261 // Note that the encoder object is given to the compression session as the | 257 // Note that the encoder object is given to the compression session as the |
262 // callback context using a raw pointer. The C API does not allow us to use a | 258 // callback context using a raw pointer. The C API does not allow us to use a |
263 // smart pointer, nor is this encoder ref counted. However, this is still | 259 // smart pointer, nor is this encoder ref counted. However, this is still |
264 // safe, because we 1) we own the compression session and 2) we tear it down | 260 // safe, because we 1) we own the compression session and 2) we tear it down |
265 // safely. When destructing the encoder, the compression session is flushed | 261 // safely. When destructing the encoder, the compression session is flushed |
266 // and invalidated. Internally, VideoToolbox will join all of its threads | 262 // and invalidated. Internally, VideoToolbox will join all of its threads |
267 // before returning to the client. Therefore, when control returns to us, we | 263 // before returning to the client. Therefore, when control returns to us, we |
268 // are guaranteed that the output callback will not execute again. | 264 // are guaranteed that the output callback will not execute again. |
269 OSStatus status = videotoolbox_glue_->VTCompressionSessionCreate( | 265 OSStatus status = VTCompressionSessionCreate( |
270 kCFAllocatorDefault, frame_size_.width(), frame_size_.height(), | 266 kCFAllocatorDefault, frame_size_.width(), frame_size_.height(), |
271 CoreMediaGlue::kCMVideoCodecType_H264, encoder_spec, buffer_attributes, | 267 kCMVideoCodecType_H264, encoder_spec, buffer_attributes, |
272 nullptr /* compressedDataAllocator */, | 268 nullptr /* compressedDataAllocator */, |
273 &H264VideoToolboxEncoder::CompressionCallback, | 269 &H264VideoToolboxEncoder::CompressionCallback, |
274 reinterpret_cast<void*>(this), compression_session_.InitializeInto()); | 270 reinterpret_cast<void*>(this), compression_session_.InitializeInto()); |
275 if (status != noErr) { | 271 if (status != noErr) { |
276 DLOG(ERROR) << " VTCompressionSessionCreate failed: " << status; | 272 DLOG(ERROR) << " VTCompressionSessionCreate failed: " << status; |
277 // Notify that reinitialization has failed. | 273 // Notify that reinitialization has failed. |
278 cast_environment_->PostTask( | 274 cast_environment_->PostTask( |
279 CastEnvironment::MAIN, FROM_HERE, | 275 CastEnvironment::MAIN, FROM_HERE, |
280 base::Bind(status_change_cb_, STATUS_CODEC_INIT_FAILED)); | 276 base::Bind(status_change_cb_, STATUS_CODEC_INIT_FAILED)); |
281 return; | 277 return; |
282 } | 278 } |
283 | 279 |
284 // Configure the session (apply session properties based on the current state | 280 // Configure the session (apply session properties based on the current state |
285 // of the encoder, experimental tuning and requirements). | 281 // of the encoder, experimental tuning and requirements). |
286 ConfigureCompressionSession(); | 282 ConfigureCompressionSession(); |
287 | 283 |
288 // Update the video frame factory. | 284 // Update the video frame factory. |
289 base::ScopedCFTypeRef<CVPixelBufferPoolRef> pool( | 285 base::ScopedCFTypeRef<CVPixelBufferPoolRef> pool( |
290 videotoolbox_glue_->VTCompressionSessionGetPixelBufferPool( | 286 VTCompressionSessionGetPixelBufferPool(compression_session_), |
291 compression_session_), | |
292 base::scoped_policy::RETAIN); | 287 base::scoped_policy::RETAIN); |
293 video_frame_factory_->Update(pool, frame_size_); | 288 video_frame_factory_->Update(pool, frame_size_); |
294 | 289 |
295 // Notify that reinitialization is done. | 290 // Notify that reinitialization is done. |
296 cast_environment_->PostTask( | 291 cast_environment_->PostTask( |
297 CastEnvironment::MAIN, FROM_HERE, | 292 CastEnvironment::MAIN, FROM_HERE, |
298 base::Bind(status_change_cb_, STATUS_INITIALIZED)); | 293 base::Bind(status_change_cb_, STATUS_INITIALIZED)); |
299 } | 294 } |
300 | 295 |
301 void H264VideoToolboxEncoder::ConfigureCompressionSession() { | 296 void H264VideoToolboxEncoder::ConfigureCompressionSession() { |
302 video_toolbox::SessionPropertySetter session_property_setter( | 297 video_toolbox::SessionPropertySetter session_property_setter( |
303 compression_session_, videotoolbox_glue_); | 298 compression_session_); |
| 299 session_property_setter.Set(kVTCompressionPropertyKey_ProfileLevel, |
| 300 kVTProfileLevel_H264_Main_AutoLevel); |
| 301 session_property_setter.Set(kVTCompressionPropertyKey_RealTime, true); |
| 302 session_property_setter.Set(kVTCompressionPropertyKey_AllowFrameReordering, |
| 303 false); |
| 304 session_property_setter.Set(kVTCompressionPropertyKey_MaxKeyFrameInterval, |
| 305 240); |
304 session_property_setter.Set( | 306 session_property_setter.Set( |
305 videotoolbox_glue_->kVTCompressionPropertyKey_ProfileLevel(), | 307 kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration, 240); |
306 videotoolbox_glue_->kVTProfileLevel_H264_Main_AutoLevel()); | |
307 session_property_setter.Set( | |
308 videotoolbox_glue_->kVTCompressionPropertyKey_RealTime(), true); | |
309 session_property_setter.Set( | |
310 videotoolbox_glue_->kVTCompressionPropertyKey_AllowFrameReordering(), | |
311 false); | |
312 session_property_setter.Set( | |
313 videotoolbox_glue_->kVTCompressionPropertyKey_MaxKeyFrameInterval(), 240); | |
314 session_property_setter.Set( | |
315 videotoolbox_glue_ | |
316 ->kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration(), | |
317 240); | |
318 // TODO(jfroy): implement better bitrate control | 308 // TODO(jfroy): implement better bitrate control |
319 // https://crbug.com/425352 | 309 // https://crbug.com/425352 |
320 session_property_setter.Set( | 310 session_property_setter.Set( |
321 videotoolbox_glue_->kVTCompressionPropertyKey_AverageBitRate(), | 311 kVTCompressionPropertyKey_AverageBitRate, |
322 (video_config_.min_bitrate + video_config_.max_bitrate) / 2); | 312 (video_config_.min_bitrate + video_config_.max_bitrate) / 2); |
323 session_property_setter.Set( | 313 session_property_setter.Set( |
324 videotoolbox_glue_->kVTCompressionPropertyKey_ExpectedFrameRate(), | 314 kVTCompressionPropertyKey_ExpectedFrameRate, |
325 static_cast<int>(video_config_.max_frame_rate + 0.5)); | 315 static_cast<int>(video_config_.max_frame_rate + 0.5)); |
326 // Keep these attachment settings in-sync with those in Initialize(). | 316 // Keep these attachment settings in-sync with those in Initialize(). |
327 session_property_setter.Set( | 317 session_property_setter.Set(kVTCompressionPropertyKey_ColorPrimaries, |
328 videotoolbox_glue_->kVTCompressionPropertyKey_ColorPrimaries(), | 318 kCVImageBufferColorPrimaries_ITU_R_709_2); |
329 kCVImageBufferColorPrimaries_ITU_R_709_2); | 319 session_property_setter.Set(kVTCompressionPropertyKey_TransferFunction, |
330 session_property_setter.Set( | 320 kCVImageBufferTransferFunction_ITU_R_709_2); |
331 videotoolbox_glue_->kVTCompressionPropertyKey_TransferFunction(), | 321 session_property_setter.Set(kVTCompressionPropertyKey_YCbCrMatrix, |
332 kCVImageBufferTransferFunction_ITU_R_709_2); | 322 kCVImageBufferYCbCrMatrix_ITU_R_709_2); |
333 session_property_setter.Set( | |
334 videotoolbox_glue_->kVTCompressionPropertyKey_YCbCrMatrix(), | |
335 kCVImageBufferYCbCrMatrix_ITU_R_709_2); | |
336 if (video_config_.video_codec_params.max_number_of_video_buffers_used > 0) { | 323 if (video_config_.video_codec_params.max_number_of_video_buffers_used > 0) { |
337 session_property_setter.Set( | 324 session_property_setter.Set( |
338 videotoolbox_glue_->kVTCompressionPropertyKey_MaxFrameDelayCount(), | 325 kVTCompressionPropertyKey_MaxFrameDelayCount, |
339 video_config_.video_codec_params.max_number_of_video_buffers_used); | 326 video_config_.video_codec_params.max_number_of_video_buffers_used); |
340 } | 327 } |
341 } | 328 } |
342 | 329 |
343 void H264VideoToolboxEncoder::DestroyCompressionSession() { | 330 void H264VideoToolboxEncoder::DestroyCompressionSession() { |
344 DCHECK(thread_checker_.CalledOnValidThread()); | 331 DCHECK(thread_checker_.CalledOnValidThread()); |
345 | 332 |
346 // If the compression session exists, invalidate it. This blocks until all | 333 // If the compression session exists, invalidate it. This blocks until all |
347 // pending output callbacks have returned and any internal threads have | 334 // pending output callbacks have returned and any internal threads have |
348 // joined, ensuring no output callback ever sees a dangling encoder pointer. | 335 // joined, ensuring no output callback ever sees a dangling encoder pointer. |
349 // | 336 // |
350 // Before destroying the compression session, the video frame factory's pool | 337 // Before destroying the compression session, the video frame factory's pool |
351 // is updated to null so that no thread will produce new video frames via the | 338 // is updated to null so that no thread will produce new video frames via the |
352 // factory until a new compression session is created. The current frame size | 339 // factory until a new compression session is created. The current frame size |
353 // is passed to prevent the video frame factory from posting |UpdateFrameSize| | 340 // is passed to prevent the video frame factory from posting |UpdateFrameSize| |
354 // tasks. Indeed, |DestroyCompressionSession| is either called from | 341 // tasks. Indeed, |DestroyCompressionSession| is either called from |
355 // |ResetCompressionSession|, in which case a new pool and frame size will be | 342 // |ResetCompressionSession|, in which case a new pool and frame size will be |
356 // set, or from callsites that require that there be no compression session | 343 // set, or from callsites that require that there be no compression session |
357 // (ex: the dtor). | 344 // (ex: the dtor). |
358 if (compression_session_) { | 345 if (compression_session_) { |
359 video_frame_factory_->Update( | 346 video_frame_factory_->Update( |
360 base::ScopedCFTypeRef<CVPixelBufferPoolRef>(nullptr), frame_size_); | 347 base::ScopedCFTypeRef<CVPixelBufferPoolRef>(nullptr), frame_size_); |
361 videotoolbox_glue_->VTCompressionSessionInvalidate(compression_session_); | 348 VTCompressionSessionInvalidate(compression_session_); |
362 compression_session_.reset(); | 349 compression_session_.reset(); |
363 } | 350 } |
364 } | 351 } |
365 | 352 |
366 bool H264VideoToolboxEncoder::EncodeVideoFrame( | 353 bool H264VideoToolboxEncoder::EncodeVideoFrame( |
367 const scoped_refptr<media::VideoFrame>& video_frame, | 354 const scoped_refptr<media::VideoFrame>& video_frame, |
368 const base::TimeTicks& reference_time, | 355 const base::TimeTicks& reference_time, |
369 const FrameEncodedCallback& frame_encoded_callback) { | 356 const FrameEncodedCallback& frame_encoded_callback) { |
370 DCHECK(thread_checker_.CalledOnValidThread()); | 357 DCHECK(thread_checker_.CalledOnValidThread()); |
371 DCHECK(!frame_encoded_callback.is_null()); | 358 DCHECK(!frame_encoded_callback.is_null()); |
(...skipping 23 matching lines...) Expand all Loading... |
395 // compression session's pixel buffer pool. This will eliminate a copy of the | 382 // compression session's pixel buffer pool. This will eliminate a copy of the |
396 // frame into memory visible by the hardware encoder. The VideoFrame's | 383 // frame into memory visible by the hardware encoder. The VideoFrame's |
397 // lifetime is extended for the lifetime of the returned CVPixelBuffer. | 384 // lifetime is extended for the lifetime of the returned CVPixelBuffer. |
398 auto pixel_buffer = media::WrapVideoFrameInCVPixelBuffer(*video_frame); | 385 auto pixel_buffer = media::WrapVideoFrameInCVPixelBuffer(*video_frame); |
399 if (!pixel_buffer) { | 386 if (!pixel_buffer) { |
400 DLOG(ERROR) << "WrapVideoFrameInCVPixelBuffer failed."; | 387 DLOG(ERROR) << "WrapVideoFrameInCVPixelBuffer failed."; |
401 return false; | 388 return false; |
402 } | 389 } |
403 | 390 |
404 // Convert the frame timestamp to CMTime. | 391 // Convert the frame timestamp to CMTime. |
405 auto timestamp_cm = CoreMediaGlue::CMTimeMake( | 392 auto timestamp_cm = |
406 video_frame->timestamp().InMicroseconds(), USEC_PER_SEC); | 393 CMTimeMake(video_frame->timestamp().InMicroseconds(), USEC_PER_SEC); |
407 | 394 |
408 // Wrap information we'll need after the frame is encoded in a heap object. | 395 // Wrap information we'll need after the frame is encoded in a heap object. |
409 // We'll get the pointer back from the VideoToolbox completion callback. | 396 // We'll get the pointer back from the VideoToolbox completion callback. |
410 std::unique_ptr<InProgressFrameEncode> request(new InProgressFrameEncode( | 397 std::unique_ptr<InProgressFrameEncode> request(new InProgressFrameEncode( |
411 RtpTimeTicks::FromTimeDelta(video_frame->timestamp(), kVideoFrequency), | 398 RtpTimeTicks::FromTimeDelta(video_frame->timestamp(), kVideoFrequency), |
412 reference_time, frame_encoded_callback)); | 399 reference_time, frame_encoded_callback)); |
413 | 400 |
414 // Build a suitable frame properties dictionary for keyframes. | 401 // Build a suitable frame properties dictionary for keyframes. |
415 base::ScopedCFTypeRef<CFDictionaryRef> frame_props; | 402 base::ScopedCFTypeRef<CFDictionaryRef> frame_props; |
416 if (encode_next_frame_as_keyframe_) { | 403 if (encode_next_frame_as_keyframe_) { |
417 frame_props = video_toolbox::DictionaryWithKeyValue( | 404 frame_props = video_toolbox::DictionaryWithKeyValue( |
418 videotoolbox_glue_->kVTEncodeFrameOptionKey_ForceKeyFrame(), | 405 kVTEncodeFrameOptionKey_ForceKeyFrame, kCFBooleanTrue); |
419 kCFBooleanTrue); | |
420 encode_next_frame_as_keyframe_ = false; | 406 encode_next_frame_as_keyframe_ = false; |
421 } | 407 } |
422 | 408 |
423 // Submit the frame to the compression session. The function returns as soon | 409 // Submit the frame to the compression session. The function returns as soon |
424 // as the frame has been enqueued. | 410 // as the frame has been enqueued. |
425 OSStatus status = videotoolbox_glue_->VTCompressionSessionEncodeFrame( | 411 OSStatus status = VTCompressionSessionEncodeFrame( |
426 compression_session_, pixel_buffer, timestamp_cm, | 412 compression_session_, pixel_buffer, timestamp_cm, CMTime{0, 0, 0, 0}, |
427 CoreMediaGlue::CMTime{0, 0, 0, 0}, frame_props, | 413 frame_props, reinterpret_cast<void*>(request.release()), nullptr); |
428 reinterpret_cast<void*>(request.release()), nullptr); | |
429 if (status != noErr) { | 414 if (status != noErr) { |
430 DLOG(ERROR) << " VTCompressionSessionEncodeFrame failed: " << status; | 415 DLOG(ERROR) << " VTCompressionSessionEncodeFrame failed: " << status; |
431 return false; | 416 return false; |
432 } | 417 } |
433 | 418 |
434 return true; | 419 return true; |
435 } | 420 } |
436 | 421 |
437 void H264VideoToolboxEncoder::UpdateFrameSize(const gfx::Size& size_needed) { | 422 void H264VideoToolboxEncoder::UpdateFrameSize(const gfx::Size& size_needed) { |
438 DCHECK(thread_checker_.CalledOnValidThread()); | 423 DCHECK(thread_checker_.CalledOnValidThread()); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
475 DCHECK(thread_checker_.CalledOnValidThread()); | 460 DCHECK(thread_checker_.CalledOnValidThread()); |
476 return std::unique_ptr<VideoFrameFactory>( | 461 return std::unique_ptr<VideoFrameFactory>( |
477 new VideoFrameFactoryImpl::Proxy(video_frame_factory_)); | 462 new VideoFrameFactoryImpl::Proxy(video_frame_factory_)); |
478 } | 463 } |
479 | 464 |
480 void H264VideoToolboxEncoder::EmitFrames() { | 465 void H264VideoToolboxEncoder::EmitFrames() { |
481 DCHECK(thread_checker_.CalledOnValidThread()); | 466 DCHECK(thread_checker_.CalledOnValidThread()); |
482 if (!compression_session_) | 467 if (!compression_session_) |
483 return; | 468 return; |
484 | 469 |
485 OSStatus status = videotoolbox_glue_->VTCompressionSessionCompleteFrames( | 470 OSStatus status = VTCompressionSessionCompleteFrames(compression_session_, |
486 compression_session_, CoreMediaGlue::CMTime{0, 0, 0, 0}); | 471 CMTime{0, 0, 0, 0}); |
487 if (status != noErr) { | 472 if (status != noErr) { |
488 DLOG(ERROR) << " VTCompressionSessionCompleteFrames failed: " << status; | 473 DLOG(ERROR) << " VTCompressionSessionCompleteFrames failed: " << status; |
489 } | 474 } |
490 } | 475 } |
491 | 476 |
492 void H264VideoToolboxEncoder::OnSuspend() { | 477 void H264VideoToolboxEncoder::OnSuspend() { |
493 VLOG(1) | 478 VLOG(1) |
494 << "OnSuspend: Emitting all frames and destroying compression session."; | 479 << "OnSuspend: Emitting all frames and destroying compression session."; |
495 EmitFrames(); | 480 EmitFrames(); |
496 DestroyCompressionSession(); | 481 DestroyCompressionSession(); |
(...skipping 22 matching lines...) Expand all Loading... |
519 const std::unique_ptr<InProgressFrameEncode> request( | 504 const std::unique_ptr<InProgressFrameEncode> request( |
520 reinterpret_cast<InProgressFrameEncode*>(request_opaque)); | 505 reinterpret_cast<InProgressFrameEncode*>(request_opaque)); |
521 bool keyframe = false; | 506 bool keyframe = false; |
522 bool has_frame_data = false; | 507 bool has_frame_data = false; |
523 | 508 |
524 if (status != noErr) { | 509 if (status != noErr) { |
525 DLOG(ERROR) << " encoding failed: " << status; | 510 DLOG(ERROR) << " encoding failed: " << status; |
526 encoder->cast_environment_->PostTask( | 511 encoder->cast_environment_->PostTask( |
527 CastEnvironment::MAIN, FROM_HERE, | 512 CastEnvironment::MAIN, FROM_HERE, |
528 base::Bind(encoder->status_change_cb_, STATUS_CODEC_RUNTIME_ERROR)); | 513 base::Bind(encoder->status_change_cb_, STATUS_CODEC_RUNTIME_ERROR)); |
529 } else if ((info & VideoToolboxGlue::kVTEncodeInfo_FrameDropped)) { | 514 } else if ((info & kVTEncodeInfo_FrameDropped)) { |
530 DVLOG(2) << " frame dropped"; | 515 DVLOG(2) << " frame dropped"; |
531 } else { | 516 } else { |
532 auto* sample_attachments = | 517 auto* sample_attachments = |
533 static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex( | 518 static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex( |
534 CoreMediaGlue::CMSampleBufferGetSampleAttachmentsArray(sbuf, true), | 519 CMSampleBufferGetSampleAttachmentsArray(sbuf, true), 0)); |
535 0)); | |
536 | 520 |
537 // If the NotSync key is not present, it implies Sync, which indicates a | 521 // If the NotSync key is not present, it implies Sync, which indicates a |
538 // keyframe (at least I think, VT documentation is, erm, sparse). Could | 522 // keyframe (at least I think, VT documentation is, erm, sparse). Could |
539 // alternatively use kCMSampleAttachmentKey_DependsOnOthers == false. | 523 // alternatively use kCMSampleAttachmentKey_DependsOnOthers == false. |
540 keyframe = !CFDictionaryContainsKey( | 524 keyframe = !CFDictionaryContainsKey(sample_attachments, |
541 sample_attachments, | 525 kCMSampleAttachmentKey_NotSync); |
542 CoreMediaGlue::kCMSampleAttachmentKey_NotSync()); | |
543 has_frame_data = true; | 526 has_frame_data = true; |
544 } | 527 } |
545 | 528 |
546 // Grab the next frame ID and increment |next_frame_id_| for next time. | 529 // Grab the next frame ID and increment |next_frame_id_| for next time. |
547 // VideoToolbox calls the output callback serially, so this is safe. | 530 // VideoToolbox calls the output callback serially, so this is safe. |
548 const FrameId frame_id = encoder->next_frame_id_++; | 531 const FrameId frame_id = encoder->next_frame_id_++; |
549 | 532 |
550 std::unique_ptr<SenderEncodedFrame> encoded_frame(new SenderEncodedFrame()); | 533 std::unique_ptr<SenderEncodedFrame> encoded_frame(new SenderEncodedFrame()); |
551 encoded_frame->frame_id = frame_id; | 534 encoded_frame->frame_id = frame_id; |
552 encoded_frame->reference_time = request->reference_time; | 535 encoded_frame->reference_time = request->reference_time; |
(...skipping 26 matching lines...) Expand all Loading... |
579 encoded_frame->encode_completion_time = | 562 encoded_frame->encode_completion_time = |
580 encoder->cast_environment_->Clock()->NowTicks(); | 563 encoder->cast_environment_->Clock()->NowTicks(); |
581 encoder->cast_environment_->PostTask( | 564 encoder->cast_environment_->PostTask( |
582 CastEnvironment::MAIN, FROM_HERE, | 565 CastEnvironment::MAIN, FROM_HERE, |
583 base::Bind(request->frame_encoded_callback, | 566 base::Bind(request->frame_encoded_callback, |
584 base::Passed(&encoded_frame))); | 567 base::Passed(&encoded_frame))); |
585 } | 568 } |
586 | 569 |
587 } // namespace cast | 570 } // namespace cast |
588 } // namespace media | 571 } // namespace media |
OLD | NEW |