1 // Copyright 2019 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef C2_E2E_TEST_MEDIACODEC_DECODER_H_
6 #define C2_E2E_TEST_MEDIACODEC_DECODER_H_
7 
8 #include <condition_variable>
9 #include <memory>
10 #include <mutex>
11 #include <queue>
12 #include <string>
13 #include <thread>
14 #include <vector>
15 
16 #include <media/NdkMediaCodec.h>
17 
18 #include "common.h"
19 #include "encoded_data_helper.h"
20 
21 namespace android {
22 
23 // Wrapper class to manipulate a MediaCodec video decoder.
24 class MediaCodecDecoder {
25 public:
26     // Checks the argument and create MediaCodecDecoder instance.
27     static std::unique_ptr<MediaCodecDecoder> Create(const std::string& input_path,
28                                                      VideoCodecProfile profile, bool use_sw_decoder,
29                                                      const Size& video_size, int frame_rate,
30                                                      ANativeWindow* surface, bool renderOnRelease,
31                                                      bool loop, bool use_fake_renderer);
32 
33     MediaCodecDecoder() = delete;
34     ~MediaCodecDecoder();
35 
36     // The callback function that is called when output buffer is ready. Note that
37     // the buffer will be null if the decoder is in surface mode.
38     using OutputBufferReadyCb = std::function<void(
39             const uint8_t* /* data */, size_t /* buffer_size */, int /* output_index */)>;
40     void AddOutputBufferReadyCb(const OutputBufferReadyCb& cb);
41 
42     // The callback function that is called when output format is changed.
43     using OutputFormatChangedCb =
44             std::function<void(const Size& /* coded_size */, const Size& /* visible_size */,
45                                int32_t /* color_format */)>;
46     void AddOutputFormatChangedCb(const OutputFormatChangedCb& cb);
47 
48     // Decoder manipulation methods.
49 
50     // Rewind the input stream to the first frame as well as frame index.
51     void Rewind();
52 
53     // Wrapper of AMediaCodec_configure.
54     bool Configure();
55 
56     // Wrapper of AMediaCodec_start.
57     bool Start();
58 
59     // Decode the input stream. After decoding, send EOS request to the decoder.
60     // Return true if EOS output buffer is received.
61     bool Decode();
62 
63     // Wrapper of AMediaCodec_stop.
64     bool Stop();
65 
StopLooping()66     void StopLooping() { looping_ = false; }
67 
68     double dropped_frame_rate() const;
69 
70     void OnAsyncInputAvailable(int32_t idx);
71     void OnAsyncOutputAvailable(int32_t idx, AMediaCodecBufferInfo* info);
72     void OnAsyncFormatChanged(AMediaFormat* format);
73 
74     void FakeRenderLoop();
75 
76 private:
77     enum CodecEventType { INPUT_AVAILABLE, OUTPUT_AVAILABLE, FORMAT_CHANGED, FAKE_FRAME_RENDERED };
78     struct CodecEvent {
79         CodecEventType type;
80         int32_t idx;
81         AMediaCodecBufferInfo info;
82     };
83 
84     MediaCodecDecoder(AMediaCodec* codec, std::unique_ptr<EncodedDataHelper> encoded_data_helper,
85                       VideoCodecType type, const Size& size, int frame_rate, ANativeWindow* surface,
86                       bool renderOnRelease, bool loop, bool use_fake_renderer);
87 
88     // Enum class of the status of dequeueing output buffer.
89     enum class DequeueStatus { RETRY, SUCCESS, FAILURE };
90 
91     // Fill all available input buffers and enqueue.
92     bool EnqueueInputBuffers(int32_t idx);
93 
94     // Try to dequeue one output buffer and return DequeueStatus.
95     bool DequeueOutputBuffer(int32_t idx, AMediaCodecBufferInfo info);
96 
97     // Read the sample data from AMediaExtractor or CSD data and feed into the
98     // input buffer.
99     // |index| is the index of the target input buffer.
100     bool FeedInputBuffer(size_t index);
101 
102     // Feed an empty buffer with EOS flag.
103     // |index| is the index of the target input buffer.
104     bool FeedEOSInputBuffer(size_t index);
105 
106     // Receive the output buffer and make mOutputBufferReadyCb callback if given.
107     // |index| is the index of the target output buffer.
108     // |info| is the buffer info of the target output buffer.
109     bool ReceiveOutputBuffer(int32_t index, const AMediaCodecBufferInfo& info, bool render_buffer);
110 
111     // Get output format by AMediaCodec_getOutputFormat and make
112     // |output_format_changed_cb_| callback if given.
113     // Return false if required information is missing, e.g. width, color format.
114     bool GetOutputFormat();
115 
116     int64_t GetReleaseTimestampNs(size_t frame_order);
117 
118     // The target mediacodec decoder.
119     AMediaCodec* codec_;
120 
121     // The reference of EncodedDataHelper.
122     std::unique_ptr<EncodedDataHelper> encoded_data_helper_;
123 
124     // The codec type of decoding.
125     VideoCodecType type_;
126     // The output video visible size.
127     Size input_visible_size_;
128     int frame_rate_;
129 
130     // The list of callback functions which are called in order when a output
131     // buffer is ready.
132     std::vector<OutputBufferReadyCb> output_buffer_ready_cbs_;
133     // The list of callback functions that are called in order when output format
134     // is changed.
135     std::vector<OutputFormatChangedCb> output_format_changed_cbs_;
136 
137     // The fragment index that indicates which frame is sent to the decoder at
138     // next round.
139     int64_t input_fragment_index_ = 0;
140     // The total number of received output buffers. Only used for logging.
141     int received_outputs_ = 0;
142 
143     // The indication of input done.
144     bool input_done_ = false;
145     // The indication of output done.
146     bool output_done_ = false;
147 
148     ANativeWindow* surface_ = nullptr;
149     bool render_on_release_ = false;
150 
151     int64_t base_timestamp_ns_ = 0;
152     int32_t drop_frame_count_ = 0;
153 
154     std::atomic<bool> looping_;
155 
156     std::queue<CodecEvent> event_queue_;  // guarded by event_queue_mut_
157     std::mutex event_queue_mut_;
158     std::condition_variable event_queue_cv_;
159 
160     std::atomic<bool> fake_renderer_running_;
161     std::thread fake_render_thread_;
162     std::mutex fake_render_mut_;
163     std::condition_variable fake_render_cv_;
164     std::queue<std::pair<int32_t, int64_t>> fake_render_frames_;
165 };
166 
167 }  // namespace android
168 
169 #endif  // C2_E2E_TEST_MEDIACODEC_DECODER_H_
170