1 #include <stdbool.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include "vidinput.h"
6
7 #include "libvmaf/libvmaf.h"
8
9 /** Linkage will break without this if using a C++ compiler, and will issue
10 * warnings without this for a C compiler*/
11 #if defined(__cplusplus)
12 # define OC_EXTERN extern
13 #else
14 # define OC_EXTERN
15 #endif
16
17 typedef struct yuv_input {
18 FILE *fin;
19 unsigned width, height;
20 enum VmafPixelFormat pix_fmt;
21 unsigned bitdepth;
22 size_t dst_buf_sz;
23 uint8_t *dst_buf;
24 int src_c_dec_v, src_c_dec_h;
25 int dst_c_dec_h, dst_c_dec_v;
26 } yuv_input;
27
28
yuv_input_open(FILE * _fin,unsigned width,unsigned height,enum VmafPixelFormat pix_fmt,unsigned bitdepth)29 static yuv_input *yuv_input_open(FILE *_fin,
30 unsigned width, unsigned height,
31 enum VmafPixelFormat pix_fmt,
32 unsigned bitdepth)
33 {
34 yuv_input *yuv = malloc(sizeof(*yuv));
35 if (!yuv) {
36 fprintf(stderr, "Could not allocate yuv reader state.\n");
37 return NULL;
38 }
39
40 yuv->fin = _fin;
41 yuv->width = width;
42 yuv->height = height;
43 yuv->pix_fmt = pix_fmt;
44 yuv->bitdepth = bitdepth;
45 bool hbd = yuv->bitdepth > 8;
46
47 switch (yuv->pix_fmt) {
48 case VMAF_PIX_FMT_YUV420P:
49 yuv->src_c_dec_h=yuv->dst_c_dec_h=yuv->src_c_dec_v=yuv->dst_c_dec_v=2;
50 yuv->dst_buf_sz = (yuv->width*yuv->height
51 +2*((yuv->width+1)/2)*((yuv->height+1)/2)) << hbd;
52 break;
53 case VMAF_PIX_FMT_YUV422P:
54 yuv->src_c_dec_h=yuv->dst_c_dec_h=2;
55 yuv->src_c_dec_v=yuv->dst_c_dec_v=1;
56 yuv->dst_buf_sz = (yuv->width*yuv->height +
57 2*(((yuv->width+1)/2) * yuv->height)) << hbd;
58 break;
59 case VMAF_PIX_FMT_YUV444P:
60 yuv->src_c_dec_h=yuv->dst_c_dec_h=yuv->src_c_dec_v=yuv->dst_c_dec_v=1;
61 yuv->dst_buf_sz = (yuv->width*yuv->height*3) << hbd;
62 break;
63 default:
64 goto fail;
65 }
66
67 yuv->dst_buf = malloc(yuv->dst_buf_sz);
68 if (!yuv->dst_buf) {
69 fprintf(stderr, "Could not allocate yuv reader buffer.\n");
70 goto fail;
71 }
72
73 return yuv;
74
75 fail:
76 free(yuv);
77 return NULL;
78 }
79
pix_fmt_map(enum VmafPixelFormat pix_fmt)80 static int pix_fmt_map(enum VmafPixelFormat pix_fmt)
81 {
82 switch (pix_fmt) {
83 case VMAF_PIX_FMT_YUV420P:
84 return PF_420;
85 case VMAF_PIX_FMT_YUV422P:
86 return PF_422;
87 case VMAF_PIX_FMT_YUV444P:
88 return PF_444;
89 default:
90 return 0;
91 }
92 }
93
yuv_input_get_info(yuv_input * _yuv,video_input_info * _info)94 static void yuv_input_get_info(yuv_input *_yuv, video_input_info *_info)
95 {
96 memset(_info, 0, sizeof(*_info));
97 _info->frame_w = _info->pic_w = _yuv->width;
98 _info->frame_h = _info->pic_h = _yuv->height;
99 _info->pixel_fmt = pix_fmt_map(_yuv->pix_fmt);
100 _info->depth = _yuv->bitdepth;
101 }
102
yuv_input_fetch_frame(yuv_input * yuv,FILE * fin,video_input_ycbcr _ycbcr,char _tag[5])103 static int yuv_input_fetch_frame(yuv_input *yuv, FILE *fin,
104 video_input_ycbcr _ycbcr, char _tag[5])
105 {
106 size_t bytes_read = fread(yuv->dst_buf, 1, yuv->dst_buf_sz, fin);
107 if (bytes_read == 0) return 0;
108 if (bytes_read != yuv->dst_buf_sz) {
109 fprintf(stderr, "Error reading YUV frame data.\n");
110 return -1;
111 }
112
113 (void) _tag;
114
115 unsigned xstride = (yuv->bitdepth>8)?2:1;
116 ptrdiff_t pic_sz = yuv->width * yuv->height * xstride;
117 unsigned frame_c_w = yuv->width/yuv->dst_c_dec_h;
118 unsigned frame_c_h = yuv->height/yuv->dst_c_dec_v;
119 unsigned c_w = (yuv->width+yuv->dst_c_dec_h-1)/yuv->dst_c_dec_h;
120 unsigned c_h = (yuv->height+yuv->dst_c_dec_v-1)/yuv->dst_c_dec_v;
121 unsigned c_sz = c_w*c_h*xstride;
122
123 _ycbcr[0].width = yuv->width;
124 _ycbcr[0].height = yuv->height;
125 _ycbcr[0].stride = yuv->width*xstride;
126 _ycbcr[0].data = yuv->dst_buf;
127 _ycbcr[1].width = frame_c_w;
128 _ycbcr[1].height = frame_c_h;
129 _ycbcr[1].stride = c_w*xstride;
130 _ycbcr[1].data = yuv->dst_buf + pic_sz;
131 _ycbcr[2].width = frame_c_w;
132 _ycbcr[2].height = frame_c_h;
133 _ycbcr[2].stride = c_w*xstride;
134 _ycbcr[2].data = _ycbcr[1].data+c_sz;
135
136 return 1;
137 }
138
yuv_input_close(yuv_input * _yuv)139 static void yuv_input_close(yuv_input *_yuv){
140 free(_yuv->dst_buf);
141 }
142
143 OC_EXTERN const raw_input_vtbl YUV_INPUT_VTBL={
144 (raw_input_open_func)yuv_input_open,
145 (video_input_get_info_func)yuv_input_get_info,
146 (video_input_fetch_frame_func)yuv_input_fetch_frame,
147 (video_input_close_func)yuv_input_close
148 };
149