Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(638)

Unified Diff: content/common/gpu/media/vt_video_decode_accelerator.cc

Issue 723993003: Sandbox initialization for VideoToolbox. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@vt_queue_frames
Patch Set: Header comment Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/common/gpu/media/vt_video_decode_accelerator.h ('k') | content/common/sandbox_mac.mm » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 1cae8f255a43e391096088d820713abd00400fcf..6f1e18ab86bf9da90cf7a62d96a927ada372ca3f 100644
--- a/content/common/gpu/media/vt_video_decode_accelerator.cc
+++ b/content/common/gpu/media/vt_video_decode_accelerator.cc
@@ -38,6 +38,121 @@ 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;
+}
+
+// The purpose of this function is to preload the generic and hardware-specific
+// libraries required by VideoToolbox before the GPU sandbox is enabled.
+// VideoToolbox normally loads the hardware-specific libraries lazily, so we
+// must actually create a decompression session.
+//
+// If creating a decompression session fails, hardware decoding will be disabled
+// (Initialize() will always return false). If it succeeds but a required
+// library is not loaded yet (I have not experienced this, but the details are
+// not documented), then VideoToolbox will fall back on software decoding
DaleCurtis 2014/11/21 21:00:49 Is there a way you record when this happens as a U
sandersd (OOO until July 31) 2014/11/21 21:20:19 It's possible, but is also expected when the resol
+// internally. If that happens, the likely solution is to expand the scope of
+// this initialization.
+void InitializeVideoToolbox() {
+ 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.
+ // SPS and PPS data were taken from the 480p encoding of Big Buck Bunny.
+ const uint8_t sps[] = {0x67, 0x64, 0x00, 0x1e, 0xac, 0xd9, 0x80, 0xd4, 0x3d,
+ 0xa1, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03,
+ 0x00, 0x30, 0x8f, 0x16, 0x2d, 0x9a};
+ const uint8_t pps[] = {0x68, 0xe9, 0x7b, 0xcb};
+ const uint8_t* data_ptrs[] = {sps, pps};
+ const size_t data_sizes[] = {arraysize(sps), arraysize(pps)};
+
+ base::ScopedCFTypeRef<CMFormatDescriptionRef> format;
+ OSStatus status = CMVideoFormatDescriptionCreateFromH264ParameterSets(
+ kCFAllocatorDefault,
+ 2, // parameter_set_count
+ data_ptrs, // &parameter_set_pointers
+ data_sizes, // &parameter_set_sizes
+ kNALUHeaderLength, // nal_unit_header_length
+ format.InitializeInto());
+ if (status) {
+ LOG(ERROR) << "Failed to create CMVideoFormatDescription while "
DaleCurtis 2014/11/21 21:00:49 Check out OSSTATUS_LOG and OSSTATUS_DLOG. You can
sandersd (OOO until July 31) 2014/11/21 21:20:19 Done.
+ << "initializing VideoToolbox";
+ content_common_gpu_media::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;
DaleCurtis 2014/11/21 21:00:49 Worth using = {0} to zero all potential fields?
sandersd (OOO until July 31) 2014/11/21 21:20:19 Done. (Although the regular path does not do this.
+ 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;
+ content_common_gpu_media::UninitializeVt();
+ return;
+ }
DaleCurtis 2014/11/21 21:00:49 Is the session automatically dropped once all refs
sandersd (OOO until July 31) 2014/11/21 21:20:19 It is, VTDecompressionSessionInvalidate() just let
+}
+
// Route decoded frame callbacks back into the VTVideoDecodeAccelerator.
static void OutputThunk(
void* decompression_output_refcon,
@@ -92,27 +207,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;
@@ -193,25 +294,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();
« no previous file with comments | « content/common/gpu/media/vt_video_decode_accelerator.h ('k') | content/common/sandbox_mac.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698