 Chromium Code Reviews
 Chromium Code Reviews Issue 723993003:
  Sandbox initialization for VideoToolbox.  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@vt_queue_frames
    
  
    Issue 723993003:
  Sandbox initialization for VideoToolbox.  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@vt_queue_frames| Index: content/common/gpu/media/vt_video_decode_accelerator.cc | 
| diff --git a/content/common/gpu/media/vt_video_decode_accelerator.cc b/content/common/gpu/media/vt_video_decode_accelerator.cc | 
| index 9a8dcc5b9abfe88d4a600634fbe31a3c8020a849..2df95905e5b7a0353659fa34b0afc79add55b608 100644 | 
| --- a/content/common/gpu/media/vt_video_decode_accelerator.cc | 
| +++ b/content/common/gpu/media/vt_video_decode_accelerator.cc | 
| @@ -38,6 +38,112 @@ static const int kNALUHeaderLength = 4; | 
| // requirements are low, as we don't need the textures to be backed by storage. | 
| static const int kNumPictureBuffers = media::limits::kMaxVideoFrames + 1; | 
| +// Build an |image_config| dictionary for VideoToolbox initialization. | 
| +static CFMutableDictionaryRef BuildImageConfig( | 
| + CMVideoDimensions coded_dimensions) { | 
| + // TODO(sandersd): RGBA option for 4:4:4 video. | 
| + int32_t pixel_format = kCVPixelFormatType_422YpCbCr8; | 
| + | 
| +#define CFINT(i) CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i) | 
| + base::ScopedCFTypeRef<CFNumberRef> cf_pixel_format(CFINT(pixel_format)); | 
| + base::ScopedCFTypeRef<CFNumberRef> cf_width(CFINT(coded_dimensions.width)); | 
| + base::ScopedCFTypeRef<CFNumberRef> cf_height(CFINT(coded_dimensions.height)); | 
| +#undef CFINT | 
| + | 
| + CFMutableDictionaryRef image_config = CFDictionaryCreateMutable( | 
| + kCFAllocatorDefault, | 
| + 4, // capacity | 
| + &kCFTypeDictionaryKeyCallBacks, | 
| + &kCFTypeDictionaryValueCallBacks); | 
| + CFDictionarySetValue(image_config, kCVPixelBufferPixelFormatTypeKey, | 
| + cf_pixel_format); | 
| + CFDictionarySetValue(image_config, kCVPixelBufferWidthKey, cf_width); | 
| + CFDictionarySetValue(image_config, kCVPixelBufferHeightKey, cf_height); | 
| + CFDictionarySetValue(image_config, kCVPixelBufferOpenGLCompatibilityKey, | 
| + kCFBooleanTrue); | 
| + | 
| + return image_config; | 
| +} | 
| + | 
| +// TODO(sandersd): Also decode a frame if it turns out to be necessary for some | 
| +// hardware. | 
| +void InitializeVideoToolbox() { | 
| 
DaleCurtis
2014/11/21 19:01:02
What's the impact on gpu process startup time with
 
sandersd (OOO until July 31)
2014/11/21 20:19:35
Based on the benchmarking I just did, the perf tes
 | 
| + if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 
| + switches::kDisableAcceleratedVideoDecode)) { | 
| + return; | 
| + } | 
| + | 
| + if (!IsVtInitialized()) { | 
| + // CoreVideo is also required, but the loader stops after the first path is | 
| + // loaded. Instead we rely on the transitive dependency from VideoToolbox to | 
| + // CoreVideo. | 
| + // TODO(sandersd): Fallback to PrivateFrameworks. | 
| + StubPathMap paths; | 
| + paths[kModuleVt].push_back(FILE_PATH_LITERAL( | 
| + "/System/Library/Frameworks/VideoToolbox.framework/VideoToolbox")); | 
| + if (!InitializeStubs(paths)) | 
| + return; | 
| + } | 
| + | 
| + // Create a decoding session. | 
| 
DaleCurtis
2014/11/20 23:08:33
This seems a bit crazy, wouldn't we normally handl
 
sandersd (OOO until July 31)
2014/11/21 00:04:52
Yes, but we don't have actual data because no vide
 
DaleCurtis
2014/11/21 02:04:13
Is there any impact on the ability to play two vid
 
sandersd (OOO until July 31)
2014/11/21 02:07:07
No, this initialization is called once per GPU pro
 
DaleCurtis
2014/11/21 19:01:02
To be clear, you're running this here so that all
 
sandersd (OOO until July 31)
2014/11/21 20:19:35
Done.
 | 
| + // SPS and PPS data were taken from the 480p encoding of Big Buck Bunny. | 
| + uint8_t sps[] = {0x67, 0x64, 0x00, 0x1e, 0xac, 0xd9, 0x80, 0xd4, 0x3d, 0xa1, | 
| 
DaleCurtis
2014/11/21 19:01:02
Will the API let you const all these?
 
sandersd (OOO until July 31)
2014/11/21 20:19:35
Done.
 | 
| + 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x30, | 
| + 0x8f, 0x16, 0x2d, 0x9a}; | 
| + uint8_t pps[] = {0x68, 0xe9, 0x7b, 0xcb}; | 
| + uint8_t* data_ptrs[] = {sps, pps}; | 
| + size_t data_sizes[] = {arraysize(sps), arraysize(pps)}; | 
| + | 
| + base::ScopedCFTypeRef<CMFormatDescriptionRef> format; | 
| + OSStatus status = CMVideoFormatDescriptionCreateFromH264ParameterSets( | 
| + kCFAllocatorDefault, | 
| + 2, // parameter_set_count | 
| + data_ptrs, // ¶meter_set_pointers | 
| + data_sizes, // ¶meter_set_sizes | 
| + kNALUHeaderLength, // nal_unit_header_length | 
| + format.InitializeInto()); | 
| + if (status) { | 
| + LOG(ERROR) << "Failed to create CMVideoFormatDescription while " | 
| + << "initializing VideoToolbox"; | 
| + UninitializeVt(); | 
| + return; | 
| + } | 
| + | 
| + base::ScopedCFTypeRef<CFMutableDictionaryRef> decoder_config( | 
| + CFDictionaryCreateMutable( | 
| + kCFAllocatorDefault, | 
| + 1, // capacity | 
| + &kCFTypeDictionaryKeyCallBacks, | 
| + &kCFTypeDictionaryValueCallBacks)); | 
| + | 
| + CFDictionarySetValue( | 
| + decoder_config, | 
| + // kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder | 
| + CFSTR("RequireHardwareAcceleratedVideoDecoder"), | 
| + kCFBooleanTrue); | 
| + | 
| + base::ScopedCFTypeRef<CFMutableDictionaryRef> image_config( | 
| + BuildImageConfig(CMVideoFormatDescriptionGetDimensions(format))); | 
| + | 
| + VTDecompressionOutputCallbackRecord callback; | 
| + callback.decompressionOutputCallback = NULL; | 
| + callback.decompressionOutputRefCon = NULL; | 
| + | 
| + base::ScopedCFTypeRef<VTDecompressionSessionRef> session; | 
| + status = VTDecompressionSessionCreate( | 
| + kCFAllocatorDefault, | 
| + format, // video_format_description | 
| + decoder_config, // video_decoder_specification | 
| + image_config, // destination_image_buffer_attributes | 
| + &callback, // output_callback | 
| + session.InitializeInto()); | 
| + if (status) { | 
| + LOG(ERROR) << "Initializing VideoToolbox failed with status " << status; | 
| + UninitializeVt(); | 
| + return; | 
| + } | 
| +} | 
| + | 
| // Route decoded frame callbacks back into the VTVideoDecodeAccelerator. | 
| static void OutputThunk( | 
| void* decompression_output_refcon, | 
| @@ -91,27 +197,13 @@ bool VTVideoDecodeAccelerator::Initialize( | 
| DCHECK(gpu_thread_checker_.CalledOnValidThread()); | 
| client_ = client; | 
| - // Only H.264 is supported. | 
| - if (profile < media::H264PROFILE_MIN || profile > media::H264PROFILE_MAX) | 
| + if (!IsVtInitialized()) | 
| return false; | 
| - // Require --no-sandbox until VideoToolbox library loading is part of sandbox | 
| - // startup (and this VDA is ready for regular users). | 
| - if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoSandbox)) | 
| + // Only H.264 is supported. | 
| + if (profile < media::H264PROFILE_MIN || profile > media::H264PROFILE_MAX) | 
| return false; | 
| - if (!IsVtInitialized()) { | 
| - // CoreVideo is also required, but the loader stops after the first | 
| - // path is loaded. Instead we rely on the transitive dependency from | 
| - // VideoToolbox to CoreVideo. | 
| - // TODO(sandersd): Fallback to PrivateFrameworks for VideoToolbox. | 
| - StubPathMap paths; | 
| - paths[kModuleVt].push_back(FILE_PATH_LITERAL( | 
| - "/System/Library/Frameworks/VideoToolbox.framework/VideoToolbox")); | 
| - if (!InitializeStubs(paths)) | 
| - return false; | 
| - } | 
| - | 
| // Spawn a thread to handle parsing and calling VideoToolbox. | 
| if (!decoder_thread_.Start()) | 
| return false; | 
| @@ -192,25 +284,7 @@ bool VTVideoDecodeAccelerator::ConfigureDecoder() { | 
| kCFBooleanTrue); | 
| base::ScopedCFTypeRef<CFMutableDictionaryRef> image_config( | 
| - CFDictionaryCreateMutable( | 
| - kCFAllocatorDefault, | 
| - 4, // capacity | 
| - &kCFTypeDictionaryKeyCallBacks, | 
| - &kCFTypeDictionaryValueCallBacks)); | 
| - | 
| -#define CFINT(i) CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i) | 
| - // TODO(sandersd): RGBA option for 4:4:4 video. | 
| - int32_t pixel_format = kCVPixelFormatType_422YpCbCr8; | 
| - base::ScopedCFTypeRef<CFNumberRef> cf_pixel_format(CFINT(pixel_format)); | 
| - base::ScopedCFTypeRef<CFNumberRef> cf_width(CFINT(coded_dimensions.width)); | 
| - base::ScopedCFTypeRef<CFNumberRef> cf_height(CFINT(coded_dimensions.height)); | 
| -#undef CFINT | 
| - CFDictionarySetValue( | 
| - image_config, kCVPixelBufferPixelFormatTypeKey, cf_pixel_format); | 
| - CFDictionarySetValue(image_config, kCVPixelBufferWidthKey, cf_width); | 
| - CFDictionarySetValue(image_config, kCVPixelBufferHeightKey, cf_height); | 
| - CFDictionarySetValue( | 
| - image_config, kCVPixelBufferOpenGLCompatibilityKey, kCFBooleanTrue); | 
| + BuildImageConfig(coded_dimensions)); | 
| // TODO(sandersd): Does the old session need to be flushed first? | 
| session_.reset(); |