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

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

Powered by Google App Engine
This is Rietveld 408576698