| /* |
| * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #ifndef WEBRTC_VIDEO_ENGINE_TEST_AUTO_TEST_SOURCE_FRAMEDROP_PRIMITIVES_H_ |
| #define WEBRTC_VIDEO_ENGINE_TEST_AUTO_TEST_SOURCE_FRAMEDROP_PRIMITIVES_H_ |
| |
| #include <map> |
| #include <vector> |
| |
| #include "video_engine/include/vie_codec.h" |
| #include "video_engine/include/vie_image_process.h" |
| #include "video_engine/test/auto_test/interface/vie_autotest_defines.h" |
| #include "video_engine/test/libvietest/include/vie_to_file_renderer.h" |
| |
| class FrameDropDetector; |
| class TbInterfaces; |
| |
| // Initializes the Video engine and its components, runs video playback using |
| // for KAutoTestSleepTimeMs milliseconds, then shuts down everything. |
| // The bit rate and packet loss parameters should be configured so that |
| // frames are dropped, in order to test the frame drop detection that is |
| // performed by the FrameDropDetector class. |
| void TestFullStack(const TbInterfaces& interfaces, |
| int capture_id, |
| int video_channel, |
| int width, |
| int height, |
| int bit_rate_kbps, |
| int packet_loss_percent, |
| int network_delay_ms, |
| FrameDropDetector* frame_drop_detector); |
| |
| // A frame in a video file. The four different points in the stack when |
| // register the frame state are (in time order): created, transmitted, decoded, |
| // rendered. |
| class Frame { |
| public: |
| Frame(int number, unsigned int timestamp) |
| : number_(number), |
| frame_timestamp_(timestamp), |
| created_timestamp_in_us_(-1), |
| sent_timestamp_in_us_(-1), |
| received_timestamp_in_us_(-1), |
| decoded_timestamp_in_us_(-1), |
| rendered_timestamp_in_us_(-1), |
| dropped_at_send(false), |
| dropped_at_receive(false), |
| dropped_at_decode(false), |
| dropped_at_render(false) {} |
| |
| // Frame number, starting at 0. |
| int number_; |
| |
| // Frame timestamp, that is used by Video Engine and RTP headers and set when |
| // the frame is sent into the stack. |
| unsigned int frame_timestamp_; |
| |
| // Timestamps for our measurements of when the frame is in different states. |
| int64_t created_timestamp_in_us_; |
| int64_t sent_timestamp_in_us_; |
| int64_t received_timestamp_in_us_; |
| int64_t decoded_timestamp_in_us_; |
| int64_t rendered_timestamp_in_us_; |
| |
| // Where the frame was dropped (more than one may be true). |
| bool dropped_at_send; |
| bool dropped_at_receive; |
| bool dropped_at_decode; |
| bool dropped_at_render; |
| }; |
| |
| // Fixes the output file by copying the last successful frame into the place |
| // where the dropped frame would be, for all dropped frames (if any). |
| // This method will not be able to fix data for the first frame if that is |
| // dropped, since there'll be no previous frame to copy. This case should never |
| // happen because of encoder frame dropping at least. |
| // Parameters: |
| // output_file The output file to modify (pad with frame copies |
| // for all dropped frames) |
| // frame_length_in_bytes Byte length of each frame. |
| // frames A vector of all Frame objects. Must be sorted by |
| // frame number. If empty this method will do nothing. |
| void FixOutputFileForComparison(const std::string& output_file, |
| int frame_length_in_bytes, |
| const std::vector<Frame*>& frames); |
| |
| // Handles statistics about dropped frames. Frames travel through the stack |
| // with different timestamps. The frames created and sent to the encoder have |
| // one timestamp on the sending side while the decoded/rendered frames have |
| // another timestamp on the receiving side. The difference between these |
| // timestamps is fixed, which we can use to identify the frames when they |
| // arrive, since the FrameDropDetector class gets data reported from both sides. |
| // The four different points in the stack when this class examines the frame |
| // states are (in time order): created, sent, received, decoded, rendered. |
| // |
| // The flow can be visualized like this: |
| // |
| // Created Sent Received Decoded Rendered |
| // +-------+ | +-------+ | +---------+ | +------+ +-------+ | +--------+ |
| // |Capture| | |Encoder| | | Ext. | | |Jitter| |Decoder| | | Ext. | |
| // | device|---->| |-->|transport|-->|buffer|->| |---->|renderer| |
| // +-------+ +-------+ +---------+ +------+ +-------+ +--------+ |
| // |
| // This class has no intention of being thread-safe. |
| class FrameDropDetector { |
| public: |
| enum State { |
| // A frame being created, i.e. sent to the encoder; the first step of |
| // a frame's life cycle. This timestamp becomes the frame timestamp in the |
| // Frame objects. |
| kCreated, |
| // A frame being sent in external transport (to the simulated network). This |
| // timestamp differs from the one in the Created state by a constant diff. |
| kSent, |
| // A frame being received in external transport (from the simulated |
| // network). This timestamp differs from the one in the Created state by a |
| // constant diff. |
| kReceived, |
| // A frame that has been decoded in the decoder. This timestamp differs |
| // from the one in the Created state by a constant diff. |
| kDecoded, |
| // A frame that has been rendered; the last step of a frame's life cycle. |
| // This timestamp differs from the one in the Created state by a constant |
| // diff. |
| kRendered |
| }; |
| |
| FrameDropDetector() |
| : dirty_(true), |
| dropped_frames_at_send_(0), |
| dropped_frames_at_receive_(0), |
| dropped_frames_at_decode_(0), |
| dropped_frames_at_render_(0), |
| num_created_frames_(0), |
| num_sent_frames_(0), |
| num_received_frames_(0), |
| num_decoded_frames_(0), |
| num_rendered_frames_(0), |
| timestamp_diff_(0) {} |
| |
| // Reports a frame has reached a state in the frame life cycle. |
| void ReportFrameState(State state, unsigned int timestamp); |
| |
| // Uses all the gathered timestamp information to calculate which frames have |
| // been dropped during the test and where they were dropped. Not until |
| // this method has been executed, the Frame objects will have all fields |
| // filled with the proper timestamp information. |
| void CalculateResults(); |
| |
| // Calculates the number of frames have been registered as dropped at the |
| // specified state of the frame life cycle. |
| // CalculateResults() must be called before calling this method. |
| int GetNumberOfFramesDroppedAt(State state); |
| |
| // Gets a vector of all the created frames. |
| // CalculateResults() must be called before calling this method to have all |
| // fields of the Frame objects to represent the current state. |
| const std::vector<Frame*>& GetAllFrames(); |
| |
| // Prints a detailed report about all the different frame states and which |
| // ones are detected as dropped, using ViETest::Log. |
| // CalculateResults() must be called before calling this method. |
| void PrintReport(); |
| |
| // Prints all the timestamp maps. Mainly used for debugging purposes to find |
| // missing timestamps. |
| void PrintDebugDump(); |
| private: |
| // Will be false until CalculateResults() is called. Switches to true |
| // as soon as new timestamps are reported using ReportFrameState(). |
| bool dirty_; |
| |
| // Map of frame creation timestamps to all Frame objects. |
| std::map<unsigned int, Frame*> created_frames_; |
| |
| // Maps converted frame timestamps (differ from creation timestamp) to the |
| // time they arrived in the different states of the frame's life cycle. |
| std::map<unsigned int, int64_t> sent_frames_; |
| std::map<unsigned int, int64_t> received_frames_; |
| std::map<unsigned int, int64_t> decoded_frames_; |
| std::map<unsigned int, int64_t> rendered_frames_; |
| |
| // A vector with the frames sorted in their created order. |
| std::vector<Frame*> created_frames_vector_; |
| |
| // Statistics. |
| int dropped_frames_at_send_; |
| int dropped_frames_at_receive_; |
| int dropped_frames_at_decode_; |
| int dropped_frames_at_render_; |
| |
| int num_created_frames_; |
| int num_sent_frames_; |
| int num_received_frames_; |
| int num_decoded_frames_; |
| int num_rendered_frames_; |
| |
| // The constant diff between the created and transmitted frames, since their |
| // timestamps are converted. |
| unsigned int timestamp_diff_; |
| }; |
| |
| // Tracks which frames are received on the remote side and reports back to the |
| // FrameDropDetector class when they are rendered. |
| class FrameDropMonitoringRemoteFileRenderer : public ViEToFileRenderer { |
| public: |
| explicit FrameDropMonitoringRemoteFileRenderer( |
| FrameDropDetector* frame_drop_detector) |
| : frame_drop_detector_(frame_drop_detector) {} |
| virtual ~FrameDropMonitoringRemoteFileRenderer() {} |
| |
| // Implementation of ExternalRenderer: |
| int FrameSizeChange(unsigned int width, unsigned int height, |
| unsigned int number_of_streams); |
| int DeliverFrame(unsigned char* buffer, int buffer_size, |
| uint32_t time_stamp, |
| int64_t render_time); |
| private: |
| FrameDropDetector* frame_drop_detector_; |
| }; |
| |
| #endif // WEBRTC_VIDEO_ENGINE_TEST_AUTO_TEST_SOURCE_FRAMEDROP_PRIMITIVES_H_ |