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

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: rebase 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 client_->NotifyEndOfBitstreamBuffer(bitstream_buffer.id());
Ami GONE FROM CHROMIUM 2012/05/30 00:07:55 Isn't this (prematurely) duplicating the NEOBB not
sail 2012/06/02 21:05:49 Yea, this code doesn't handle multiple NALUs in a
156 if (nalu_type < 1 || nalu_type > 5) { 135 return;
157 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( 136 }
158 &MacVideoDecodeAccelerator::NotifyInputBufferRead, this, 137 RETURN_ON_FAILURE(result = content::H264Parser::kOk,
Ami GONE FROM CHROMIUM 2012/05/30 00:07:55 Assignment instead of comparison.
sail 2012/06/02 21:05:49 Done.
159 bitstream_buffer.id())); 138 "Unable to parse bitstream.", UNREADABLE_INPUT,);
160 return; 139 if (!did_build_config_record_) {
161 } 140 bool did_consume_nalu = false;
Ami GONE FROM CHROMIUM 2012/05/30 00:07:55 unused
sail 2012/06/02 21:05:49 Done.
162 141 std::vector<uint8_t> config_record;
163 // Keep a ref counted copy of the buffer. 142 RETURN_ON_FAILURE(config_record_builder_.ProcessNALU(&h264_parser_, nalu,
164 std::vector<uint8_t> vbuffer(buffer, buffer + buffer_size); 143 &config_record),
165 scoped_refptr<base::RefCountedBytes> bytes( 144 "Unable to build AVC configuraiton record.",
166 base::RefCountedBytes::TakeVector(&vbuffer)); 145 UNREADABLE_INPUT,);
167 146 if (!config_record.empty()) {
168 // Store the buffer size at the beginning of the buffer as the decoder 147 did_build_config_record_ = true;
169 // expects. 148 if (!CreateDecoder(config_record))
170 size_t frame_buffer_size = buffer_size - nalu_len_field_size_; 149 return;
171 const uint64_t max_frame_buffer_size = 150 }
172 (1llu << (nalu_len_field_size_ * 8)) - 1; 151 if (did_consume_nalu)
173 DCHECK_LE(nalu_len_field_size_, 4u); 152 continue;
Ami GONE FROM CHROMIUM 2012/05/30 00:07:55 unreachable
sail 2012/06/02 21:05:49 Done.
174 RETURN_ON_FAILURE(frame_buffer_size <= max_frame_buffer_size, 153 }
175 "Bitstream buffer is too large.", INVALID_ARGUMENT,); 154 // If the decoder has been created and this is a slice type then pass it
176 for (size_t i = 0; i < nalu_len_field_size_; ++i) { 155 // to the decoder.
177 size_t shift = nalu_len_field_size_ * 8 - (i + 1) * 8; 156 if (vda_support_.get() && nalu.nal_unit_type >= 1 &&
178 bytes->data()[i] = (frame_buffer_size >> shift) & 0xff; 157 nalu.nal_unit_type <= 5) {
179 } 158 DecodeNALU(nalu, bitstream_buffer.id());
180 159 }
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 } 160 }
190 } 161 }
191 162
192 void MacVideoDecodeAccelerator::AssignPictureBuffers( 163 void MacVideoDecodeAccelerator::AssignPictureBuffers(
193 const std::vector<media::PictureBuffer>& buffers) { 164 const std::vector<media::PictureBuffer>& buffers) {
194 DCHECK(CalledOnValidThread()); 165 DCHECK(CalledOnValidThread());
195 RETURN_ON_FAILURE(client_, 166 RETURN_ON_FAILURE(client_,
196 "Call to AssignPictureBuffers() during invalid state.", 167 "Call to AssignPictureBuffers() during invalid state.",
Ami GONE FROM CHROMIUM 2012/05/30 00:07:55 This pattern generally is incorrect because of que
197 ILLEGAL_STATE,); 168 ILLEGAL_STATE,);
198 available_pictures_.insert( 169 available_pictures_.insert(
199 available_pictures_.end(), buffers.begin(), buffers.end()); 170 available_pictures_.end(), buffers.begin(), buffers.end());
200 SendImages(); 171 SendImages();
201 } 172 }
202 173
203 void MacVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { 174 void MacVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) {
204 DCHECK(CalledOnValidThread()); 175 DCHECK(CalledOnValidThread());
205 RETURN_ON_FAILURE(client_, 176 RETURN_ON_FAILURE(client_,
206 "Call to ReusePictureBuffe() during invalid state.", 177 "Call to ReusePictureBuffe() during invalid state.",
207 ILLEGAL_STATE,); 178 ILLEGAL_STATE,);
208 179
209 std::map<int32, UsedPictureInfo>::iterator it = 180 std::map<int32, UsedPictureInfo>::iterator it =
210 used_pictures_.find(picture_buffer_id); 181 used_pictures_.find(picture_buffer_id);
211 RETURN_ON_FAILURE(it != used_pictures_.end(), 182 RETURN_ON_FAILURE(it != used_pictures_.end(),
212 "Missing picture buffer id: " << picture_buffer_id, 183 "Missing picture buffer id: " << picture_buffer_id,
213 INVALID_ARGUMENT,); 184 INVALID_ARGUMENT,);
214 UsedPictureInfo info = it->second; 185 UsedPictureInfo info = it->second;
215 used_pictures_.erase(it); 186 used_pictures_.erase(it);
216 available_pictures_.push_back(info.picture_buffer); 187 available_pictures_.push_back(info.picture_buffer);
217 SendImages(); 188 SendImages();
218 } 189 }
219 190
220 void MacVideoDecodeAccelerator::Flush() { 191 void MacVideoDecodeAccelerator::Flush() {
221 DCHECK(CalledOnValidThread()); 192 DCHECK(CalledOnValidThread());
222 RETURN_ON_FAILURE(client_, 193 RETURN_ON_FAILURE(client_,
Ami GONE FROM CHROMIUM 2012/05/30 00:07:55 did you mean to s/client_/vda_support_/ (here and
sail 2012/06/02 21:05:49 Done.
223 "Call to Flush() during invalid state.", ILLEGAL_STATE,); 194 "Call to Flush() during invalid state.", ILLEGAL_STATE,);
224 vda_support_->Flush(true); 195 vda_support_->Flush(true);
225 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( 196 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
226 &MacVideoDecodeAccelerator::NotifyFlushDone, this)); 197 &MacVideoDecodeAccelerator::NotifyFlushDone, this));
227 } 198 }
228 199
229 void MacVideoDecodeAccelerator::Reset() { 200 void MacVideoDecodeAccelerator::Reset() {
230 DCHECK(CalledOnValidThread()); 201 DCHECK(CalledOnValidThread());
231 RETURN_ON_FAILURE(client_, 202 RETURN_ON_FAILURE(client_,
232 "Call to Reset() during invalid state.", ILLEGAL_STATE,); 203 "Call to Reset() during invalid state.", ILLEGAL_STATE,);
(...skipping 28 matching lines...) Expand all
261 PLATFORM_FAILURE,); 232 PLATFORM_FAILURE,);
262 if (!client_) 233 if (!client_)
263 return; 234 return;
264 if (image) { 235 if (image) {
265 DecodedImageInfo info; 236 DecodedImageInfo info;
266 info.image.reset(image, base::mac::RETAIN); 237 info.image.reset(image, base::mac::RETAIN);
267 info.bitstream_buffer_id = bitstream_buffer_id; 238 info.bitstream_buffer_id = bitstream_buffer_id;
268 decoded_images_.push_back(info); 239 decoded_images_.push_back(info);
269 SendImages(); 240 SendImages();
270 } 241 }
271 // TODO(sail): this assumes Decode() is handed a single NALU at a time. Make 242 // TODO(sail): this assumes Decode() is handed a single NALU at a time. Make
Ami GONE FROM CHROMIUM 2012/05/30 00:07:55 Isn't this assumption tripped up by the vda_unitte
sail 2012/06/02 21:05:49 Yea, currently the tests that use multiple NALUs a
272 // that assumption go away. 243 // that assumption go away.
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
(...skipping 14 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_);
Ami GONE FROM CHROMIUM 2012/05/30 00:07:55 client_ might be gone if a parse error occurs befo
sail 2012/06/02 21:05:49 The code only sets client_ to NULL using the RETUR
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

Powered by Google App Engine
This is Rietveld 408576698