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 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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*>(×tamp_alpha); | 608 void* user_priv_alpha = reinterpret_cast<void*>(×tamp_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 Loading... |
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 |
OLD | NEW |