1 /*
2 * libde265 example application "dec265".
3 * Copyright (c) 2013-2014 struktur AG, Dirk Farin <farin@struktur.de>
4 *
5 * This file is part of dec265, an example application using libde265.
6 *
7 * dec265 is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * dec265 is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with dec265. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #define DO_MEMORY_LOGGING 0
22
23 #include "de265.h"
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <limits>
30 #include <getopt.h>
31 #ifdef HAVE_MALLOC_H
32 #include <malloc.h>
33 #endif
34 #include <signal.h>
35
36 #ifndef _MSC_VER
37 #include <sys/time.h>
38 #include <unistd.h>
39 #endif
40
41 #include "libde265/quality.h"
42
43 #if HAVE_VIDEOGFX
44 #include <libvideogfx.hh>
45 using namespace videogfx;
46 #endif
47
48 #if HAVE_SDL
49 #include "sdl.hh"
50 #endif
51
52
53 #define BUFFER_SIZE 40960
54 #define NUM_THREADS 4
55
56 int nThreads=0;
57 bool nal_input=false;
58 int quiet=0;
59 bool check_hash=false;
60 bool show_help=false;
61 bool dump_headers=false;
62 bool write_yuv=false;
63 bool output_with_videogfx=false;
64 bool logging=true;
65 bool no_acceleration=false;
66 const char *output_filename = "out.yuv";
67 uint32_t max_frames=UINT32_MAX;
68 bool write_bytestream=false;
69 const char *bytestream_filename;
70 bool measure_quality=false;
71 bool show_ssim_map=false;
72 bool show_psnr_map=false;
73 const char* reference_filename;
74 FILE* reference_file;
75 int highestTID = 100;
76 int verbosity=0;
77 int disable_deblocking=0;
78 int disable_sao=0;
79
80 static struct option long_options[] = {
81 {"quiet", no_argument, 0, 'q' },
82 {"threads", required_argument, 0, 't' },
83 {"check-hash", no_argument, 0, 'c' },
84 {"profile", no_argument, 0, 'p' },
85 {"frames", required_argument, 0, 'f' },
86 {"output", required_argument, 0, 'o' },
87 {"dump", no_argument, 0, 'd' },
88 {"nal", no_argument, 0, 'n' },
89 {"videogfx", no_argument, 0, 'V' },
90 {"no-logging", no_argument, 0, 'L' },
91 {"help", no_argument, 0, 'h' },
92 {"noaccel", no_argument, 0, '0' },
93 {"write-bytestream", required_argument,0, 'B' },
94 {"measure", required_argument, 0, 'm' },
95 {"ssim", no_argument, 0, 's' },
96 {"errmap", no_argument, 0, 'e' },
97 {"highest-TID", required_argument, 0, 'T' },
98 {"verbose", no_argument, 0, 'v' },
99 {"disable-deblocking", no_argument, &disable_deblocking, 1 },
100 {"disable-sao", no_argument, &disable_sao, 1 },
101 {0, 0, 0, 0 }
102 };
103
104
105
write_picture(const de265_image * img)106 static void write_picture(const de265_image* img)
107 {
108 static FILE* fh = NULL;
109 if (fh==NULL) { fh = fopen(output_filename, "wb"); }
110
111
112
113 for (int c=0;c<3;c++) {
114 int stride;
115 const uint8_t* p = de265_get_image_plane(img, c, &stride);
116 int width = de265_get_image_width(img,c);
117
118 if (de265_get_bits_per_pixel(img,c)<=8) {
119 // --- save 8 bit YUV ---
120
121 for (int y=0;y<de265_get_image_height(img,c);y++) {
122 fwrite(p + y*stride, width, 1, fh);
123 }
124 }
125 else {
126 // --- save 16 bit YUV ---
127
128 uint8_t* buf = new uint8_t[width*2];
129 uint16_t* p16 = (uint16_t*)p;
130
131 for (int y=0;y<de265_get_image_height(img,c);y++) {
132 for (int x=0;x<width;x++) {
133 uint16_t pixel_value = (p16+y*stride)[x];
134 buf[2*x+0] = pixel_value & 0xFF;
135 buf[2*x+1] = pixel_value >> 8;
136 }
137
138 fwrite(buf, width*2, 1, fh);
139 }
140
141 delete[] buf;
142 }
143 }
144
145 fflush(fh);
146 }
147
148
149
150 #if HAVE_VIDEOGFX
display_image(const struct de265_image * img)151 void display_image(const struct de265_image* img)
152 {
153 static X11Win win;
154
155 // display picture
156
157 static bool first=true;
158
159 if (first) {
160 first=false;
161 win.Create(de265_get_image_width(img,0),
162 de265_get_image_height(img,0),
163 "de265 output");
164 }
165
166
167
168 int width = de265_get_image_width(img,0);
169 int height = de265_get_image_height(img,0);
170 de265_chroma chroma = de265_get_chroma_format(img);
171
172 ChromaFormat vgfx_chroma;
173 Colorspace vgfx_cs = Colorspace_YUV;
174
175 switch (chroma) {
176 case de265_chroma_420: vgfx_chroma = Chroma_420; break;
177 case de265_chroma_422: vgfx_chroma = Chroma_422; break;
178 case de265_chroma_444: vgfx_chroma = Chroma_444; break;
179 case de265_chroma_mono: vgfx_cs = Colorspace_Greyscale; break;
180 }
181
182 Image<Pixel> visu;
183 visu.Create(width, height, vgfx_cs, vgfx_chroma);
184
185 int nChannels = 3;
186 if (chroma == de265_chroma_mono) {
187 nChannels = 1;
188 }
189
190 for (int ch=0;ch<nChannels;ch++) {
191 const uint8_t* data;
192 int stride;
193
194 data = de265_get_image_plane(img,ch,&stride);
195 width = de265_get_image_width(img,ch);
196 height = de265_get_image_height(img,ch);
197
198 int bit_depth = de265_get_bits_per_pixel(img,ch);
199
200 if (bit_depth==8) {
201 for (int y=0;y<height;y++) {
202 memcpy(visu.AskFrame((BitmapChannel)ch)[y], data + y*stride, width);
203 }
204 }
205 else {
206 const uint16_t* data16 = (const uint16_t*)data;
207 for (int y=0;y<height;y++) {
208 for (int x=0;x<width;x++) {
209 visu.AskFrame((BitmapChannel)ch)[y][x] = *(data16 + y*stride +x) >> (bit_depth-8);
210 }
211 }
212 }
213 }
214
215 win.Display(visu);
216 win.WaitForKeypress();
217 }
218 #endif
219
convert_to_8bit(const uint8_t * data,int width,int height,int stride,int bit_depth)220 static uint8_t* convert_to_8bit(const uint8_t* data, int width, int height, int stride, int bit_depth)
221 {
222 const uint16_t* data16 = (const uint16_t*)data;
223 uint8_t* out = new uint8_t[stride*height];
224
225 for (int y=0;y<height;y++) {
226 for (int x=0;x<width;x++) {
227 out[y*stride + x] = *(data16 + y*stride +x) >> (bit_depth-8);
228 }
229 }
230
231 return out;
232 }
233
234
235 #if HAVE_SDL
236 SDL_YUV_Display sdlWin;
237 bool sdl_active=false;
238
display_sdl(const struct de265_image * img)239 bool display_sdl(const struct de265_image* img)
240 {
241 int width = de265_get_image_width(img,0);
242 int height = de265_get_image_height(img,0);
243
244 int chroma_width = de265_get_image_width(img,1);
245 int chroma_height = de265_get_image_height(img,1);
246
247 de265_chroma chroma = de265_get_chroma_format(img);
248
249 if (!sdl_active) {
250 sdl_active=true;
251 enum SDL_YUV_Display::SDL_Chroma sdlChroma;
252 switch (chroma) {
253 case de265_chroma_420: sdlChroma = SDL_YUV_Display::SDL_CHROMA_420; break;
254 case de265_chroma_422: sdlChroma = SDL_YUV_Display::SDL_CHROMA_422; break;
255 case de265_chroma_444: sdlChroma = SDL_YUV_Display::SDL_CHROMA_444; break;
256 case de265_chroma_mono: sdlChroma = SDL_YUV_Display::SDL_CHROMA_MONO; break;
257 }
258
259 sdlWin.init(width,height, sdlChroma);
260 }
261
262 int stride,chroma_stride;
263 const uint8_t* y = de265_get_image_plane(img,0,&stride);
264 const uint8_t* cb =de265_get_image_plane(img,1,&chroma_stride);
265 const uint8_t* cr =de265_get_image_plane(img,2,NULL);
266
267 uint8_t* y16 = NULL;
268 uint8_t* cb16 = NULL;
269 uint8_t* cr16 = NULL;
270 int bd;
271
272 if ((bd=de265_get_bits_per_pixel(img, 0)) > 8) {
273 y16 = convert_to_8bit(y, width,height,stride,bd); y=y16;
274 }
275
276 if (chroma != de265_chroma_mono) {
277 if ((bd=de265_get_bits_per_pixel(img, 1)) > 8) {
278 cb16 = convert_to_8bit(cb, chroma_width,chroma_height,chroma_stride,bd); cb=cb16;
279 }
280 if ((bd=de265_get_bits_per_pixel(img, 2)) > 8) {
281 cr16 = convert_to_8bit(cr, chroma_width,chroma_height,chroma_stride,bd); cr=cr16;
282 }
283 }
284
285 sdlWin.display(y,cb,cr, stride, chroma_stride);
286
287 delete[] y16;
288 delete[] cb16;
289 delete[] cr16;
290
291 return sdlWin.doQuit();
292 }
293 #endif
294
295
296 static int width,height;
297 static uint32_t framecnt=0;
298
output_image(const de265_image * img)299 bool output_image(const de265_image* img)
300 {
301 bool stop=false;
302
303 width = de265_get_image_width(img,0);
304 height = de265_get_image_height(img,0);
305
306 framecnt++;
307 //printf("SHOW POC: %d / PTS: %ld / integrity: %d\n",img->PicOrderCntVal, img->pts, img->integrity);
308
309
310 if (0) {
311 const char* nal_unit_name;
312 int nuh_layer_id;
313 int nuh_temporal_id;
314 de265_get_image_NAL_header(img, NULL, &nal_unit_name, &nuh_layer_id, &nuh_temporal_id);
315
316 printf("NAL: %s layer:%d temporal:%d\n",nal_unit_name, nuh_layer_id, nuh_temporal_id);
317 }
318
319
320 if (!quiet) {
321 #if HAVE_SDL && HAVE_VIDEOGFX
322 if (output_with_videogfx) {
323 display_image(img);
324 } else {
325 stop = display_sdl(img);
326 }
327 #elif HAVE_SDL
328 stop = display_sdl(img);
329 #elif HAVE_VIDEOGFX
330 display_image(img);
331 #endif
332 }
333 if (write_yuv) {
334 write_picture(img);
335 }
336
337 if ((framecnt%100)==0) {
338 fprintf(stderr,"frame %d\r",framecnt);
339 }
340
341 if (framecnt>=max_frames) {
342 stop=true;
343 }
344
345 return stop;
346 }
347
348
349 static double mse_y=0.0, mse_cb=0.0, mse_cr=0.0;
350 static int mse_frames=0;
351
352 static double ssim_y=0.0;
353 static int ssim_frames=0;
354
measure(const de265_image * img)355 void measure(const de265_image* img)
356 {
357 // --- compute PSNR ---
358
359 int width = de265_get_image_width(img,0);
360 int height = de265_get_image_height(img,0);
361
362 uint8_t* p = (uint8_t*)malloc(width*height*3/2);
363 if (p == NULL) {
364 return;
365 }
366
367 size_t toread = width*height*3/2;
368 if (fread(p,1,toread,reference_file) != toread) {
369 free(p);
370 return;
371 }
372
373 int stride, cstride;
374 const uint8_t* yptr = de265_get_image_plane(img,0, &stride);
375 const uint8_t* cbptr = de265_get_image_plane(img,1, &cstride);
376 const uint8_t* crptr = de265_get_image_plane(img,2, &cstride);
377
378 double img_mse_y = MSE( yptr, stride, p, width, width, height);
379 double img_mse_cb = MSE(cbptr, cstride, p+width*height, width/2, width/2,height/2);
380 double img_mse_cr = MSE(crptr, cstride, p+width*height*5/4, width/2, width/2,height/2);
381
382 mse_frames++;
383
384 mse_y += img_mse_y;
385 mse_cb += img_mse_cb;
386 mse_cr += img_mse_cr;
387
388
389
390 // --- compute SSIM ---
391
392 double ssimSum = 0.0;
393
394 #if HAVE_VIDEOGFX
395 Bitmap<Pixel> ref, coded;
396 ref .Create(width, height); // reference image
397 coded.Create(width, height); // coded image
398
399 const uint8_t* data;
400 data = de265_get_image_plane(img,0,&stride);
401
402 for (int y=0;y<height;y++) {
403 memcpy(coded[y], data + y*stride, width);
404 memcpy(ref[y], p + y*stride, width);
405 }
406
407 SSIM ssimAlgo;
408 Bitmap<float> ssim = ssimAlgo.calcSSIM(ref,coded);
409
410 Bitmap<Pixel> ssimMap;
411 ssimMap.Create(width,height);
412
413 for (int y=0;y<height;y++)
414 for (int x=0;x<width;x++)
415 {
416 float v = ssim[y][x];
417 ssimSum += v;
418 v = v*v;
419 v = 255*v; //pow(v, 20);
420
421 //assert(v<=255.0);
422 ssimMap[y][x] = v;
423 }
424
425 ssimSum /= width*height;
426
427
428 Bitmap<Pixel> error_map = CalcErrorMap(ref, coded, TransferCurve_Sqrt);
429
430
431 // display PSNR error map
432
433 if (show_psnr_map) {
434 static X11Win win;
435 static bool first=true;
436
437 if (first) {
438 first=false;
439 win.Create(de265_get_image_width(img,0),
440 de265_get_image_height(img,0),
441 "psnr output");
442 }
443
444 win.Display(MakeImage(error_map));
445 }
446
447
448 // display SSIM error map
449
450 if (show_ssim_map) {
451 static X11Win win;
452 static bool first=true;
453
454 if (first) {
455 first=false;
456 win.Create(de265_get_image_width(img,0),
457 de265_get_image_height(img,0),
458 "ssim output");
459 }
460
461 win.Display(MakeImage(ssimMap));
462 }
463 #endif
464
465 ssim_frames++;
466 ssim_y += ssimSum;
467
468 printf("%5d %6f %6f %6f %6f\n",
469 framecnt,
470 PSNR(img_mse_y), PSNR(img_mse_cb), PSNR(img_mse_cr),
471 ssimSum);
472
473 free(p);
474 }
475
476
477 #ifdef WIN32
478 #include <time.h>
479 #define WIN32_LEAN_AND_MEAN
480 #include <winsock.h>
gettimeofday(struct timeval * tp,void *)481 int gettimeofday(struct timeval *tp, void *)
482 {
483 time_t clock;
484 struct tm tm;
485 SYSTEMTIME wtm;
486
487 GetLocalTime(&wtm);
488 tm.tm_year = wtm.wYear - 1900;
489 tm.tm_mon = wtm.wMonth - 1;
490 tm.tm_mday = wtm.wDay;
491 tm.tm_hour = wtm.wHour;
492 tm.tm_min = wtm.wMinute;
493 tm.tm_sec = wtm.wSecond;
494 tm. tm_isdst = -1;
495 clock = mktime(&tm);
496 tp->tv_sec = (long) clock;
497 tp->tv_usec = wtm.wMilliseconds * 1000;
498
499 return (0);
500 }
501 #endif
502
503 #ifdef HAVE___MALLOC_HOOK
504 #ifdef __GNUC__
505 #pragma GCC diagnostic push
506 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
507 #endif
508 static void *(*old_malloc_hook)(size_t, const void *);
509
new_malloc_hook(size_t size,const void * caller)510 static void *new_malloc_hook(size_t size, const void *caller) {
511 void *mem;
512
513 /*
514 if (size>1000000) {
515 raise(SIGINT);
516 }
517 */
518
519 __malloc_hook = old_malloc_hook;
520 mem = malloc(size);
521 fprintf(stderr, "%p: malloc(%zu) = %p\n", caller, size, mem);
522 __malloc_hook = new_malloc_hook;
523
524 return mem;
525 }
526
init_my_hooks(void)527 static void init_my_hooks(void) {
528 old_malloc_hook = __malloc_hook;
529 __malloc_hook = new_malloc_hook;
530 }
531
532 #if DO_MEMORY_LOGGING
533 void (*volatile __malloc_initialize_hook)(void) = init_my_hooks;
534 #endif
535 #ifdef __GNUC__
536 #pragma GCC diagnostic pop
537 #endif
538 #endif
539
540
main(int argc,char ** argv)541 int main(int argc, char** argv)
542 {
543 while (1) {
544 int option_index = 0;
545
546 int c = getopt_long(argc, argv, "qt:chf:o:dLB:n0vT:m:se"
547 #if HAVE_VIDEOGFX && HAVE_SDL
548 "V"
549 #endif
550 , long_options, &option_index);
551 if (c == -1)
552 break;
553
554 switch (c) {
555 case 'q': quiet++; break;
556 case 't': nThreads=atoi(optarg); break;
557 case 'c': check_hash=true; break;
558 case 'f': max_frames=atoi(optarg); break;
559 case 'o': write_yuv=true; output_filename=optarg; break;
560 case 'h': show_help=true; break;
561 case 'd': dump_headers=true; break;
562 case 'n': nal_input=true; break;
563 case 'V': output_with_videogfx=true; break;
564 case 'L': logging=false; break;
565 case '0': no_acceleration=true; break;
566 case 'B': write_bytestream=true; bytestream_filename=optarg; break;
567 case 'm': measure_quality=true; reference_filename=optarg; break;
568 case 's': show_ssim_map=true; break;
569 case 'e': show_psnr_map=true; break;
570 case 'T': highestTID=atoi(optarg); break;
571 case 'v': verbosity++; break;
572 }
573 }
574
575 if (optind != argc-1 || show_help) {
576 fprintf(stderr," dec265 v%s\n", de265_get_version());
577 fprintf(stderr,"--------------\n");
578 fprintf(stderr,"usage: dec265 [options] videofile.bin\n");
579 fprintf(stderr,"The video file must be a raw bitstream, or a stream with NAL units (option -n).\n");
580 fprintf(stderr,"\n");
581 fprintf(stderr,"options:\n");
582 fprintf(stderr," -q, --quiet do not show decoded image\n");
583 fprintf(stderr," -t, --threads N set number of worker threads (0 - no threading)\n");
584 fprintf(stderr," -c, --check-hash perform hash check\n");
585 fprintf(stderr," -n, --nal input is a stream with 4-byte length prefixed NAL units\n");
586 fprintf(stderr," -f, --frames N set number of frames to process\n");
587 fprintf(stderr," -o, --output write YUV reconstruction\n");
588 fprintf(stderr," -d, --dump dump headers\n");
589 #if HAVE_VIDEOGFX && HAVE_SDL
590 fprintf(stderr," -V, --videogfx output with videogfx instead of SDL\n");
591 #endif
592 fprintf(stderr," -0, --noaccel do not use any accelerated code (SSE)\n");
593 fprintf(stderr," -v, --verbose increase verbosity level (up to 3 times)\n");
594 fprintf(stderr," -L, --no-logging disable logging\n");
595 fprintf(stderr," -B, --write-bytestream FILENAME write raw bytestream (from NAL input)\n");
596 fprintf(stderr," -m, --measure YUV compute PSNRs relative to reference YUV\n");
597 #if HAVE_VIDEOGFX
598 fprintf(stderr," -s, --ssim show SSIM-map (only when -m active)\n");
599 fprintf(stderr," -e, --errmap show error-map (only when -m active)\n");
600 #endif
601 fprintf(stderr," -T, --highest-TID select highest temporal sublayer to decode\n");
602 fprintf(stderr," --disable-deblocking disable deblocking filter\n");
603 fprintf(stderr," --disable-sao disable sample-adaptive offset filter\n");
604 fprintf(stderr," -h, --help show help\n");
605
606 exit(show_help ? 0 : 5);
607 }
608
609
610 de265_error err =DE265_OK;
611
612 de265_decoder_context* ctx = de265_new_decoder();
613
614 de265_set_parameter_bool(ctx, DE265_DECODER_PARAM_BOOL_SEI_CHECK_HASH, check_hash);
615 de265_set_parameter_bool(ctx, DE265_DECODER_PARAM_SUPPRESS_FAULTY_PICTURES, false);
616
617 de265_set_parameter_bool(ctx, DE265_DECODER_PARAM_DISABLE_DEBLOCKING, disable_deblocking);
618 de265_set_parameter_bool(ctx, DE265_DECODER_PARAM_DISABLE_SAO, disable_sao);
619
620 if (dump_headers) {
621 de265_set_parameter_int(ctx, DE265_DECODER_PARAM_DUMP_SPS_HEADERS, 1);
622 de265_set_parameter_int(ctx, DE265_DECODER_PARAM_DUMP_VPS_HEADERS, 1);
623 de265_set_parameter_int(ctx, DE265_DECODER_PARAM_DUMP_PPS_HEADERS, 1);
624 de265_set_parameter_int(ctx, DE265_DECODER_PARAM_DUMP_SLICE_HEADERS, 1);
625 }
626
627 if (no_acceleration) {
628 de265_set_parameter_int(ctx, DE265_DECODER_PARAM_ACCELERATION_CODE, de265_acceleration_SCALAR);
629 }
630
631 if (!logging) {
632 de265_disable_logging();
633 }
634
635 de265_set_verbosity(verbosity);
636
637
638 if (argc>=3) {
639 if (nThreads>0) {
640 err = de265_start_worker_threads(ctx, nThreads);
641 }
642 }
643
644 de265_set_limit_TID(ctx, highestTID);
645
646
647 if (measure_quality) {
648 reference_file = fopen(reference_filename, "rb");
649 }
650
651
652 FILE* fh = fopen(argv[optind], "rb");
653 if (fh==NULL) {
654 fprintf(stderr,"cannot open file %s!\n", argv[1]);
655 exit(10);
656 }
657
658 FILE* bytestream_fh = NULL;
659
660 if (write_bytestream) {
661 bytestream_fh = fopen(bytestream_filename, "wb");
662 }
663
664 bool stop=false;
665
666 struct timeval tv_start;
667 gettimeofday(&tv_start, NULL);
668
669 int pos=0;
670
671 while (!stop)
672 {
673 //tid = (framecnt/1000) & 1;
674 //de265_set_limit_TID(ctx, tid);
675
676 if (nal_input) {
677 uint8_t len[4];
678 int n = fread(len,1,4,fh);
679 int length = (len[0]<<24) + (len[1]<<16) + (len[2]<<8) + len[3];
680
681 uint8_t* buf = (uint8_t*)malloc(length);
682 n = fread(buf,1,length,fh);
683 err = de265_push_NAL(ctx, buf,n, pos, (void*)1);
684
685 if (write_bytestream) {
686 uint8_t sc[3] = { 0,0,1 };
687 fwrite(sc ,1,3,bytestream_fh);
688 fwrite(buf,1,n,bytestream_fh);
689 }
690
691 free(buf);
692 pos+=n;
693 }
694 else {
695 // read a chunk of input data
696 uint8_t buf[BUFFER_SIZE];
697 int n = fread(buf,1,BUFFER_SIZE,fh);
698
699 // decode input data
700 if (n) {
701 err = de265_push_data(ctx, buf, n, pos, (void*)2);
702 if (err != DE265_OK) {
703 break;
704 }
705 }
706
707 pos+=n;
708
709 if (0) { // fake skipping
710 if (pos>1000000) {
711 printf("RESET\n");
712 de265_reset(ctx);
713 pos=0;
714
715 fseek(fh,-200000,SEEK_CUR);
716 }
717 }
718 }
719
720 // printf("pending data: %d\n", de265_get_number_of_input_bytes_pending(ctx));
721
722 if (feof(fh)) {
723 err = de265_flush_data(ctx); // indicate end of stream
724 stop = true;
725 }
726
727
728 // decoding / display loop
729
730 int more=1;
731 while (more)
732 {
733 more = 0;
734
735 // decode some more
736
737 err = de265_decode(ctx, &more);
738 if (err != DE265_OK) {
739 // if (quiet<=1) fprintf(stderr,"ERROR: %s\n", de265_get_error_text(err));
740
741 if (check_hash && err == DE265_ERROR_CHECKSUM_MISMATCH)
742 stop = 1;
743 more = 0;
744 break;
745 }
746
747 // show available images
748
749 const de265_image* img = de265_get_next_picture(ctx);
750 if (img) {
751 if (measure_quality) {
752 measure(img);
753 }
754
755 stop = output_image(img);
756 if (stop) more=0;
757 else more=1;
758 }
759
760 // show warnings
761
762 for (;;) {
763 de265_error warning = de265_get_warning(ctx);
764 if (warning==DE265_OK) {
765 break;
766 }
767
768 if (quiet<=1) fprintf(stderr,"WARNING: %s\n", de265_get_error_text(warning));
769 }
770 }
771 }
772
773 fclose(fh);
774
775 if (write_bytestream) {
776 fclose(bytestream_fh);
777 }
778
779 if (measure_quality) {
780 printf("#total %6f %6f %6f %6f\n",
781 PSNR(mse_y /mse_frames),
782 PSNR(mse_cb/mse_frames),
783 PSNR(mse_cr/mse_frames),
784 ssim_y/ssim_frames);
785
786 fclose(reference_file);
787 }
788
789 de265_free_decoder(ctx);
790
791 struct timeval tv_end;
792 gettimeofday(&tv_end, NULL);
793
794 if (err != DE265_OK) {
795 if (quiet<=1) fprintf(stderr,"decoding error: %s (code=%d)\n", de265_get_error_text(err), err);
796 }
797
798 double secs = tv_end.tv_sec-tv_start.tv_sec;
799 secs += (tv_end.tv_usec - tv_start.tv_usec)*0.001*0.001;
800
801 if (quiet<=1) fprintf(stderr,"nFrames decoded: %d (%dx%d @ %5.2f fps)\n",framecnt,
802 width,height,framecnt/secs);
803
804
805 return err==DE265_OK ? 0 : 10;
806 }
807