Chromium Code Reviews| 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/vaapi_video_decode_accelerator.h" | |
| 6 | |
| 5 #include "base/bind.h" | 7 #include "base/bind.h" |
| 6 #include "base/logging.h" | 8 #include "base/logging.h" |
| 7 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 8 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
| 9 #include "base/strings/string_util.h" | 11 #include "base/strings/string_util.h" |
| 10 #include "base/synchronization/waitable_event.h" | 12 #include "base/synchronization/waitable_event.h" |
| 11 #include "base/trace_event/trace_event.h" | 13 #include "base/trace_event/trace_event.h" |
| 12 #include "content/common/gpu/gpu_channel.h" | 14 #include "content/common/gpu/gpu_channel.h" |
| 15 #include "content/common/gpu/media/accelerated_video_decoder.h" | |
| 16 #include "content/common/gpu/media/h264_decoder.h" | |
| 13 #include "content/common/gpu/media/vaapi_picture.h" | 17 #include "content/common/gpu/media/vaapi_picture.h" |
| 14 #include "content/common/gpu/media/vaapi_video_decode_accelerator.h" | |
| 15 #include "media/base/bind_to_current_loop.h" | 18 #include "media/base/bind_to_current_loop.h" |
| 16 #include "media/video/picture.h" | 19 #include "media/video/picture.h" |
| 17 #include "ui/gl/gl_bindings.h" | 20 #include "ui/gl/gl_bindings.h" |
| 18 #include "ui/gl/gl_image.h" | 21 #include "ui/gl/gl_image.h" |
| 19 | 22 |
| 20 static void ReportToUMA( | 23 namespace content { |
| 21 content::VaapiH264Decoder::VAVDAH264DecoderFailure failure) { | 24 |
| 22 UMA_HISTOGRAM_ENUMERATION( | 25 namespace { |
| 23 "Media.VAVDAH264.DecoderFailure", | 26 // UMA errors that the VaapiVideoDecodeAccelerator class reports. |
| 24 failure, | 27 enum VAVDADecoderFailure { |
| 25 content::VaapiH264Decoder::VAVDA_H264_DECODER_FAILURES_MAX); | 28 VAAPI_ERROR = 0, |
| 29 VAVDA_DECODER_FAILURES_MAX, | |
| 30 }; | |
| 26 } | 31 } |
| 27 | 32 |
| 28 namespace content { | 33 static void ReportToUMA(VAVDADecoderFailure failure) { |
| 34 UMA_HISTOGRAM_ENUMERATION("Media.VAVDA.DecoderFailure", failure, | |
| 35 VAVDA_DECODER_FAILURES_MAX); | |
| 36 } | |
| 29 | 37 |
| 30 #define RETURN_AND_NOTIFY_ON_FAILURE(result, log, error_code, ret) \ | 38 #define RETURN_AND_NOTIFY_ON_FAILURE(result, log, error_code, ret) \ |
| 31 do { \ | 39 do { \ |
| 32 if (!(result)) { \ | 40 if (!(result)) { \ |
| 33 LOG(ERROR) << log; \ | 41 LOG(ERROR) << log; \ |
| 34 NotifyError(error_code); \ | 42 NotifyError(error_code); \ |
| 35 return ret; \ | 43 return ret; \ |
| 36 } \ | 44 } \ |
| 37 } while (0) | 45 } while (0) |
| 38 | 46 |
| 47 class VaapiVideoDecodeAccelerator::VaapiDecodeSurface | |
| 48 : public base::RefCountedThreadSafe<VaapiDecodeSurface> { | |
| 49 public: | |
| 50 VaapiDecodeSurface(int32 bitstream_id, | |
| 51 const scoped_refptr<VASurface>& va_surface); | |
| 52 | |
| 53 int32 bitstream_id() const { return bitstream_id_; } | |
| 54 scoped_refptr<VASurface> va_surface() { return va_surface_; } | |
| 55 | |
| 56 private: | |
| 57 friend class base::RefCountedThreadSafe<VaapiDecodeSurface>; | |
| 58 ~VaapiDecodeSurface(); | |
| 59 | |
| 60 int32 bitstream_id_; | |
| 61 scoped_refptr<VASurface> va_surface_; | |
| 62 }; | |
| 63 | |
| 64 VaapiVideoDecodeAccelerator::VaapiDecodeSurface::VaapiDecodeSurface( | |
| 65 int32 bitstream_id, | |
| 66 const scoped_refptr<VASurface>& va_surface) | |
| 67 : bitstream_id_(bitstream_id), va_surface_(va_surface) { | |
| 68 } | |
| 69 | |
| 70 VaapiVideoDecodeAccelerator::VaapiDecodeSurface::~VaapiDecodeSurface() { | |
| 71 } | |
| 72 | |
| 73 class VaapiH264Picture : public H264Picture { | |
| 74 public: | |
| 75 VaapiH264Picture(const scoped_refptr< | |
| 76 VaapiVideoDecodeAccelerator::VaapiDecodeSurface>& dec_surface); | |
| 77 | |
| 78 VaapiH264Picture* AsVaapiH264Picture() override { return this; } | |
| 79 scoped_refptr<VaapiVideoDecodeAccelerator::VaapiDecodeSurface> dec_surface() { | |
| 80 return dec_surface_; | |
| 81 } | |
| 82 | |
| 83 private: | |
| 84 ~VaapiH264Picture() override; | |
| 85 | |
| 86 scoped_refptr<VaapiVideoDecodeAccelerator::VaapiDecodeSurface> dec_surface_; | |
| 87 | |
| 88 DISALLOW_COPY_AND_ASSIGN(VaapiH264Picture); | |
| 89 }; | |
| 90 | |
| 91 VaapiH264Picture::VaapiH264Picture(const scoped_refptr< | |
| 92 VaapiVideoDecodeAccelerator::VaapiDecodeSurface>& dec_surface) | |
| 93 : dec_surface_(dec_surface) { | |
| 94 } | |
| 95 | |
| 96 VaapiH264Picture::~VaapiH264Picture() { | |
| 97 } | |
| 98 | |
| 99 class VaapiVideoDecodeAccelerator::VaapiH264Accelerator | |
| 100 : public H264Decoder::H264Accelerator { | |
| 101 public: | |
| 102 VaapiH264Accelerator(VaapiVideoDecodeAccelerator* vaapi_dec, | |
| 103 VaapiWrapper* vaapi_wrapper); | |
| 104 ~VaapiH264Accelerator() override; | |
| 105 | |
| 106 // H264Decoder::H264Accelerator implementation. | |
| 107 scoped_refptr<H264Picture> CreateH264Picture() override; | |
| 108 | |
| 109 bool SubmitFrameMetadata(const media::H264SPS* sps, | |
| 110 const media::H264PPS* pps, | |
| 111 const H264DPB& dpb, | |
| 112 const H264Picture::Vector& ref_pic_listp0, | |
| 113 const H264Picture::Vector& ref_pic_listb0, | |
| 114 const H264Picture::Vector& ref_pic_listb1, | |
| 115 const scoped_refptr<H264Picture>& pic) override; | |
| 116 | |
| 117 bool SubmitSlice(const media::H264PPS* pps, | |
| 118 const media::H264SliceHeader* slice_hdr, | |
| 119 const H264Picture::Vector& ref_pic_list0, | |
| 120 const H264Picture::Vector& ref_pic_list1, | |
| 121 const scoped_refptr<H264Picture>& pic, | |
| 122 const uint8_t* data, | |
| 123 size_t size) override; | |
| 124 | |
| 125 bool SubmitDecode(const scoped_refptr<H264Picture>& pic) override; | |
| 126 bool OutputPicture(const scoped_refptr<H264Picture>& pic) override; | |
| 127 | |
| 128 void Reset() override; | |
| 129 | |
| 130 private: | |
| 131 scoped_refptr<VaapiDecodeSurface> H264PictureToVaapiDecodeSurface( | |
| 132 const scoped_refptr<H264Picture>& pic); | |
| 133 | |
| 134 void FillVAPicture(VAPictureH264* va_pic, scoped_refptr<H264Picture> pic); | |
| 135 int FillVARefFramesFromDPB(const H264DPB& dpb, | |
| 136 VAPictureH264* va_pics, | |
| 137 int num_pics); | |
| 138 | |
| 139 VaapiWrapper* vaapi_wrapper_; | |
| 140 VaapiVideoDecodeAccelerator* vaapi_dec_; | |
| 141 | |
| 142 DISALLOW_COPY_AND_ASSIGN(VaapiH264Accelerator); | |
| 143 }; | |
| 144 | |
| 39 VaapiVideoDecodeAccelerator::InputBuffer::InputBuffer() : id(0), size(0) { | 145 VaapiVideoDecodeAccelerator::InputBuffer::InputBuffer() : id(0), size(0) { |
| 40 } | 146 } |
| 41 | 147 |
| 42 VaapiVideoDecodeAccelerator::InputBuffer::~InputBuffer() { | 148 VaapiVideoDecodeAccelerator::InputBuffer::~InputBuffer() { |
| 43 } | 149 } |
| 44 | 150 |
| 45 void VaapiVideoDecodeAccelerator::NotifyError(Error error) { | 151 void VaapiVideoDecodeAccelerator::NotifyError(Error error) { |
| 46 if (message_loop_ != base::MessageLoop::current()) { | 152 if (message_loop_ != base::MessageLoop::current()) { |
| 47 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread()); | 153 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread()); |
| 48 message_loop_->PostTask(FROM_HERE, base::Bind( | 154 message_loop_->PostTask(FROM_HERE, base::Bind( |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 117 } | 223 } |
| 118 #elif defined(USE_OZONE) | 224 #elif defined(USE_OZONE) |
| 119 if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) { | 225 if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) { |
| 120 DVLOG(1) << "HW video decode acceleration not available without " | 226 DVLOG(1) << "HW video decode acceleration not available without " |
| 121 << "EGLGLES2."; | 227 << "EGLGLES2."; |
| 122 return false; | 228 return false; |
| 123 } | 229 } |
| 124 #endif // USE_X11 | 230 #endif // USE_X11 |
| 125 | 231 |
| 126 vaapi_wrapper_ = VaapiWrapper::CreateForVideoCodec( | 232 vaapi_wrapper_ = VaapiWrapper::CreateForVideoCodec( |
| 127 VaapiWrapper::kDecode, profile, | 233 VaapiWrapper::kDecode, profile, base::Bind(&ReportToUMA, VAAPI_ERROR)); |
| 128 base::Bind(&ReportToUMA, content::VaapiH264Decoder::VAAPI_ERROR)); | |
| 129 | 234 |
| 130 if (!vaapi_wrapper_.get()) { | 235 if (!vaapi_wrapper_.get()) { |
| 131 DVLOG(1) << "Failed initializing VAAPI for profile " << profile; | 236 DVLOG(1) << "Failed initializing VAAPI for profile " << profile; |
| 132 return false; | 237 return false; |
| 133 } | 238 } |
| 134 | 239 |
| 135 decoder_.reset( | 240 if (!(profile >= media::H264PROFILE_MIN && |
| 136 new VaapiH264Decoder( | 241 profile <= media::H264PROFILE_MAX)) { |
| 137 vaapi_wrapper_.get(), | 242 DLOG(ERROR) << "Unsupported profile " << profile; |
| 138 media::BindToCurrentLoop(base::Bind( | 243 return false; |
| 139 &VaapiVideoDecodeAccelerator::SurfaceReady, weak_this_)), | 244 } |
| 140 base::Bind(&ReportToUMA))); | 245 |
| 246 h264_accelerator_.reset(new VaapiH264Accelerator(this, vaapi_wrapper_.get())); | |
| 247 decoder_.reset(new H264Decoder(h264_accelerator_.get())); | |
| 141 | 248 |
| 142 CHECK(decoder_thread_.Start()); | 249 CHECK(decoder_thread_.Start()); |
| 143 decoder_thread_proxy_ = decoder_thread_.message_loop_proxy(); | 250 decoder_thread_proxy_ = decoder_thread_.message_loop_proxy(); |
| 144 | 251 |
| 145 state_ = kIdle; | 252 state_ = kIdle; |
| 146 return true; | 253 return true; |
| 147 } | 254 } |
| 148 | 255 |
| 149 void VaapiVideoDecodeAccelerator::SurfaceReady( | |
| 150 int32 input_id, | |
| 151 const scoped_refptr<VASurface>& va_surface) { | |
| 152 DCHECK_EQ(message_loop_, base::MessageLoop::current()); | |
| 153 DCHECK(!awaiting_va_surfaces_recycle_); | |
| 154 | |
| 155 // Drop any requests to output if we are resetting or being destroyed. | |
| 156 if (state_ == kResetting || state_ == kDestroying) | |
| 157 return; | |
| 158 | |
| 159 pending_output_cbs_.push( | |
| 160 base::Bind(&VaapiVideoDecodeAccelerator::OutputPicture, | |
| 161 weak_this_, va_surface, input_id)); | |
| 162 | |
| 163 TryOutputSurface(); | |
| 164 } | |
| 165 | |
| 166 void VaapiVideoDecodeAccelerator::OutputPicture( | 256 void VaapiVideoDecodeAccelerator::OutputPicture( |
| 167 const scoped_refptr<VASurface>& va_surface, | 257 const scoped_refptr<VASurface>& va_surface, |
| 168 int32 input_id, | 258 int32 input_id, |
| 169 VaapiPicture* picture) { | 259 VaapiPicture* picture) { |
| 170 DCHECK_EQ(message_loop_, base::MessageLoop::current()); | 260 DCHECK_EQ(message_loop_, base::MessageLoop::current()); |
| 171 | 261 |
| 172 int32 output_id = picture->picture_buffer_id(); | 262 int32 output_id = picture->picture_buffer_id(); |
| 173 | 263 |
| 174 TRACE_EVENT2("Video Decoder", "VAVDA::OutputSurface", | 264 TRACE_EVENT2("Video Decoder", "VAVDA::OutputSurface", |
| 175 "input_id", input_id, | 265 "input_id", input_id, |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 276 | 366 |
| 277 curr_input_buffer_ = input_buffers_.front(); | 367 curr_input_buffer_ = input_buffers_.front(); |
| 278 input_buffers_.pop(); | 368 input_buffers_.pop(); |
| 279 | 369 |
| 280 DVLOG(4) << "New current bitstream buffer, id: " | 370 DVLOG(4) << "New current bitstream buffer, id: " |
| 281 << curr_input_buffer_->id | 371 << curr_input_buffer_->id |
| 282 << " size: " << curr_input_buffer_->size; | 372 << " size: " << curr_input_buffer_->size; |
| 283 | 373 |
| 284 decoder_->SetStream( | 374 decoder_->SetStream( |
| 285 static_cast<uint8*>(curr_input_buffer_->shm->memory()), | 375 static_cast<uint8*>(curr_input_buffer_->shm->memory()), |
| 286 curr_input_buffer_->size, curr_input_buffer_->id); | 376 curr_input_buffer_->size); |
| 287 return true; | 377 return true; |
| 288 | 378 |
| 289 default: | 379 default: |
| 290 // We got woken up due to being destroyed/reset, ignore any already | 380 // We got woken up due to being destroyed/reset, ignore any already |
| 291 // queued inputs. | 381 // queued inputs. |
| 292 return false; | 382 return false; |
| 293 } | 383 } |
| 294 } | 384 } |
| 295 | 385 |
| 296 void VaapiVideoDecodeAccelerator::ReturnCurrInputBuffer_Locked() { | 386 void VaapiVideoDecodeAccelerator::ReturnCurrInputBuffer_Locked() { |
| 297 lock_.AssertAcquired(); | 387 lock_.AssertAcquired(); |
| 298 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread()); | 388 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread()); |
| 299 DCHECK(curr_input_buffer_.get()); | 389 DCHECK(curr_input_buffer_.get()); |
| 300 | 390 |
| 301 int32 id = curr_input_buffer_->id; | 391 int32 id = curr_input_buffer_->id; |
| 302 curr_input_buffer_.reset(); | 392 curr_input_buffer_.reset(); |
| 303 DVLOG(4) << "End of input buffer " << id; | 393 DVLOG(4) << "End of input buffer " << id; |
| 304 message_loop_->PostTask(FROM_HERE, base::Bind( | 394 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 305 &Client::NotifyEndOfBitstreamBuffer, client_, id)); | 395 &Client::NotifyEndOfBitstreamBuffer, client_, id)); |
| 306 | 396 |
| 307 --num_stream_bufs_at_decoder_; | 397 --num_stream_bufs_at_decoder_; |
| 308 TRACE_COUNTER1("Video Decoder", "Stream buffers at decoder", | 398 TRACE_COUNTER1("Video Decoder", "Stream buffers at decoder", |
| 309 num_stream_bufs_at_decoder_); | 399 num_stream_bufs_at_decoder_); |
| 310 } | 400 } |
| 311 | 401 |
| 312 bool VaapiVideoDecodeAccelerator::FeedDecoderWithOutputSurfaces_Locked() { | 402 // TODO(posciak): refactor the whole class to remove sleeping in wait for |
| 403 // surfaces, and reschedule DecodeTask instead. | |
|
wuchengli
2015/03/30 11:02:55
nit: I think one TODO in vaapi_video_decode_accele
Pawel Osciak
2015/04/03 07:06:00
Done.
| |
| 404 bool VaapiVideoDecodeAccelerator::WaitForSurfaces_Locked() { | |
| 313 lock_.AssertAcquired(); | 405 lock_.AssertAcquired(); |
| 314 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread()); | 406 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread()); |
| 315 | 407 |
| 316 while (available_va_surfaces_.empty() && | 408 while (available_va_surfaces_.empty() && |
| 317 (state_ == kDecoding || state_ == kFlushing || state_ == kIdle)) { | 409 (state_ == kDecoding || state_ == kFlushing || state_ == kIdle)) { |
| 318 surfaces_available_.Wait(); | 410 surfaces_available_.Wait(); |
| 319 } | 411 } |
| 320 | 412 |
| 321 if (state_ != kDecoding && state_ != kFlushing && state_ != kIdle) | 413 if (state_ != kDecoding && state_ != kFlushing && state_ != kIdle) |
| 322 return false; | 414 return false; |
| 323 | 415 |
| 324 DCHECK(!awaiting_va_surfaces_recycle_); | |
| 325 while (!available_va_surfaces_.empty()) { | |
| 326 scoped_refptr<VASurface> va_surface( | |
| 327 new VASurface(available_va_surfaces_.front(), requested_pic_size_, | |
| 328 va_surface_release_cb_)); | |
| 329 available_va_surfaces_.pop_front(); | |
| 330 decoder_->ReuseSurface(va_surface); | |
| 331 } | |
| 332 | |
| 333 return true; | 416 return true; |
| 334 } | 417 } |
| 335 | 418 |
| 336 void VaapiVideoDecodeAccelerator::DecodeTask() { | 419 void VaapiVideoDecodeAccelerator::DecodeTask() { |
| 337 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread()); | 420 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread()); |
| 338 TRACE_EVENT0("Video Decoder", "VAVDA::DecodeTask"); | 421 TRACE_EVENT0("Video Decoder", "VAVDA::DecodeTask"); |
| 339 base::AutoLock auto_lock(lock_); | 422 base::AutoLock auto_lock(lock_); |
| 340 | 423 |
| 341 if (state_ != kDecoding) | 424 if (state_ != kDecoding) |
| 342 return; | 425 return; |
| 343 | 426 |
| 344 // Main decode task. | 427 // Main decode task. |
| 345 DVLOG(4) << "Decode task"; | 428 DVLOG(4) << "Decode task"; |
| 346 | 429 |
| 347 // Try to decode what stream data is (still) in the decoder until we run out | 430 // Try to decode what stream data is (still) in the decoder until we run out |
| 348 // of it. | 431 // of it. |
| 349 while (GetInputBuffer_Locked()) { | 432 while (GetInputBuffer_Locked()) { |
| 350 DCHECK(curr_input_buffer_.get()); | 433 DCHECK(curr_input_buffer_.get()); |
| 351 | 434 |
| 352 VaapiH264Decoder::DecResult res; | 435 AcceleratedVideoDecoder::DecodeResult res; |
| 353 { | 436 { |
| 354 // We are OK releasing the lock here, as decoder never calls our methods | 437 // We are OK releasing the lock here, as decoder never calls our methods |
| 355 // directly and we will reacquire the lock before looking at state again. | 438 // directly and we will reacquire the lock before looking at state again. |
| 356 // This is the main decode function of the decoder and while keeping | 439 // This is the main decode function of the decoder and while keeping |
| 357 // the lock for its duration would be fine, it would defeat the purpose | 440 // the lock for its duration would be fine, it would defeat the purpose |
| 358 // of having a separate decoder thread. | 441 // of having a separate decoder thread. |
| 359 base::AutoUnlock auto_unlock(lock_); | 442 base::AutoUnlock auto_unlock(lock_); |
| 360 res = decoder_->Decode(); | 443 res = decoder_->Decode(); |
| 361 } | 444 } |
| 362 | 445 |
| 363 switch (res) { | 446 switch (res) { |
| 364 case VaapiH264Decoder::kAllocateNewSurfaces: | 447 case AcceleratedVideoDecoder::kAllocateNewSurfaces: |
| 365 DVLOG(1) << "Decoder requesting a new set of surfaces"; | 448 DVLOG(1) << "Decoder requesting a new set of surfaces"; |
| 366 message_loop_->PostTask(FROM_HERE, base::Bind( | 449 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 367 &VaapiVideoDecodeAccelerator::InitiateSurfaceSetChange, weak_this_, | 450 &VaapiVideoDecodeAccelerator::InitiateSurfaceSetChange, weak_this_, |
| 368 decoder_->GetRequiredNumOfPictures(), | 451 decoder_->GetRequiredNumOfPictures(), |
| 369 decoder_->GetPicSize())); | 452 decoder_->GetPicSize())); |
| 370 // We'll get rescheduled once ProvidePictureBuffers() finishes. | 453 // We'll get rescheduled once ProvidePictureBuffers() finishes. |
| 371 return; | 454 return; |
| 372 | 455 |
| 373 case VaapiH264Decoder::kRanOutOfStreamData: | 456 case AcceleratedVideoDecoder::kRanOutOfStreamData: |
| 374 ReturnCurrInputBuffer_Locked(); | 457 ReturnCurrInputBuffer_Locked(); |
| 375 break; | 458 break; |
| 376 | 459 |
| 377 case VaapiH264Decoder::kRanOutOfSurfaces: | 460 case AcceleratedVideoDecoder::kRanOutOfSurfaces: |
| 378 // No more output buffers in the decoder, try getting more or go to | 461 // No more output buffers in the decoder, try getting more or go to |
| 379 // sleep waiting for them. | 462 // sleep waiting for them. |
| 380 if (!FeedDecoderWithOutputSurfaces_Locked()) | 463 if (!WaitForSurfaces_Locked()) |
| 381 return; | 464 return; |
| 382 | 465 |
| 383 break; | 466 break; |
| 384 | 467 |
| 385 case VaapiH264Decoder::kDecodeError: | 468 case AcceleratedVideoDecoder::kDecodeError: |
| 386 RETURN_AND_NOTIFY_ON_FAILURE(false, "Error decoding stream", | 469 RETURN_AND_NOTIFY_ON_FAILURE(false, "Error decoding stream", |
| 387 PLATFORM_FAILURE, ); | 470 PLATFORM_FAILURE, ); |
| 388 return; | 471 return; |
| 389 } | 472 } |
| 390 } | 473 } |
| 391 } | 474 } |
| 392 | 475 |
| 393 void VaapiVideoDecodeAccelerator::InitiateSurfaceSetChange(size_t num_pics, | 476 void VaapiVideoDecodeAccelerator::InitiateSurfaceSetChange(size_t num_pics, |
| 394 gfx::Size size) { | 477 gfx::Size size) { |
| 395 DCHECK_EQ(message_loop_, base::MessageLoop::current()); | 478 DCHECK_EQ(message_loop_, base::MessageLoop::current()); |
| (...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 741 void VaapiVideoDecodeAccelerator::Destroy() { | 824 void VaapiVideoDecodeAccelerator::Destroy() { |
| 742 DCHECK_EQ(message_loop_, base::MessageLoop::current()); | 825 DCHECK_EQ(message_loop_, base::MessageLoop::current()); |
| 743 Cleanup(); | 826 Cleanup(); |
| 744 delete this; | 827 delete this; |
| 745 } | 828 } |
| 746 | 829 |
| 747 bool VaapiVideoDecodeAccelerator::CanDecodeOnIOThread() { | 830 bool VaapiVideoDecodeAccelerator::CanDecodeOnIOThread() { |
| 748 return false; | 831 return false; |
| 749 } | 832 } |
| 750 | 833 |
| 834 bool VaapiVideoDecodeAccelerator::DecodeSurface( | |
| 835 const scoped_refptr<VaapiDecodeSurface>& dec_surface) { | |
| 836 if (!vaapi_wrapper_->ExecuteAndDestroyPendingBuffers( | |
| 837 dec_surface->va_surface()->id())) { | |
| 838 DVLOG(1) << "Failed decoding picture"; | |
| 839 return false; | |
| 840 } | |
| 841 | |
| 842 return true; | |
| 843 } | |
| 844 | |
| 845 void VaapiVideoDecodeAccelerator::SurfaceReady( | |
| 846 const scoped_refptr<VaapiDecodeSurface>& dec_surface) { | |
| 847 if (message_loop_ != base::MessageLoop::current()) { | |
| 848 message_loop_->PostTask( | |
| 849 FROM_HERE, base::Bind(&VaapiVideoDecodeAccelerator::SurfaceReady, | |
| 850 weak_this_, dec_surface)); | |
| 851 return; | |
| 852 } | |
| 853 | |
| 854 DCHECK(!awaiting_va_surfaces_recycle_); | |
| 855 | |
| 856 // Drop any requests to output if we are resetting or being destroyed. | |
| 857 if (state_ == kResetting || state_ == kDestroying) | |
|
wuchengli
2015/04/01 05:17:38
auto_lock(lock_); to protect |state_|?
Pawel Osciak
2015/04/03 07:06:00
Done.
| |
| 858 return; | |
| 859 | |
| 860 pending_output_cbs_.push( | |
| 861 base::Bind(&VaapiVideoDecodeAccelerator::OutputPicture, weak_this_, | |
| 862 dec_surface->va_surface(), dec_surface->bitstream_id())); | |
| 863 | |
| 864 TryOutputSurface(); | |
| 865 } | |
| 866 | |
| 867 scoped_refptr<VaapiVideoDecodeAccelerator::VaapiDecodeSurface> | |
| 868 VaapiVideoDecodeAccelerator::CreateSurface() { | |
| 869 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread()); | |
| 870 base::AutoLock auto_lock(lock_); | |
| 871 | |
| 872 if (available_va_surfaces_.empty()) | |
| 873 return nullptr; | |
| 874 | |
| 875 DCHECK(!awaiting_va_surfaces_recycle_); | |
| 876 scoped_refptr<VASurface> va_surface( | |
| 877 new VASurface(available_va_surfaces_.front(), requested_pic_size_, | |
| 878 va_surface_release_cb_)); | |
| 879 available_va_surfaces_.pop_front(); | |
| 880 | |
| 881 scoped_refptr<VaapiDecodeSurface> dec_surface = | |
| 882 new VaapiDecodeSurface(curr_input_buffer_->id, va_surface); | |
| 883 | |
| 884 return dec_surface; | |
| 885 } | |
| 886 | |
| 887 VaapiVideoDecodeAccelerator::VaapiH264Accelerator::VaapiH264Accelerator( | |
| 888 VaapiVideoDecodeAccelerator* vaapi_dec, | |
| 889 VaapiWrapper* vaapi_wrapper) | |
| 890 : vaapi_wrapper_(vaapi_wrapper), vaapi_dec_(vaapi_dec) { | |
| 891 DCHECK(vaapi_wrapper_); | |
| 892 DCHECK(vaapi_dec_); | |
| 893 } | |
| 894 | |
| 895 VaapiVideoDecodeAccelerator::VaapiH264Accelerator::~VaapiH264Accelerator() { | |
| 896 } | |
| 897 | |
| 898 scoped_refptr<H264Picture> | |
| 899 VaapiVideoDecodeAccelerator::VaapiH264Accelerator::CreateH264Picture() { | |
| 900 scoped_refptr<VaapiDecodeSurface> va_surface = vaapi_dec_->CreateSurface(); | |
| 901 if (!va_surface) | |
| 902 return nullptr; | |
| 903 | |
| 904 return new VaapiH264Picture(va_surface); | |
| 905 } | |
| 906 | |
| 907 // Fill |va_pic| with default/neutral values. | |
| 908 static void InitVAPicture(VAPictureH264* va_pic) { | |
| 909 memset(va_pic, 0, sizeof(*va_pic)); | |
| 910 va_pic->picture_id = VA_INVALID_ID; | |
| 911 va_pic->flags = VA_PICTURE_H264_INVALID; | |
| 912 } | |
| 913 | |
| 914 bool VaapiVideoDecodeAccelerator::VaapiH264Accelerator::SubmitFrameMetadata( | |
| 915 const media::H264SPS* sps, | |
| 916 const media::H264PPS* pps, | |
| 917 const H264DPB& dpb, | |
| 918 const H264Picture::Vector& ref_pic_listp0, | |
| 919 const H264Picture::Vector& ref_pic_listb0, | |
| 920 const H264Picture::Vector& ref_pic_listb1, | |
| 921 const scoped_refptr<H264Picture>& pic) { | |
| 922 VAPictureParameterBufferH264 pic_param; | |
| 923 memset(&pic_param, 0, sizeof(VAPictureParameterBufferH264)); | |
| 924 | |
| 925 #define FROM_SPS_TO_PP(a) pic_param.a = sps->a; | |
| 926 #define FROM_SPS_TO_PP2(a, b) pic_param.b = sps->a; | |
| 927 FROM_SPS_TO_PP2(pic_width_in_mbs_minus1, picture_width_in_mbs_minus1); | |
| 928 // This assumes non-interlaced video | |
| 929 FROM_SPS_TO_PP2(pic_height_in_map_units_minus1, picture_height_in_mbs_minus1); | |
| 930 FROM_SPS_TO_PP(bit_depth_luma_minus8); | |
| 931 FROM_SPS_TO_PP(bit_depth_chroma_minus8); | |
| 932 #undef FROM_SPS_TO_PP | |
| 933 #undef FROM_SPS_TO_PP2 | |
| 934 | |
| 935 #define FROM_SPS_TO_PP_SF(a) pic_param.seq_fields.bits.a = sps->a; | |
| 936 #define FROM_SPS_TO_PP_SF2(a, b) pic_param.seq_fields.bits.b = sps->a; | |
| 937 FROM_SPS_TO_PP_SF(chroma_format_idc); | |
| 938 FROM_SPS_TO_PP_SF2(separate_colour_plane_flag, | |
| 939 residual_colour_transform_flag); | |
| 940 FROM_SPS_TO_PP_SF(gaps_in_frame_num_value_allowed_flag); | |
| 941 FROM_SPS_TO_PP_SF(frame_mbs_only_flag); | |
| 942 FROM_SPS_TO_PP_SF(mb_adaptive_frame_field_flag); | |
| 943 FROM_SPS_TO_PP_SF(direct_8x8_inference_flag); | |
| 944 pic_param.seq_fields.bits.MinLumaBiPredSize8x8 = (sps->level_idc >= 31); | |
| 945 FROM_SPS_TO_PP_SF(log2_max_frame_num_minus4); | |
| 946 FROM_SPS_TO_PP_SF(pic_order_cnt_type); | |
| 947 FROM_SPS_TO_PP_SF(log2_max_pic_order_cnt_lsb_minus4); | |
| 948 FROM_SPS_TO_PP_SF(delta_pic_order_always_zero_flag); | |
| 949 #undef FROM_SPS_TO_PP_SF | |
| 950 #undef FROM_SPS_TO_PP_SF2 | |
| 951 | |
| 952 #define FROM_PPS_TO_PP(a) pic_param.a = pps->a; | |
| 953 FROM_PPS_TO_PP(num_slice_groups_minus1); | |
| 954 pic_param.slice_group_map_type = 0; | |
| 955 pic_param.slice_group_change_rate_minus1 = 0; | |
| 956 FROM_PPS_TO_PP(pic_init_qp_minus26); | |
| 957 FROM_PPS_TO_PP(pic_init_qs_minus26); | |
| 958 FROM_PPS_TO_PP(chroma_qp_index_offset); | |
| 959 FROM_PPS_TO_PP(second_chroma_qp_index_offset); | |
| 960 #undef FROM_PPS_TO_PP | |
| 961 | |
| 962 #define FROM_PPS_TO_PP_PF(a) pic_param.pic_fields.bits.a = pps->a; | |
| 963 #define FROM_PPS_TO_PP_PF2(a, b) pic_param.pic_fields.bits.b = pps->a; | |
| 964 FROM_PPS_TO_PP_PF(entropy_coding_mode_flag); | |
| 965 FROM_PPS_TO_PP_PF(weighted_pred_flag); | |
| 966 FROM_PPS_TO_PP_PF(weighted_bipred_idc); | |
| 967 FROM_PPS_TO_PP_PF(transform_8x8_mode_flag); | |
| 968 | |
| 969 pic_param.pic_fields.bits.field_pic_flag = 0; | |
| 970 FROM_PPS_TO_PP_PF(constrained_intra_pred_flag); | |
| 971 FROM_PPS_TO_PP_PF2(bottom_field_pic_order_in_frame_present_flag, | |
| 972 pic_order_present_flag); | |
| 973 FROM_PPS_TO_PP_PF(deblocking_filter_control_present_flag); | |
| 974 FROM_PPS_TO_PP_PF(redundant_pic_cnt_present_flag); | |
| 975 pic_param.pic_fields.bits.reference_pic_flag = pic->ref; | |
| 976 #undef FROM_PPS_TO_PP_PF | |
| 977 #undef FROM_PPS_TO_PP_PF2 | |
| 978 | |
| 979 pic_param.frame_num = pic->frame_num; | |
| 980 | |
| 981 InitVAPicture(&pic_param.CurrPic); | |
| 982 FillVAPicture(&pic_param.CurrPic, pic); | |
| 983 | |
| 984 // Init reference pictures' array. | |
| 985 for (int i = 0; i < 16; ++i) | |
| 986 InitVAPicture(&pic_param.ReferenceFrames[i]); | |
| 987 | |
| 988 // And fill it with picture info from DPB. | |
| 989 FillVARefFramesFromDPB(dpb, pic_param.ReferenceFrames, | |
| 990 arraysize(pic_param.ReferenceFrames)); | |
| 991 | |
| 992 pic_param.num_ref_frames = sps->max_num_ref_frames; | |
| 993 | |
| 994 if (!vaapi_wrapper_->SubmitBuffer(VAPictureParameterBufferType, | |
| 995 sizeof(VAPictureParameterBufferH264), | |
| 996 &pic_param)) | |
| 997 return false; | |
| 998 | |
| 999 VAIQMatrixBufferH264 iq_matrix_buf; | |
| 1000 memset(&iq_matrix_buf, 0, sizeof(VAIQMatrixBufferH264)); | |
| 1001 | |
| 1002 if (pps->pic_scaling_matrix_present_flag) { | |
| 1003 for (int i = 0; i < 6; ++i) { | |
| 1004 for (int j = 0; j < 16; ++j) | |
| 1005 iq_matrix_buf.ScalingList4x4[i][j] = pps->scaling_list4x4[i][j]; | |
| 1006 } | |
| 1007 | |
| 1008 for (int i = 0; i < 2; ++i) { | |
| 1009 for (int j = 0; j < 64; ++j) | |
| 1010 iq_matrix_buf.ScalingList8x8[i][j] = pps->scaling_list8x8[i][j]; | |
| 1011 } | |
| 1012 } else { | |
| 1013 for (int i = 0; i < 6; ++i) { | |
| 1014 for (int j = 0; j < 16; ++j) | |
| 1015 iq_matrix_buf.ScalingList4x4[i][j] = sps->scaling_list4x4[i][j]; | |
| 1016 } | |
| 1017 | |
| 1018 for (int i = 0; i < 2; ++i) { | |
| 1019 for (int j = 0; j < 64; ++j) | |
| 1020 iq_matrix_buf.ScalingList8x8[i][j] = sps->scaling_list8x8[i][j]; | |
| 1021 } | |
| 1022 } | |
| 1023 | |
| 1024 return vaapi_wrapper_->SubmitBuffer(VAIQMatrixBufferType, | |
| 1025 sizeof(VAIQMatrixBufferH264), | |
| 1026 &iq_matrix_buf); | |
| 1027 } | |
| 1028 | |
| 1029 bool VaapiVideoDecodeAccelerator::VaapiH264Accelerator::SubmitSlice( | |
| 1030 const media::H264PPS* pps, | |
| 1031 const media::H264SliceHeader* slice_hdr, | |
| 1032 const H264Picture::Vector& ref_pic_list0, | |
| 1033 const H264Picture::Vector& ref_pic_list1, | |
| 1034 const scoped_refptr<H264Picture>& pic, | |
| 1035 const uint8_t* data, | |
| 1036 size_t size) { | |
| 1037 VASliceParameterBufferH264 slice_param; | |
| 1038 memset(&slice_param, 0, sizeof(VASliceParameterBufferH264)); | |
|
kcwu
2015/03/31 15:20:09
I prefer sizeof(slice_param) instead.
Pawel Osciak
2015/04/03 07:06:00
Me too. Done.
| |
| 1039 | |
| 1040 slice_param.slice_data_size = slice_hdr->nalu_size; | |
| 1041 slice_param.slice_data_offset = 0; | |
| 1042 slice_param.slice_data_flag = VA_SLICE_DATA_FLAG_ALL; | |
| 1043 slice_param.slice_data_bit_offset = slice_hdr->header_bit_size; | |
| 1044 | |
| 1045 #define SHDRToSP(a) slice_param.a = slice_hdr->a; | |
| 1046 SHDRToSP(first_mb_in_slice); | |
| 1047 slice_param.slice_type = slice_hdr->slice_type % 5; | |
| 1048 SHDRToSP(direct_spatial_mv_pred_flag); | |
| 1049 | |
| 1050 // TODO posciak: make sure parser sets those even when override flags | |
| 1051 // in slice header is off. | |
| 1052 SHDRToSP(num_ref_idx_l0_active_minus1); | |
| 1053 SHDRToSP(num_ref_idx_l1_active_minus1); | |
| 1054 SHDRToSP(cabac_init_idc); | |
| 1055 SHDRToSP(slice_qp_delta); | |
| 1056 SHDRToSP(disable_deblocking_filter_idc); | |
| 1057 SHDRToSP(slice_alpha_c0_offset_div2); | |
| 1058 SHDRToSP(slice_beta_offset_div2); | |
| 1059 | |
| 1060 if (((slice_hdr->IsPSlice() || slice_hdr->IsSPSlice()) && | |
| 1061 pps->weighted_pred_flag) || | |
| 1062 (slice_hdr->IsBSlice() && pps->weighted_bipred_idc == 1)) { | |
| 1063 SHDRToSP(luma_log2_weight_denom); | |
| 1064 SHDRToSP(chroma_log2_weight_denom); | |
| 1065 | |
| 1066 SHDRToSP(luma_weight_l0_flag); | |
| 1067 SHDRToSP(luma_weight_l1_flag); | |
| 1068 | |
| 1069 SHDRToSP(chroma_weight_l0_flag); | |
| 1070 SHDRToSP(chroma_weight_l1_flag); | |
| 1071 | |
| 1072 for (int i = 0; i <= slice_param.num_ref_idx_l0_active_minus1; ++i) { | |
| 1073 slice_param.luma_weight_l0[i] = | |
| 1074 slice_hdr->pred_weight_table_l0.luma_weight[i]; | |
| 1075 slice_param.luma_offset_l0[i] = | |
| 1076 slice_hdr->pred_weight_table_l0.luma_offset[i]; | |
| 1077 | |
| 1078 for (int j = 0; j < 2; ++j) { | |
| 1079 slice_param.chroma_weight_l0[i][j] = | |
| 1080 slice_hdr->pred_weight_table_l0.chroma_weight[i][j]; | |
| 1081 slice_param.chroma_offset_l0[i][j] = | |
| 1082 slice_hdr->pred_weight_table_l0.chroma_offset[i][j]; | |
| 1083 } | |
| 1084 } | |
| 1085 | |
| 1086 if (slice_hdr->IsBSlice()) { | |
| 1087 for (int i = 0; i <= slice_param.num_ref_idx_l1_active_minus1; ++i) { | |
| 1088 slice_param.luma_weight_l1[i] = | |
| 1089 slice_hdr->pred_weight_table_l1.luma_weight[i]; | |
| 1090 slice_param.luma_offset_l1[i] = | |
| 1091 slice_hdr->pred_weight_table_l1.luma_offset[i]; | |
| 1092 | |
| 1093 for (int j = 0; j < 2; ++j) { | |
| 1094 slice_param.chroma_weight_l1[i][j] = | |
| 1095 slice_hdr->pred_weight_table_l1.chroma_weight[i][j]; | |
| 1096 slice_param.chroma_offset_l1[i][j] = | |
| 1097 slice_hdr->pred_weight_table_l1.chroma_offset[i][j]; | |
| 1098 } | |
| 1099 } | |
| 1100 } | |
| 1101 } | |
| 1102 | |
| 1103 static_assert( | |
| 1104 arraysize(slice_param.RefPicList0) == arraysize(slice_param.RefPicList1), | |
| 1105 "Invalid RefPicList sizes"); | |
| 1106 | |
| 1107 for (size_t i = 0; i < arraysize(slice_param.RefPicList0); ++i) { | |
| 1108 InitVAPicture(&slice_param.RefPicList0[i]); | |
| 1109 InitVAPicture(&slice_param.RefPicList1[i]); | |
| 1110 } | |
| 1111 | |
| 1112 for (size_t i = 0; | |
| 1113 i < ref_pic_list0.size() && i < arraysize(slice_param.RefPicList0); | |
| 1114 ++i) { | |
| 1115 if (ref_pic_list0[i]) | |
| 1116 FillVAPicture(&slice_param.RefPicList0[i], ref_pic_list0[i]); | |
| 1117 } | |
| 1118 for (size_t i = 0; | |
| 1119 i < ref_pic_list1.size() && i < arraysize(slice_param.RefPicList1); | |
| 1120 ++i) { | |
| 1121 if (ref_pic_list1[i]) | |
| 1122 FillVAPicture(&slice_param.RefPicList1[i], ref_pic_list1[i]); | |
| 1123 } | |
| 1124 | |
| 1125 if (!vaapi_wrapper_->SubmitBuffer(VASliceParameterBufferType, | |
| 1126 sizeof(VASliceParameterBufferH264), | |
| 1127 &slice_param)) | |
| 1128 return false; | |
| 1129 | |
| 1130 // Can't help it, blame libva... | |
| 1131 void* non_const_ptr = const_cast<uint8*>(data); | |
| 1132 return vaapi_wrapper_->SubmitBuffer(VASliceDataBufferType, size, | |
| 1133 non_const_ptr); | |
| 1134 } | |
| 1135 | |
| 1136 bool VaapiVideoDecodeAccelerator::VaapiH264Accelerator::SubmitDecode( | |
| 1137 const scoped_refptr<H264Picture>& pic) { | |
| 1138 DVLOG(4) << "Decoding POC " << pic->pic_order_cnt; | |
| 1139 scoped_refptr<VaapiDecodeSurface> dec_surface = | |
| 1140 H264PictureToVaapiDecodeSurface(pic); | |
| 1141 | |
| 1142 return vaapi_dec_->DecodeSurface(dec_surface); | |
| 1143 } | |
| 1144 | |
| 1145 bool VaapiVideoDecodeAccelerator::VaapiH264Accelerator::OutputPicture( | |
| 1146 const scoped_refptr<H264Picture>& pic) { | |
| 1147 scoped_refptr<VaapiDecodeSurface> dec_surface = | |
| 1148 H264PictureToVaapiDecodeSurface(pic); | |
| 1149 | |
| 1150 vaapi_dec_->SurfaceReady(dec_surface); | |
| 1151 | |
| 1152 return true; | |
| 1153 } | |
| 1154 | |
| 1155 void VaapiVideoDecodeAccelerator::VaapiH264Accelerator::Reset() { | |
| 1156 vaapi_wrapper_->DestroyPendingBuffers(); | |
| 1157 } | |
| 1158 | |
| 1159 scoped_refptr<VaapiVideoDecodeAccelerator::VaapiDecodeSurface> | |
| 1160 VaapiVideoDecodeAccelerator::VaapiH264Accelerator:: | |
| 1161 H264PictureToVaapiDecodeSurface(const scoped_refptr<H264Picture>& pic) { | |
| 1162 VaapiH264Picture* vaapi_pic = pic->AsVaapiH264Picture(); | |
| 1163 CHECK(vaapi_pic); | |
| 1164 return vaapi_pic->dec_surface(); | |
| 1165 } | |
| 1166 | |
| 1167 void VaapiVideoDecodeAccelerator::VaapiH264Accelerator::FillVAPicture( | |
| 1168 VAPictureH264* va_pic, | |
| 1169 scoped_refptr<H264Picture> pic) { | |
| 1170 scoped_refptr<VaapiDecodeSurface> dec_surface = | |
| 1171 H264PictureToVaapiDecodeSurface(pic); | |
| 1172 | |
| 1173 va_pic->picture_id = dec_surface->va_surface()->id(); | |
| 1174 va_pic->frame_idx = pic->frame_num; | |
| 1175 va_pic->flags = 0; | |
| 1176 | |
| 1177 switch (pic->field) { | |
| 1178 case H264Picture::FIELD_NONE: | |
| 1179 break; | |
| 1180 case H264Picture::FIELD_TOP: | |
| 1181 va_pic->flags |= VA_PICTURE_H264_TOP_FIELD; | |
| 1182 break; | |
| 1183 case H264Picture::FIELD_BOTTOM: | |
| 1184 va_pic->flags |= VA_PICTURE_H264_BOTTOM_FIELD; | |
| 1185 break; | |
| 1186 } | |
| 1187 | |
| 1188 if (pic->ref) { | |
| 1189 va_pic->flags |= pic->long_term ? VA_PICTURE_H264_LONG_TERM_REFERENCE | |
| 1190 : VA_PICTURE_H264_SHORT_TERM_REFERENCE; | |
| 1191 } | |
| 1192 | |
| 1193 va_pic->TopFieldOrderCnt = pic->top_field_order_cnt; | |
| 1194 va_pic->BottomFieldOrderCnt = pic->bottom_field_order_cnt; | |
| 1195 } | |
| 1196 | |
| 1197 int VaapiVideoDecodeAccelerator::VaapiH264Accelerator::FillVARefFramesFromDPB( | |
| 1198 const H264DPB& dpb, | |
| 1199 VAPictureH264* va_pics, | |
| 1200 int num_pics) { | |
| 1201 H264Picture::Vector::const_reverse_iterator rit; | |
| 1202 int i; | |
| 1203 | |
| 1204 // Return reference frames in reverse order of insertion. | |
| 1205 // Libva does not document this, but other implementations (e.g. mplayer) | |
| 1206 // do it this way as well. | |
| 1207 for (rit = dpb.rbegin(), i = 0; rit != dpb.rend() && i < num_pics; ++rit) { | |
| 1208 if ((*rit)->ref) | |
| 1209 FillVAPicture(&va_pics[i++], *rit); | |
| 1210 } | |
| 1211 | |
| 1212 return i; | |
| 1213 } | |
| 1214 | |
| 751 } // namespace content | 1215 } // namespace content |
| OLD | NEW |