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

Side by Side Diff: content/common/gpu/media/mac_video_decode_accelerator.mm

Issue 10411085: Build AVC decoder configuration record (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix compontent build Created 8 years, 6 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "content/common/gpu/media/mac_video_decode_accelerator.h" 5 #include "content/common/gpu/media/mac_video_decode_accelerator.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/file_path.h" 8 #include "base/file_path.h"
9 #import "base/mac/foundation_util.h" 9 #import "base/mac/foundation_util.h"
10 #import "base/memory/ref_counted_memory.h" 10 #import "base/memory/ref_counted_memory.h"
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
88 0) != kCGLNoError) { 88 0) != kCGLNoError) {
89 DVLOG(1) << "Failed to bind image to texture."; 89 DVLOG(1) << "Failed to bind image to texture.";
90 return false; 90 return false;
91 } 91 }
92 return glGetError() == GL_NO_ERROR; 92 return glGetError() == GL_NO_ERROR;
93 } 93 }
94 94
95 MacVideoDecodeAccelerator::MacVideoDecodeAccelerator( 95 MacVideoDecodeAccelerator::MacVideoDecodeAccelerator(
96 media::VideoDecodeAccelerator::Client* client) 96 media::VideoDecodeAccelerator::Client* client)
97 : client_(client), 97 : client_(client),
98 cgl_context_(NULL), 98 cgl_context_(NULL) {
99 nalu_len_field_size_(0),
100 did_request_pictures_(false) {
101 } 99 }
102 100
103 void MacVideoDecodeAccelerator::SetCGLContext(CGLContextObj cgl_context) { 101 void MacVideoDecodeAccelerator::SetCGLContext(CGLContextObj cgl_context) {
104 DCHECK(CalledOnValidThread()); 102 DCHECK(CalledOnValidThread());
105 cgl_context_ = cgl_context; 103 cgl_context_ = cgl_context;
106 } 104 }
107 105
108 bool MacVideoDecodeAccelerator::SetConfigInfo(
109 uint32_t frame_width,
110 uint32_t frame_height,
111 const std::vector<uint8_t>& avc_data) {
112 DCHECK(CalledOnValidThread());
113 frame_size_ = gfx::Size(frame_width, frame_height);
114 nalu_len_field_size_ = (avc_data[4] & 0x03) + 1;
115
116 DCHECK(!vda_support_.get());
117 vda_support_ = new gfx::VideoDecodeAccelerationSupport();
118 gfx::VideoDecodeAccelerationSupport::Status status = vda_support_->Create(
119 frame_size_.width(), frame_size_.height(), kCVPixelFormatType_422YpCbCr8,
120 &avc_data.front(), avc_data.size());
121 RETURN_ON_FAILURE(status == gfx::VideoDecodeAccelerationSupport::SUCCESS,
122 "Creating video decoder failed with error: " << status,
123 PLATFORM_FAILURE, false);
124 return true;
125 }
126
127 bool MacVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile) { 106 bool MacVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile) {
128 DCHECK(CalledOnValidThread()); 107 DCHECK(CalledOnValidThread());
129 108
130 IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize(); 109 IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize();
131 if (!io_surface_support) 110 if (!io_surface_support)
132 return false; 111 return false;
133 112
134 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( 113 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
135 &MacVideoDecodeAccelerator::NotifyInitializeDone, this)); 114 &MacVideoDecodeAccelerator::NotifyInitializeDone, this));
136 return true; 115 return true;
137 } 116 }
138 117
139 void MacVideoDecodeAccelerator::Decode( 118 void MacVideoDecodeAccelerator::Decode(
140 const media::BitstreamBuffer& bitstream_buffer) { 119 const media::BitstreamBuffer& bitstream_buffer) {
141 DCHECK(CalledOnValidThread()); 120 DCHECK(CalledOnValidThread());
142 RETURN_ON_FAILURE(client_, 121 RETURN_ON_FAILURE(client_,
143 "Call to Decode() during invalid state.", ILLEGAL_STATE,); 122 "Call to Decode() during invalid state.", ILLEGAL_STATE,);
144 123
145 base::SharedMemory memory(bitstream_buffer.handle(), true); 124 base::SharedMemory memory(bitstream_buffer.handle(), true);
146 RETURN_ON_FAILURE(memory.Map(bitstream_buffer.size()), 125 RETURN_ON_FAILURE(memory.Map(bitstream_buffer.size()),
147 "Failed to SharedMemory::Map().", UNREADABLE_INPUT,); 126 "Failed to SharedMemory::Map().", UNREADABLE_INPUT,);
148 127
149 size_t buffer_size = bitstream_buffer.size(); 128 h264_parser_.SetStream(static_cast<const uint8_t*>(memory.memory()),
150 RETURN_ON_FAILURE(buffer_size > nalu_len_field_size_, 129 bitstream_buffer.size());
151 "Bitstream contains invalid data.", INVALID_ARGUMENT,); 130 while (true) {
152 131 content::H264NALU nalu;
153 // The decoder can only handle slice types 1-5. 132 content::H264Parser::Result result = h264_parser_.AdvanceToNextNALU(&nalu);
154 const uint8_t* buffer = static_cast<const uint8_t*>(memory.memory()); 133 if (result == content::H264Parser::kEOStream) {
155 uint8_t nalu_type = buffer[nalu_len_field_size_] & 0x1f; 134 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
156 if (nalu_type < 1 || nalu_type > 5) { 135 &MacVideoDecodeAccelerator::NotifyInputBufferRead, this,
157 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( 136 bitstream_buffer.id()));
158 &MacVideoDecodeAccelerator::NotifyInputBufferRead, this, 137 return;
159 bitstream_buffer.id())); 138 }
160 return; 139 RETURN_ON_FAILURE(result == content::H264Parser::kOk,
161 } 140 "Unable to parse bitstream.", UNREADABLE_INPUT,);
162 141 if (!did_build_config_record_) {
163 // Keep a ref counted copy of the buffer. 142 std::vector<uint8_t> config_record;
164 std::vector<uint8_t> vbuffer(buffer, buffer + buffer_size); 143 RETURN_ON_FAILURE(config_record_builder_.ProcessNALU(&h264_parser_, nalu,
165 scoped_refptr<base::RefCountedBytes> bytes( 144 &config_record),
166 base::RefCountedBytes::TakeVector(&vbuffer)); 145 "Unable to build AVC configuraiton record.",
167 146 UNREADABLE_INPUT,);
168 // Store the buffer size at the beginning of the buffer as the decoder 147 if (!config_record.empty()) {
169 // expects. 148 did_build_config_record_ = true;
170 size_t frame_buffer_size = buffer_size - nalu_len_field_size_; 149 if (!CreateDecoder(config_record))
171 const uint64_t max_frame_buffer_size = 150 return;
172 (1llu << (nalu_len_field_size_ * 8)) - 1; 151 }
173 DCHECK_LE(nalu_len_field_size_, 4u); 152 }
174 RETURN_ON_FAILURE(frame_buffer_size <= max_frame_buffer_size, 153 // If the decoder has been created and this is a slice type then pass it
175 "Bitstream buffer is too large.", INVALID_ARGUMENT,); 154 // to the decoder.
176 for (size_t i = 0; i < nalu_len_field_size_; ++i) { 155 if (vda_support_.get() && nalu.nal_unit_type >= 1 &&
177 size_t shift = nalu_len_field_size_ * 8 - (i + 1) * 8; 156 nalu.nal_unit_type <= 5) {
178 bytes->data()[i] = (frame_buffer_size >> shift) & 0xff; 157 DecodeNALU(nalu, bitstream_buffer.id());
179 } 158 }
180
181 vda_support_->Decode(bytes->front(), bytes->size(),
182 base::Bind(&MacVideoDecodeAccelerator::OnFrameReady,
183 this, bitstream_buffer.id(), bytes));
184
185 if (!did_request_pictures_) {
186 did_request_pictures_ = true;
187 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
188 &MacVideoDecodeAccelerator::RequestPictures, this));
189 } 159 }
190 } 160 }
191 161
192 void MacVideoDecodeAccelerator::AssignPictureBuffers( 162 void MacVideoDecodeAccelerator::AssignPictureBuffers(
193 const std::vector<media::PictureBuffer>& buffers) { 163 const std::vector<media::PictureBuffer>& buffers) {
194 DCHECK(CalledOnValidThread()); 164 DCHECK(CalledOnValidThread());
195 RETURN_ON_FAILURE(client_, 165 RETURN_ON_FAILURE(client_,
196 "Call to AssignPictureBuffers() during invalid state.", 166 "Call to AssignPictureBuffers() during invalid state.",
197 ILLEGAL_STATE,); 167 ILLEGAL_STATE,);
198 available_pictures_.insert( 168 available_pictures_.insert(
(...skipping 13 matching lines...) Expand all
212 "Missing picture buffer id: " << picture_buffer_id, 182 "Missing picture buffer id: " << picture_buffer_id,
213 INVALID_ARGUMENT,); 183 INVALID_ARGUMENT,);
214 UsedPictureInfo info = it->second; 184 UsedPictureInfo info = it->second;
215 used_pictures_.erase(it); 185 used_pictures_.erase(it);
216 available_pictures_.push_back(info.picture_buffer); 186 available_pictures_.push_back(info.picture_buffer);
217 SendImages(); 187 SendImages();
218 } 188 }
219 189
220 void MacVideoDecodeAccelerator::Flush() { 190 void MacVideoDecodeAccelerator::Flush() {
221 DCHECK(CalledOnValidThread()); 191 DCHECK(CalledOnValidThread());
222 RETURN_ON_FAILURE(client_, 192 RETURN_ON_FAILURE(vda_support_,
223 "Call to Flush() during invalid state.", ILLEGAL_STATE,); 193 "Call to Flush() during invalid state.", ILLEGAL_STATE,);
224 vda_support_->Flush(true); 194 vda_support_->Flush(true);
225 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( 195 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
226 &MacVideoDecodeAccelerator::NotifyFlushDone, this)); 196 &MacVideoDecodeAccelerator::NotifyFlushDone, this));
227 } 197 }
228 198
229 void MacVideoDecodeAccelerator::Reset() { 199 void MacVideoDecodeAccelerator::Reset() {
230 DCHECK(CalledOnValidThread()); 200 DCHECK(CalledOnValidThread());
231 RETURN_ON_FAILURE(client_, 201 RETURN_ON_FAILURE(vda_support_,
232 "Call to Reset() during invalid state.", ILLEGAL_STATE,); 202 "Call to Reset() during invalid state.", ILLEGAL_STATE,);
233 vda_support_->Flush(false); 203 vda_support_->Flush(false);
234 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( 204 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
235 &MacVideoDecodeAccelerator::NotifyResetDone, this)); 205 &MacVideoDecodeAccelerator::NotifyResetDone, this));
236 } 206 }
237 207
238 void MacVideoDecodeAccelerator::Destroy() { 208 void MacVideoDecodeAccelerator::Destroy() {
239 DCHECK(CalledOnValidThread()); 209 DCHECK(CalledOnValidThread());
240 if (vda_support_) { 210 if (vda_support_) {
241 vda_support_->Destroy(); 211 vda_support_->Destroy();
(...skipping 20 matching lines...) Expand all
262 if (!client_) 232 if (!client_)
263 return; 233 return;
264 if (image) { 234 if (image) {
265 DecodedImageInfo info; 235 DecodedImageInfo info;
266 info.image.reset(image, base::scoped_policy::RETAIN); 236 info.image.reset(image, base::scoped_policy::RETAIN);
267 info.bitstream_buffer_id = bitstream_buffer_id; 237 info.bitstream_buffer_id = bitstream_buffer_id;
268 decoded_images_.push_back(info); 238 decoded_images_.push_back(info);
269 SendImages(); 239 SendImages();
270 } 240 }
271 // TODO(sail): this assumes Decode() is handed a single NALU at a time. Make 241 // TODO(sail): this assumes Decode() is handed a single NALU at a time. Make
272 // that assumption go away. 242 // that assumption go away. See VideoDecodeAcceleratorTest.DecodeVariations
243 // for an example of a test the fails due to this assumption.
273 client_->NotifyEndOfBitstreamBuffer(bitstream_buffer_id); 244 client_->NotifyEndOfBitstreamBuffer(bitstream_buffer_id);
274 } 245 }
275 246
276 void MacVideoDecodeAccelerator::SendImages() { 247 void MacVideoDecodeAccelerator::SendImages() {
277 if (!client_) { 248 if (!client_) {
278 DCHECK(decoded_images_.empty()); 249 DCHECK(decoded_images_.empty());
279 return; 250 return;
280 } 251 }
281 252
282 while (available_pictures_.size() && decoded_images_.size()) { 253 while (available_pictures_.size() && decoded_images_.size()) {
(...skipping 13 matching lines...) Expand all
296 } 267 }
297 } 268 }
298 269
299 void MacVideoDecodeAccelerator::StopOnError( 270 void MacVideoDecodeAccelerator::StopOnError(
300 media::VideoDecodeAccelerator::Error error) { 271 media::VideoDecodeAccelerator::Error error) {
301 if (client_) 272 if (client_)
302 client_->NotifyError(error); 273 client_->NotifyError(error);
303 Destroy(); 274 Destroy();
304 } 275 }
305 276
277 bool MacVideoDecodeAccelerator::CreateDecoder(
278 const std::vector<uint8_t>& extra_data) {
279 DCHECK(client_);
280 DCHECK(!vda_support_.get());
281
282 vda_support_ = new gfx::VideoDecodeAccelerationSupport();
283 gfx::VideoDecodeAccelerationSupport::Status status = vda_support_->Create(
284 config_record_builder_.coded_width(),
285 config_record_builder_.coded_height(),
286 kCVPixelFormatType_422YpCbCr8,
287 &extra_data[0], extra_data.size());
288 RETURN_ON_FAILURE(status == gfx::VideoDecodeAccelerationSupport::SUCCESS,
289 "Creating video decoder failed with error: " << status,
290 PLATFORM_FAILURE, false);
291
292 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
293 &MacVideoDecodeAccelerator::RequestPictures, this));
294 return true;
295 }
296
297 void MacVideoDecodeAccelerator::DecodeNALU(const content::H264NALU& nalu,
298 int32 bitstream_buffer_id) {
299 // Assume the NALU length field size is 4 bytes.
300 const int kNALULengthFieldSize = 4;
301 std::vector<uint8_t> data(kNALULengthFieldSize + nalu.size);
302
303 // Store the buffer size at the beginning of the buffer as the decoder
304 // expects.
305 for (size_t i = 0; i < kNALULengthFieldSize; ++i) {
306 size_t shift = kNALULengthFieldSize * 8 - (i + 1) * 8;
307 data[i] = (nalu.size >> shift) & 0xff;
308 }
309
310 // Copy the NALU data.
311 memcpy(&data[kNALULengthFieldSize], nalu.data, nalu.size);
312
313 // Keep a ref counted copy of the buffer.
314 scoped_refptr<base::RefCountedBytes> bytes(
315 base::RefCountedBytes::TakeVector(&data));
316 vda_support_->Decode(bytes->front(), bytes->size(),
317 base::Bind(&MacVideoDecodeAccelerator::OnFrameReady,
318 this, bitstream_buffer_id, bytes));
319 }
320
306 void MacVideoDecodeAccelerator::NotifyInitializeDone() { 321 void MacVideoDecodeAccelerator::NotifyInitializeDone() {
307 if (client_) 322 if (client_)
308 client_->NotifyInitializeDone(); 323 client_->NotifyInitializeDone();
309 } 324 }
310 325
311 void MacVideoDecodeAccelerator::RequestPictures() { 326 void MacVideoDecodeAccelerator::RequestPictures() {
312 if (client_) 327 if (client_) {
313 client_->ProvidePictureBuffers(kNumPictureBuffers, frame_size_); 328 client_->ProvidePictureBuffers(
329 kNumPictureBuffers,
330 gfx::Size(config_record_builder_.coded_width(),
331 config_record_builder_.coded_height()));
332 }
314 } 333 }
315 334
316 void MacVideoDecodeAccelerator::NotifyFlushDone() { 335 void MacVideoDecodeAccelerator::NotifyFlushDone() {
317 if (client_) 336 if (client_)
318 client_->NotifyFlushDone(); 337 client_->NotifyFlushDone();
319 } 338 }
320 339
321 void MacVideoDecodeAccelerator::NotifyResetDone() { 340 void MacVideoDecodeAccelerator::NotifyResetDone() {
322 decoded_images_.clear(); 341 decoded_images_.clear();
323 if (client_) 342 if (client_)
(...skipping 13 matching lines...) Expand all
337 } 356 }
338 357
339 MacVideoDecodeAccelerator::UsedPictureInfo::~UsedPictureInfo() { 358 MacVideoDecodeAccelerator::UsedPictureInfo::~UsedPictureInfo() {
340 } 359 }
341 360
342 MacVideoDecodeAccelerator::DecodedImageInfo::DecodedImageInfo() { 361 MacVideoDecodeAccelerator::DecodedImageInfo::DecodedImageInfo() {
343 } 362 }
344 363
345 MacVideoDecodeAccelerator::DecodedImageInfo::~DecodedImageInfo() { 364 MacVideoDecodeAccelerator::DecodedImageInfo::~DecodedImageInfo() {
346 } 365 }
OLDNEW
« no previous file with comments | « content/common/gpu/media/mac_video_decode_accelerator.h ('k') | content/common/gpu/media/video_decode_accelerator_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698