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

Side by Side Diff: media/filters/vpx_video_decoder.cc

Issue 1869303004: media: Implement zero-copy video playback for VP8. Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: optimize only VP8 Created 4 years, 8 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
« no previous file with comments | « media/filters/vpx_video_decoder.h ('k') | media/renderers/default_renderer_factory.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "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
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
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
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*>(&timestamp_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
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*>(&timestamp_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
OLDNEW
« no previous file with comments | « media/filters/vpx_video_decoder.h ('k') | media/renderers/default_renderer_factory.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698