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 |