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

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: address review comments 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.",
Ami GONE FROM CHROMIUM 2012/06/05 15:47:43 I think you missed this comment I made on a previo
Ami GONE FROM CHROMIUM 2012/06/05 16:10:18 Oops; I was reading this as a DCHECK, not a R_O_F.
197 ILLEGAL_STATE,); 167 ILLEGAL_STATE,);
198 available_pictures_.insert( 168 available_pictures_.insert(
199 available_pictures_.end(), buffers.begin(), buffers.end()); 169 available_pictures_.end(), buffers.begin(), buffers.end());
200 SendImages(); 170 SendImages();
201 } 171 }
202 172
203 void MacVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { 173 void MacVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) {
204 DCHECK(CalledOnValidThread()); 174 DCHECK(CalledOnValidThread());
205 RETURN_ON_FAILURE(client_, 175 RETURN_ON_FAILURE(client_,
206 "Call to ReusePictureBuffe() during invalid state.", 176 "Call to ReusePictureBuffe() during invalid state.",
207 ILLEGAL_STATE,); 177 ILLEGAL_STATE,);
208 178
209 std::map<int32, UsedPictureInfo>::iterator it = 179 std::map<int32, UsedPictureInfo>::iterator it =
210 used_pictures_.find(picture_buffer_id); 180 used_pictures_.find(picture_buffer_id);
211 RETURN_ON_FAILURE(it != used_pictures_.end(), 181 RETURN_ON_FAILURE(it != used_pictures_.end(),
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(client_,
Ami GONE FROM CHROMIUM 2012/06/05 15:47:43 I don't think it is.
sail 2012/06/05 16:42:53 Fixed. I changed Flush() and Reset() to check for
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(client_,
232 "Call to Reset() during invalid state.", ILLEGAL_STATE,); 202 "Call to Reset() during invalid state.", ILLEGAL_STATE,);
(...skipping 29 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.
Ami GONE FROM CHROMIUM 2012/06/05 15:47:43 Can you refer to the specific test that doesn't pa
sail 2012/06/05 16:42:53 Done.
273 client_->NotifyEndOfBitstreamBuffer(bitstream_buffer_id); 243 client_->NotifyEndOfBitstreamBuffer(bitstream_buffer_id);
274 } 244 }
275 245
276 void MacVideoDecodeAccelerator::SendImages() { 246 void MacVideoDecodeAccelerator::SendImages() {
277 if (!client_) { 247 if (!client_) {
278 DCHECK(decoded_images_.empty()); 248 DCHECK(decoded_images_.empty());
279 return; 249 return;
280 } 250 }
281 251
282 while (available_pictures_.size() && decoded_images_.size()) { 252 while (available_pictures_.size() && decoded_images_.size()) {
(...skipping 13 matching lines...) Expand all
296 } 266 }
297 } 267 }
298 268
299 void MacVideoDecodeAccelerator::StopOnError( 269 void MacVideoDecodeAccelerator::StopOnError(
300 media::VideoDecodeAccelerator::Error error) { 270 media::VideoDecodeAccelerator::Error error) {
301 if (client_) 271 if (client_)
302 client_->NotifyError(error); 272 client_->NotifyError(error);
303 Destroy(); 273 Destroy();
304 } 274 }
305 275
276 bool MacVideoDecodeAccelerator::CreateDecoder(
277 const std::vector<uint8_t>& extra_data) {
278 DCHECK(client_);
279 DCHECK(!vda_support_.get());
280
281 vda_support_ = new gfx::VideoDecodeAccelerationSupport();
282 gfx::VideoDecodeAccelerationSupport::Status status = vda_support_->Create(
283 config_record_builder_.coded_width(),
284 config_record_builder_.coded_height(),
285 kCVPixelFormatType_422YpCbCr8,
286 &extra_data[0], extra_data.size());
287 RETURN_ON_FAILURE(status == gfx::VideoDecodeAccelerationSupport::SUCCESS,
288 "Creating video decoder failed with error: " << status,
289 PLATFORM_FAILURE, false);
290
291 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
292 &MacVideoDecodeAccelerator::RequestPictures, this));
293 return true;
294 }
295
296 void MacVideoDecodeAccelerator::DecodeNALU(const content::H264NALU& nalu,
297 int32 bitstream_buffer_id) {
298 // Assume the NALU length field size is 4 bytes.
299 const int kNALULengthFieldSize = 4;
300 std::vector<uint8_t> data(kNALULengthFieldSize + nalu.size);
301
302 // Store the buffer size at the beginning of the buffer as the decoder
303 // expects.
304 for (size_t i = 0; i < kNALULengthFieldSize; ++i) {
305 size_t shift = kNALULengthFieldSize * 8 - (i + 1) * 8;
306 data[i] = (nalu.size >> shift) & 0xff;
307 }
308
309 // Copy the NALU data.
310 memcpy(&data[kNALULengthFieldSize], nalu.data, nalu.size);
311
312 // Keep a ref counted copy of the buffer.
313 scoped_refptr<base::RefCountedBytes> bytes(
314 base::RefCountedBytes::TakeVector(&data));
315 vda_support_->Decode(bytes->front(), bytes->size(),
316 base::Bind(&MacVideoDecodeAccelerator::OnFrameReady,
317 this, bitstream_buffer_id, bytes));
318 }
319
306 void MacVideoDecodeAccelerator::NotifyInitializeDone() { 320 void MacVideoDecodeAccelerator::NotifyInitializeDone() {
307 if (client_) 321 if (client_)
308 client_->NotifyInitializeDone(); 322 client_->NotifyInitializeDone();
309 } 323 }
310 324
311 void MacVideoDecodeAccelerator::RequestPictures() { 325 void MacVideoDecodeAccelerator::RequestPictures() {
312 if (client_) 326 if (client_) {
313 client_->ProvidePictureBuffers(kNumPictureBuffers, frame_size_); 327 client_->ProvidePictureBuffers(
328 kNumPictureBuffers,
329 gfx::Size(config_record_builder_.coded_width(),
330 config_record_builder_.coded_height()));
331 }
314 } 332 }
315 333
316 void MacVideoDecodeAccelerator::NotifyFlushDone() { 334 void MacVideoDecodeAccelerator::NotifyFlushDone() {
317 if (client_) 335 if (client_)
318 client_->NotifyFlushDone(); 336 client_->NotifyFlushDone();
319 } 337 }
320 338
321 void MacVideoDecodeAccelerator::NotifyResetDone() { 339 void MacVideoDecodeAccelerator::NotifyResetDone() {
322 decoded_images_.clear(); 340 decoded_images_.clear();
323 if (client_) 341 if (client_)
(...skipping 13 matching lines...) Expand all
337 } 355 }
338 356
339 MacVideoDecodeAccelerator::UsedPictureInfo::~UsedPictureInfo() { 357 MacVideoDecodeAccelerator::UsedPictureInfo::~UsedPictureInfo() {
340 } 358 }
341 359
342 MacVideoDecodeAccelerator::DecodedImageInfo::DecodedImageInfo() { 360 MacVideoDecodeAccelerator::DecodedImageInfo::DecodedImageInfo() {
343 } 361 }
344 362
345 MacVideoDecodeAccelerator::DecodedImageInfo::~DecodedImageInfo() { 363 MacVideoDecodeAccelerator::DecodedImageInfo::~DecodedImageInfo() {
346 } 364 }
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