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

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: Logging 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
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"
11 #include "base/logging.h"
12 #include "base/mac/mac_logging.h"
11 #include "base/sys_byteorder.h" 13 #include "base/sys_byteorder.h"
12 #include "base/thread_task_runner_handle.h" 14 #include "base/thread_task_runner_handle.h"
13 #include "content/common/gpu/media/vt_video_decode_accelerator.h" 15 #include "content/common/gpu/media/vt_video_decode_accelerator.h"
14 #include "content/public/common/content_switches.h" 16 #include "content/public/common/content_switches.h"
15 #include "media/base/limits.h" 17 #include "media/base/limits.h"
16 #include "media/filters/h264_parser.h" 18 #include "media/filters/h264_parser.h"
17 #include "ui/gl/scoped_binders.h" 19 #include "ui/gl/scoped_binders.h"
18 20
19 using content_common_gpu_media::kModuleVt; 21 using content_common_gpu_media::kModuleVt;
20 using content_common_gpu_media::InitializeStubs; 22 using content_common_gpu_media::InitializeStubs;
21 using content_common_gpu_media::IsVtInitialized; 23 using content_common_gpu_media::IsVtInitialized;
22 using content_common_gpu_media::StubPathMap; 24 using content_common_gpu_media::StubPathMap;
23 25
24 #define NOTIFY_STATUS(name, status) \ 26 #define NOTIFY_STATUS(name, status) \
25 do { \ 27 do { \
26 DLOG(ERROR) << name << " failed with status " << status; \ 28 OSSTATUS_DLOG(ERROR, status) << name; \
27 NotifyError(PLATFORM_FAILURE); \ 29 NotifyError(PLATFORM_FAILURE); \
28 } while (0) 30 } while (0)
29 31
30 namespace content { 32 namespace content {
31 33
32 // Size to use for NALU length headers in AVC format (can be 1, 2, or 4). 34 // Size to use for NALU length headers in AVC format (can be 1, 2, or 4).
33 static const int kNALUHeaderLength = 4; 35 static const int kNALUHeaderLength = 4;
34 36
35 // We request 5 picture buffers from the client, each of which has a texture ID 37 // 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 38 // 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 39 // 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. 40 // requirements are low, as we don't need the textures to be backed by storage.
39 static const int kNumPictureBuffers = media::limits::kMaxVideoFrames + 1; 41 static const int kNumPictureBuffers = media::limits::kMaxVideoFrames + 1;
40 42
43 // Build an |image_config| dictionary for VideoToolbox initialization.
44 static CFMutableDictionaryRef BuildImageConfig(
jeremy 2014/11/23 10:29:16 return a ScopedCFTypeRef ?
sandersd (OOO until July 31) 2014/11/24 19:06:16 Done.
45 CMVideoDimensions coded_dimensions) {
jeremy 2014/11/23 10:29:16 nit: will this fit on the line above?
sandersd (OOO until July 31) 2014/11/24 19:06:16 Nope. (And especially not anymore.)
sandersd (OOO until July 31) 2014/11/24 19:06:16 Nope.
46 // TODO(sandersd): RGBA option for 4:4:4 video.
47 int32_t pixel_format = kCVPixelFormatType_422YpCbCr8;
48
49 #define CFINT(i) CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i)
50 base::ScopedCFTypeRef<CFNumberRef> cf_pixel_format(CFINT(pixel_format));
51 base::ScopedCFTypeRef<CFNumberRef> cf_width(CFINT(coded_dimensions.width));
52 base::ScopedCFTypeRef<CFNumberRef> cf_height(CFINT(coded_dimensions.height));
53 #undef CFINT
54
55 CFMutableDictionaryRef image_config = CFDictionaryCreateMutable(
56 kCFAllocatorDefault,
57 4, // capacity
58 &kCFTypeDictionaryKeyCallBacks,
59 &kCFTypeDictionaryValueCallBacks);
60 CFDictionarySetValue(image_config, kCVPixelBufferPixelFormatTypeKey,
61 cf_pixel_format);
62 CFDictionarySetValue(image_config, kCVPixelBufferWidthKey, cf_width);
63 CFDictionarySetValue(image_config, kCVPixelBufferHeightKey, cf_height);
64 CFDictionarySetValue(image_config, kCVPixelBufferOpenGLCompatibilityKey,
65 kCFBooleanTrue);
66
67 return image_config;
68 }
69
70 // The purpose of this function is to preload the generic and hardware-specific
71 // libraries required by VideoToolbox before the GPU sandbox is enabled.
72 // VideoToolbox normally loads the hardware-specific libraries lazily, so we
73 // must actually create a decompression session.
74 //
75 // If creating a decompression session fails, hardware decoding will be disabled
76 // (Initialize() will always return false). If it succeeds but a required
77 // library is not loaded yet (I have not experienced this, but the details are
78 // not documented), then VideoToolbox will fall back on software decoding
79 // internally. If that happens, the likely solution is to expand the scope of
80 // this initialization.
81 void InitializeVideoToolbox() {
82 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
83 switches::kDisableAcceleratedVideoDecode)) {
84 return;
85 }
86
87 if (!IsVtInitialized()) {
88 // CoreVideo is also required, but the loader stops after the first path is
89 // loaded. Instead we rely on the transitive dependency from VideoToolbox to
90 // CoreVideo.
91 // TODO(sandersd): Fallback to PrivateFrameworks.
jeremy 2014/11/23 10:29:16 Can you expand on this TODO a bit, why do we need
sandersd (OOO until July 31) 2014/11/24 19:06:16 Done.
92 StubPathMap paths;
93 paths[kModuleVt].push_back(FILE_PATH_LITERAL(
94 "/System/Library/Frameworks/VideoToolbox.framework/VideoToolbox"));
95 if (!InitializeStubs(paths))
96 return;
97 }
98
99 // Create a decoding session.
100 // SPS and PPS data were taken from the 480p encoding of Big Buck Bunny.
101 const uint8_t sps[] = {0x67, 0x64, 0x00, 0x1e, 0xac, 0xd9, 0x80, 0xd4, 0x3d,
102 0xa1, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03,
103 0x00, 0x30, 0x8f, 0x16, 0x2d, 0x9a};
104 const uint8_t pps[] = {0x68, 0xe9, 0x7b, 0xcb};
105 const uint8_t* data_ptrs[] = {sps, pps};
106 const size_t data_sizes[] = {arraysize(sps), arraysize(pps)};
107
108 base::ScopedCFTypeRef<CMFormatDescriptionRef> format;
109 OSStatus status = CMVideoFormatDescriptionCreateFromH264ParameterSets(
110 kCFAllocatorDefault,
111 2, // parameter_set_count
112 data_ptrs, // &parameter_set_pointers
113 data_sizes, // &parameter_set_sizes
114 kNALUHeaderLength, // nal_unit_header_length
115 format.InitializeInto());
116 if (status) {
117 OSSTATUS_LOG(ERROR, status) << "Failed to create CMVideoFormatDescription "
118 << "while initializing VideoToolbox";
119 content_common_gpu_media::UninitializeVt();
jeremy 2014/11/23 10:29:16 nit: I'd feel better if there was a scoped object
sandersd (OOO until July 31) 2014/11/24 19:06:16 A good point, but I think it's overkill in this ca
120 return;
121 }
122
123 base::ScopedCFTypeRef<CFMutableDictionaryRef> decoder_config(
124 CFDictionaryCreateMutable(
125 kCFAllocatorDefault,
126 1, // capacity
127 &kCFTypeDictionaryKeyCallBacks,
128 &kCFTypeDictionaryValueCallBacks));
129
130 CFDictionarySetValue(
131 decoder_config,
132 // kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder
133 CFSTR("RequireHardwareAcceleratedVideoDecoder"),
134 kCFBooleanTrue);
135
136 base::ScopedCFTypeRef<CFMutableDictionaryRef> image_config(
137 BuildImageConfig(CMVideoFormatDescriptionGetDimensions(format)));
138
139 VTDecompressionOutputCallbackRecord callback = {0};
140
141 base::ScopedCFTypeRef<VTDecompressionSessionRef> session;
142 status = VTDecompressionSessionCreate(
143 kCFAllocatorDefault,
144 format, // video_format_description
145 decoder_config, // video_decoder_specification
146 image_config, // destination_image_buffer_attributes
147 &callback, // output_callback
148 session.InitializeInto());
149 if (status) {
150 OSSTATUS_LOG(ERROR, status) << "Failed to create VTDecompressionSession "
151 << "while initializing VideoToolbox";
152 content_common_gpu_media::UninitializeVt();
153 return;
154 }
155 }
156
41 // Route decoded frame callbacks back into the VTVideoDecodeAccelerator. 157 // Route decoded frame callbacks back into the VTVideoDecodeAccelerator.
42 static void OutputThunk( 158 static void OutputThunk(
43 void* decompression_output_refcon, 159 void* decompression_output_refcon,
44 void* source_frame_refcon, 160 void* source_frame_refcon,
45 OSStatus status, 161 OSStatus status,
46 VTDecodeInfoFlags info_flags, 162 VTDecodeInfoFlags info_flags,
47 CVImageBufferRef image_buffer, 163 CVImageBufferRef image_buffer,
48 CMTime presentation_time_stamp, 164 CMTime presentation_time_stamp,
49 CMTime presentation_duration) { 165 CMTime presentation_duration) {
50 VTVideoDecodeAccelerator* vda = 166 VTVideoDecodeAccelerator* vda =
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 201
86 VTVideoDecodeAccelerator::~VTVideoDecodeAccelerator() { 202 VTVideoDecodeAccelerator::~VTVideoDecodeAccelerator() {
87 } 203 }
88 204
89 bool VTVideoDecodeAccelerator::Initialize( 205 bool VTVideoDecodeAccelerator::Initialize(
90 media::VideoCodecProfile profile, 206 media::VideoCodecProfile profile,
91 Client* client) { 207 Client* client) {
92 DCHECK(gpu_thread_checker_.CalledOnValidThread()); 208 DCHECK(gpu_thread_checker_.CalledOnValidThread());
93 client_ = client; 209 client_ = client;
94 210
211 if (!IsVtInitialized())
212 return false;
213
95 // Only H.264 is supported. 214 // Only H.264 is supported.
96 if (profile < media::H264PROFILE_MIN || profile > media::H264PROFILE_MAX) 215 if (profile < media::H264PROFILE_MIN || profile > media::H264PROFILE_MAX)
97 return false; 216 return false;
98 217
99 // Require --no-sandbox until VideoToolbox library loading is part of sandbox
100 // startup (and this VDA is ready for regular users).
101 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoSandbox))
102 return false;
103
104 if (!IsVtInitialized()) {
105 // CoreVideo is also required, but the loader stops after the first
106 // path is loaded. Instead we rely on the transitive dependency from
107 // VideoToolbox to CoreVideo.
108 // TODO(sandersd): Fallback to PrivateFrameworks for VideoToolbox.
109 StubPathMap paths;
110 paths[kModuleVt].push_back(FILE_PATH_LITERAL(
111 "/System/Library/Frameworks/VideoToolbox.framework/VideoToolbox"));
112 if (!InitializeStubs(paths))
113 return false;
114 }
115
116 // Spawn a thread to handle parsing and calling VideoToolbox. 218 // Spawn a thread to handle parsing and calling VideoToolbox.
117 if (!decoder_thread_.Start()) 219 if (!decoder_thread_.Start())
118 return false; 220 return false;
119 221
120 return true; 222 return true;
121 } 223 }
122 224
123 bool VTVideoDecodeAccelerator::FinishDelayedFrames() { 225 bool VTVideoDecodeAccelerator::FinishDelayedFrames() {
124 DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread()); 226 DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread());
125 if (session_) { 227 if (session_) {
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 &kCFTypeDictionaryKeyCallBacks, 288 &kCFTypeDictionaryKeyCallBacks,
187 &kCFTypeDictionaryValueCallBacks)); 289 &kCFTypeDictionaryValueCallBacks));
188 290
189 CFDictionarySetValue( 291 CFDictionarySetValue(
190 decoder_config, 292 decoder_config,
191 // kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder 293 // kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder
192 CFSTR("EnableHardwareAcceleratedVideoDecoder"), 294 CFSTR("EnableHardwareAcceleratedVideoDecoder"),
193 kCFBooleanTrue); 295 kCFBooleanTrue);
194 296
195 base::ScopedCFTypeRef<CFMutableDictionaryRef> image_config( 297 base::ScopedCFTypeRef<CFMutableDictionaryRef> image_config(
196 CFDictionaryCreateMutable( 298 BuildImageConfig(coded_dimensions));
197 kCFAllocatorDefault,
198 4, // capacity
199 &kCFTypeDictionaryKeyCallBacks,
200 &kCFTypeDictionaryValueCallBacks));
201
202 #define CFINT(i) CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i)
203 // TODO(sandersd): RGBA option for 4:4:4 video.
204 int32_t pixel_format = kCVPixelFormatType_422YpCbCr8;
205 base::ScopedCFTypeRef<CFNumberRef> cf_pixel_format(CFINT(pixel_format));
206 base::ScopedCFTypeRef<CFNumberRef> cf_width(CFINT(coded_dimensions.width));
207 base::ScopedCFTypeRef<CFNumberRef> cf_height(CFINT(coded_dimensions.height));
208 #undef CFINT
209 CFDictionarySetValue(
210 image_config, kCVPixelBufferPixelFormatTypeKey, cf_pixel_format);
211 CFDictionarySetValue(image_config, kCVPixelBufferWidthKey, cf_width);
212 CFDictionarySetValue(image_config, kCVPixelBufferHeightKey, cf_height);
213 CFDictionarySetValue(
214 image_config, kCVPixelBufferOpenGLCompatibilityKey, kCFBooleanTrue);
215 299
216 // TODO(sandersd): Does the old session need to be flushed first? 300 // TODO(sandersd): Does the old session need to be flushed first?
217 session_.reset(); 301 session_.reset();
218 status = VTDecompressionSessionCreate( 302 status = VTDecompressionSessionCreate(
219 kCFAllocatorDefault, 303 kCFAllocatorDefault,
220 format_, // video_format_description 304 format_, // video_format_description
221 decoder_config, // video_decoder_specification 305 decoder_config, // video_decoder_specification
222 image_config, // destination_image_buffer_attributes 306 image_config, // destination_image_buffer_attributes
223 &callback_, // output_callback 307 &callback_, // output_callback
224 session_.InitializeInto()); 308 session_.InitializeInto());
(...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after
672 assigned_bitstream_ids_.clear(); 756 assigned_bitstream_ids_.clear();
673 state_ = STATE_DESTROYING; 757 state_ = STATE_DESTROYING;
674 QueueFlush(TASK_DESTROY); 758 QueueFlush(TASK_DESTROY);
675 } 759 }
676 760
677 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() { 761 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() {
678 return false; 762 return false;
679 } 763 }
680 764
681 } // namespace content 765 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698