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

Side by Side 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: Reduce code duplication. 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 unified diff | 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 »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 <CoreVideo/CoreVideo.h> 5 #include <CoreVideo/CoreVideo.h>
6 #include <OpenGL/CGLIOSurface.h> 6 #include <OpenGL/CGLIOSurface.h>
7 #include <OpenGL/gl.h> 7 #include <OpenGL/gl.h>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/command_line.h" 10 #include "base/command_line.h"
(...skipping 20 matching lines...) Expand all
31 31
32 // Size to use for NALU length headers in AVC format (can be 1, 2, or 4). 32 // Size to use for NALU length headers in AVC format (can be 1, 2, or 4).
33 static const int kNALUHeaderLength = 4; 33 static const int kNALUHeaderLength = 4;
34 34
35 // We request 5 picture buffers from the client, each of which has a texture ID 35 // We request 5 picture buffers from the client, each of which has a texture ID
36 // that we can bind decoded frames to. We need enough to satisfy preroll, and 36 // that we can bind decoded frames to. We need enough to satisfy preroll, and
37 // enough to avoid unnecessary stalling, but no more than that. The resource 37 // enough to avoid unnecessary stalling, but no more than that. The resource
38 // requirements are low, as we don't need the textures to be backed by storage. 38 // requirements are low, as we don't need the textures to be backed by storage.
39 static const int kNumPictureBuffers = media::limits::kMaxVideoFrames + 1; 39 static const int kNumPictureBuffers = media::limits::kMaxVideoFrames + 1;
40 40
41 // Build an |image_config| dictionary for VideoToolbox initialization.
42 static CFMutableDictionaryRef BuildImageConfig(
43 CMVideoDimensions coded_dimensions) {
44 // TODO(sandersd): RGBA option for 4:4:4 video.
45 int32_t pixel_format = kCVPixelFormatType_422YpCbCr8;
46
47 #define CFINT(i) CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i)
48 base::ScopedCFTypeRef<CFNumberRef> cf_pixel_format(CFINT(pixel_format));
49 base::ScopedCFTypeRef<CFNumberRef> cf_width(CFINT(coded_dimensions.width));
50 base::ScopedCFTypeRef<CFNumberRef> cf_height(CFINT(coded_dimensions.height));
51 #undef CFINT
52
53 CFMutableDictionaryRef image_config = CFDictionaryCreateMutable(
54 kCFAllocatorDefault,
55 4, // capacity
56 &kCFTypeDictionaryKeyCallBacks,
57 &kCFTypeDictionaryValueCallBacks);
58 CFDictionarySetValue(image_config, kCVPixelBufferPixelFormatTypeKey,
59 cf_pixel_format);
60 CFDictionarySetValue(image_config, kCVPixelBufferWidthKey, cf_width);
61 CFDictionarySetValue(image_config, kCVPixelBufferHeightKey, cf_height);
62 CFDictionarySetValue(image_config, kCVPixelBufferOpenGLCompatibilityKey,
63 kCFBooleanTrue);
64
65 return image_config;
66 }
67
68 // TODO(sandersd): Also decode a frame if it turns out to be necessary for some
69 // hardware.
70 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
71 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
72 switches::kDisableAcceleratedVideoDecode)) {
73 return;
74 }
75
76 if (!IsVtInitialized()) {
77 // CoreVideo is also required, but the loader stops after the first path is
78 // loaded. Instead we rely on the transitive dependency from VideoToolbox to
79 // CoreVideo.
80 // TODO(sandersd): Fallback to PrivateFrameworks.
81 StubPathMap paths;
82 paths[kModuleVt].push_back(FILE_PATH_LITERAL(
83 "/System/Library/Frameworks/VideoToolbox.framework/VideoToolbox"));
84 if (!InitializeStubs(paths))
85 return;
86 }
87
88 // 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.
89 // SPS and PPS data were taken from the 480p encoding of Big Buck Bunny.
90 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.
91 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x30,
92 0x8f, 0x16, 0x2d, 0x9a};
93 uint8_t pps[] = {0x68, 0xe9, 0x7b, 0xcb};
94 uint8_t* data_ptrs[] = {sps, pps};
95 size_t data_sizes[] = {arraysize(sps), arraysize(pps)};
96
97 base::ScopedCFTypeRef<CMFormatDescriptionRef> format;
98 OSStatus status = CMVideoFormatDescriptionCreateFromH264ParameterSets(
99 kCFAllocatorDefault,
100 2, // parameter_set_count
101 data_ptrs, // &parameter_set_pointers
102 data_sizes, // &parameter_set_sizes
103 kNALUHeaderLength, // nal_unit_header_length
104 format.InitializeInto());
105 if (status) {
106 LOG(ERROR) << "Failed to create CMVideoFormatDescription while "
107 << "initializing VideoToolbox";
108 UninitializeVt();
109 return;
110 }
111
112 base::ScopedCFTypeRef<CFMutableDictionaryRef> decoder_config(
113 CFDictionaryCreateMutable(
114 kCFAllocatorDefault,
115 1, // capacity
116 &kCFTypeDictionaryKeyCallBacks,
117 &kCFTypeDictionaryValueCallBacks));
118
119 CFDictionarySetValue(
120 decoder_config,
121 // kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder
122 CFSTR("RequireHardwareAcceleratedVideoDecoder"),
123 kCFBooleanTrue);
124
125 base::ScopedCFTypeRef<CFMutableDictionaryRef> image_config(
126 BuildImageConfig(CMVideoFormatDescriptionGetDimensions(format)));
127
128 VTDecompressionOutputCallbackRecord callback;
129 callback.decompressionOutputCallback = NULL;
130 callback.decompressionOutputRefCon = NULL;
131
132 base::ScopedCFTypeRef<VTDecompressionSessionRef> session;
133 status = VTDecompressionSessionCreate(
134 kCFAllocatorDefault,
135 format, // video_format_description
136 decoder_config, // video_decoder_specification
137 image_config, // destination_image_buffer_attributes
138 &callback, // output_callback
139 session.InitializeInto());
140 if (status) {
141 LOG(ERROR) << "Initializing VideoToolbox failed with status " << status;
142 UninitializeVt();
143 return;
144 }
145 }
146
41 // Route decoded frame callbacks back into the VTVideoDecodeAccelerator. 147 // Route decoded frame callbacks back into the VTVideoDecodeAccelerator.
42 static void OutputThunk( 148 static void OutputThunk(
43 void* decompression_output_refcon, 149 void* decompression_output_refcon,
44 void* source_frame_refcon, 150 void* source_frame_refcon,
45 OSStatus status, 151 OSStatus status,
46 VTDecodeInfoFlags info_flags, 152 VTDecodeInfoFlags info_flags,
47 CVImageBufferRef image_buffer, 153 CVImageBufferRef image_buffer,
48 CMTime presentation_time_stamp, 154 CMTime presentation_time_stamp,
49 CMTime presentation_duration) { 155 CMTime presentation_duration) {
50 VTVideoDecodeAccelerator* vda = 156 VTVideoDecodeAccelerator* vda =
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 190
85 VTVideoDecodeAccelerator::~VTVideoDecodeAccelerator() { 191 VTVideoDecodeAccelerator::~VTVideoDecodeAccelerator() {
86 } 192 }
87 193
88 bool VTVideoDecodeAccelerator::Initialize( 194 bool VTVideoDecodeAccelerator::Initialize(
89 media::VideoCodecProfile profile, 195 media::VideoCodecProfile profile,
90 Client* client) { 196 Client* client) {
91 DCHECK(gpu_thread_checker_.CalledOnValidThread()); 197 DCHECK(gpu_thread_checker_.CalledOnValidThread());
92 client_ = client; 198 client_ = client;
93 199
200 if (!IsVtInitialized())
201 return false;
202
94 // Only H.264 is supported. 203 // Only H.264 is supported.
95 if (profile < media::H264PROFILE_MIN || profile > media::H264PROFILE_MAX) 204 if (profile < media::H264PROFILE_MIN || profile > media::H264PROFILE_MAX)
96 return false; 205 return false;
97 206
98 // Require --no-sandbox until VideoToolbox library loading is part of sandbox
99 // startup (and this VDA is ready for regular users).
100 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoSandbox))
101 return false;
102
103 if (!IsVtInitialized()) {
104 // CoreVideo is also required, but the loader stops after the first
105 // path is loaded. Instead we rely on the transitive dependency from
106 // VideoToolbox to CoreVideo.
107 // TODO(sandersd): Fallback to PrivateFrameworks for VideoToolbox.
108 StubPathMap paths;
109 paths[kModuleVt].push_back(FILE_PATH_LITERAL(
110 "/System/Library/Frameworks/VideoToolbox.framework/VideoToolbox"));
111 if (!InitializeStubs(paths))
112 return false;
113 }
114
115 // Spawn a thread to handle parsing and calling VideoToolbox. 207 // Spawn a thread to handle parsing and calling VideoToolbox.
116 if (!decoder_thread_.Start()) 208 if (!decoder_thread_.Start())
117 return false; 209 return false;
118 210
119 return true; 211 return true;
120 } 212 }
121 213
122 bool VTVideoDecodeAccelerator::FinishDelayedFrames() { 214 bool VTVideoDecodeAccelerator::FinishDelayedFrames() {
123 DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread()); 215 DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread());
124 if (session_) { 216 if (session_) {
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
185 &kCFTypeDictionaryKeyCallBacks, 277 &kCFTypeDictionaryKeyCallBacks,
186 &kCFTypeDictionaryValueCallBacks)); 278 &kCFTypeDictionaryValueCallBacks));
187 279
188 CFDictionarySetValue( 280 CFDictionarySetValue(
189 decoder_config, 281 decoder_config,
190 // kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder 282 // kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder
191 CFSTR("EnableHardwareAcceleratedVideoDecoder"), 283 CFSTR("EnableHardwareAcceleratedVideoDecoder"),
192 kCFBooleanTrue); 284 kCFBooleanTrue);
193 285
194 base::ScopedCFTypeRef<CFMutableDictionaryRef> image_config( 286 base::ScopedCFTypeRef<CFMutableDictionaryRef> image_config(
195 CFDictionaryCreateMutable( 287 BuildImageConfig(coded_dimensions));
196 kCFAllocatorDefault,
197 4, // capacity
198 &kCFTypeDictionaryKeyCallBacks,
199 &kCFTypeDictionaryValueCallBacks));
200
201 #define CFINT(i) CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i)
202 // TODO(sandersd): RGBA option for 4:4:4 video.
203 int32_t pixel_format = kCVPixelFormatType_422YpCbCr8;
204 base::ScopedCFTypeRef<CFNumberRef> cf_pixel_format(CFINT(pixel_format));
205 base::ScopedCFTypeRef<CFNumberRef> cf_width(CFINT(coded_dimensions.width));
206 base::ScopedCFTypeRef<CFNumberRef> cf_height(CFINT(coded_dimensions.height));
207 #undef CFINT
208 CFDictionarySetValue(
209 image_config, kCVPixelBufferPixelFormatTypeKey, cf_pixel_format);
210 CFDictionarySetValue(image_config, kCVPixelBufferWidthKey, cf_width);
211 CFDictionarySetValue(image_config, kCVPixelBufferHeightKey, cf_height);
212 CFDictionarySetValue(
213 image_config, kCVPixelBufferOpenGLCompatibilityKey, kCFBooleanTrue);
214 288
215 // TODO(sandersd): Does the old session need to be flushed first? 289 // TODO(sandersd): Does the old session need to be flushed first?
216 session_.reset(); 290 session_.reset();
217 status = VTDecompressionSessionCreate( 291 status = VTDecompressionSessionCreate(
218 kCFAllocatorDefault, 292 kCFAllocatorDefault,
219 format_, // video_format_description 293 format_, // video_format_description
220 decoder_config, // video_decoder_specification 294 decoder_config, // video_decoder_specification
221 image_config, // destination_image_buffer_attributes 295 image_config, // destination_image_buffer_attributes
222 &callback_, // output_callback 296 &callback_, // output_callback
223 session_.InitializeInto()); 297 session_.InitializeInto());
(...skipping 443 matching lines...) Expand 10 before | Expand all | Expand 10 after
667 assigned_bitstream_ids_.clear(); 741 assigned_bitstream_ids_.clear();
668 state_ = STATE_DESTROYING; 742 state_ = STATE_DESTROYING;
669 QueueFlush(TASK_DESTROY); 743 QueueFlush(TASK_DESTROY);
670 } 744 }
671 745
672 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() { 746 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() {
673 return false; 747 return false;
674 } 748 }
675 749
676 } // namespace content 750 } // namespace content
OLDNEW
« 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