Home | History | Annotate | Download | only in test
      1 /*
      2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #ifndef WEBRTC_MODULES_VIDEO_CODING_CODECS_TEST_VIDEOPROCESSOR_H_
     12 #define WEBRTC_MODULES_VIDEO_CODING_CODECS_TEST_VIDEOPROCESSOR_H_
     13 
     14 #include <string>
     15 
     16 #include "webrtc/base/checks.h"
     17 #include "webrtc/common_video/libyuv/include/scaler.h"
     18 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
     19 #include "webrtc/modules/video_coding/include/video_codec_interface.h"
     20 #include "webrtc/modules/video_coding/codecs/test/packet_manipulator.h"
     21 #include "webrtc/modules/video_coding/codecs/test/stats.h"
     22 #include "webrtc/system_wrappers/include/tick_util.h"
     23 #include "webrtc/test/testsupport/frame_reader.h"
     24 #include "webrtc/test/testsupport/frame_writer.h"
     25 #include "webrtc/video_frame.h"
     26 
     27 namespace webrtc {
     28 namespace test {
     29 
     30 // Defines which frame types shall be excluded from packet loss and when.
     31 enum ExcludeFrameTypes {
     32   // Will exclude the first keyframe in the video sequence from packet loss.
     33   // Following keyframes will be targeted for packet loss.
     34   kExcludeOnlyFirstKeyFrame,
     35   // Exclude all keyframes from packet loss, no matter where in the video
     36   // sequence they occur.
     37   kExcludeAllKeyFrames
     38 };
     39 // Returns a string representation of the enum value.
     40 const char* ExcludeFrameTypesToStr(ExcludeFrameTypes e);
     41 
     42 // Test configuration for a test run
     43 struct TestConfig {
     44   TestConfig();
     45   ~TestConfig();
     46 
     47   // Name of the test. This is purely metadata and does not affect
     48   // the test in any way.
     49   std::string name;
     50 
     51   // More detailed description of the test. This is purely metadata and does
     52   // not affect the test in any way.
     53   std::string description;
     54 
     55   // Number of this test. Useful if multiple runs of the same test with
     56   // different configurations shall be managed.
     57   int test_number;
     58 
     59   // File to process for the test. This must be a video file in the YUV format.
     60   std::string input_filename;
     61 
     62   // File to write to during processing for the test. Will be a video file
     63   // in the YUV format.
     64   std::string output_filename;
     65 
     66   // Path to the directory where encoded files will be put
     67   // (absolute or relative to the executable). Default: "out".
     68   std::string output_dir;
     69 
     70   // Configurations related to networking.
     71   NetworkingConfig networking_config;
     72 
     73   // Decides how the packet loss simulations shall exclude certain frames
     74   // from packet loss. Default: kExcludeOnlyFirstKeyFrame.
     75   ExcludeFrameTypes exclude_frame_types;
     76 
     77   // The length of a single frame of the input video file. This value is
     78   // calculated out of the width and height according to the video format
     79   // specification. Must be set before processing.
     80   size_t frame_length_in_bytes;
     81 
     82   // Force the encoder and decoder to use a single core for processing.
     83   // Using a single core is necessary to get a deterministic behavior for the
     84   // encoded frames - using multiple cores will produce different encoded frames
     85   // since multiple cores are competing to consume the byte budget for each
     86   // frame in parallel.
     87   // If set to false, the maximum number of available cores will be used.
     88   // Default: false.
     89   bool use_single_core;
     90 
     91   // If set to a value >0 this setting forces the encoder to create a keyframe
     92   // every Nth frame. Note that the encoder may create a keyframe in other
     93   // locations in addition to the interval that is set using this parameter.
     94   // Forcing key frames may also affect encoder planning optimizations in
     95   // a negative way, since it will suddenly be forced to produce an expensive
     96   // key frame.
     97   // Default: 0.
     98   int keyframe_interval;
     99 
    100   // The codec settings to use for the test (target bitrate, video size,
    101   // framerate and so on). This struct must be created and filled in using
    102   // the VideoCodingModule::Codec() method.
    103   webrtc::VideoCodec* codec_settings;
    104 
    105   // If printing of information to stdout shall be performed during processing.
    106   bool verbose;
    107 };
    108 
    109 // Returns a string representation of the enum value.
    110 const char* VideoCodecTypeToStr(webrtc::VideoCodecType e);
    111 
    112 // Handles encoding/decoding of video using the VideoEncoder/VideoDecoder
    113 // interfaces. This is done in a sequential manner in order to be able to
    114 // measure times properly.
    115 // The class processes a frame at the time for the configured input file.
    116 // It maintains state of where in the source input file the processing is at.
    117 //
    118 // Regarding packet loss: Note that keyframes are excluded (first or all
    119 // depending on the ExcludeFrameTypes setting). This is because if key frames
    120 // would be altered, all the following delta frames would be pretty much
    121 // worthless. VP8 has an error-resilience feature that makes it able to handle
    122 // packet loss in key non-first keyframes, which is why only the first is
    123 // excluded by default.
    124 // Packet loss in such important frames is handled on a higher level in the
    125 // Video Engine, where signaling would request a retransmit of the lost packets,
    126 // since they're so important.
    127 //
    128 // Note this class is not thread safe in any way and is meant for simple testing
    129 // purposes.
    130 class VideoProcessor {
    131  public:
    132   virtual ~VideoProcessor() {}
    133 
    134   // Performs initial calculations about frame size, sets up callbacks etc.
    135   // Returns false if an error has occurred, in addition to printing to stderr.
    136   virtual bool Init() = 0;
    137 
    138   // Processes a single frame. Returns true as long as there's more frames
    139   // available in the source clip.
    140   // Frame number must be an integer >=0.
    141   virtual bool ProcessFrame(int frame_number) = 0;
    142 
    143   // Updates the encoder with the target bit rate and the frame rate.
    144   virtual void SetRates(int bit_rate, int frame_rate) = 0;
    145 
    146   // Return the size of the encoded frame in bytes. Dropped frames by the
    147   // encoder are regarded as zero size.
    148   virtual size_t EncodedFrameSize() = 0;
    149 
    150   // Return the encoded frame type (key or delta).
    151   virtual FrameType EncodedFrameType() = 0;
    152 
    153   // Return the number of dropped frames.
    154   virtual int NumberDroppedFrames() = 0;
    155 
    156   // Return the number of spatial resizes.
    157   virtual int NumberSpatialResizes() = 0;
    158 };
    159 
    160 class VideoProcessorImpl : public VideoProcessor {
    161  public:
    162   VideoProcessorImpl(webrtc::VideoEncoder* encoder,
    163                      webrtc::VideoDecoder* decoder,
    164                      FrameReader* frame_reader,
    165                      FrameWriter* frame_writer,
    166                      PacketManipulator* packet_manipulator,
    167                      const TestConfig& config,
    168                      Stats* stats);
    169   virtual ~VideoProcessorImpl();
    170   bool Init() override;
    171   bool ProcessFrame(int frame_number) override;
    172 
    173  private:
    174   // Invoked by the callback when a frame has completed encoding.
    175   void FrameEncoded(const webrtc::EncodedImage& encodedImage);
    176   // Invoked by the callback when a frame has completed decoding.
    177   void FrameDecoded(const webrtc::VideoFrame& image);
    178   // Used for getting a 32-bit integer representing time
    179   // (checks the size is within signed 32-bit bounds before casting it)
    180   int GetElapsedTimeMicroseconds(const webrtc::TickTime& start,
    181                                  const webrtc::TickTime& stop);
    182   // Updates the encoder with the target bit rate and the frame rate.
    183   void SetRates(int bit_rate, int frame_rate) override;
    184   // Return the size of the encoded frame in bytes.
    185   size_t EncodedFrameSize() override;
    186   // Return the encoded frame type (key or delta).
    187   FrameType EncodedFrameType() override;
    188   // Return the number of dropped frames.
    189   int NumberDroppedFrames() override;
    190   // Return the number of spatial resizes.
    191   int NumberSpatialResizes() override;
    192 
    193   webrtc::VideoEncoder* encoder_;
    194   webrtc::VideoDecoder* decoder_;
    195   FrameReader* frame_reader_;
    196   FrameWriter* frame_writer_;
    197   PacketManipulator* packet_manipulator_;
    198   const TestConfig& config_;
    199   Stats* stats_;
    200 
    201   EncodedImageCallback* encode_callback_;
    202   DecodedImageCallback* decode_callback_;
    203   // Buffer used for reading the source video file:
    204   uint8_t* source_buffer_;
    205   // Keep track of the last successful frame, since we need to write that
    206   // when decoding fails:
    207   uint8_t* last_successful_frame_buffer_;
    208   webrtc::VideoFrame source_frame_;
    209   // To keep track of if we have excluded the first key frame from packet loss:
    210   bool first_key_frame_has_been_excluded_;
    211   // To tell the decoder previous frame have been dropped due to packet loss:
    212   bool last_frame_missing_;
    213   // If Init() has executed successfully.
    214   bool initialized_;
    215   size_t encoded_frame_size_;
    216   FrameType encoded_frame_type_;
    217   int prev_time_stamp_;
    218   int num_dropped_frames_;
    219   int num_spatial_resizes_;
    220   int last_encoder_frame_width_;
    221   int last_encoder_frame_height_;
    222   Scaler scaler_;
    223 
    224   // Statistics
    225   double bit_rate_factor_;  // multiply frame length with this to get bit rate
    226   webrtc::TickTime encode_start_;
    227   webrtc::TickTime decode_start_;
    228 
    229   // Callback class required to implement according to the VideoEncoder API.
    230   class VideoProcessorEncodeCompleteCallback
    231       : public webrtc::EncodedImageCallback {
    232    public:
    233     explicit VideoProcessorEncodeCompleteCallback(VideoProcessorImpl* vp)
    234         : video_processor_(vp) {}
    235     int32_t Encoded(
    236         const webrtc::EncodedImage& encoded_image,
    237         const webrtc::CodecSpecificInfo* codec_specific_info,
    238         const webrtc::RTPFragmentationHeader* fragmentation) override;
    239 
    240    private:
    241     VideoProcessorImpl* video_processor_;
    242   };
    243 
    244   // Callback class required to implement according to the VideoDecoder API.
    245   class VideoProcessorDecodeCompleteCallback
    246       : public webrtc::DecodedImageCallback {
    247    public:
    248     explicit VideoProcessorDecodeCompleteCallback(VideoProcessorImpl* vp)
    249         : video_processor_(vp) {}
    250     int32_t Decoded(webrtc::VideoFrame& image) override;
    251     int32_t Decoded(webrtc::VideoFrame& image,
    252                     int64_t decode_time_ms) override {
    253       RTC_NOTREACHED();
    254       return -1;
    255     }
    256 
    257    private:
    258     VideoProcessorImpl* video_processor_;
    259   };
    260 };
    261 
    262 }  // namespace test
    263 }  // namespace webrtc
    264 
    265 #endif  // WEBRTC_MODULES_VIDEO_CODING_CODECS_TEST_VIDEOPROCESSOR_H_
    266