| 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 "media/filters/vpx_video_decoder.h" | 5 #include "media/filters/vpx_video_decoder.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 | 9 |
| 10 #include <algorithm> | 10 #include <algorithm> |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 #include "base/sys_info.h" | 26 #include "base/sys_info.h" |
| 27 #include "base/threading/thread.h" | 27 #include "base/threading/thread.h" |
| 28 #include "base/trace_event/memory_allocator_dump.h" | 28 #include "base/trace_event/memory_allocator_dump.h" |
| 29 #include "base/trace_event/memory_dump_manager.h" | 29 #include "base/trace_event/memory_dump_manager.h" |
| 30 #include "base/trace_event/memory_dump_provider.h" | 30 #include "base/trace_event/memory_dump_provider.h" |
| 31 #include "base/trace_event/process_memory_dump.h" | 31 #include "base/trace_event/process_memory_dump.h" |
| 32 #include "base/trace_event/trace_event.h" | 32 #include "base/trace_event/trace_event.h" |
| 33 #include "media/base/bind_to_current_loop.h" | 33 #include "media/base/bind_to_current_loop.h" |
| 34 #include "media/base/decoder_buffer.h" | 34 #include "media/base/decoder_buffer.h" |
| 35 #include "media/base/media_switches.h" | 35 #include "media/base/media_switches.h" |
| 36 #include "media/video/gpu_memory_buffer_video_frame_pool.h" |
| 36 | 37 |
| 37 // Include libvpx header files. | 38 // Include libvpx header files. |
| 38 // VPX_CODEC_DISABLE_COMPAT excludes parts of the libvpx API that provide | 39 // VPX_CODEC_DISABLE_COMPAT excludes parts of the libvpx API that provide |
| 39 // backwards compatibility for legacy applications using the library. | 40 // backwards compatibility for legacy applications using the library. |
| 40 #define VPX_CODEC_DISABLE_COMPAT 1 | 41 #define VPX_CODEC_DISABLE_COMPAT 1 |
| 41 extern "C" { | 42 extern "C" { |
| 42 #include "third_party/libvpx/source/libvpx/vpx/vp8dx.h" | 43 #include "third_party/libvpx/source/libvpx/vpx/vp8dx.h" |
| 43 #include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h" | 44 #include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h" |
| 44 #include "third_party/libvpx/source/libvpx/vpx/vpx_frame_buffer.h" | 45 #include "third_party/libvpx/source/libvpx/vpx/vpx_frame_buffer.h" |
| 45 } | 46 } |
| (...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 351 } | 352 } |
| 352 | 353 |
| 353 void VpxVideoDecoder::MemoryPool::OnVideoFrameDestroyed( | 354 void VpxVideoDecoder::MemoryPool::OnVideoFrameDestroyed( |
| 354 VP9FrameBuffer* frame_buffer) { | 355 VP9FrameBuffer* frame_buffer) { |
| 355 --frame_buffer->ref_cnt; | 356 --frame_buffer->ref_cnt; |
| 356 if (frame_buffer->ref_cnt) | 357 if (frame_buffer->ref_cnt) |
| 357 --in_use_by_decoder_and_video_frame_; | 358 --in_use_by_decoder_and_video_frame_; |
| 358 } | 359 } |
| 359 | 360 |
| 360 VpxVideoDecoder::VpxVideoDecoder() | 361 VpxVideoDecoder::VpxVideoDecoder() |
| 361 : state_(kUninitialized), vpx_codec_(nullptr), vpx_codec_alpha_(nullptr) { | 362 : VpxVideoDecoder(std::unique_ptr<GpuMemoryBufferVideoFramePool>()) {} |
| 363 |
| 364 VpxVideoDecoder::VpxVideoDecoder( |
| 365 std::unique_ptr<GpuMemoryBufferVideoFramePool> gpu_video_frame_pool) |
| 366 : state_(kUninitialized), |
| 367 vpx_codec_(nullptr), |
| 368 vpx_codec_alpha_(nullptr), |
| 369 gpu_video_frame_pool_(std::move(gpu_video_frame_pool)) { |
| 362 thread_checker_.DetachFromThread(); | 370 thread_checker_.DetachFromThread(); |
| 363 } | 371 } |
| 364 | 372 |
| 365 VpxVideoDecoder::~VpxVideoDecoder() { | 373 VpxVideoDecoder::~VpxVideoDecoder() { |
| 366 DCHECK(thread_checker_.CalledOnValidThread()); | 374 DCHECK(thread_checker_.CalledOnValidThread()); |
| 367 CloseDecoder(); | 375 CloseDecoder(); |
| 368 // Ensure CloseDecoder() released the offload thread. | 376 // Ensure CloseDecoder() released the offload thread. |
| 369 DCHECK(!offload_task_runner_); | 377 DCHECK(!offload_task_runner_); |
| 370 } | 378 } |
| 371 | 379 |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 563 if (!vpx_image) { | 571 if (!vpx_image) { |
| 564 *video_frame = nullptr; | 572 *video_frame = nullptr; |
| 565 return true; | 573 return true; |
| 566 } | 574 } |
| 567 | 575 |
| 568 if (vpx_image->user_priv != user_priv) { | 576 if (vpx_image->user_priv != user_priv) { |
| 569 DLOG(ERROR) << "Invalid output timestamp."; | 577 DLOG(ERROR) << "Invalid output timestamp."; |
| 570 return false; | 578 return false; |
| 571 } | 579 } |
| 572 | 580 |
| 573 if (!CopyVpxImageToVideoFrame(vpx_image, video_frame)) | 581 if (!CopyVpxImageToVideoFrame(vpx_image, buffer, video_frame)) |
| 574 return false; | 582 return false; |
| 575 | 583 |
| 584 // VP8 alpha vpx_image_t is missing. Regard it as success. |
| 585 if (!(*video_frame)) |
| 586 return true; |
| 587 |
| 576 (*video_frame)->set_timestamp(base::TimeDelta::FromMicroseconds(timestamp)); | 588 (*video_frame)->set_timestamp(base::TimeDelta::FromMicroseconds(timestamp)); |
| 577 | 589 |
| 578 // Default to the color space from the config, but if the bistream specifies | 590 // Default to the color space from the config, but if the bistream specifies |
| 579 // one, prefer that instead. | 591 // one, prefer that instead. |
| 580 ColorSpace color_space = config_.color_space(); | 592 ColorSpace color_space = config_.color_space(); |
| 581 if (vpx_image->cs == VPX_CS_BT_709) | 593 if (vpx_image->cs == VPX_CS_BT_709) |
| 582 color_space = COLOR_SPACE_HD_REC709; | 594 color_space = COLOR_SPACE_HD_REC709; |
| 583 else if (vpx_image->cs == VPX_CS_BT_601) | 595 else if (vpx_image->cs == VPX_CS_BT_601) |
| 584 color_space = COLOR_SPACE_SD_REC601; | 596 color_space = COLOR_SPACE_SD_REC601; |
| 585 (*video_frame) | 597 (*video_frame) |
| 586 ->metadata() | 598 ->metadata() |
| 587 ->SetInteger(VideoFrameMetadata::COLOR_SPACE, color_space); | 599 ->SetInteger(VideoFrameMetadata::COLOR_SPACE, color_space); |
| 588 | 600 |
| 589 if (!vpx_codec_alpha_) | |
| 590 return true; | |
| 591 | |
| 592 if (buffer->side_data_size() < 8) { | |
| 593 // TODO(mcasas): Is this a warning or an error? | |
| 594 DLOG(WARNING) << "Making Alpha channel opaque due to missing input"; | |
| 595 const uint32_t kAlphaOpaqueValue = 255; | |
| 596 libyuv::SetPlane((*video_frame)->visible_data(VideoFrame::kAPlane), | |
| 597 (*video_frame)->stride(VideoFrame::kAPlane), | |
| 598 (*video_frame)->visible_rect().width(), | |
| 599 (*video_frame)->visible_rect().height(), | |
| 600 kAlphaOpaqueValue); | |
| 601 return true; | |
| 602 } | |
| 603 | |
| 604 // First 8 bytes of side data is |side_data_id| in big endian. | |
| 605 const uint64_t side_data_id = base::NetToHost64( | |
| 606 *(reinterpret_cast<const uint64_t*>(buffer->side_data()))); | |
| 607 if (side_data_id != 1) | |
| 608 return true; | |
| 609 | |
| 610 // Try and decode buffer->side_data() minus the first 8 bytes as a full frame. | |
| 611 int64_t timestamp_alpha = buffer->timestamp().InMicroseconds(); | |
| 612 void* user_priv_alpha = reinterpret_cast<void*>(×tamp_alpha); | |
| 613 { | |
| 614 TRACE_EVENT1("media", "vpx_codec_decode_alpha", "timestamp_alpha", | |
| 615 timestamp_alpha); | |
| 616 vpx_codec_err_t status = vpx_codec_decode( | |
| 617 vpx_codec_alpha_, buffer->side_data() + 8, buffer->side_data_size() - 8, | |
| 618 user_priv_alpha, 0 /* deadline */); | |
| 619 if (status != VPX_CODEC_OK) { | |
| 620 DLOG(ERROR) << "vpx_codec_decode() failed for the alpha: " | |
| 621 << vpx_codec_error(vpx_codec_); | |
| 622 return false; | |
| 623 } | |
| 624 } | |
| 625 | |
| 626 vpx_codec_iter_t iter_alpha = NULL; | |
| 627 const vpx_image_t* vpx_image_alpha = | |
| 628 vpx_codec_get_frame(vpx_codec_alpha_, &iter_alpha); | |
| 629 if (!vpx_image_alpha) { | |
| 630 *video_frame = nullptr; | |
| 631 return true; | |
| 632 } | |
| 633 | |
| 634 if (vpx_image_alpha->user_priv != user_priv_alpha) { | |
| 635 DLOG(ERROR) << "Invalid output timestamp on alpha."; | |
| 636 return false; | |
| 637 } | |
| 638 | |
| 639 if (vpx_image_alpha->d_h != vpx_image->d_h || | |
| 640 vpx_image_alpha->d_w != vpx_image->d_w) { | |
| 641 DLOG(ERROR) << "The alpha plane dimensions are not the same as the " | |
| 642 "image dimensions."; | |
| 643 return false; | |
| 644 } | |
| 645 | |
| 646 libyuv::CopyPlane(vpx_image_alpha->planes[VPX_PLANE_Y], | |
| 647 vpx_image_alpha->stride[VPX_PLANE_Y], | |
| 648 (*video_frame)->visible_data(VideoFrame::kAPlane), | |
| 649 (*video_frame)->stride(VideoFrame::kAPlane), | |
| 650 (*video_frame)->visible_rect().width(), | |
| 651 (*video_frame)->visible_rect().height()); | |
| 652 return true; | 601 return true; |
| 653 } | 602 } |
| 654 | 603 |
| 655 bool VpxVideoDecoder::CopyVpxImageToVideoFrame( | 604 bool VpxVideoDecoder::CopyVpxImageToVideoFrame( |
| 656 const struct vpx_image* vpx_image, | 605 const struct vpx_image* vpx_image, |
| 606 const scoped_refptr<DecoderBuffer>& buffer, |
| 657 scoped_refptr<VideoFrame>* video_frame) { | 607 scoped_refptr<VideoFrame>* video_frame) { |
| 658 DCHECK(vpx_image); | 608 DCHECK(vpx_image); |
| 659 | 609 |
| 660 VideoPixelFormat codec_format; | 610 VideoPixelFormat codec_format; |
| 661 switch (vpx_image->fmt) { | 611 switch (vpx_image->fmt) { |
| 662 case VPX_IMG_FMT_I420: | 612 case VPX_IMG_FMT_I420: |
| 663 codec_format = vpx_codec_alpha_ ? PIXEL_FORMAT_YV12A : PIXEL_FORMAT_YV12; | 613 codec_format = vpx_codec_alpha_ ? PIXEL_FORMAT_YV12A : PIXEL_FORMAT_YV12; |
| 664 break; | 614 break; |
| 665 | 615 |
| 666 case VPX_IMG_FMT_I444: | 616 case VPX_IMG_FMT_I444: |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 703 UMA_HISTOGRAM_COUNTS( | 653 UMA_HISTOGRAM_COUNTS( |
| 704 "Media.Vpx.VideoDecoderBuffersInUseByDecoderAndVideoFrame", | 654 "Media.Vpx.VideoDecoderBuffersInUseByDecoderAndVideoFrame", |
| 705 memory_pool_->NumberOfFrameBuffersInUseByDecoderAndVideoFrame()); | 655 memory_pool_->NumberOfFrameBuffersInUseByDecoderAndVideoFrame()); |
| 706 | 656 |
| 707 return true; | 657 return true; |
| 708 } | 658 } |
| 709 | 659 |
| 710 DCHECK(codec_format == PIXEL_FORMAT_YV12 || | 660 DCHECK(codec_format == PIXEL_FORMAT_YV12 || |
| 711 codec_format == PIXEL_FORMAT_YV12A); | 661 codec_format == PIXEL_FORMAT_YV12A); |
| 712 | 662 |
| 713 *video_frame = frame_pool_.CreateFrame( | 663 std::unique_ptr<VideoFrameFuture> video_frame_future = |
| 714 codec_format, visible_size, gfx::Rect(visible_size), | 664 gpu_video_frame_pool_->CreateFrame( |
| 715 config_.natural_size(), kNoTimestamp()); | 665 codec_format, visible_size, gfx::Rect(visible_size), |
| 716 if (!(*video_frame)) | 666 config_.natural_size(), kNoTimestamp()); |
| 717 return false; | |
| 718 | |
| 719 libyuv::I420Copy( | 667 libyuv::I420Copy( |
| 720 vpx_image->planes[VPX_PLANE_Y], vpx_image->stride[VPX_PLANE_Y], | 668 vpx_image->planes[VPX_PLANE_Y], vpx_image->stride[VPX_PLANE_Y], |
| 721 vpx_image->planes[VPX_PLANE_U], vpx_image->stride[VPX_PLANE_U], | 669 vpx_image->planes[VPX_PLANE_U], vpx_image->stride[VPX_PLANE_U], |
| 722 vpx_image->planes[VPX_PLANE_V], vpx_image->stride[VPX_PLANE_V], | 670 vpx_image->planes[VPX_PLANE_V], vpx_image->stride[VPX_PLANE_V], |
| 723 (*video_frame)->visible_data(VideoFrame::kYPlane), | 671 video_frame_future->data(VideoFrame::kYPlane), |
| 724 (*video_frame)->stride(VideoFrame::kYPlane), | 672 video_frame_future->stride(VideoFrame::kYPlane), |
| 725 (*video_frame)->visible_data(VideoFrame::kUPlane), | 673 video_frame_future->data(VideoFrame::kUPlane), |
| 726 (*video_frame)->stride(VideoFrame::kUPlane), | 674 video_frame_future->stride(VideoFrame::kUPlane), |
| 727 (*video_frame)->visible_data(VideoFrame::kVPlane), | 675 video_frame_future->data(VideoFrame::kVPlane), |
| 728 (*video_frame)->stride(VideoFrame::kVPlane), coded_size.width(), | 676 video_frame_future->stride(VideoFrame::kVPlane), coded_size.width(), |
| 729 coded_size.height()); | 677 coded_size.height()); |
| 730 | 678 |
| 679 for (int i = 0; i < 1 && vpx_codec_alpha_; i++) { |
| 680 if (buffer->side_data_size() < 8) { |
| 681 // TODO(mcasas): Is this a warning or an error? |
| 682 DLOG(WARNING) << "Making Alpha channel opaque due to missing input"; |
| 683 const uint32_t kAlphaOpaqueValue = 255; |
| 684 libyuv::SetPlane(video_frame_future->data(VideoFrame::kAPlane), |
| 685 video_frame_future->stride(VideoFrame::kAPlane), |
| 686 coded_size.width(), coded_size.height(), |
| 687 kAlphaOpaqueValue); |
| 688 break; |
| 689 } |
| 690 |
| 691 // First 8 bytes of side data is |side_data_id| in big endian. |
| 692 const uint64_t side_data_id = base::NetToHost64( |
| 693 *(reinterpret_cast<const uint64_t*>(buffer->side_data()))); |
| 694 if (side_data_id != 1) |
| 695 break; |
| 696 |
| 697 // Try and decode buffer->side_data() minus the first 8 bytes as a full |
| 698 // frame. |
| 699 int64_t timestamp_alpha = buffer->timestamp().InMicroseconds(); |
| 700 void* user_priv_alpha = reinterpret_cast<void*>(×tamp_alpha); |
| 701 { |
| 702 TRACE_EVENT1("media", "vpx_codec_decode_alpha", "timestamp_alpha", |
| 703 timestamp_alpha); |
| 704 vpx_codec_err_t status = vpx_codec_decode( |
| 705 vpx_codec_alpha_, buffer->side_data() + 8, |
| 706 buffer->side_data_size() - 8, user_priv_alpha, 0 /* deadline */); |
| 707 if (status != VPX_CODEC_OK) { |
| 708 DLOG(ERROR) << "vpx_codec_decode() failed for the alpha: " |
| 709 << vpx_codec_error(vpx_codec_); |
| 710 return false; |
| 711 } |
| 712 } |
| 713 |
| 714 vpx_codec_iter_t iter_alpha = NULL; |
| 715 const vpx_image_t* vpx_image_alpha = |
| 716 vpx_codec_get_frame(vpx_codec_alpha_, &iter_alpha); |
| 717 if (!vpx_image_alpha) { |
| 718 *video_frame = nullptr; |
| 719 return true; |
| 720 } |
| 721 |
| 722 if (vpx_image_alpha->user_priv != user_priv_alpha) { |
| 723 DLOG(ERROR) << "Invalid output timestamp on alpha."; |
| 724 return false; |
| 725 } |
| 726 |
| 727 if (vpx_image_alpha->d_h != vpx_image->d_h || |
| 728 vpx_image_alpha->d_w != vpx_image->d_w) { |
| 729 DLOG(ERROR) << "The alpha plane dimensions are not the same as the " |
| 730 "image dimensions."; |
| 731 return false; |
| 732 } |
| 733 |
| 734 libyuv::CopyPlane(vpx_image_alpha->planes[VPX_PLANE_Y], |
| 735 vpx_image_alpha->stride[VPX_PLANE_Y], |
| 736 video_frame_future->data(VideoFrame::kAPlane), |
| 737 video_frame_future->stride(VideoFrame::kAPlane), |
| 738 coded_size.width(), coded_size.height()); |
| 739 } |
| 740 |
| 741 *video_frame = video_frame_future->Release(); |
| 742 if (!(*video_frame)) |
| 743 return false; |
| 731 return true; | 744 return true; |
| 732 } | 745 } |
| 733 | 746 |
| 734 } // namespace media | 747 } // namespace media |
| OLD | NEW |