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

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

Issue 2096813002: media/vpx: Add support for VP9 alpha channel (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: add test files for real Created 4 years, 6 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/test/data/bear-vp9a.webm » ('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 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
193 static int32_t ReleaseVP9FrameBuffer(void* user_priv, 193 static int32_t ReleaseVP9FrameBuffer(void* user_priv,
194 vpx_codec_frame_buffer* fb); 194 vpx_codec_frame_buffer* fb);
195 195
196 // Generates a "no_longer_needed" closure that holds a reference to this pool. 196 // Generates a "no_longer_needed" closure that holds a reference to this pool.
197 base::Closure CreateFrameCallback(void* fb_priv_data); 197 base::Closure CreateFrameCallback(void* fb_priv_data);
198 198
199 // base::MemoryDumpProvider. 199 // base::MemoryDumpProvider.
200 bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, 200 bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
201 base::trace_event::ProcessMemoryDump* pmd) override; 201 base::trace_event::ProcessMemoryDump* pmd) override;
202 202
203 private:
204 friend class base::RefCountedThreadSafe<VpxVideoDecoder::MemoryPool>;
205 ~MemoryPool() override;
206
207 // Reference counted frame buffers used for VP9 decoding. Reference counting 203 // Reference counted frame buffers used for VP9 decoding. Reference counting
208 // is done manually because both chromium and libvpx has to release this 204 // is done manually because both chromium and libvpx has to release this
209 // before a buffer can be re-used. 205 // before a buffer can be re-used.
210 struct VP9FrameBuffer { 206 struct VP9FrameBuffer {
211 VP9FrameBuffer() : ref_cnt(0) {} 207 VP9FrameBuffer() : ref_cnt(0) {}
212 std::vector<uint8_t> data; 208 std::vector<uint8_t> data;
209 std::vector<uint8_t> alpha_data;
213 uint32_t ref_cnt; 210 uint32_t ref_cnt;
214 }; 211 };
215 212
213 private:
214 friend class base::RefCountedThreadSafe<VpxVideoDecoder::MemoryPool>;
215 ~MemoryPool() override;
216
216 // Gets the next available frame buffer for use by libvpx. 217 // Gets the next available frame buffer for use by libvpx.
217 VP9FrameBuffer* GetFreeFrameBuffer(size_t min_size); 218 VP9FrameBuffer* GetFreeFrameBuffer(size_t min_size);
218 219
219 // Method that gets called when a VideoFrame that references this pool gets 220 // Method that gets called when a VideoFrame that references this pool gets
220 // destroyed. 221 // destroyed.
221 void OnVideoFrameDestroyed(VP9FrameBuffer* frame_buffer); 222 void OnVideoFrameDestroyed(VP9FrameBuffer* frame_buffer);
222 223
223 // Frame buffers to be used by libvpx for VP9 Decoding. 224 // Frame buffers to be used by libvpx for VP9 Decoding.
224 std::vector<VP9FrameBuffer*> frame_buffers_; 225 std::vector<VP9FrameBuffer*> frame_buffers_;
225 226
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after
439 state_ = kNormal; 440 state_ = kNormal;
440 // PostTask() to avoid calling |closure| inmediately. 441 // PostTask() to avoid calling |closure| inmediately.
441 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, closure); 442 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, closure);
442 } 443 }
443 444
444 bool VpxVideoDecoder::ConfigureDecoder(const VideoDecoderConfig& config) { 445 bool VpxVideoDecoder::ConfigureDecoder(const VideoDecoderConfig& config) {
445 if (config.codec() != kCodecVP8 && config.codec() != kCodecVP9) 446 if (config.codec() != kCodecVP8 && config.codec() != kCodecVP9)
446 return false; 447 return false;
447 448
448 // These are the combinations of codec-pixel format supported in principle. 449 // These are the combinations of codec-pixel format supported in principle.
449 // Note that VP9 does not support Alpha in the current implementation.
450 DCHECK( 450 DCHECK(
451 (config.codec() == kCodecVP8 && config.format() == PIXEL_FORMAT_YV12) || 451 (config.codec() == kCodecVP8 && config.format() == PIXEL_FORMAT_YV12) ||
452 (config.codec() == kCodecVP8 && config.format() == PIXEL_FORMAT_YV12A) || 452 (config.codec() == kCodecVP8 && config.format() == PIXEL_FORMAT_YV12A) ||
453 (config.codec() == kCodecVP9 && config.format() == PIXEL_FORMAT_YV12) || 453 (config.codec() == kCodecVP9 && config.format() == PIXEL_FORMAT_YV12) ||
454 (config.codec() == kCodecVP9 && config.format() == PIXEL_FORMAT_YV12A) ||
454 (config.codec() == kCodecVP9 && config.format() == PIXEL_FORMAT_YV24)); 455 (config.codec() == kCodecVP9 && config.format() == PIXEL_FORMAT_YV24));
455 456
456 #if !defined(DISABLE_FFMPEG_VIDEO_DECODERS) 457 #if !defined(DISABLE_FFMPEG_VIDEO_DECODERS)
457 // When FFmpegVideoDecoder is available it handles VP8 that doesn't have 458 // When FFmpegVideoDecoder is available it handles VP8 that doesn't have
458 // alpha, and VpxVideoDecoder will handle VP8 with alpha. 459 // alpha, and VpxVideoDecoder will handle VP8 with alpha.
459 if (config.codec() == kCodecVP8 && config.format() != PIXEL_FORMAT_YV12A) 460 if (config.codec() == kCodecVP8 && config.format() != PIXEL_FORMAT_YV12A)
460 return false; 461 return false;
461 #endif 462 #endif
462 463
463 CloseDecoder(); 464 CloseDecoder();
464 465
465 vpx_codec_ = InitializeVpxContext(vpx_codec_, config); 466 vpx_codec_ = InitializeVpxContext(vpx_codec_, config);
466 if (!vpx_codec_) 467 if (!vpx_codec_)
467 return false; 468 return false;
468 469
469 // Configure VP9 to decode on our buffers to skip a data copy on decoding. 470 // Configure VP9 to decode on our buffers to skip a data copy on
471 // decoding. For YV12A-VP9, we use our buffers for the Y, U and V planes and
472 // copy the A plane.
470 if (config.codec() == kCodecVP9) { 473 if (config.codec() == kCodecVP9) {
471 DCHECK_NE(PIXEL_FORMAT_YV12A, config.format());
472 DCHECK(vpx_codec_get_caps(vpx_codec_->iface) & 474 DCHECK(vpx_codec_get_caps(vpx_codec_->iface) &
473 VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER); 475 VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER);
474 476
475 // Move high resolution vp9 decodes off of the main media thread (otherwise 477 // Move high resolution vp9 decodes off of the main media thread (otherwise
476 // decode may block audio decoding, demuxing, and other control activities). 478 // decode may block audio decoding, demuxing, and other control activities).
477 if (config.coded_size().width() >= 1024) { 479 if (config.coded_size().width() >= 1024) {
478 offload_task_runner_ = 480 offload_task_runner_ =
479 g_vpx_offload_thread.Pointer()->RequestOffloadThread(); 481 g_vpx_offload_thread.Pointer()->RequestOffloadThread();
480 } 482 }
481 483
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
542 if (!vpx_image) { 544 if (!vpx_image) {
543 *video_frame = nullptr; 545 *video_frame = nullptr;
544 return true; 546 return true;
545 } 547 }
546 548
547 if (vpx_image->user_priv != user_priv) { 549 if (vpx_image->user_priv != user_priv) {
548 DLOG(ERROR) << "Invalid output timestamp."; 550 DLOG(ERROR) << "Invalid output timestamp.";
549 return false; 551 return false;
550 } 552 }
551 553
552 if (!CopyVpxImageToVideoFrame(vpx_image, video_frame)) 554 const vpx_image_t* vpx_image_alpha = nullptr;
555 AlphaDecodeStatus alpha_decode_status =
556 DecodeAlphaPlane(vpx_image, &vpx_image_alpha, buffer);
557 if (alpha_decode_status == kAlphaPlaneError) {
553 return false; 558 return false;
559 } else if (alpha_decode_status == kNoAlphaPlaneData) {
560 *video_frame = nullptr;
561 return true;
562 }
563 if (!CopyVpxImageToVideoFrame(vpx_image, vpx_image_alpha, video_frame)) {
564 return false;
565 }
566 if (vpx_image_alpha && config_.codec() == kCodecVP8) {
567 libyuv::CopyPlane(vpx_image_alpha->planes[VPX_PLANE_Y],
568 vpx_image_alpha->stride[VPX_PLANE_Y],
569 (*video_frame)->visible_data(VideoFrame::kAPlane),
570 (*video_frame)->stride(VideoFrame::kAPlane),
571 (*video_frame)->visible_rect().width(),
572 (*video_frame)->visible_rect().height());
573 }
554 574
555 (*video_frame)->set_timestamp(base::TimeDelta::FromMicroseconds(timestamp)); 575 (*video_frame)->set_timestamp(base::TimeDelta::FromMicroseconds(timestamp));
556 576
557 // Default to the color space from the config, but if the bistream specifies 577 // Default to the color space from the config, but if the bistream specifies
558 // one, prefer that instead. 578 // one, prefer that instead.
559 ColorSpace color_space = config_.color_space(); 579 ColorSpace color_space = config_.color_space();
560 if (vpx_image->cs == VPX_CS_BT_709) 580 if (vpx_image->cs == VPX_CS_BT_709)
561 color_space = COLOR_SPACE_HD_REC709; 581 color_space = COLOR_SPACE_HD_REC709;
562 else if (vpx_image->cs == VPX_CS_BT_601) 582 else if (vpx_image->cs == VPX_CS_BT_601)
563 color_space = COLOR_SPACE_SD_REC601; 583 color_space = COLOR_SPACE_SD_REC601;
564 (*video_frame) 584 (*video_frame)
565 ->metadata() 585 ->metadata()
566 ->SetInteger(VideoFrameMetadata::COLOR_SPACE, color_space); 586 ->SetInteger(VideoFrameMetadata::COLOR_SPACE, color_space);
587 return true;
588 }
567 589
568 if (!vpx_codec_alpha_) 590 VpxVideoDecoder::AlphaDecodeStatus VpxVideoDecoder::DecodeAlphaPlane(
569 return true; 591 const struct vpx_image* vpx_image,
570 592 const struct vpx_image** vpx_image_alpha,
571 if (buffer->side_data_size() < 8) { 593 const scoped_refptr<DecoderBuffer>& buffer) {
572 // TODO(mcasas): Is this a warning or an error? 594 if (!vpx_codec_alpha_ || buffer->side_data_size() < 8) {
573 DLOG(WARNING) << "Making Alpha channel opaque due to missing input"; 595 return kAlphaPlaneProcessed;
574 const uint32_t kAlphaOpaqueValue = 255;
575 libyuv::SetPlane((*video_frame)->visible_data(VideoFrame::kAPlane),
576 (*video_frame)->stride(VideoFrame::kAPlane),
577 (*video_frame)->visible_rect().width(),
578 (*video_frame)->visible_rect().height(),
579 kAlphaOpaqueValue);
580 return true;
581 } 596 }
582 597
583 // First 8 bytes of side data is |side_data_id| in big endian. 598 // First 8 bytes of side data is |side_data_id| in big endian.
584 const uint64_t side_data_id = base::NetToHost64( 599 const uint64_t side_data_id = base::NetToHost64(
585 *(reinterpret_cast<const uint64_t*>(buffer->side_data()))); 600 *(reinterpret_cast<const uint64_t*>(buffer->side_data())));
586 if (side_data_id != 1) 601 if (side_data_id != 1) {
587 return true; 602 return kAlphaPlaneProcessed;
603 }
588 604
589 // Try and decode buffer->side_data() minus the first 8 bytes as a full frame. 605 // Try and decode buffer->side_data() minus the first 8 bytes as a full
606 // frame.
590 int64_t timestamp_alpha = buffer->timestamp().InMicroseconds(); 607 int64_t timestamp_alpha = buffer->timestamp().InMicroseconds();
591 void* user_priv_alpha = reinterpret_cast<void*>(&timestamp_alpha); 608 void* user_priv_alpha = reinterpret_cast<void*>(&timestamp_alpha);
592 { 609 {
593 TRACE_EVENT1("media", "vpx_codec_decode_alpha", "timestamp_alpha", 610 TRACE_EVENT1("media", "vpx_codec_decode_alpha", "timestamp_alpha",
594 timestamp_alpha); 611 timestamp_alpha);
595 vpx_codec_err_t status = vpx_codec_decode( 612 vpx_codec_err_t status = vpx_codec_decode(
596 vpx_codec_alpha_, buffer->side_data() + 8, buffer->side_data_size() - 8, 613 vpx_codec_alpha_, buffer->side_data() + 8, buffer->side_data_size() - 8,
597 user_priv_alpha, 0 /* deadline */); 614 user_priv_alpha, 0 /* deadline */);
598 if (status != VPX_CODEC_OK) { 615 if (status != VPX_CODEC_OK) {
599 DLOG(ERROR) << "vpx_codec_decode() failed for the alpha: " 616 DLOG(ERROR) << "vpx_codec_decode() failed for the alpha: "
600 << vpx_codec_error(vpx_codec_); 617 << vpx_codec_error(vpx_codec_);
601 return false; 618 return kAlphaPlaneError;
602 } 619 }
603 } 620 }
604 621
605 vpx_codec_iter_t iter_alpha = NULL; 622 vpx_codec_iter_t iter_alpha = NULL;
606 const vpx_image_t* vpx_image_alpha = 623 *vpx_image_alpha = vpx_codec_get_frame(vpx_codec_alpha_, &iter_alpha);
607 vpx_codec_get_frame(vpx_codec_alpha_, &iter_alpha); 624 if (!(*vpx_image_alpha)) {
608 if (!vpx_image_alpha) { 625 return kNoAlphaPlaneData;
609 *video_frame = nullptr;
610 return true;
611 } 626 }
612 627
613 if (vpx_image_alpha->user_priv != user_priv_alpha) { 628 if ((*vpx_image_alpha)->user_priv != user_priv_alpha) {
614 DLOG(ERROR) << "Invalid output timestamp on alpha."; 629 DLOG(ERROR) << "Invalid output timestamp on alpha.";
615 return false; 630 return kAlphaPlaneError;
616 } 631 }
617 632
618 if (vpx_image_alpha->d_h != vpx_image->d_h || 633 if ((*vpx_image_alpha)->d_h != vpx_image->d_h ||
619 vpx_image_alpha->d_w != vpx_image->d_w) { 634 (*vpx_image_alpha)->d_w != vpx_image->d_w) {
620 DLOG(ERROR) << "The alpha plane dimensions are not the same as the " 635 DLOG(ERROR) << "The alpha plane dimensions are not the same as the "
621 "image dimensions."; 636 "image dimensions.";
622 return false; 637 return kAlphaPlaneError;
623 } 638 }
624 639
625 libyuv::CopyPlane(vpx_image_alpha->planes[VPX_PLANE_Y], 640 if (config_.codec() == kCodecVP9) {
626 vpx_image_alpha->stride[VPX_PLANE_Y], 641 VpxVideoDecoder::MemoryPool::VP9FrameBuffer* frame_buffer =
627 (*video_frame)->visible_data(VideoFrame::kAPlane), 642 static_cast<VpxVideoDecoder::MemoryPool::VP9FrameBuffer*>(
628 (*video_frame)->stride(VideoFrame::kAPlane), 643 vpx_image->fb_priv);
629 (*video_frame)->visible_rect().width(), 644 uint64_t alpha_plane_size =
630 (*video_frame)->visible_rect().height()); 645 (*vpx_image_alpha)->stride[VPX_PLANE_Y] * (*vpx_image_alpha)->d_h;
631 return true; 646 if (frame_buffer->alpha_data.size() < alpha_plane_size) {
647 frame_buffer->alpha_data.resize(alpha_plane_size);
648 }
649 libyuv::CopyPlane((*vpx_image_alpha)->planes[VPX_PLANE_Y],
650 (*vpx_image_alpha)->stride[VPX_PLANE_Y],
651 &frame_buffer->alpha_data[0],
652 (*vpx_image_alpha)->stride[VPX_PLANE_Y],
653 (*vpx_image_alpha)->d_w, (*vpx_image_alpha)->d_h);
654 }
655 return kAlphaPlaneProcessed;
632 } 656 }
633 657
634 bool VpxVideoDecoder::CopyVpxImageToVideoFrame( 658 bool VpxVideoDecoder::CopyVpxImageToVideoFrame(
635 const struct vpx_image* vpx_image, 659 const struct vpx_image* vpx_image,
660 const struct vpx_image* vpx_image_alpha,
636 scoped_refptr<VideoFrame>* video_frame) { 661 scoped_refptr<VideoFrame>* video_frame) {
637 DCHECK(vpx_image); 662 DCHECK(vpx_image);
638 663
639 VideoPixelFormat codec_format; 664 VideoPixelFormat codec_format;
640 switch (vpx_image->fmt) { 665 switch (vpx_image->fmt) {
641 case VPX_IMG_FMT_I420: 666 case VPX_IMG_FMT_I420:
642 codec_format = vpx_codec_alpha_ ? PIXEL_FORMAT_YV12A : PIXEL_FORMAT_YV12; 667 codec_format = vpx_image_alpha ? PIXEL_FORMAT_YV12A : PIXEL_FORMAT_YV12;
643 break; 668 break;
644 669
645 case VPX_IMG_FMT_I444: 670 case VPX_IMG_FMT_I444:
646 codec_format = PIXEL_FORMAT_YV24; 671 codec_format = PIXEL_FORMAT_YV24;
647 break; 672 break;
648 673
649 default: 674 default:
650 DLOG(ERROR) << "Unsupported pixel format: " << vpx_image->fmt; 675 DLOG(ERROR) << "Unsupported pixel format: " << vpx_image->fmt;
651 return false; 676 return false;
652 } 677 }
653 678
654 // The mixed |w|/|d_h| in |coded_size| is intentional. Setting the correct 679 // The mixed |w|/|d_h| in |coded_size| is intentional. Setting the correct
655 // coded width is necessary to allow coalesced memory access, which may avoid 680 // coded width is necessary to allow coalesced memory access, which may avoid
656 // frame copies. Setting the correct coded height however does not have any 681 // frame copies. Setting the correct coded height however does not have any
657 // benefit, and only risk copying too much data. 682 // benefit, and only risk copying too much data.
658 const gfx::Size coded_size(vpx_image->w, vpx_image->d_h); 683 const gfx::Size coded_size(vpx_image->w, vpx_image->d_h);
659 const gfx::Size visible_size(vpx_image->d_w, vpx_image->d_h); 684 const gfx::Size visible_size(vpx_image->d_w, vpx_image->d_h);
660 685
661 if (memory_pool_.get()) { 686 if (memory_pool_.get()) {
662 DCHECK_EQ(kCodecVP9, config_.codec()); 687 DCHECK_EQ(kCodecVP9, config_.codec());
663 DCHECK(!vpx_codec_alpha_) << "Uh-oh, VP9 and Alpha shouldn't coexist."; 688 if (vpx_image_alpha) {
664 *video_frame = VideoFrame::WrapExternalYuvData( 689 VpxVideoDecoder::MemoryPool::VP9FrameBuffer* frame_buffer =
665 codec_format, 690 static_cast<VpxVideoDecoder::MemoryPool::VP9FrameBuffer*>(
666 coded_size, gfx::Rect(visible_size), config_.natural_size(), 691 vpx_image->fb_priv);
667 vpx_image->stride[VPX_PLANE_Y], 692 *video_frame = VideoFrame::WrapExternalYuvaData(
668 vpx_image->stride[VPX_PLANE_U], 693 codec_format, coded_size, gfx::Rect(visible_size),
669 vpx_image->stride[VPX_PLANE_V], 694 config_.natural_size(), vpx_image->stride[VPX_PLANE_Y],
670 vpx_image->planes[VPX_PLANE_Y], 695 vpx_image->stride[VPX_PLANE_U], vpx_image->stride[VPX_PLANE_V],
671 vpx_image->planes[VPX_PLANE_U], 696 vpx_image_alpha->stride[VPX_PLANE_Y], vpx_image->planes[VPX_PLANE_Y],
672 vpx_image->planes[VPX_PLANE_V], 697 vpx_image->planes[VPX_PLANE_U], vpx_image->planes[VPX_PLANE_V],
673 kNoTimestamp()); 698 &frame_buffer->alpha_data[0], kNoTimestamp());
699 } else {
700 *video_frame = VideoFrame::WrapExternalYuvData(
701 codec_format, coded_size, gfx::Rect(visible_size),
702 config_.natural_size(), vpx_image->stride[VPX_PLANE_Y],
703 vpx_image->stride[VPX_PLANE_U], vpx_image->stride[VPX_PLANE_V],
704 vpx_image->planes[VPX_PLANE_Y], vpx_image->planes[VPX_PLANE_U],
705 vpx_image->planes[VPX_PLANE_V], kNoTimestamp());
706 }
674 if (!(*video_frame)) 707 if (!(*video_frame))
675 return false; 708 return false;
676 709
677 video_frame->get()->AddDestructionObserver( 710 video_frame->get()->AddDestructionObserver(
678 memory_pool_->CreateFrameCallback(vpx_image->fb_priv)); 711 memory_pool_->CreateFrameCallback(vpx_image->fb_priv));
679 return true; 712 return true;
680 } 713 }
681 714
682 DCHECK(codec_format == PIXEL_FORMAT_YV12 || 715 DCHECK(codec_format == PIXEL_FORMAT_YV12 ||
683 codec_format == PIXEL_FORMAT_YV12A); 716 codec_format == PIXEL_FORMAT_YV12A);
(...skipping 13 matching lines...) Expand all
697 (*video_frame)->visible_data(VideoFrame::kUPlane), 730 (*video_frame)->visible_data(VideoFrame::kUPlane),
698 (*video_frame)->stride(VideoFrame::kUPlane), 731 (*video_frame)->stride(VideoFrame::kUPlane),
699 (*video_frame)->visible_data(VideoFrame::kVPlane), 732 (*video_frame)->visible_data(VideoFrame::kVPlane),
700 (*video_frame)->stride(VideoFrame::kVPlane), coded_size.width(), 733 (*video_frame)->stride(VideoFrame::kVPlane), coded_size.width(),
701 coded_size.height()); 734 coded_size.height());
702 735
703 return true; 736 return true;
704 } 737 }
705 738
706 } // namespace media 739 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/vpx_video_decoder.h ('k') | media/test/data/bear-vp9a.webm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698