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

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

Issue 397883002: Implement actually decoding frames in VTVideoDecodeAccelerator. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix nits. Created 6 years, 4 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') | no next file » | 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 7
8 #include "base/bind.h" 8 #include "base/bind.h"
9 #include "base/sys_byteorder.h"
9 #include "base/thread_task_runner_handle.h" 10 #include "base/thread_task_runner_handle.h"
10 #include "content/common/gpu/media/vt_video_decode_accelerator.h" 11 #include "content/common/gpu/media/vt_video_decode_accelerator.h"
11 #include "media/filters/h264_parser.h" 12 #include "media/filters/h264_parser.h"
13 #include "ui/gl/scoped_binders.h"
14 #include "ui/gl/scoped_cgl.h"
12 15
13 using content_common_gpu_media::kModuleVt; 16 using content_common_gpu_media::kModuleVt;
14 using content_common_gpu_media::InitializeStubs; 17 using content_common_gpu_media::InitializeStubs;
15 using content_common_gpu_media::IsVtInitialized; 18 using content_common_gpu_media::IsVtInitialized;
16 using content_common_gpu_media::StubPathMap; 19 using content_common_gpu_media::StubPathMap;
17 20
18 namespace content { 21 namespace content {
19 22
20 // Size of length headers prepended to NALUs in MPEG-4 framing. (1, 2, or 4.) 23 // Size of NALU length headers in AVCC/MPEG-4 format (can be 1, 2, or 4).
21 static const int kNALUHeaderLength = 4; 24 static const int kNALUHeaderLength = 4;
22 25
26 // We only request 5 picture buffers from the client which are used to hold the
27 // decoded samples. These buffers are then reused when the client tells us that
28 // it is done with the buffer.
29 static const int kNumPictureBuffers = 5;
30
23 // Route decoded frame callbacks back into the VTVideoDecodeAccelerator. 31 // Route decoded frame callbacks back into the VTVideoDecodeAccelerator.
24 static void OutputThunk( 32 static void OutputThunk(
25 void* decompression_output_refcon, 33 void* decompression_output_refcon,
26 void* source_frame_refcon, 34 void* source_frame_refcon,
27 OSStatus status, 35 OSStatus status,
28 VTDecodeInfoFlags info_flags, 36 VTDecodeInfoFlags info_flags,
29 CVImageBufferRef image_buffer, 37 CVImageBufferRef image_buffer,
30 CMTime presentation_time_stamp, 38 CMTime presentation_time_stamp,
31 CMTime presentation_duration) { 39 CMTime presentation_duration) {
40 // TODO(sandersd): Implement flush-before-delete to guarantee validity.
32 VTVideoDecodeAccelerator* vda = 41 VTVideoDecodeAccelerator* vda =
33 reinterpret_cast<VTVideoDecodeAccelerator*>(decompression_output_refcon); 42 reinterpret_cast<VTVideoDecodeAccelerator*>(decompression_output_refcon);
34 int32_t* bitstream_id_ptr = reinterpret_cast<int32_t*>(source_frame_refcon); 43 int32_t bitstream_id = reinterpret_cast<intptr_t>(source_frame_refcon);
Pawel Osciak 2014/08/03 04:26:30 I meant reinterpret_cast<int32_t>...
35 int32_t bitstream_id = *bitstream_id_ptr; 44 vda->Output(bitstream_id, status, image_buffer);
36 delete bitstream_id_ptr; 45 }
37 CFRetain(image_buffer); 46
38 vda->Output(bitstream_id, status, info_flags, image_buffer); 47 VTVideoDecodeAccelerator::DecodedFrame::DecodedFrame(
48 int32_t bitstream_id,
49 CVImageBufferRef image_buffer)
50 : bitstream_id(bitstream_id),
51 image_buffer(image_buffer) {
52 }
53
54 VTVideoDecodeAccelerator::DecodedFrame::~DecodedFrame() {
39 } 55 }
40 56
41 VTVideoDecodeAccelerator::VTVideoDecodeAccelerator(CGLContextObj cgl_context) 57 VTVideoDecodeAccelerator::VTVideoDecodeAccelerator(CGLContextObj cgl_context)
42 : cgl_context_(cgl_context), 58 : cgl_context_(cgl_context),
43 client_(NULL), 59 client_(NULL),
44 decoder_thread_("VTDecoderThread"),
45 format_(NULL), 60 format_(NULL),
46 session_(NULL), 61 session_(NULL),
47 weak_this_factory_(this) { 62 gpu_task_runner_(base::ThreadTaskRunnerHandle::Get()),
63 weak_this_factory_(this),
64 decoder_thread_("VTDecoderThread") {
48 callback_.decompressionOutputCallback = OutputThunk; 65 callback_.decompressionOutputCallback = OutputThunk;
49 callback_.decompressionOutputRefCon = this; 66 callback_.decompressionOutputRefCon = this;
50 } 67 }
51 68
52 VTVideoDecodeAccelerator::~VTVideoDecodeAccelerator() { 69 VTVideoDecodeAccelerator::~VTVideoDecodeAccelerator() {
53 } 70 }
54 71
55 bool VTVideoDecodeAccelerator::Initialize( 72 bool VTVideoDecodeAccelerator::Initialize(
56 media::VideoCodecProfile profile, 73 media::VideoCodecProfile profile,
57 Client* client) { 74 Client* client) {
58 DCHECK(CalledOnValidThread()); 75 DCHECK(CalledOnValidThread());
59 client_ = client; 76 client_ = client;
60 77
61 // Only H.264 is supported. 78 // Only H.264 is supported.
62 if (profile < media::H264PROFILE_MIN || profile > media::H264PROFILE_MAX) 79 if (profile < media::H264PROFILE_MIN || profile > media::H264PROFILE_MAX)
63 return false; 80 return false;
64 81
65 // TODO(sandersd): Move VideoToolbox library loading to sandbox startup; 82 // TODO(sandersd): Move VideoToolbox library loading to sandbox startup;
66 // until then, --no-sandbox is required. 83 // until then, --no-sandbox is required.
67 if (!IsVtInitialized()) { 84 if (!IsVtInitialized()) {
68 StubPathMap paths;
69 // CoreVideo is also required, but the loader stops after the first 85 // CoreVideo is also required, but the loader stops after the first
70 // path is loaded. Instead we rely on the transitive dependency from 86 // path is loaded. Instead we rely on the transitive dependency from
71 // VideoToolbox to CoreVideo. 87 // VideoToolbox to CoreVideo.
72 // TODO(sandersd): Fallback to PrivateFrameworks for VideoToolbox. 88 // TODO(sandersd): Fallback to PrivateFrameworks for VideoToolbox.
89 StubPathMap paths;
73 paths[kModuleVt].push_back(FILE_PATH_LITERAL( 90 paths[kModuleVt].push_back(FILE_PATH_LITERAL(
74 "/System/Library/Frameworks/VideoToolbox.framework/VideoToolbox")); 91 "/System/Library/Frameworks/VideoToolbox.framework/VideoToolbox"));
75 if (!InitializeStubs(paths)) 92 if (!InitializeStubs(paths))
76 return false; 93 return false;
77 } 94 }
78 95
79 // Spawn a thread to handle parsing and calling VideoToolbox. 96 // Spawn a thread to handle parsing and calling VideoToolbox.
80 if (!decoder_thread_.Start()) 97 if (!decoder_thread_.Start())
81 return false; 98 return false;
82 99
83 // Note that --ignore-gpu-blacklist is still required to get here. 100 // Note that --ignore-gpu-blacklist is still required to get here.
84 return true; 101 return true;
85 } 102 }
86 103
87 // TODO(sandersd): Proper error reporting instead of CHECKs. 104 // TODO(sandersd): Proper error reporting instead of CHECKs.
88 void VTVideoDecodeAccelerator::ConfigureDecoder( 105 void VTVideoDecodeAccelerator::ConfigureDecoder(
89 const std::vector<const uint8_t*>& nalu_data_ptrs, 106 const std::vector<const uint8_t*>& nalu_data_ptrs,
90 const std::vector<size_t>& nalu_data_sizes) { 107 const std::vector<size_t>& nalu_data_sizes) {
108 DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread());
109 // Construct a new format description from the parameter sets.
110 // TODO(sandersd): Replace this with custom code to support OS X < 10.9.
91 format_.reset(); 111 format_.reset();
92 CHECK(!CMVideoFormatDescriptionCreateFromH264ParameterSets( 112 CHECK(!CMVideoFormatDescriptionCreateFromH264ParameterSets(
93 kCFAllocatorDefault, 113 kCFAllocatorDefault,
94 nalu_data_ptrs.size(), // parameter_set_count 114 nalu_data_ptrs.size(), // parameter_set_count
95 &nalu_data_ptrs.front(), // &parameter_set_pointers 115 &nalu_data_ptrs.front(), // &parameter_set_pointers
96 &nalu_data_sizes.front(), // &parameter_set_sizes 116 &nalu_data_sizes.front(), // &parameter_set_sizes
97 kNALUHeaderLength, // nal_unit_header_length 117 kNALUHeaderLength, // nal_unit_header_length
98 format_.InitializeInto() 118 format_.InitializeInto()));
99 )); 119 CMVideoDimensions coded_dimensions =
120 CMVideoFormatDescriptionGetDimensions(format_);
100 121
101 // TODO(sandersd): Check if the size has changed and handle picture requests. 122 // Prepare VideoToolbox configuration dictionaries.
102 CMVideoDimensions coded_size = CMVideoFormatDescriptionGetDimensions(format_);
103 coded_size_.SetSize(coded_size.width, coded_size.height);
104
105 base::ScopedCFTypeRef<CFMutableDictionaryRef> decoder_config( 123 base::ScopedCFTypeRef<CFMutableDictionaryRef> decoder_config(
106 CFDictionaryCreateMutable( 124 CFDictionaryCreateMutable(
107 kCFAllocatorDefault, 125 kCFAllocatorDefault,
108 1, // capacity 126 1, // capacity
109 &kCFTypeDictionaryKeyCallBacks, 127 &kCFTypeDictionaryKeyCallBacks,
110 &kCFTypeDictionaryValueCallBacks)); 128 &kCFTypeDictionaryValueCallBacks));
111 129
112 CFDictionarySetValue( 130 CFDictionarySetValue(
113 decoder_config, 131 decoder_config,
114 // kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder 132 // kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder
115 CFSTR("EnableHardwareAcceleratedVideoDecoder"), 133 CFSTR("EnableHardwareAcceleratedVideoDecoder"),
116 kCFBooleanTrue); 134 kCFBooleanTrue);
117 135
118 base::ScopedCFTypeRef<CFMutableDictionaryRef> image_config( 136 base::ScopedCFTypeRef<CFMutableDictionaryRef> image_config(
119 CFDictionaryCreateMutable( 137 CFDictionaryCreateMutable(
120 kCFAllocatorDefault, 138 kCFAllocatorDefault,
121 4, // capacity 139 4, // capacity
122 &kCFTypeDictionaryKeyCallBacks, 140 &kCFTypeDictionaryKeyCallBacks,
123 &kCFTypeDictionaryValueCallBacks)); 141 &kCFTypeDictionaryValueCallBacks));
124 142
125 // TODO(sandersd): ARGB for video that is not 4:2:0.
126 int32_t pixel_format = '2vuy';
127 #define CFINT(i) CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i) 143 #define CFINT(i) CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i)
144 // TODO(sandersd): RGBA option for 4:4:4 video.
145 int32_t pixel_format = kCVPixelFormatType_422YpCbCr8;
128 base::ScopedCFTypeRef<CFNumberRef> cf_pixel_format(CFINT(pixel_format)); 146 base::ScopedCFTypeRef<CFNumberRef> cf_pixel_format(CFINT(pixel_format));
129 base::ScopedCFTypeRef<CFNumberRef> cf_width(CFINT(coded_size.width)); 147 base::ScopedCFTypeRef<CFNumberRef> cf_width(CFINT(coded_dimensions.width));
130 base::ScopedCFTypeRef<CFNumberRef> cf_height(CFINT(coded_size.height)); 148 base::ScopedCFTypeRef<CFNumberRef> cf_height(CFINT(coded_dimensions.height));
131 #undef CFINT 149 #undef CFINT
132 CFDictionarySetValue( 150 CFDictionarySetValue(
133 image_config, kCVPixelBufferPixelFormatTypeKey, cf_pixel_format); 151 image_config, kCVPixelBufferPixelFormatTypeKey, cf_pixel_format);
134 CFDictionarySetValue(image_config, kCVPixelBufferWidthKey, cf_width); 152 CFDictionarySetValue(image_config, kCVPixelBufferWidthKey, cf_width);
135 CFDictionarySetValue(image_config, kCVPixelBufferHeightKey, cf_height); 153 CFDictionarySetValue(image_config, kCVPixelBufferHeightKey, cf_height);
136 CFDictionarySetValue( 154 CFDictionarySetValue(
137 image_config, kCVPixelBufferOpenGLCompatibilityKey, kCFBooleanTrue); 155 image_config, kCVPixelBufferOpenGLCompatibilityKey, kCFBooleanTrue);
138 156
139 // TODO(sandersd): Skip if the session is compatible. 157 // TODO(sandersd): Check if the session is already compatible.
140 // TODO(sandersd): Flush frames when resetting. 158 // TODO(sandersd): Flush.
141 session_.reset(); 159 session_.reset();
142 CHECK(!VTDecompressionSessionCreate( 160 CHECK(!VTDecompressionSessionCreate(
143 kCFAllocatorDefault, 161 kCFAllocatorDefault,
144 format_, // video_format_description 162 format_, // video_format_description
145 decoder_config, // video_decoder_specification 163 decoder_config, // video_decoder_specification
146 image_config, // destination_image_buffer_attributes 164 image_config, // destination_image_buffer_attributes
147 &callback_, // output_callback 165 &callback_, // output_callback
148 session_.InitializeInto() 166 session_.InitializeInto()));
149 )); 167
150 DVLOG(2) << "Created VTDecompressionSession"; 168 // If the size has changed, trigger a request for new picture buffers.
169 gfx::Size new_coded_size(coded_dimensions.width, coded_dimensions.height);
170 if (coded_size_ != new_coded_size) {
171 coded_size_ = new_coded_size;
172 gpu_task_runner_->PostTask(FROM_HERE, base::Bind(
173 &VTVideoDecodeAccelerator::SizeChangedTask,
174 weak_this_factory_.GetWeakPtr(),
175 coded_size_));;
176 }
151 } 177 }
152 178
153 void VTVideoDecodeAccelerator::Decode(const media::BitstreamBuffer& bitstream) { 179 void VTVideoDecodeAccelerator::Decode(const media::BitstreamBuffer& bitstream) {
154 DCHECK(CalledOnValidThread()); 180 DCHECK(CalledOnValidThread());
181 // TODO(sandersd): Test what happens if bitstream buffers are passed to VT out
182 // of order.
155 decoder_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind( 183 decoder_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind(
156 &VTVideoDecodeAccelerator::DecodeTask, base::Unretained(this), 184 &VTVideoDecodeAccelerator::DecodeTask, base::Unretained(this),
157 bitstream)); 185 bitstream));
158 } 186 }
159 187
188 // TODO(sandersd): Proper error reporting instead of CHECKs.
160 void VTVideoDecodeAccelerator::DecodeTask( 189 void VTVideoDecodeAccelerator::DecodeTask(
161 const media::BitstreamBuffer bitstream) { 190 const media::BitstreamBuffer bitstream) {
162 DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread()); 191 DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread());
163 192
164 // Map the bitstream buffer. 193 // Map the bitstream buffer.
165 base::SharedMemory memory(bitstream.handle(), true); 194 base::SharedMemory memory(bitstream.handle(), true);
166 size_t size = bitstream.size(); 195 size_t size = bitstream.size();
167 CHECK(memory.Map(size)); 196 CHECK(memory.Map(size));
168 const uint8_t* buf = static_cast<uint8_t*>(memory.memory()); 197 const uint8_t* buf = static_cast<uint8_t*>(memory.memory());
169 198
170 // Locate relevant NALUs in the buffer. 199 // NALUs are stored with Annex B format in the bitstream buffer (start codes),
200 // but VideoToolbox expects AVCC/MPEG-4 format (length headers), so we must
201 // rewrite the data.
202 //
203 // 1. Locate relevant NALUs and compute the size of the translated data.
204 // Also record any parameter sets for VideoToolbox initialization.
171 size_t data_size = 0; 205 size_t data_size = 0;
172 std::vector<media::H264NALU> nalus; 206 std::vector<media::H264NALU> nalus;
173 std::vector<const uint8_t*> config_nalu_data_ptrs; 207 std::vector<const uint8_t*> config_nalu_data_ptrs;
174 std::vector<size_t> config_nalu_data_sizes; 208 std::vector<size_t> config_nalu_data_sizes;
175 parser_.SetStream(buf, size); 209 parser_.SetStream(buf, size);
176 media::H264NALU nalu; 210 media::H264NALU nalu;
177 while (true) { 211 while (true) {
178 media::H264Parser::Result result = parser_.AdvanceToNextNALU(&nalu); 212 media::H264Parser::Result result = parser_.AdvanceToNextNALU(&nalu);
179 if (result == media::H264Parser::kEOStream) 213 if (result == media::H264Parser::kEOStream)
180 break; 214 break;
181 CHECK_EQ(result, media::H264Parser::kOk); 215 CHECK_EQ(result, media::H264Parser::kOk);
216 // TODO(sandersd): Check that these are only at the start.
182 if (nalu.nal_unit_type == media::H264NALU::kSPS || 217 if (nalu.nal_unit_type == media::H264NALU::kSPS ||
183 nalu.nal_unit_type == media::H264NALU::kPPS || 218 nalu.nal_unit_type == media::H264NALU::kPPS ||
184 nalu.nal_unit_type == media::H264NALU::kSPSExt) { 219 nalu.nal_unit_type == media::H264NALU::kSPSExt) {
220 DVLOG(2) << "Parameter set " << nalu.nal_unit_type;
185 config_nalu_data_ptrs.push_back(nalu.data); 221 config_nalu_data_ptrs.push_back(nalu.data);
186 config_nalu_data_sizes.push_back(nalu.size); 222 config_nalu_data_sizes.push_back(nalu.size);
223 } else {
224 nalus.push_back(nalu);
225 data_size += kNALUHeaderLength + nalu.size;
187 } 226 }
188 nalus.push_back(nalu);
189 // Each NALU will have a 4-byte length header prepended.
190 data_size += kNALUHeaderLength + nalu.size;
191 } 227 }
192 228
193 if (!config_nalu_data_ptrs.empty()) 229 // 2. Initialize VideoToolbox.
230 // TODO(sandersd): Reinitialize when there are new parameter sets.
231 if (!session_)
194 ConfigureDecoder(config_nalu_data_ptrs, config_nalu_data_sizes); 232 ConfigureDecoder(config_nalu_data_ptrs, config_nalu_data_sizes);
195 233
196 // TODO(sandersd): Rewrite slice NALU headers and send for decoding. 234 // 3. Allocate a memory-backed CMBlockBuffer for the translated data.
235 base::ScopedCFTypeRef<CMBlockBufferRef> data;
236 CHECK(!CMBlockBufferCreateWithMemoryBlock(
237 kCFAllocatorDefault,
238 NULL, // &memory_block
239 data_size, // block_length
240 kCFAllocatorDefault, // block_allocator
241 NULL, // &custom_block_source
242 0, // offset_to_data
243 data_size, // data_length
244 0, // flags
245 data.InitializeInto()));
246
247 // 4. Copy NALU data, inserting length headers.
248 size_t offset = 0;
249 for (size_t i = 0; i < nalus.size(); i++) {
250 media::H264NALU& nalu = nalus[i];
251 uint32_t header = base::HostToNet32(checked_cast<uint32_t>(nalu.size));
252 CHECK(!CMBlockBufferReplaceDataBytes(
253 &header, data, offset, kNALUHeaderLength));
254 offset += kNALUHeaderLength;
255 CHECK(!CMBlockBufferReplaceDataBytes(nalu.data, data, offset, nalu.size));
256 offset += nalu.size;
257 }
258
259 // 5. Package the data for VideoToolbox and request decoding.
260 base::ScopedCFTypeRef<CMSampleBufferRef> frame;
261 CHECK(!CMSampleBufferCreate(
262 kCFAllocatorDefault,
263 data, // data_buffer
264 true, // data_ready
265 NULL, // make_data_ready_callback
266 NULL, // make_data_ready_refcon
267 format_, // format_description
268 1, // num_samples
269 0, // num_sample_timing_entries
270 NULL, // &sample_timing_array
271 0, // num_sample_size_entries
272 NULL, // &sample_size_array
273 frame.InitializeInto()));
274
275 // Asynchronous Decompression allows for parallel submission of frames
276 // (without it, DecodeFrame() does not return until the frame has been
277 // decoded). We don't enable Temporal Processing so that frames are always
278 // returned in decode order; this makes it easier to avoid deadlock.
279 VTDecodeFrameFlags decode_flags =
280 kVTDecodeFrame_EnableAsynchronousDecompression;
281
282 intptr_t bitstream_id = bitstream.id();
283 CHECK(!VTDecompressionSessionDecodeFrame(
284 session_,
285 frame, // sample_buffer
286 decode_flags, // decode_flags
287 reinterpret_cast<void*>(bitstream_id), // source_frame_refcon
288 NULL)); // &info_flags_out
197 } 289 }
198 290
199 // This method may be called on any VideoToolbox thread. 291 // This method may be called on any VideoToolbox thread.
292 // TODO(sandersd): Proper error reporting instead of CHECKs.
200 void VTVideoDecodeAccelerator::Output( 293 void VTVideoDecodeAccelerator::Output(
201 int32_t bitstream_id, 294 int32_t bitstream_id,
202 OSStatus status, 295 OSStatus status,
203 VTDecodeInfoFlags info_flags,
204 CVImageBufferRef image_buffer) { 296 CVImageBufferRef image_buffer) {
205 // TODO(sandersd): Store the frame in a queue. 297 CHECK(!status);
206 CFRelease(image_buffer); 298 CHECK_EQ(CFGetTypeID(image_buffer), CVPixelBufferGetTypeID());
299 CFRetain(image_buffer);
300 gpu_task_runner_->PostTask(FROM_HERE, base::Bind(
301 &VTVideoDecodeAccelerator::OutputTask,
302 weak_this_factory_.GetWeakPtr(),
303 DecodedFrame(bitstream_id, image_buffer)));
304 }
305
306 void VTVideoDecodeAccelerator::OutputTask(DecodedFrame frame) {
307 DCHECK(CalledOnValidThread());
308 decoded_frames_.push(frame);
309 SendPictures();
310 }
311
312 void VTVideoDecodeAccelerator::SizeChangedTask(gfx::Size coded_size) {
313 DCHECK(CalledOnValidThread());
314 texture_size_ = coded_size;
315 // TODO(sandersd): Dismiss existing picture buffers.
316 client_->ProvidePictureBuffers(
317 kNumPictureBuffers, texture_size_, GL_TEXTURE_RECTANGLE_ARB);
207 } 318 }
208 319
209 void VTVideoDecodeAccelerator::AssignPictureBuffers( 320 void VTVideoDecodeAccelerator::AssignPictureBuffers(
210 const std::vector<media::PictureBuffer>& pictures) { 321 const std::vector<media::PictureBuffer>& pictures) {
211 DCHECK(CalledOnValidThread()); 322 DCHECK(CalledOnValidThread());
323
324 for (size_t i = 0; i < pictures.size(); i++) {
325 CHECK(!available_picture_ids_.count(pictures[i].id()));
Pawel Osciak 2014/08/03 04:26:30 Nice, pretty crafty!
sandersd (OOO until July 31) 2014/08/04 19:24:20 Turns out to be wrong to :-(
326 available_picture_ids_.push(pictures[i].id());
327 texture_ids_[pictures[i].id()] = pictures[i].texture_id();
Pawel Osciak 2014/08/03 04:26:30 Should probably check this is empty too though...?
sandersd (OOO until July 31) 2014/08/04 19:24:20 This is a better plan.
328 }
329
330 // Pictures are not marked as uncleared until this method returns. They will
331 // become broken if they are used before that happens.
332 gpu_task_runner_->PostTask(FROM_HERE, base::Bind(
333 &VTVideoDecodeAccelerator::SendPictures,
334 weak_this_factory_.GetWeakPtr()));
212 } 335 }
213 336
214 void VTVideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_id) { 337 void VTVideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_id) {
215 DCHECK(CalledOnValidThread()); 338 DCHECK(CalledOnValidThread());
339 DCHECK_EQ(CFGetRetainCount(picture_bindings_[picture_id]), 1);
340 picture_bindings_.erase(picture_id);
341 available_picture_ids_.push(picture_id);
342 SendPictures();
343 }
344
345 // TODO(sandersd): Proper error reporting instead of CHECKs.
346 void VTVideoDecodeAccelerator::SendPictures() {
347 DCHECK(CalledOnValidThread());
348 if (available_picture_ids_.empty() || decoded_frames_.empty())
349 return;
350
351 gfx::ScopedCGLSetCurrentContext scoped_set_current_context(cgl_context_);
352 glEnable(GL_TEXTURE_RECTANGLE_ARB);
353
354 while (!available_picture_ids_.empty() && !decoded_frames_.empty()) {
355 int32_t picture_id = available_picture_ids_.front();
356 available_picture_ids_.pop();
357 DecodedFrame frame = decoded_frames_.front();
358 decoded_frames_.pop();
359 IOSurfaceRef surface = CVPixelBufferGetIOSurface(frame.image_buffer);
360
361 gfx::ScopedTextureBinder
362 texture_binder(GL_TEXTURE_RECTANGLE_ARB, texture_ids_[picture_id]);
363 CHECK(!CGLTexImageIOSurface2D(
364 cgl_context_, // ctx
365 GL_TEXTURE_RECTANGLE_ARB, // target
366 GL_RGB, // internal_format
367 texture_size_.width(), // width
368 texture_size_.height(), // height
369 GL_YCBCR_422_APPLE, // format
370 GL_UNSIGNED_SHORT_8_8_APPLE, // type
371 surface, // io_surface
372 0)); // plane
373
374 picture_bindings_[picture_id] = frame.image_buffer;
375 client_->PictureReady(media::Picture(picture_id, frame.bitstream_id));
376 client_->NotifyEndOfBitstreamBuffer(frame.bitstream_id);
377 }
378
379 glDisable(GL_TEXTURE_RECTANGLE_ARB);
216 } 380 }
217 381
218 void VTVideoDecodeAccelerator::Flush() { 382 void VTVideoDecodeAccelerator::Flush() {
219 DCHECK(CalledOnValidThread()); 383 DCHECK(CalledOnValidThread());
220 // TODO(sandersd): Trigger flush, sending frames. 384 // TODO(sandersd): Trigger flush, sending frames.
221 } 385 }
222 386
223 void VTVideoDecodeAccelerator::Reset() { 387 void VTVideoDecodeAccelerator::Reset() {
224 DCHECK(CalledOnValidThread()); 388 DCHECK(CalledOnValidThread());
225 // TODO(sandersd): Trigger flush, discarding frames. 389 // TODO(sandersd): Trigger flush, discarding frames.
226 } 390 }
227 391
228 void VTVideoDecodeAccelerator::Destroy() { 392 void VTVideoDecodeAccelerator::Destroy() {
229 DCHECK(CalledOnValidThread()); 393 DCHECK(CalledOnValidThread());
230 // TODO(sandersd): Trigger flush, discarding frames, and wait for them. 394 // TODO(sandersd): Trigger flush, discarding frames, and wait for them.
231 delete this; 395 delete this;
232 } 396 }
233 397
234 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() { 398 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() {
235 return false; 399 return false;
236 } 400 }
237 401
238 } // namespace content 402 } // namespace content
OLDNEW
« no previous file with comments | « content/common/gpu/media/vt_video_decode_accelerator.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698