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