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

Side by Side Diff: content/common/gpu/media/vt_video_decode_accelerator.cc

Issue 374153003: Use PPS/SPS NALUs to initialize a VTDecompressionSession. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Move parsing to decoder thread. Created 6 years, 5 months 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>
6 #include <OpenGL/CGLIOSurface.h>
7
8 #include "base/bind.h"
9 #include "base/thread_task_runner_handle.h"
5 #include "content/common/gpu/media/vt_video_decode_accelerator.h" 10 #include "content/common/gpu/media/vt_video_decode_accelerator.h"
11 #include "media/filters/h264_parser.h"
12
13 using content_common_gpu_media::kModuleVt;
14 using content_common_gpu_media::InitializeStubs;
15 using content_common_gpu_media::IsVtInitialized;
16 using content_common_gpu_media::StubPathMap;
6 17
7 namespace content { 18 namespace content {
8 19
20 // Route decoded frame callbacks back into the VTVideoDecodeAccelerator.
21 static void OutputThunk(
22 void* decompression_output_refcon,
23 void* source_frame_refcon,
24 OSStatus status,
25 VTDecodeInfoFlags info_flags,
26 CVImageBufferRef image_buffer,
27 CMTime presentation_time_stamp,
28 CMTime presentation_duration) {
29 VTVideoDecodeAccelerator* vda =
30 reinterpret_cast<VTVideoDecodeAccelerator*>(decompression_output_refcon);
31 int32_t* bitstream_id_ptr = reinterpret_cast<int32_t*>(source_frame_refcon);
32 int32_t bitstream_id = *bitstream_id_ptr;
33 delete bitstream_id_ptr;
34 CFRetain(image_buffer);
35 vda->Output(bitstream_id, status, info_flags, image_buffer);
36 }
37
9 VTVideoDecodeAccelerator::VTVideoDecodeAccelerator(CGLContextObj cgl_context) 38 VTVideoDecodeAccelerator::VTVideoDecodeAccelerator(CGLContextObj cgl_context)
10 : loop_proxy_(base::MessageLoopProxy::current()), 39 : gpu_task_runner_(base::ThreadTaskRunnerHandle::Get()),
11 cgl_context_(cgl_context), 40 cgl_context_(cgl_context),
12 client_(NULL), 41 client_(NULL),
13 weak_this_factory_(this) { 42 decoder_thread_("VTDecoderThread"),
43 format_(NULL),
44 session_(NULL),
45 coded_width_(0),
46 coded_height_(0),
47 weak_factory_(this) {
48 callback_.decompressionOutputCallback = OutputThunk;
49 callback_.decompressionOutputRefCon = this;
14 } 50 }
15 51
16 VTVideoDecodeAccelerator::~VTVideoDecodeAccelerator() { 52 VTVideoDecodeAccelerator::~VTVideoDecodeAccelerator() {
53 // TODO(sandersd): Move these into scoped pointers.
scherkus (not reviewing) 2014/07/09 18:32:48 can we use base/mac/scoped_cftyperef.h now? if so
sandersd (OOO until July 31) 2014/07/09 20:07:11 Done.
54 if (format_)
55 CFRelease(format_);
56 if (session_)
57 CFRelease(session_);
17 } 58 }
18 59
19 bool VTVideoDecodeAccelerator::Initialize( 60 bool VTVideoDecodeAccelerator::Initialize(
20 media::VideoCodecProfile profile, 61 media::VideoCodecProfile profile,
21 Client* client) { 62 Client* client) {
22 DCHECK(CalledOnValidThread()); 63 DCHECK(CalledOnValidThread());
23 DVLOG(2) << __FUNCTION__;
24 client_ = client; 64 client_ = client;
25 65
26 // Only H.264 is supported. 66 // Only H.264 is supported.
27 if (profile < media::H264PROFILE_MIN || profile > media::H264PROFILE_MAX) 67 if (profile < media::H264PROFILE_MIN || profile > media::H264PROFILE_MAX)
28 return false; 68 return false;
29 69
30 // Prevent anyone from using VTVideoDecoder for now. http://crbug.com/133828 70 // TODO(sandersd): Move VideoToolbox library loading to sandbox startup;
31 return false; 71 // until then, --no-sandbox is required.
72 if (!IsVtInitialized()) {
73 StubPathMap paths;
74 // CoreVideo is also required, but the loader stops after the first
75 // path is loaded. Instead we rely on the transitive dependency from
76 // VideoToolbox to CoreVideo.
77 // TODO(sandersd): Fallback to PrivateFrameworks for VideoToolbox.
78 paths[kModuleVt].push_back(FILE_PATH_LITERAL(
79 "/System/Library/Frameworks/VideoToolbox.framework/VideoToolbox"));
80 if (!InitializeStubs(paths))
81 return false;
82 }
83
84 // Spawn a thread to handle parsing and calling VideoToolbox.
85 if (!decoder_thread_.Start())
86 return false;
87 decoder_task_runner_ = decoder_thread_.message_loop_proxy();
88
89 // Note that --ignore-gpu-blacklist is still required to get here.
90 return true;
91 }
92
93 // TODO(sandersd): Proper error reporting instead of CHECKs.
94 void VTVideoDecodeAccelerator::ConfigureDecoder(
95 const std::vector<const uint8_t*>& nalu_data_ptrs,
96 const std::vector<size_t>& nalu_data_sizes) {
97 if (format_ != NULL) {
scherkus (not reviewing) 2014/07/09 18:32:48 nit: (!format_)
sandersd (OOO until July 31) 2014/07/09 20:07:11 Done.
98 CFRelease(format_);
99 format_ = NULL;
100 }
101
102 CHECK(!CMVideoFormatDescriptionCreateFromH264ParameterSets(
103 kCFAllocatorDefault,
104 nalu_data_ptrs.size(), // parameter_set_count
105 &nalu_data_ptrs.front(), // &parameter_set_pointers
106 &nalu_data_sizes.front(), // &parameter_set_sizes
107 4, // nal_unit_header_length
108 &format_
109 ));
110
111 // TODO(sandersd): Check if the size has changed and handle picture requests.
112 CMVideoDimensions coded_size = CMVideoFormatDescriptionGetDimensions(format_);
113 coded_width_ = coded_size.width;
114 coded_height_ = coded_size.height;
115
116 // TODO(sandersd): Scoped pointers.
scherkus (not reviewing) 2014/07/09 18:32:49 I'd go for scoped pointers right away
sandersd (OOO until July 31) 2014/07/09 20:07:11 Done.
117 CFMutableDictionaryRef decoder_config = CFDictionaryCreateMutable(
118 kCFAllocatorDefault,
119 1, // capacity
120 &kCFTypeDictionaryKeyCallBacks,
121 &kCFTypeDictionaryValueCallBacks);
122
123 CFDictionarySetValue(
124 decoder_config,
125 // kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder
126 CFSTR("EnableHardwareAcceleratedVideoDecoder"),
127 kCFBooleanTrue);
128
129 CFMutableDictionaryRef image_config = CFDictionaryCreateMutable(
130 kCFAllocatorDefault,
131 4, // capacity
132 &kCFTypeDictionaryKeyCallBacks,
133 &kCFTypeDictionaryValueCallBacks);
134
135 // TODO(sandersd): ARGB for video that is not 4:2:0.
136 int32_t pixel_format = '2vuy';
137 #define CFINT(i) CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i)
138 CFNumberRef cf_pixel_format = CFINT(pixel_format);
139 CFNumberRef cf_width = CFINT(coded_width_);
140 CFNumberRef cf_height = CFINT(coded_height_);
141 CFDictionarySetValue(
142 image_config, kCVPixelBufferPixelFormatTypeKey, cf_pixel_format);
scherkus (not reviewing) 2014/07/09 18:32:48 AFAIK (and you may want to verify this) you can di
sandersd (OOO until July 31) 2014/07/09 20:07:12 Sadly that would leak memory, but I've gone ahead
scherkus (not reviewing) 2014/07/09 20:37:44 Yeah I've seen both instances in the Chromium code
143 CFDictionarySetValue(image_config, kCVPixelBufferWidthKey, cf_width);
144 CFDictionarySetValue(image_config, kCVPixelBufferHeightKey, cf_height);
145 CFDictionarySetValue(
146 image_config, kCVPixelBufferOpenGLCompatibilityKey, kCFBooleanTrue);
147 CFRelease(cf_pixel_format);
148 CFRelease(cf_width);
149 CFRelease(cf_height);
150
151 if (session_ != NULL) {
scherkus (not reviewing) 2014/07/09 18:32:49 !session_
sandersd (OOO until July 31) 2014/07/09 20:07:12 Done.
152 // TODO(sandersd): Check if the session is compatable first.
153 // TODO(sandersd): Flush frames.
154 CFRelease(session_);
155 session_ = NULL;
156 }
157
158 CHECK(!VTDecompressionSessionCreate(
159 kCFAllocatorDefault,
160 format_, // video_format_description
161 decoder_config, // video_decoder_specification
162 image_config, // destination_image_buffer_attributes
163 &callback_, // output_callback
164 &session_
165 ));
166 DVLOG(2) << "Created VTDecompressionSession";
167
168 CFRelease(decoder_config);
169 CFRelease(image_config);
32 } 170 }
33 171
34 void VTVideoDecodeAccelerator::Decode(const media::BitstreamBuffer& bitstream) { 172 void VTVideoDecodeAccelerator::Decode(const media::BitstreamBuffer& bitstream) {
35 DCHECK(CalledOnValidThread()); 173 DCHECK(CalledOnValidThread());
174 decoder_task_runner_->PostTask(FROM_HERE, base::Bind(
175 &VTVideoDecodeAccelerator::DecodeTask, weak_factory_.GetWeakPtr(),
176 bitstream));
177 }
178
179 void VTVideoDecodeAccelerator::DecodeTask(
180 const media::BitstreamBuffer bitstream) {
181 // Map the bitstream buffer.
scherkus (not reviewing) 2014/07/09 18:32:48 DCHECK(decode_thread_.message_loop_proxy()->Belong
sandersd (OOO until July 31) 2014/07/09 20:07:11 Done.
182 base::SharedMemory memory(bitstream.handle(), true);
183 size_t size = bitstream.size();
184 CHECK(memory.Map(size));
185 const uint8_t* buf = static_cast<uint8_t*>(memory.memory());
186
187 // Locate relevant NALUs in the buffer.
188 size_t data_size = 0;
189 std::vector<media::H264NALU> nalus;
190 std::vector<const uint8_t*> config_nalu_data_ptrs;
191 std::vector<size_t> config_nalu_data_sizes;
192 parser_.SetStream(buf, size);
193 media::H264NALU nalu;
194 while (true) {
195 media::H264Parser::Result result = parser_.AdvanceToNextNALU(&nalu);
196 if (result == media::H264Parser::kEOStream)
197 break;
198 CHECK(result == media::H264Parser::kOk);
scherkus (not reviewing) 2014/07/09 18:32:48 CHECK_EQ
sandersd (OOO until July 31) 2014/07/09 20:07:12 Done.
199 if (nalu.nal_unit_type == media::H264NALU::kSPS ||
200 nalu.nal_unit_type == media::H264NALU::kPPS ||
201 nalu.nal_unit_type == media::H264NALU::kSPSExt) {
202 config_nalu_data_ptrs.push_back(nalu.data);
203 config_nalu_data_sizes.push_back(nalu.size);
204 }
205 nalus.push_back(nalu);
206 data_size += 4 + nalu.size;
207 }
208
209 if (!config_nalu_data_ptrs.empty())
210 ConfigureDecoder(config_nalu_data_ptrs, config_nalu_data_sizes);
211
212 // TODO(sandersd): Rewrite slice NALU headers and send for decoding.
213 }
214
215 // This method may be called on any VideoToolbox thread.
216 void VTVideoDecodeAccelerator::Output(
217 int32_t bitstream_id,
218 OSStatus status,
219 VTDecodeInfoFlags info_flags,
220 CVImageBufferRef image_buffer) {
221 // TODO(sandersd): Store the frame in a queue.
222 CFRelease(image_buffer);
36 } 223 }
37 224
38 void VTVideoDecodeAccelerator::AssignPictureBuffers( 225 void VTVideoDecodeAccelerator::AssignPictureBuffers(
39 const std::vector<media::PictureBuffer>& pictures) { 226 const std::vector<media::PictureBuffer>& pictures) {
40 DCHECK(CalledOnValidThread()); 227 DCHECK(CalledOnValidThread());
41 } 228 }
42 229
43 void VTVideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_id) { 230 void VTVideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_id) {
44 DCHECK(CalledOnValidThread()); 231 DCHECK(CalledOnValidThread());
45 } 232 }
46 233
47 void VTVideoDecodeAccelerator::Flush() { 234 void VTVideoDecodeAccelerator::Flush() {
48 DCHECK(CalledOnValidThread()); 235 DCHECK(CalledOnValidThread());
236 // TODO(sandersd): Trigger flush, sending frames.
49 } 237 }
50 238
51 void VTVideoDecodeAccelerator::Reset() { 239 void VTVideoDecodeAccelerator::Reset() {
52 DCHECK(CalledOnValidThread()); 240 DCHECK(CalledOnValidThread());
241 // TODO(sandersd): Trigger flush, discarding frames.
53 } 242 }
54 243
55 void VTVideoDecodeAccelerator::Destroy() { 244 void VTVideoDecodeAccelerator::Destroy() {
56 DCHECK(CalledOnValidThread()); 245 DCHECK(CalledOnValidThread());
246 // TODO(sandersd): Trigger flush, discarding frames, and wait for them.
247 delete this;
57 } 248 }
58 249
59 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() { 250 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() {
60 return false; 251 return false;
61 } 252 }
62 253
63 } // namespace content 254 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698