| OLD | NEW |
| 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 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 105 } | 105 } |
| 106 | 106 |
| 107 bool MacVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile) { | 107 bool MacVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile) { |
| 108 DCHECK(CalledOnValidThread()); | 108 DCHECK(CalledOnValidThread()); |
| 109 | 109 |
| 110 IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize(); | 110 IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize(); |
| 111 if (!io_surface_support) | 111 if (!io_surface_support) |
| 112 return false; | 112 return false; |
| 113 | 113 |
| 114 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 114 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( |
| 115 &MacVideoDecodeAccelerator::NotifyInitializeDone, this)); | 115 &MacVideoDecodeAccelerator::NotifyInitializeDone, base::AsWeakPtr(this))); |
| 116 return true; | 116 return true; |
| 117 } | 117 } |
| 118 | 118 |
| 119 void MacVideoDecodeAccelerator::Decode( | 119 void MacVideoDecodeAccelerator::Decode( |
| 120 const media::BitstreamBuffer& bitstream_buffer) { | 120 const media::BitstreamBuffer& bitstream_buffer) { |
| 121 DCHECK(CalledOnValidThread()); | 121 DCHECK(CalledOnValidThread()); |
| 122 RETURN_ON_FAILURE(client_, | 122 RETURN_ON_FAILURE(client_, |
| 123 "Call to Decode() during invalid state.", ILLEGAL_STATE,); | 123 "Call to Decode() during invalid state.", ILLEGAL_STATE,); |
| 124 | 124 |
| 125 base::SharedMemory memory(bitstream_buffer.handle(), true); | 125 base::SharedMemory memory(bitstream_buffer.handle(), true); |
| 126 RETURN_ON_FAILURE(memory.Map(bitstream_buffer.size()), | 126 RETURN_ON_FAILURE(memory.Map(bitstream_buffer.size()), |
| 127 "Failed to SharedMemory::Map().", UNREADABLE_INPUT,); | 127 "Failed to SharedMemory::Map().", UNREADABLE_INPUT,); |
| 128 | 128 |
| 129 h264_parser_.SetStream(static_cast<const uint8_t*>(memory.memory()), | 129 h264_parser_.SetStream(static_cast<const uint8_t*>(memory.memory()), |
| 130 bitstream_buffer.size()); | 130 bitstream_buffer.size()); |
| 131 while (true) { | 131 while (true) { |
| 132 content::H264NALU nalu; | 132 content::H264NALU nalu; |
| 133 content::H264Parser::Result result = h264_parser_.AdvanceToNextNALU(&nalu); | 133 content::H264Parser::Result result = h264_parser_.AdvanceToNextNALU(&nalu); |
| 134 if (result == content::H264Parser::kEOStream) { | 134 if (result == content::H264Parser::kEOStream) { |
| 135 if (bitstream_nalu_count_.count(bitstream_buffer.id()) == 0) { | 135 if (bitstream_nalu_count_.count(bitstream_buffer.id()) == 0) { |
| 136 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 136 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( |
| 137 &MacVideoDecodeAccelerator::NotifyInputBufferRead, this, | 137 &MacVideoDecodeAccelerator::NotifyInputBufferRead, |
| 138 bitstream_buffer.id())); | 138 base::AsWeakPtr(this), bitstream_buffer.id())); |
| 139 } | 139 } |
| 140 return; | 140 return; |
| 141 } | 141 } |
| 142 RETURN_ON_FAILURE(result == content::H264Parser::kOk, | 142 RETURN_ON_FAILURE(result == content::H264Parser::kOk, |
| 143 "Unable to parse bitstream.", UNREADABLE_INPUT,); | 143 "Unable to parse bitstream.", UNREADABLE_INPUT,); |
| 144 if (!did_build_config_record_) { | 144 if (!did_build_config_record_) { |
| 145 std::vector<uint8_t> config_record; | 145 std::vector<uint8_t> config_record; |
| 146 RETURN_ON_FAILURE(config_record_builder_.ProcessNALU(&h264_parser_, nalu, | 146 RETURN_ON_FAILURE(config_record_builder_.ProcessNALU(&h264_parser_, nalu, |
| 147 &config_record), | 147 &config_record), |
| 148 "Unable to build AVC configuraiton record.", | 148 "Unable to build AVC configuraiton record.", |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 190 available_pictures_.push_back(info.picture_buffer); | 190 available_pictures_.push_back(info.picture_buffer); |
| 191 SendImages(); | 191 SendImages(); |
| 192 } | 192 } |
| 193 | 193 |
| 194 void MacVideoDecodeAccelerator::Flush() { | 194 void MacVideoDecodeAccelerator::Flush() { |
| 195 DCHECK(CalledOnValidThread()); | 195 DCHECK(CalledOnValidThread()); |
| 196 RETURN_ON_FAILURE(vda_support_, | 196 RETURN_ON_FAILURE(vda_support_, |
| 197 "Call to Flush() during invalid state.", ILLEGAL_STATE,); | 197 "Call to Flush() during invalid state.", ILLEGAL_STATE,); |
| 198 vda_support_->Flush(true); | 198 vda_support_->Flush(true); |
| 199 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 199 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( |
| 200 &MacVideoDecodeAccelerator::NotifyFlushDone, this)); | 200 &MacVideoDecodeAccelerator::NotifyFlushDone, base::AsWeakPtr(this))); |
| 201 } | 201 } |
| 202 | 202 |
| 203 void MacVideoDecodeAccelerator::Reset() { | 203 void MacVideoDecodeAccelerator::Reset() { |
| 204 DCHECK(CalledOnValidThread()); | 204 DCHECK(CalledOnValidThread()); |
| 205 RETURN_ON_FAILURE(vda_support_, | 205 RETURN_ON_FAILURE(vda_support_, |
| 206 "Call to Reset() during invalid state.", ILLEGAL_STATE,); | 206 "Call to Reset() during invalid state.", ILLEGAL_STATE,); |
| 207 vda_support_->Flush(false); | 207 vda_support_->Flush(false); |
| 208 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 208 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( |
| 209 &MacVideoDecodeAccelerator::NotifyResetDone, this)); | 209 &MacVideoDecodeAccelerator::NotifyResetDone, base::AsWeakPtr(this))); |
| 210 } | 210 } |
| 211 | 211 |
| 212 void MacVideoDecodeAccelerator::Destroy() { | 212 void MacVideoDecodeAccelerator::Cleanup() { |
| 213 DCHECK(CalledOnValidThread()); | 213 DCHECK(CalledOnValidThread()); |
| 214 if (vda_support_) { | 214 if (vda_support_) { |
| 215 vda_support_->Destroy(); | 215 vda_support_->Destroy(); |
| 216 vda_support_ = NULL; | 216 vda_support_ = NULL; |
| 217 } | 217 } |
| 218 client_ = NULL; | 218 client_ = NULL; |
| 219 decoded_images_.clear(); | 219 decoded_images_.clear(); |
| 220 } | 220 } |
| 221 | 221 |
| 222 void MacVideoDecodeAccelerator::Destroy() { |
| 223 DCHECK(CalledOnValidThread()); |
| 224 Cleanup(); |
| 225 delete this; |
| 226 } |
| 227 |
| 222 MacVideoDecodeAccelerator::~MacVideoDecodeAccelerator() { | 228 MacVideoDecodeAccelerator::~MacVideoDecodeAccelerator() { |
| 223 DCHECK(CalledOnValidThread()); | 229 DCHECK(CalledOnValidThread()); |
| 224 Destroy(); | 230 DCHECK(!vda_support_); |
| 231 DCHECK(!client_); |
| 232 DCHECK(decoded_images_.empty()); |
| 225 } | 233 } |
| 226 | 234 |
| 227 void MacVideoDecodeAccelerator::OnFrameReady( | 235 void MacVideoDecodeAccelerator::OnFrameReady( |
| 228 int32 bitstream_buffer_id, | 236 int32 bitstream_buffer_id, |
| 229 scoped_refptr<base::RefCountedBytes> bytes, | 237 scoped_refptr<base::RefCountedBytes> bytes, |
| 230 CVImageBufferRef image, | 238 CVImageBufferRef image, |
| 231 int status) { | 239 int status) { |
| 232 DCHECK(CalledOnValidThread()); | 240 DCHECK(CalledOnValidThread()); |
| 233 RETURN_ON_FAILURE(status == noErr, | 241 RETURN_ON_FAILURE(status == noErr, |
| 234 "Decoding image failed with error code: " << status, | 242 "Decoding image failed with error code: " << status, |
| 235 PLATFORM_FAILURE,); | 243 PLATFORM_FAILURE,); |
| 236 if (!client_) | 244 if (!client_) |
| 237 return; | 245 return; |
| 238 if (image) { | 246 if (image) { |
| 239 DecodedImageInfo info; | 247 DecodedImageInfo info; |
| 240 info.image.reset(image, base::scoped_policy::RETAIN); | 248 info.image.reset(image, base::scoped_policy::RETAIN); |
| 241 info.bitstream_buffer_id = bitstream_buffer_id; | 249 info.bitstream_buffer_id = bitstream_buffer_id; |
| 242 decoded_images_.push_back(info); | 250 decoded_images_.push_back(info); |
| 243 SendImages(); | 251 SendImages(); |
| 244 } | 252 } |
| 245 std::map<int32, int>::iterator bitstream_count_it = | 253 std::map<int32, int>::iterator bitstream_count_it = |
| 246 bitstream_nalu_count_.find(bitstream_buffer_id); | 254 bitstream_nalu_count_.find(bitstream_buffer_id); |
| 247 if (--bitstream_count_it->second == 0) { | 255 if (--bitstream_count_it->second == 0) { |
| 248 bitstream_nalu_count_.erase(bitstream_count_it); | 256 bitstream_nalu_count_.erase(bitstream_count_it); |
| 249 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 257 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( |
| 250 &MacVideoDecodeAccelerator::NotifyInputBufferRead, this, | 258 &MacVideoDecodeAccelerator::NotifyInputBufferRead, |
| 251 bitstream_buffer_id)); | 259 base::AsWeakPtr(this), bitstream_buffer_id)); |
| 252 } | 260 } |
| 253 } | 261 } |
| 254 | 262 |
| 255 void MacVideoDecodeAccelerator::SendImages() { | 263 void MacVideoDecodeAccelerator::SendImages() { |
| 256 if (!client_) { | 264 if (!client_) { |
| 257 DCHECK(decoded_images_.empty()); | 265 DCHECK(decoded_images_.empty()); |
| 258 return; | 266 return; |
| 259 } | 267 } |
| 260 | 268 |
| 261 while (available_pictures_.size() && decoded_images_.size()) { | 269 while (available_pictures_.size() && decoded_images_.size()) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 272 picture_buffer.id(), UsedPictureInfo(picture_buffer, info.image))); | 280 picture_buffer.id(), UsedPictureInfo(picture_buffer, info.image))); |
| 273 client_->PictureReady( | 281 client_->PictureReady( |
| 274 media::Picture(picture_buffer.id(), info.bitstream_buffer_id)); | 282 media::Picture(picture_buffer.id(), info.bitstream_buffer_id)); |
| 275 } | 283 } |
| 276 } | 284 } |
| 277 | 285 |
| 278 void MacVideoDecodeAccelerator::StopOnError( | 286 void MacVideoDecodeAccelerator::StopOnError( |
| 279 media::VideoDecodeAccelerator::Error error) { | 287 media::VideoDecodeAccelerator::Error error) { |
| 280 if (client_) | 288 if (client_) |
| 281 client_->NotifyError(error); | 289 client_->NotifyError(error); |
| 282 Destroy(); | 290 Cleanup(); |
| 283 } | 291 } |
| 284 | 292 |
| 285 bool MacVideoDecodeAccelerator::CreateDecoder( | 293 bool MacVideoDecodeAccelerator::CreateDecoder( |
| 286 const std::vector<uint8_t>& extra_data) { | 294 const std::vector<uint8_t>& extra_data) { |
| 287 DCHECK(client_); | 295 DCHECK(client_); |
| 288 DCHECK(!vda_support_.get()); | 296 DCHECK(!vda_support_.get()); |
| 289 | 297 |
| 290 vda_support_ = new gfx::VideoDecodeAccelerationSupport(); | 298 vda_support_ = new gfx::VideoDecodeAccelerationSupport(); |
| 291 gfx::VideoDecodeAccelerationSupport::Status status = vda_support_->Create( | 299 gfx::VideoDecodeAccelerationSupport::Status status = vda_support_->Create( |
| 292 config_record_builder_.coded_width(), | 300 config_record_builder_.coded_width(), |
| 293 config_record_builder_.coded_height(), | 301 config_record_builder_.coded_height(), |
| 294 kCVPixelFormatType_422YpCbCr8, | 302 kCVPixelFormatType_422YpCbCr8, |
| 295 &extra_data[0], extra_data.size()); | 303 &extra_data[0], extra_data.size()); |
| 296 RETURN_ON_FAILURE(status == gfx::VideoDecodeAccelerationSupport::SUCCESS, | 304 RETURN_ON_FAILURE(status == gfx::VideoDecodeAccelerationSupport::SUCCESS, |
| 297 "Creating video decoder failed with error: " << status, | 305 "Creating video decoder failed with error: " << status, |
| 298 PLATFORM_FAILURE, false); | 306 PLATFORM_FAILURE, false); |
| 299 | 307 |
| 300 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 308 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( |
| 301 &MacVideoDecodeAccelerator::RequestPictures, this)); | 309 &MacVideoDecodeAccelerator::RequestPictures, base::AsWeakPtr(this))); |
| 302 return true; | 310 return true; |
| 303 } | 311 } |
| 304 | 312 |
| 305 void MacVideoDecodeAccelerator::DecodeNALU(const content::H264NALU& nalu, | 313 void MacVideoDecodeAccelerator::DecodeNALU(const content::H264NALU& nalu, |
| 306 int32 bitstream_buffer_id) { | 314 int32 bitstream_buffer_id) { |
| 307 // Assume the NALU length field size is 4 bytes. | 315 // Assume the NALU length field size is 4 bytes. |
| 308 const int kNALULengthFieldSize = 4; | 316 const int kNALULengthFieldSize = 4; |
| 309 std::vector<uint8_t> data(kNALULengthFieldSize + nalu.size); | 317 std::vector<uint8_t> data(kNALULengthFieldSize + nalu.size); |
| 310 | 318 |
| 311 // Store the buffer size at the beginning of the buffer as the decoder | 319 // Store the buffer size at the beginning of the buffer as the decoder |
| 312 // expects. | 320 // expects. |
| 313 for (size_t i = 0; i < kNALULengthFieldSize; ++i) { | 321 for (size_t i = 0; i < kNALULengthFieldSize; ++i) { |
| 314 size_t shift = kNALULengthFieldSize * 8 - (i + 1) * 8; | 322 size_t shift = kNALULengthFieldSize * 8 - (i + 1) * 8; |
| 315 data[i] = (nalu.size >> shift) & 0xff; | 323 data[i] = (nalu.size >> shift) & 0xff; |
| 316 } | 324 } |
| 317 | 325 |
| 318 // Copy the NALU data. | 326 // Copy the NALU data. |
| 319 memcpy(&data[kNALULengthFieldSize], nalu.data, nalu.size); | 327 memcpy(&data[kNALULengthFieldSize], nalu.data, nalu.size); |
| 320 | 328 |
| 321 // Keep a ref counted copy of the buffer. | 329 // Keep a ref counted copy of the buffer. |
| 322 scoped_refptr<base::RefCountedBytes> bytes( | 330 scoped_refptr<base::RefCountedBytes> bytes( |
| 323 base::RefCountedBytes::TakeVector(&data)); | 331 base::RefCountedBytes::TakeVector(&data)); |
| 324 vda_support_->Decode(bytes->front(), bytes->size(), | 332 vda_support_->Decode(bytes->front(), bytes->size(), base::Bind( |
| 325 base::Bind(&MacVideoDecodeAccelerator::OnFrameReady, | 333 &MacVideoDecodeAccelerator::OnFrameReady, |
| 326 this, bitstream_buffer_id, bytes)); | 334 base::AsWeakPtr(this), bitstream_buffer_id, bytes)); |
| 327 } | 335 } |
| 328 | 336 |
| 329 void MacVideoDecodeAccelerator::NotifyInitializeDone() { | 337 void MacVideoDecodeAccelerator::NotifyInitializeDone() { |
| 330 if (client_) | 338 if (client_) |
| 331 client_->NotifyInitializeDone(); | 339 client_->NotifyInitializeDone(); |
| 332 } | 340 } |
| 333 | 341 |
| 334 void MacVideoDecodeAccelerator::RequestPictures() { | 342 void MacVideoDecodeAccelerator::RequestPictures() { |
| 335 if (client_) { | 343 if (client_) { |
| 336 client_->ProvidePictureBuffers( | 344 client_->ProvidePictureBuffers( |
| (...skipping 28 matching lines...) Expand all Loading... |
| 365 } | 373 } |
| 366 | 374 |
| 367 MacVideoDecodeAccelerator::UsedPictureInfo::~UsedPictureInfo() { | 375 MacVideoDecodeAccelerator::UsedPictureInfo::~UsedPictureInfo() { |
| 368 } | 376 } |
| 369 | 377 |
| 370 MacVideoDecodeAccelerator::DecodedImageInfo::DecodedImageInfo() { | 378 MacVideoDecodeAccelerator::DecodedImageInfo::DecodedImageInfo() { |
| 371 } | 379 } |
| 372 | 380 |
| 373 MacVideoDecodeAccelerator::DecodedImageInfo::~DecodedImageInfo() { | 381 MacVideoDecodeAccelerator::DecodedImageInfo::~DecodedImageInfo() { |
| 374 } | 382 } |
| OLD | NEW |