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