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

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: gfx::Size 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
« no previous file with comments | « content/common/gpu/media/vt_video_decode_accelerator.h ('k') | content/content_common.gypi » ('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>
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 : cgl_context_(cgl_context),
11 cgl_context_(cgl_context),
12 client_(NULL), 40 client_(NULL),
41 decoder_thread_("VTDecoderThread"),
42 format_(NULL),
43 session_(NULL),
13 weak_this_factory_(this) { 44 weak_this_factory_(this) {
45 callback_.decompressionOutputCallback = OutputThunk;
46 callback_.decompressionOutputRefCon = this;
14 } 47 }
15 48
16 VTVideoDecodeAccelerator::~VTVideoDecodeAccelerator() { 49 VTVideoDecodeAccelerator::~VTVideoDecodeAccelerator() {
17 } 50 }
18 51
19 bool VTVideoDecodeAccelerator::Initialize( 52 bool VTVideoDecodeAccelerator::Initialize(
20 media::VideoCodecProfile profile, 53 media::VideoCodecProfile profile,
21 Client* client) { 54 Client* client) {
22 DCHECK(CalledOnValidThread()); 55 DCHECK(CalledOnValidThread());
23 DVLOG(2) << __FUNCTION__;
24 client_ = client; 56 client_ = client;
25 57
26 // Only H.264 is supported. 58 // Only H.264 is supported.
27 if (profile < media::H264PROFILE_MIN || profile > media::H264PROFILE_MAX) 59 if (profile < media::H264PROFILE_MIN || profile > media::H264PROFILE_MAX)
28 return false; 60 return false;
29 61
30 // Prevent anyone from using VTVideoDecoder for now. http://crbug.com/133828 62 // TODO(sandersd): Move VideoToolbox library loading to sandbox startup;
31 return false; 63 // until then, --no-sandbox is required.
64 if (!IsVtInitialized()) {
65 StubPathMap paths;
66 // CoreVideo is also required, but the loader stops after the first
67 // path is loaded. Instead we rely on the transitive dependency from
68 // VideoToolbox to CoreVideo.
69 // TODO(sandersd): Fallback to PrivateFrameworks for VideoToolbox.
70 paths[kModuleVt].push_back(FILE_PATH_LITERAL(
71 "/System/Library/Frameworks/VideoToolbox.framework/VideoToolbox"));
72 if (!InitializeStubs(paths))
73 return false;
74 }
75
76 // Spawn a thread to handle parsing and calling VideoToolbox.
77 if (!decoder_thread_.Start())
78 return false;
79
80 // Note that --ignore-gpu-blacklist is still required to get here.
81 return true;
82 }
83
84 // TODO(sandersd): Proper error reporting instead of CHECKs.
85 void VTVideoDecodeAccelerator::ConfigureDecoder(
86 const std::vector<const uint8_t*>& nalu_data_ptrs,
87 const std::vector<size_t>& nalu_data_sizes) {
88 format_.reset();
89 CHECK(!CMVideoFormatDescriptionCreateFromH264ParameterSets(
90 kCFAllocatorDefault,
91 nalu_data_ptrs.size(), // parameter_set_count
92 &nalu_data_ptrs.front(), // &parameter_set_pointers
93 &nalu_data_sizes.front(), // &parameter_set_sizes
94 4, // nal_unit_header_length
95 format_.InitializeInto()
96 ));
97
98 // TODO(sandersd): Check if the size has changed and handle picture requests.
99 CMVideoDimensions coded_size = CMVideoFormatDescriptionGetDimensions(format_);
100 coded_size_.SetSize(coded_size.width, coded_size.height);
101
102 base::ScopedCFTypeRef<CFMutableDictionaryRef> decoder_config(
103 CFDictionaryCreateMutable(
104 kCFAllocatorDefault,
105 1, // capacity
106 &kCFTypeDictionaryKeyCallBacks,
107 &kCFTypeDictionaryValueCallBacks));
108
109 CFDictionarySetValue(
110 decoder_config,
111 // kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder
112 CFSTR("EnableHardwareAcceleratedVideoDecoder"),
113 kCFBooleanTrue);
114
115 base::ScopedCFTypeRef<CFMutableDictionaryRef> image_config(
116 CFDictionaryCreateMutable(
117 kCFAllocatorDefault,
118 4, // capacity
119 &kCFTypeDictionaryKeyCallBacks,
120 &kCFTypeDictionaryValueCallBacks));
121
122 // TODO(sandersd): ARGB for video that is not 4:2:0.
123 int32_t pixel_format = '2vuy';
124 #define CFINT(i) CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i)
125 base::ScopedCFTypeRef<CFNumberRef> cf_pixel_format(CFINT(pixel_format));
126 base::ScopedCFTypeRef<CFNumberRef> cf_width(CFINT(coded_size.width));
127 base::ScopedCFTypeRef<CFNumberRef> cf_height(CFINT(coded_size.height));
128 #undef CFINT
129 CFDictionarySetValue(
130 image_config, kCVPixelBufferPixelFormatTypeKey, cf_pixel_format);
131 CFDictionarySetValue(image_config, kCVPixelBufferWidthKey, cf_width);
132 CFDictionarySetValue(image_config, kCVPixelBufferHeightKey, cf_height);
133 CFDictionarySetValue(
134 image_config, kCVPixelBufferOpenGLCompatibilityKey, kCFBooleanTrue);
135
136 // TODO(sandersd): Skip if the session is compatable.
137 // TODO(sandersd): Flush frames when resetting.
138 session_.reset();
139 CHECK(!VTDecompressionSessionCreate(
140 kCFAllocatorDefault,
141 format_, // video_format_description
142 decoder_config, // video_decoder_specification
143 image_config, // destination_image_buffer_attributes
144 &callback_, // output_callback
145 session_.InitializeInto()
146 ));
147 DVLOG(2) << "Created VTDecompressionSession";
32 } 148 }
33 149
34 void VTVideoDecodeAccelerator::Decode(const media::BitstreamBuffer& bitstream) { 150 void VTVideoDecodeAccelerator::Decode(const media::BitstreamBuffer& bitstream) {
35 DCHECK(CalledOnValidThread()); 151 DCHECK(CalledOnValidThread());
152 decoder_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind(
153 &VTVideoDecodeAccelerator::DecodeTask, base::Unretained(this),
154 bitstream));
155 }
156
157 void VTVideoDecodeAccelerator::DecodeTask(
158 const media::BitstreamBuffer bitstream) {
159 DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread());
160
161 // Map the bitstream buffer.
162 base::SharedMemory memory(bitstream.handle(), true);
163 size_t size = bitstream.size();
164 CHECK(memory.Map(size));
165 const uint8_t* buf = static_cast<uint8_t*>(memory.memory());
166
167 // Locate relevant NALUs in the buffer.
168 size_t data_size = 0;
169 std::vector<media::H264NALU> nalus;
170 std::vector<const uint8_t*> config_nalu_data_ptrs;
171 std::vector<size_t> config_nalu_data_sizes;
172 parser_.SetStream(buf, size);
173 media::H264NALU nalu;
174 while (true) {
175 media::H264Parser::Result result = parser_.AdvanceToNextNALU(&nalu);
176 if (result == media::H264Parser::kEOStream)
177 break;
178 CHECK_EQ(result, media::H264Parser::kOk);
179 if (nalu.nal_unit_type == media::H264NALU::kSPS ||
180 nalu.nal_unit_type == media::H264NALU::kPPS ||
181 nalu.nal_unit_type == media::H264NALU::kSPSExt) {
182 config_nalu_data_ptrs.push_back(nalu.data);
183 config_nalu_data_sizes.push_back(nalu.size);
184 }
185 nalus.push_back(nalu);
186 // Each NALU will have a 4-byte length header prepended.
Pawel Osciak 2014/07/10 00:43:12 Is this header something VT-specific?
sandersd (OOO until July 31) 2014/07/10 00:47:52 Yes, VT expects AVCC formatting.
187 data_size += 4 + nalu.size;
188 }
189
190 if (!config_nalu_data_ptrs.empty())
191 ConfigureDecoder(config_nalu_data_ptrs, config_nalu_data_sizes);
192
193 // TODO(sandersd): Rewrite slice NALU headers and send for decoding.
194 }
195
196 // This method may be called on any VideoToolbox thread.
197 void VTVideoDecodeAccelerator::Output(
198 int32_t bitstream_id,
199 OSStatus status,
200 VTDecodeInfoFlags info_flags,
201 CVImageBufferRef image_buffer) {
202 // TODO(sandersd): Store the frame in a queue.
203 CFRelease(image_buffer);
36 } 204 }
37 205
38 void VTVideoDecodeAccelerator::AssignPictureBuffers( 206 void VTVideoDecodeAccelerator::AssignPictureBuffers(
39 const std::vector<media::PictureBuffer>& pictures) { 207 const std::vector<media::PictureBuffer>& pictures) {
40 DCHECK(CalledOnValidThread()); 208 DCHECK(CalledOnValidThread());
41 } 209 }
42 210
43 void VTVideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_id) { 211 void VTVideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_id) {
44 DCHECK(CalledOnValidThread()); 212 DCHECK(CalledOnValidThread());
45 } 213 }
46 214
47 void VTVideoDecodeAccelerator::Flush() { 215 void VTVideoDecodeAccelerator::Flush() {
48 DCHECK(CalledOnValidThread()); 216 DCHECK(CalledOnValidThread());
217 // TODO(sandersd): Trigger flush, sending frames.
49 } 218 }
50 219
51 void VTVideoDecodeAccelerator::Reset() { 220 void VTVideoDecodeAccelerator::Reset() {
52 DCHECK(CalledOnValidThread()); 221 DCHECK(CalledOnValidThread());
222 // TODO(sandersd): Trigger flush, discarding frames.
53 } 223 }
54 224
55 void VTVideoDecodeAccelerator::Destroy() { 225 void VTVideoDecodeAccelerator::Destroy() {
56 DCHECK(CalledOnValidThread()); 226 DCHECK(CalledOnValidThread());
227 // TODO(sandersd): Trigger flush, discarding frames, and wait for them.
228 delete this;
57 } 229 }
58 230
59 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() { 231 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() {
60 return false; 232 return false;
61 } 233 }
62 234
63 } // namespace content 235 } // namespace content
OLDNEW
« no previous file with comments | « content/common/gpu/media/vt_video_decode_accelerator.h ('k') | content/content_common.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698