1 /*
2 * Copyright(c) 2019 Netflix, Inc.
3 *
4 * This source code is subject to the terms of the BSD 2 Clause License and
5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 * was not distributed with this source code in the LICENSE file, you can
7 * obtain it at https://www.aomedia.org/license/software-license. If the Alliance for Open
8 * Media Patent License 1.0 was not distributed with this source code in the
9 * PATENTS file, you can obtain it at https://www.aomedia.org/license/patent-license.
10 */
11
12 /******************************************************************************
13 * @file FrameQueue.cc
14 *
15 * @brief Impelmentation of reconstructed frame queue
16 *
17 ******************************************************************************/
18
19 #include <stdio.h>
20 #include <vector>
21 #include <algorithm>
22 #include "FrameQueue.h"
23 #include "CompareTools.h"
24 #ifdef ENABLE_DEBUG_MONITOR
25 #include "VideoMonitor.h"
26 #endif
27
28 #if _WIN32
29 #define fseeko _fseeki64
30 #define ftello _ftelli64
31 #define FOPEN(f, s, m) fopen_s(&f, s, m)
32 #else
33 #define fseeko fseek
34 #define ftello ftell
35 #define FOPEN(f, s, m) f = fopen(s, m)
36 #endif
37
38 using svt_av1_e2e_tools::compare_image;
39
compare(FrameQueue * other)40 bool FrameQueue::compare(FrameQueue *other) {
41 if (frame_count_ != other->get_frame_count()) {
42 printf("frame count(%u<-->%u) are different",
43 frame_count_,
44 other->get_frame_count());
45 return false;
46 }
47 bool is_same = true;
48 for (uint32_t i = 0; i < frame_count_; i++) {
49 VideoFrame *frame = take_frame_inorder(i);
50 VideoFrame *other_frame = other->take_frame_inorder(i);
51 is_same = compare_image(frame, other_frame);
52 if (!is_same) {
53 printf("ref_frame(%u) compare failed!!\n",
54 (uint32_t)frame->timestamp);
55 break;
56 }
57 }
58
59 return is_same;
60 }
61
62 class FrameQueueFile : public FrameQueue {
63 public:
FrameQueueFile(const VideoFrameParam & param,const char * file_path)64 FrameQueueFile(const VideoFrameParam ¶m, const char *file_path)
65 : FrameQueue(param) {
66 queue_type_ = FRAME_QUEUE_FILE;
67 max_frame_ts_ = 0;
68 FOPEN(recon_file_, file_path, "wb");
69 record_list_.clear();
70 }
~FrameQueueFile()71 virtual ~FrameQueueFile() {
72 if (recon_file_) {
73 fflush(recon_file_);
74 fclose(recon_file_);
75 recon_file_ = nullptr;
76 }
77 record_list_.clear();
78 }
add_frame(VideoFrame * frame)79 void add_frame(VideoFrame *frame) override {
80 if (recon_file_ && frame->buf_size &&
81 frame->timestamp < (uint64_t)frame_count_) {
82 if (frame->timestamp >=
83 max_frame_ts_) { // new frame is larger than max timestamp
84 fseeko(recon_file_, 0, SEEK_END);
85 for (size_t i = max_frame_ts_; i < frame->timestamp + 1; ++i) {
86 fwrite(frame->buffer, 1, frame->buf_size, recon_file_);
87 }
88 max_frame_ts_ = frame->timestamp;
89 }
90
91 rewind(recon_file_);
92 uint64_t frame_num = frame->timestamp;
93 while (frame_num > 0) {
94 int ret = fseeko(recon_file_, frame->buf_size, SEEK_CUR);
95 if (ret != 0) {
96 return;
97 }
98 frame_num--;
99 }
100 fwrite(frame->buffer, 1, frame->buf_size, recon_file_);
101 fflush(recon_file_);
102 record_list_.push_back((uint32_t)frame->timestamp);
103 }
104 delete frame;
105 }
take_frame(const uint64_t time_stamp)106 VideoFrame *take_frame(const uint64_t time_stamp) override {
107 if (recon_file_ == nullptr)
108 return nullptr;
109
110 VideoFrame *new_frame = nullptr;
111 fseeko(recon_file_, 0, SEEK_END);
112 int64_t actual_size = ftello(recon_file_);
113 if (actual_size > 0 &&
114 ((uint64_t)actual_size) > ((time_stamp + 1) * frame_size_)) {
115 int ret = fseeko(recon_file_, time_stamp * frame_size_, 0);
116 if (ret != 0) {
117 // printf("Error in fseeko returnVal %i\n", ret);
118 return nullptr;
119 }
120 new_frame = get_empty_frame();
121 if (new_frame) {
122 size_t read_size =
123 fread(new_frame->buffer, 1, frame_size_, recon_file_);
124 if (read_size != frame_size_) {
125 printf("read recon file error!\n");
126 delete_frame(new_frame);
127 new_frame = nullptr;
128 } else {
129 new_frame->timestamp = time_stamp;
130 }
131 }
132 }
133
134 return new_frame;
135 }
take_frame_inorder(const uint32_t index)136 VideoFrame *take_frame_inorder(const uint32_t index) override {
137 return take_frame(index);
138 }
recycle_frame(VideoFrame * frame)139 void recycle_frame(VideoFrame *frame) override {
140 delete_frame(frame);
141 }
delete_frame(VideoFrame * frame)142 void delete_frame(VideoFrame *frame) override {
143 delete frame;
144 }
is_compelete()145 bool is_compelete() override {
146 if (record_list_.size() < frame_count_)
147 return false;
148 std::sort(record_list_.begin(), record_list_.end());
149 if (record_list_.at(frame_count_ - 1) != frame_count_ - 1)
150 return false;
151 return true;
152 }
153
154 public:
155 FILE *recon_file_; /**< file handle to dave reconstructed video frames, set
156 it to public for accessable by create_frame_queue */
157
158 protected:
159 uint64_t max_frame_ts_; /**< maximun timestamp of current frames in list */
160 std::vector<uint32_t> record_list_; /**< list of frame timstamp, to help
161 check if the file is completed*/
162 };
163
164 class FrameQueueBufferSort_ASC {
165 public:
operator ()(VideoFrame * a,VideoFrame * b) const166 bool operator()(VideoFrame *a, VideoFrame *b) const {
167 return a->timestamp < b->timestamp;
168 }
169 };
170
171 class FrameQueueBuffer : public FrameQueue {
172 public:
FrameQueueBuffer(VideoFrameParam fmt)173 FrameQueueBuffer(VideoFrameParam fmt) : FrameQueue(fmt) {
174 queue_type_ = FRAME_QUEUE_BUFFER;
175 frame_list_.clear();
176 }
~FrameQueueBuffer()177 virtual ~FrameQueueBuffer() {
178 while (frame_list_.size() > 0) {
179 delete frame_list_.back();
180 frame_list_.pop_back();
181 }
182 }
add_frame(VideoFrame * frame)183 void add_frame(VideoFrame *frame) override {
184 if (frame->timestamp < (uint64_t)frame_count_) {
185 frame_list_.push_back(frame);
186 std::sort(frame_list_.begin(),
187 frame_list_.end(),
188 FrameQueueBufferSort_ASC());
189 } else // drop the frames out of limitation
190 delete frame;
191 }
take_frame(const uint64_t time_stamp)192 VideoFrame *take_frame(const uint64_t time_stamp) override {
193 for (VideoFrame *frame : frame_list_) {
194 if (frame->timestamp == time_stamp)
195 return frame;
196 }
197 return nullptr;
198 }
take_frame_inorder(const uint32_t index)199 VideoFrame *take_frame_inorder(const uint32_t index) override {
200 if (index < frame_list_.size())
201 return frame_list_.at(index);
202 return nullptr;
203 }
recycle_frame(VideoFrame * frame)204 void recycle_frame(VideoFrame *frame) override {
205 frame->trim_buffer();
206 }
delete_frame(VideoFrame * frame)207 void delete_frame(VideoFrame *frame) override {
208 std::vector<VideoFrame *>::iterator it =
209 std::find(frame_list_.begin(), frame_list_.end(), frame);
210 if (it != frame_list_.end()) { // if the video frame is in list
211 delete *it;
212 frame_list_.erase(it);
213 } else // only delete the video frame not in list
214 delete frame;
215 }
is_compelete()216 bool is_compelete() override {
217 if (frame_list_.size() < frame_count_)
218 return false;
219
220 VideoFrame *frame = frame_list_.at(frame_count_ - 1);
221 if (frame == nullptr || frame->timestamp != frame_count_ - 1)
222 return false;
223 return true;
224 }
225
226 protected:
227 std::vector<VideoFrame *> frame_list_; /**< list of frame containers */
228 };
229
230 class RefQueue : public ICompareQueue, FrameQueueBuffer {
231 public:
RefQueue(VideoFrameParam fmt,FrameQueue * my_friend)232 RefQueue(VideoFrameParam fmt, FrameQueue *my_friend)
233 : FrameQueueBuffer(fmt) {
234 friend_ = my_friend;
235 frame_vec_.clear();
236 #ifdef ENABLE_DEBUG_MONITOR
237 recon_monitor_ = nullptr;
238 ref_monitor_ = nullptr;
239 #endif
240 }
~RefQueue()241 virtual ~RefQueue() {
242 while (frame_vec_.size()) {
243 const VideoFrame *p = frame_vec_.back();
244 frame_vec_.pop_back();
245 if (p) {
246 // printf("Reference queue still remain frames when
247 // delete(%u)\n",
248 // (uint32_t)p->timestamp);
249 delete p;
250 }
251 }
252 friend_ = nullptr;
253 #ifdef ENABLE_DEBUG_MONITOR
254 if (recon_monitor_) {
255 delete recon_monitor_;
256 recon_monitor_ = nullptr;
257 }
258 if (ref_monitor_) {
259 delete ref_monitor_;
260 ref_monitor_ = nullptr;
261 }
262 #endif
263 }
264
265 public:
compare_video(VideoFrame & frame)266 bool compare_video(VideoFrame &frame) override {
267 VideoFrame *friend_frame = friend_->take_frame(frame.timestamp);
268 if (friend_frame) {
269 draw_frames(&frame, friend_frame);
270 bool is_same = compare_image(friend_frame, &frame);
271 if (!is_same) {
272 printf("ref_frame(%u) compare failed!!\n",
273 (uint32_t)frame.timestamp);
274 }
275 friend_->recycle_frame(friend_frame);
276 return is_same;
277 } else {
278 clone_frame(frame);
279 }
280 return true; /**< default return suceess if not found recon frame */
281 }
flush_video()282 bool flush_video() override {
283 bool is_all_same = true;
284 for (VideoFrame *frame : frame_vec_) {
285 VideoFrame *friend_frame = friend_->take_frame(frame->timestamp);
286 if (friend_frame) {
287 draw_frames(frame, friend_frame);
288 if (!compare_image(friend_frame, frame)) {
289 printf("ref_frame(%u) compare failed!!\n",
290 (uint32_t)frame->timestamp);
291 is_all_same = false;
292 }
293 friend_->recycle_frame(friend_frame);
294 }
295 }
296 return is_all_same;
297 }
298
299 private:
clone_frame(const VideoFrame & frame)300 void clone_frame(const VideoFrame &frame) {
301 VideoFrame *new_frame = new VideoFrame(frame);
302 if (new_frame)
303 frame_vec_.push_back(new_frame);
304 else
305 printf("out of memory for clone video frame!!\n");
306 }
draw_frames(const VideoFrame * frame,const VideoFrame * friend_frame)307 void draw_frames(const VideoFrame *frame, const VideoFrame *friend_frame) {
308 #ifdef ENABLE_DEBUG_MONITOR
309 if (ref_monitor_ == nullptr) {
310 /** walk-around for bit-depth is fixed set 10-bit from ref-decoder,
311 * here to use bit-depth of friend frame*/
312 ref_monitor_ = new VideoMonitor(frame->width,
313 frame->height,
314 frame->stride[0],
315 friend_frame->bits_per_sample,
316 false,
317 "Ref decode");
318 }
319 if (ref_monitor_) {
320 ref_monitor_->draw_frame(
321 frame->planes[0], frame->planes[1], frame->planes[2]);
322 }
323 // Output to monitor for debug
324 if (recon_monitor_ == nullptr) {
325 recon_monitor_ = new VideoMonitor(friend_frame->width,
326 friend_frame->height,
327 friend_frame->stride[0],
328 friend_frame->bits_per_sample,
329 false,
330 "Recon");
331 }
332 if (recon_monitor_) {
333 recon_monitor_->draw_frame(friend_frame->planes[0],
334 friend_frame->planes[1],
335 friend_frame->planes[2]);
336 }
337 #else
338 (void)frame;
339 (void)friend_frame;
340 #endif
341 }
342
343 private:
344 FrameQueue *friend_;
345 std::vector<VideoFrame *> frame_vec_;
346 #ifdef ENABLE_DEBUG_MONITOR
347 VideoMonitor *recon_monitor_;
348 VideoMonitor *ref_monitor_;
349 #endif
350 };
351
create_frame_queue(const VideoFrameParam & param,const char * file_path)352 FrameQueue *create_frame_queue(const VideoFrameParam ¶m,
353 const char *file_path) {
354 FrameQueueFile *new_queue = new FrameQueueFile(param, file_path);
355 if (new_queue) {
356 if (new_queue->recon_file_ == nullptr) {
357 delete new_queue;
358 new_queue = nullptr;
359 }
360 }
361 return new_queue;
362 }
363
create_frame_queue(const VideoFrameParam & param)364 FrameQueue *create_frame_queue(const VideoFrameParam ¶m) {
365 return new FrameQueueBuffer(param);
366 }
367
create_ref_compare_queue(const VideoFrameParam & param,FrameQueue * recon)368 ICompareQueue *create_ref_compare_queue(const VideoFrameParam ¶m,
369 FrameQueue *recon) {
370 return new RefQueue(param, recon);
371 }
372