Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
|
wuchengli
2015/09/04 11:59:44
IIRC, the first line of the change description wil
| |
| 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 |
| 11 #include "base/at_exit.h" | 11 #include "base/at_exit.h" |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 24 #include "base/threading/thread_checker.h" | 24 #include "base/threading/thread_checker.h" |
| 25 #include "base/time/time.h" | 25 #include "base/time/time.h" |
| 26 #include "base/timer/timer.h" | 26 #include "base/timer/timer.h" |
| 27 #include "content/common/gpu/media/video_accelerator_unittest_helpers.h" | 27 #include "content/common/gpu/media/video_accelerator_unittest_helpers.h" |
| 28 #include "media/base/bind_to_current_loop.h" | 28 #include "media/base/bind_to_current_loop.h" |
| 29 #include "media/base/bitstream_buffer.h" | 29 #include "media/base/bitstream_buffer.h" |
| 30 #include "media/base/decoder_buffer.h" | 30 #include "media/base/decoder_buffer.h" |
| 31 #include "media/base/test_data_util.h" | 31 #include "media/base/test_data_util.h" |
| 32 #include "media/base/video_decoder.h" | 32 #include "media/base/video_decoder.h" |
| 33 #include "media/base/video_frame.h" | 33 #include "media/base/video_frame.h" |
| 34 #include "media/base/yuv_convert.h" | |
| 34 #include "media/filters/ffmpeg_glue.h" | 35 #include "media/filters/ffmpeg_glue.h" |
| 35 #include "media/filters/ffmpeg_video_decoder.h" | 36 #include "media/filters/ffmpeg_video_decoder.h" |
| 36 #include "media/filters/h264_parser.h" | 37 #include "media/filters/h264_parser.h" |
| 37 #include "media/filters/ivf_parser.h" | 38 #include "media/filters/ivf_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 // Status has been defined as int in Xlib.h. | 51 // Status has been defined as int in Xlib.h. |
| 50 #undef Status | 52 #undef Status |
| (...skipping 557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 608 void AddDecodeBuffer(const scoped_refptr<media::DecoderBuffer>& buffer); | 610 void AddDecodeBuffer(const scoped_refptr<media::DecoderBuffer>& buffer); |
| 609 // Flush the decoder. | 611 // Flush the decoder. |
| 610 void Flush(); | 612 void Flush(); |
| 611 | 613 |
| 612 private: | 614 private: |
| 613 void InitializeCB(bool success); | 615 void InitializeCB(bool success); |
| 614 void DecodeDone(media::VideoDecoder::Status status); | 616 void DecodeDone(media::VideoDecoder::Status status); |
| 615 void FlushDone(media::VideoDecoder::Status status); | 617 void FlushDone(media::VideoDecoder::Status status); |
| 616 void VerifyOutputFrame(const scoped_refptr<media::VideoFrame>& output_frame); | 618 void VerifyOutputFrame(const scoped_refptr<media::VideoFrame>& output_frame); |
| 617 void Decode(); | 619 void Decode(); |
| 620 void SaveFrameToFile(const scoped_refptr<media::VideoFrame>& frame, | |
| 621 const base::FilePath& filename); | |
| 618 | 622 |
| 619 enum State { UNINITIALIZED, INITIALIZED, DECODING, ERROR }; | 623 enum State { UNINITIALIZED, INITIALIZED, DECODING, ERROR }; |
| 620 | 624 |
| 621 const media::VideoCodecProfile profile_; | 625 const media::VideoCodecProfile profile_; |
| 622 scoped_ptr<media::FFmpegVideoDecoder> decoder_; | 626 scoped_ptr<media::FFmpegVideoDecoder> decoder_; |
| 623 media::VideoDecoder::DecodeCB decode_cb_; | 627 media::VideoDecoder::DecodeCB decode_cb_; |
| 624 // Decode callback of an EOS buffer. | 628 // Decode callback of an EOS buffer. |
| 625 media::VideoDecoder::DecodeCB eos_decode_cb_; | 629 media::VideoDecoder::DecodeCB eos_decode_cb_; |
| 626 // Callback of Flush(). Called after all frames are decoded. | 630 // Callback of Flush(). Called after all frames are decoded. |
| 627 const base::Closure flush_complete_cb_; | 631 const base::Closure flush_complete_cb_; |
| 628 const base::Closure decode_error_cb_; | 632 const base::Closure decode_error_cb_; |
| 629 State decoder_state_; | 633 State decoder_state_; |
| 630 std::queue<scoped_refptr<media::VideoFrame>> original_frames_; | 634 std::queue<scoped_refptr<media::VideoFrame>> original_frames_; |
| 631 std::queue<scoped_refptr<media::DecoderBuffer>> decode_buffers_; | 635 std::queue<scoped_refptr<media::DecoderBuffer>> decode_buffers_; |
| 636 | |
|
wuchengli
2015/09/04 11:59:44
Document if the id starts from 0. It's confusing l
| |
| 637 int frame_id_; | |
| 632 }; | 638 }; |
| 633 | 639 |
| 634 VideoFrameQualityValidator::VideoFrameQualityValidator( | 640 VideoFrameQualityValidator::VideoFrameQualityValidator( |
| 635 const media::VideoCodecProfile profile, | 641 const media::VideoCodecProfile profile, |
| 636 const base::Closure& flush_complete_cb, | 642 const base::Closure& flush_complete_cb, |
| 637 const base::Closure& decode_error_cb) | 643 const base::Closure& decode_error_cb) |
| 638 : profile_(profile), | 644 : profile_(profile), |
| 639 decoder_(new media::FFmpegVideoDecoder(base::MessageLoop::current() | 645 decoder_(new media::FFmpegVideoDecoder(base::MessageLoop::current() |
| 640 ->task_runner())), | 646 ->task_runner())), |
| 641 decode_cb_(base::Bind(&VideoFrameQualityValidator::DecodeDone, | 647 decode_cb_(base::Bind(&VideoFrameQualityValidator::DecodeDone, |
| 642 base::Unretained(this))), | 648 base::Unretained(this))), |
| 643 eos_decode_cb_(base::Bind(&VideoFrameQualityValidator::FlushDone, | 649 eos_decode_cb_(base::Bind(&VideoFrameQualityValidator::FlushDone, |
| 644 base::Unretained(this))), | 650 base::Unretained(this))), |
| 645 flush_complete_cb_(flush_complete_cb), | 651 flush_complete_cb_(flush_complete_cb), |
| 646 decode_error_cb_(decode_error_cb), | 652 decode_error_cb_(decode_error_cb), |
| 647 decoder_state_(UNINITIALIZED) { | 653 decoder_state_(UNINITIALIZED), |
| 654 frame_id_(0) { | |
| 648 // Allow decoding of individual NALU. Entire frames are required by default. | 655 // Allow decoding of individual NALU. Entire frames are required by default. |
| 649 decoder_->set_decode_nalus(true); | 656 decoder_->set_decode_nalus(true); |
| 650 } | 657 } |
| 651 | 658 |
| 652 void VideoFrameQualityValidator::Initialize(const gfx::Size& coded_size, | 659 void VideoFrameQualityValidator::Initialize(const gfx::Size& coded_size, |
| 653 const gfx::Rect& visible_size) { | 660 const gfx::Rect& visible_size) { |
| 654 media::FFmpegGlue::InitializeFFmpeg(); | 661 media::FFmpegGlue::InitializeFFmpeg(); |
| 655 | 662 |
| 656 gfx::Size natural_size(visible_size.size()); | 663 gfx::Size natural_size(visible_size.size()); |
| 657 // The default output format of ffmpeg video decoder is YV12. | 664 // The default output format of ffmpeg video decoder is YV12. |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 733 else | 740 else |
| 734 decoder_->Decode(next_buffer, decode_cb_); | 741 decoder_->Decode(next_buffer, decode_cb_); |
| 735 } | 742 } |
| 736 } | 743 } |
| 737 | 744 |
| 738 void VideoFrameQualityValidator::VerifyOutputFrame( | 745 void VideoFrameQualityValidator::VerifyOutputFrame( |
| 739 const scoped_refptr<media::VideoFrame>& output_frame) { | 746 const scoped_refptr<media::VideoFrame>& output_frame) { |
| 740 scoped_refptr<media::VideoFrame> original_frame = original_frames_.front(); | 747 scoped_refptr<media::VideoFrame> original_frame = original_frames_.front(); |
| 741 original_frames_.pop(); | 748 original_frames_.pop(); |
| 742 gfx::Size visible_size = original_frame->visible_rect().size(); | 749 gfx::Size visible_size = original_frame->visible_rect().size(); |
| 750 frame_id_++; | |
| 743 | 751 |
| 744 int planes[] = {media::VideoFrame::kYPlane, media::VideoFrame::kUPlane, | 752 int planes[] = {media::VideoFrame::kYPlane, media::VideoFrame::kUPlane, |
| 745 media::VideoFrame::kVPlane}; | 753 media::VideoFrame::kVPlane}; |
| 746 double difference = 0; | 754 double difference = 0; |
| 747 for (int plane : planes) { | 755 for (int plane : planes) { |
| 748 uint8_t* original_plane = original_frame->data(plane); | 756 uint8_t* original_plane = original_frame->data(plane); |
| 749 uint8_t* output_plane = output_frame->data(plane); | 757 uint8_t* output_plane = output_frame->data(plane); |
| 750 | 758 |
| 751 size_t rows = | 759 size_t rows = |
| 752 media::VideoFrame::Rows(plane, kInputFormat, visible_size.height()); | 760 media::VideoFrame::Rows(plane, kInputFormat, visible_size.height()); |
| 753 size_t columns = | 761 size_t columns = |
| 754 media::VideoFrame::Columns(plane, kInputFormat, visible_size.width()); | 762 media::VideoFrame::Columns(plane, kInputFormat, visible_size.width()); |
| 755 size_t stride = original_frame->stride(plane); | 763 size_t stride = original_frame->stride(plane); |
| 756 | 764 |
| 757 for (size_t i = 0; i < rows; i++) | 765 for (size_t i = 0; i < rows; i++) |
| 758 for (size_t j = 0; j < columns; j++) | 766 for (size_t j = 0; j < columns; j++) |
| 759 difference += std::abs(original_plane[stride * i + j] - | 767 difference += std::abs(original_plane[stride * i + j] - |
| 760 output_plane[stride * i + j]); | 768 output_plane[stride * i + j]); |
| 761 } | 769 } |
| 762 // Divide the difference by the size of frame. | 770 // Divide the difference by the size of frame. |
| 763 difference /= media::VideoFrame::AllocationSize(kInputFormat, visible_size); | 771 difference /= media::VideoFrame::AllocationSize(kInputFormat, visible_size); |
| 764 EXPECT_TRUE(difference <= kDecodeSimilarityThreshold) | 772 |
| 765 << "differrence = " << difference << " > decode similarity threshold"; | 773 // Save both origin and output frames to files if its difference is larger |
|
wuchengli
2015/09/04 11:59:44
s/its/their/
| |
| 774 // than kDecodeSimilarityThreshold | |
|
wuchengli
2015/09/04 11:59:44
add . at the end.
| |
| 775 if (difference >= kDecodeSimilarityThreshold) { | |
| 776 ADD_FAILURE() << "differrence = " << difference | |
| 777 << " > decode similarity threshold"; | |
| 778 std::string filename = | |
| 779 base::StringPrintf("%.4d_origin_frame.png", frame_id_); | |
| 780 SaveFrameToFile(original_frame, base::FilePath::FromUTF8Unsafe(filename)); | |
| 781 filename = base::StringPrintf("%.4d_output_frame.png", frame_id_); | |
| 782 SaveFrameToFile(output_frame, base::FilePath::FromUTF8Unsafe(filename)); | |
| 783 } | |
| 784 } | |
| 785 | |
| 786 void VideoFrameQualityValidator::SaveFrameToFile( | |
| 787 const scoped_refptr<media::VideoFrame>& frame, | |
| 788 const base::FilePath& filename) { | |
| 789 const int RGB32_BYTES_PER_PIXEL = 4; | |
| 790 size_t row_bytes = frame->visible_rect().width() * RGB32_BYTES_PER_PIXEL; | |
| 791 uint8* rgb_pixels = reinterpret_cast<uint8*>( | |
| 792 base::AlignedAlloc(row_bytes * frame->coded_size().height() + | |
|
wuchengli
2015/09/04 11:59:44
Why do we need the alignment?
| |
| 793 media::VideoFrame::kFrameSizePadding, | |
|
wuchengli
2015/09/04 11:59:44
Is this required?
| |
| 794 media::VideoFrame::kFrameAddressAlignment)); | |
| 795 media::ConvertYUVToRGB32( | |
| 796 frame->data(media::VideoFrame::kYPlane), | |
| 797 frame->data(media::VideoFrame::kUPlane), | |
| 798 frame->data(media::VideoFrame::kVPlane), rgb_pixels, | |
| 799 frame->visible_rect().width(), frame->visible_rect().height(), | |
| 800 frame->stride(media::VideoFrame::kYPlane), | |
| 801 frame->stride(media::VideoFrame::kUPlane), row_bytes, media::YV12); | |
|
wuchengli
2015/09/04 11:59:44
Is the original frame also YV12? We should documen
| |
| 802 | |
| 803 std::vector<unsigned char> png_output; | |
| 804 LOG_ASSERT(gfx::PNGCodec::Encode( | |
| 805 rgb_pixels, gfx::PNGCodec::FORMAT_RGBA, frame->coded_size(), | |
|
wuchengli
2015/09/04 11:59:43
why this is not visible_rect()?
| |
| 806 base::checked_cast<int>(row_bytes), true, | |
| 807 std::vector<gfx::PNGCodec::Comment>(), &png_output)); | |
| 808 base::AlignedFree(rgb_pixels); | |
| 809 base::WriteFile(filename, reinterpret_cast<char*>(&png_output[0]), | |
| 810 base::checked_cast<int>(png_output.size())); | |
| 811 | |
|
wuchengli
2015/09/04 11:59:44
remove blank line
| |
| 766 } | 812 } |
| 767 | 813 |
| 768 class VEAClient : public VideoEncodeAccelerator::Client { | 814 class VEAClient : public VideoEncodeAccelerator::Client { |
| 769 public: | 815 public: |
| 770 VEAClient(TestStream* test_stream, | 816 VEAClient(TestStream* test_stream, |
| 771 ClientStateNotification<ClientState>* note, | 817 ClientStateNotification<ClientState>* note, |
| 772 bool save_to_file, | 818 bool save_to_file, |
| 773 unsigned int keyframe_period, | 819 unsigned int keyframe_period, |
| 774 bool force_bitrate, | 820 bool force_bitrate, |
| 775 bool test_perf, | 821 bool test_perf, |
| (...skipping 989 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1765 | 1811 |
| 1766 content::g_env = | 1812 content::g_env = |
| 1767 reinterpret_cast<content::VideoEncodeAcceleratorTestEnvironment*>( | 1813 reinterpret_cast<content::VideoEncodeAcceleratorTestEnvironment*>( |
| 1768 testing::AddGlobalTestEnvironment( | 1814 testing::AddGlobalTestEnvironment( |
| 1769 new content::VideoEncodeAcceleratorTestEnvironment( | 1815 new content::VideoEncodeAcceleratorTestEnvironment( |
| 1770 test_stream_data.Pass(), log_path, run_at_fps, | 1816 test_stream_data.Pass(), log_path, run_at_fps, |
| 1771 needs_encode_latency, verify_all_output))); | 1817 needs_encode_latency, verify_all_output))); |
| 1772 | 1818 |
| 1773 return RUN_ALL_TESTS(); | 1819 return RUN_ALL_TESTS(); |
| 1774 } | 1820 } |
| OLD | NEW |