Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 <inttypes.h> | 5 #include <inttypes.h> |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <queue> | 8 #include <queue> |
| 9 #include <string> | 9 #include <string> |
| 10 | 10 |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 25 #include "base/threading/thread_checker.h" | 25 #include "base/threading/thread_checker.h" |
| 26 #include "base/time/time.h" | 26 #include "base/time/time.h" |
| 27 #include "base/timer/timer.h" | 27 #include "base/timer/timer.h" |
| 28 #include "content/common/gpu/media/video_accelerator_unittest_helpers.h" | 28 #include "content/common/gpu/media/video_accelerator_unittest_helpers.h" |
| 29 #include "media/base/bind_to_current_loop.h" | 29 #include "media/base/bind_to_current_loop.h" |
| 30 #include "media/base/bitstream_buffer.h" | 30 #include "media/base/bitstream_buffer.h" |
| 31 #include "media/base/decoder_buffer.h" | 31 #include "media/base/decoder_buffer.h" |
| 32 #include "media/base/test_data_util.h" | 32 #include "media/base/test_data_util.h" |
| 33 #include "media/base/video_decoder.h" | 33 #include "media/base/video_decoder.h" |
| 34 #include "media/base/video_frame.h" | 34 #include "media/base/video_frame.h" |
| 35 #include "media/base/yuv_convert.h" | |
| 35 #include "media/filters/ffmpeg_glue.h" | 36 #include "media/filters/ffmpeg_glue.h" |
| 36 #include "media/filters/ffmpeg_video_decoder.h" | 37 #include "media/filters/ffmpeg_video_decoder.h" |
| 37 #include "media/filters/h264_parser.h" | 38 #include "media/filters/h264_parser.h" |
| 38 #include "media/video/fake_video_encode_accelerator.h" | 39 #include "media/video/fake_video_encode_accelerator.h" |
| 39 #include "media/video/video_encode_accelerator.h" | 40 #include "media/video/video_encode_accelerator.h" |
| 40 #include "testing/gtest/include/gtest/gtest.h" | 41 #include "testing/gtest/include/gtest/gtest.h" |
| 42 #include "ui/gfx/codec/png_codec.h" | |
| 41 | 43 |
| 42 #if defined(OS_CHROMEOS) | 44 #if defined(OS_CHROMEOS) |
| 43 #if defined(ARCH_CPU_ARMEL) || (defined(USE_OZONE) && defined(USE_V4L2_CODEC)) | 45 #if defined(ARCH_CPU_ARMEL) || (defined(USE_OZONE) && defined(USE_V4L2_CODEC)) |
| 44 #include "content/common/gpu/media/v4l2_video_encode_accelerator.h" | 46 #include "content/common/gpu/media/v4l2_video_encode_accelerator.h" |
| 45 #endif | 47 #endif |
| 46 #if defined(ARCH_CPU_X86_FAMILY) | 48 #if defined(ARCH_CPU_X86_FAMILY) |
| 47 #include "content/common/gpu/media/vaapi_video_encode_accelerator.h" | 49 #include "content/common/gpu/media/vaapi_video_encode_accelerator.h" |
| 48 #include "content/common/gpu/media/vaapi_wrapper.h" | 50 #include "content/common/gpu/media/vaapi_wrapper.h" |
| 49 #endif // defined(ARCH_CPU_X86_FAMILY) | 51 #endif // defined(ARCH_CPU_X86_FAMILY) |
| 50 #else | 52 #else |
| (...skipping 557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 608 const gfx::Rect& visible_size, | 610 const gfx::Rect& visible_size, |
| 609 const media::VideoCodecProfile profile); | 611 const media::VideoCodecProfile profile); |
| 610 // Push original frame to origin_frames_ queue | 612 // Push original frame to origin_frames_ queue |
| 611 void AddOriginFrame(scoped_refptr<media::VideoFrame> frame); | 613 void AddOriginFrame(scoped_refptr<media::VideoFrame> frame); |
| 612 void Decode(const scoped_refptr<media::DecoderBuffer>& buffer); | 614 void Decode(const scoped_refptr<media::DecoderBuffer>& buffer); |
| 613 | 615 |
| 614 private: | 616 private: |
| 615 void InitializeCB(bool success); | 617 void InitializeCB(bool success); |
| 616 void DecodeDone(media::VideoDecoder::Status status); | 618 void DecodeDone(media::VideoDecoder::Status status); |
| 617 void CheckOutputFrame(const scoped_refptr<media::VideoFrame>& output_frame); | 619 void CheckOutputFrame(const scoped_refptr<media::VideoFrame>& output_frame); |
| 618 | 620 void SaveFrameToFile(const scoped_refptr<media::VideoFrame>& frame, |
| 621 base::FilePath filename); | |
| 619 scoped_ptr<media::FFmpegVideoDecoder> decoder_; | 622 scoped_ptr<media::FFmpegVideoDecoder> decoder_; |
| 620 media::VideoDecoder::DecodeCB decode_cb_; | 623 media::VideoDecoder::DecodeCB decode_cb_; |
| 621 | 624 |
| 622 std::queue<scoped_refptr<media::VideoFrame>> origin_frames_; | 625 std::queue<scoped_refptr<media::VideoFrame>> origin_frames_; |
| 626 | |
| 627 int frame_id_; | |
| 623 }; | 628 }; |
| 624 | 629 |
| 625 VideoFrameQualityValidator::VideoFrameQualityValidator() | 630 VideoFrameQualityValidator::VideoFrameQualityValidator() |
| 626 : decoder_(new media::FFmpegVideoDecoder( | 631 : decoder_(new media::FFmpegVideoDecoder( |
| 627 base::MessageLoop::current()->task_runner())), | 632 base::MessageLoop::current()->task_runner())), |
| 628 decode_cb_(base::Bind(&VideoFrameQualityValidator::DecodeDone, | 633 decode_cb_(base::Bind(&VideoFrameQualityValidator::DecodeDone, |
| 629 base::Unretained(this))) { | 634 base::Unretained(this))), |
| 635 frame_id_(0) { | |
| 630 decoder_->set_decode_nalus(true); | 636 decoder_->set_decode_nalus(true); |
| 631 } | 637 } |
| 632 | 638 |
| 633 void VideoFrameQualityValidator::Initialize( | 639 void VideoFrameQualityValidator::Initialize( |
| 634 const gfx::Size& coded_size, | 640 const gfx::Size& coded_size, |
| 635 const gfx::Rect& visible_size, | 641 const gfx::Rect& visible_size, |
| 636 const media::VideoCodecProfile profile) { | 642 const media::VideoCodecProfile profile) { |
| 637 media::FFmpegGlue::InitializeFFmpeg(); | 643 media::FFmpegGlue::InitializeFFmpeg(); |
| 644 media::InitializeCPUSpecificYUVConversions(); | |
| 638 | 645 |
| 639 gfx::Size natural_size(visible_size.size()); | 646 gfx::Size natural_size(visible_size.size()); |
| 640 media::VideoDecoderConfig config; | 647 media::VideoDecoderConfig config; |
| 641 if (IsVP8(profile)) | 648 if (IsVP8(profile)) |
| 642 config.Initialize(media::kCodecVP8, media::VP8PROFILE_ANY, kInputFormat, | 649 config.Initialize(media::kCodecVP8, media::VP8PROFILE_ANY, kInputFormat, |
| 643 media::COLOR_SPACE_UNSPECIFIED, coded_size, visible_size, | 650 media::COLOR_SPACE_UNSPECIFIED, coded_size, visible_size, |
| 644 natural_size, NULL, 0, false, true); | 651 natural_size, NULL, 0, false, true); |
| 645 else if (IsH264(profile)) | 652 else if (IsH264(profile)) |
| 646 config.Initialize(media::kCodecH264, media::H264PROFILE_MAIN, kInputFormat, | 653 config.Initialize(media::kCodecH264, media::H264PROFILE_MAIN, kInputFormat, |
| 647 media::COLOR_SPACE_UNSPECIFIED, coded_size, visible_size, | 654 media::COLOR_SPACE_UNSPECIFIED, coded_size, visible_size, |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 670 | 677 |
| 671 void VideoFrameQualityValidator::Decode( | 678 void VideoFrameQualityValidator::Decode( |
| 672 const scoped_refptr<media::DecoderBuffer>& buffer) { | 679 const scoped_refptr<media::DecoderBuffer>& buffer) { |
| 673 decoder_->Decode(buffer, decode_cb_); | 680 decoder_->Decode(buffer, decode_cb_); |
| 674 } | 681 } |
| 675 | 682 |
| 676 void VideoFrameQualityValidator::CheckOutputFrame( | 683 void VideoFrameQualityValidator::CheckOutputFrame( |
| 677 const scoped_refptr<media::VideoFrame>& output_frame) { | 684 const scoped_refptr<media::VideoFrame>& output_frame) { |
| 678 scoped_refptr<media::VideoFrame> origin_frame = origin_frames_.front(); | 685 scoped_refptr<media::VideoFrame> origin_frame = origin_frames_.front(); |
| 679 origin_frames_.pop(); | 686 origin_frames_.pop(); |
| 687 frame_id_++; | |
| 680 | 688 |
| 681 gfx::Size visible_size = origin_frame->visible_rect().size(); | 689 gfx::Size visible_size = origin_frame->visible_rect().size(); |
| 682 int planes[] = {media::VideoFrame::kYPlane, | 690 int planes[] = {media::VideoFrame::kYPlane, |
| 683 media::VideoFrame::kUPlane, | 691 media::VideoFrame::kUPlane, |
| 684 media::VideoFrame::kVPlane}; | 692 media::VideoFrame::kVPlane}; |
| 685 double difference = 0; | 693 double difference = 0; |
| 686 for (int plane : planes) { | 694 for (int plane : planes) { |
| 687 uint8_t* origin_plane = origin_frame->data(plane); | 695 uint8_t* origin_plane = origin_frame->data(plane); |
| 688 uint8_t* output_plane = output_frame->data(plane); | 696 uint8_t* output_plane = output_frame->data(plane); |
| 689 | 697 |
| 690 size_t rows = | 698 size_t rows = |
| 691 media::VideoFrame::Rows(plane, kInputFormat, visible_size.height()); | 699 media::VideoFrame::Rows(plane, kInputFormat, visible_size.height()); |
| 692 size_t columns = | 700 size_t columns = |
| 693 media::VideoFrame::Columns(plane, kInputFormat, visible_size.width()); | 701 media::VideoFrame::Columns(plane, kInputFormat, visible_size.width()); |
| 694 size_t stride = origin_frame->stride(plane); | 702 size_t stride = origin_frame->stride(plane); |
| 695 | 703 |
| 696 for (size_t i = 0; i < rows; i++) | 704 for (size_t i = 0; i < rows; i++) |
| 697 for (size_t j = 0; j < columns; j++) | 705 for (size_t j = 0; j < columns; j++) |
| 698 difference += std::abs(origin_plane[stride * i + j] - | 706 difference += std::abs(origin_plane[stride * i + j] - |
| 699 output_plane[stride * i + j]); | 707 output_plane[stride * i + j]); |
| 700 } | 708 } |
| 701 // Divide the difference by the size of frame | 709 // Divide the difference by the size of frame |
| 702 difference /= media::VideoFrame::AllocationSize(kInputFormat, visible_size); | 710 difference /= media::VideoFrame::AllocationSize(kInputFormat, visible_size); |
| 711 | |
| 712 // Save both origin and output frames to files if its difference is larger | |
| 713 // than kDecodeSimilarityThreshold | |
| 703 CHECK(difference < kDecodeSimilarityThreshold) | 714 CHECK(difference < kDecodeSimilarityThreshold) |
|
Owen Lin
2015/08/12 08:07:48
I thought we will crash at CHECK and then no outpu
| |
| 704 << "differrence = " << difference << " > kDecodeSimilarityThreshold"; | 715 << "differrence = " << difference << " > kDecodeSimilarityThreshold"; |
| 716 if (difference >= kDecodeSimilarityThreshold) { | |
| 717 std::string filename = | |
| 718 base::StringPrintf("%.4d_origin_frame.png", frame_id_); | |
| 719 SaveFrameToFile(origin_frame, base::FilePath::FromUTF8Unsafe(filename)); | |
| 720 filename = base::StringPrintf("%.4d_output_frame.png", frame_id_); | |
| 721 SaveFrameToFile(output_frame, base::FilePath::FromUTF8Unsafe(filename)); | |
| 722 } | |
| 723 } | |
| 724 | |
| 725 void VideoFrameQualityValidator::SaveFrameToFile( | |
| 726 const scoped_refptr<media::VideoFrame>& frame, | |
| 727 base::FilePath filename) { | |
|
Owen Lin
2015/08/12 08:07:48
const base::FilePath &
| |
| 728 size_t row_bytes = frame->coded_size().width() * 4u; | |
|
Owen Lin
2015/08/12 08:07:48
use visible size for rgb_bytes.
| |
| 729 uint8* rgb_pixels = reinterpret_cast<uint8*>( | |
|
Owen Lin
2015/08/12 08:07:48
How do you free the rgb_pixels
| |
| 730 base::AlignedAlloc(row_bytes * frame->coded_size().height() + | |
| 731 media::VideoFrame::kFrameSizePadding, | |
| 732 media::VideoFrame::kFrameAddressAlignment)); | |
| 733 media::ConvertYUVToRGB32( | |
| 734 frame->data(media::VideoFrame::kYPlane), | |
| 735 frame->data(media::VideoFrame::kUPlane), | |
| 736 frame->data(media::VideoFrame::kVPlane), rgb_pixels, | |
| 737 frame->visible_rect().width(), frame->visible_rect().height(), | |
| 738 frame->stride(media::VideoFrame::kYPlane), | |
| 739 frame->stride(media::VideoFrame::kUPlane), row_bytes, media::YV12); | |
| 740 | |
| 741 std::vector<unsigned char> png_output; | |
| 742 bool success = gfx::PNGCodec::Encode( | |
| 743 rgb_pixels, gfx::PNGCodec::FORMAT_RGBA, frame->coded_size(), | |
| 744 base::checked_cast<int>(row_bytes), true, | |
| 745 std::vector<gfx::PNGCodec::Comment>(), &png_output); | |
| 746 if (success) { | |
|
Owen Lin
2015/08/12 08:07:48
CHECK(gfx::PNGCodec::...);
| |
| 747 base::WriteFile(filename, reinterpret_cast<char*>(&*png_output.begin()), | |
| 748 base::checked_cast<int>(png_output.size())); | |
| 749 } | |
| 705 } | 750 } |
| 706 | 751 |
| 707 class VEAClient : public VideoEncodeAccelerator::Client { | 752 class VEAClient : public VideoEncodeAccelerator::Client { |
| 708 public: | 753 public: |
| 709 VEAClient(TestStream* test_stream, | 754 VEAClient(TestStream* test_stream, |
| 710 ClientStateNotification<ClientState>* note, | 755 ClientStateNotification<ClientState>* note, |
| 711 bool save_to_file, | 756 bool save_to_file, |
| 712 unsigned int keyframe_period, | 757 unsigned int keyframe_period, |
| 713 bool force_bitrate, | 758 bool force_bitrate, |
| 714 bool test_perf, | 759 bool test_perf, |
| (...skipping 947 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1662 | 1707 |
| 1663 content::g_env = | 1708 content::g_env = |
| 1664 reinterpret_cast<content::VideoEncodeAcceleratorTestEnvironment*>( | 1709 reinterpret_cast<content::VideoEncodeAcceleratorTestEnvironment*>( |
| 1665 testing::AddGlobalTestEnvironment( | 1710 testing::AddGlobalTestEnvironment( |
| 1666 new content::VideoEncodeAcceleratorTestEnvironment( | 1711 new content::VideoEncodeAcceleratorTestEnvironment( |
| 1667 test_stream_data.Pass(), log_path, run_at_fps, | 1712 test_stream_data.Pass(), log_path, run_at_fps, |
| 1668 needs_encode_latency, verify_output))); | 1713 needs_encode_latency, verify_output))); |
| 1669 | 1714 |
| 1670 return RUN_ALL_TESTS(); | 1715 return RUN_ALL_TESTS(); |
| 1671 } | 1716 } |
| OLD | NEW |