Fix integer overflow in ft_rendered_size_line
[ilaris-y4m-tools.git] / hdify.cpp
blob7694f924a8933de703f4bef8cdac52e94a7020d9
1 #include "yuv4mpeg.hpp"
2 #include "parseval.hpp"
3 #include <iostream>
5 namespace
7 void compute_scale_factors(size_t w, size_t h, double sar, size_t& fx, size_t& fy)
9 //sar is ratio between DAR and native DAR.
10 fx = 2;
11 fy = 2;
12 while(sar <= sqrt(0.5)) {
13 fy *= 2;
14 sar *= 2;
16 while(sar > sqrt(2)) {
17 fx *= 2;
18 sar /= 2;
20 while(w * fx < 1920 && h * fy < 1080) {
21 fx *= 2;
22 fy *= 2;
26 struct scale_params
28 size_t inwidth;
29 size_t inheight;
30 size_t factor_x;
31 size_t factor_y;
32 std::string chroma;
33 void fill_csp()
35 size_t pfourths;
36 size_t p1fourths;
37 size_t pnfourths;
38 outwidth = inwidth * factor_x;
39 outheight = inheight * factor_y;
40 bool subsample_x = false;
41 bool subsample_y = false;
42 if(chroma == "rgb") {
43 pfourths = 12;
44 p1fourths = 12;
45 pnfourths = 0;
46 planes = 1;
47 mode = 0;
48 } else if(chroma == "420") {
49 pfourths = 6;
50 p1fourths = 4;
51 pnfourths = 1;
52 planes = 3;
53 subsample_x = true;
54 subsample_y = true;
55 mode = 1;
56 } else if(chroma == "420p16") {
57 pfourths = 12;
58 p1fourths = 8;
59 pnfourths = 2;
60 planes = 3;
61 subsample_x = true;
62 subsample_y = true;
63 mode = 2;
64 } else if(chroma == "422") {
65 pfourths = 8;
66 p1fourths = 4;
67 pnfourths = 2;
68 planes = 3;
69 subsample_x = true;
70 mode = 1;
71 } else if(chroma == "422p16") {
72 pfourths = 16;
73 p1fourths = 8;
74 pnfourths = 4;
75 planes = 3;
76 subsample_x = true;
77 mode = 2;
78 } else if(chroma == "444") {
79 pfourths = 12;
80 p1fourths = 4;
81 pnfourths = 4;
82 planes = 3;
83 mode = 1;
84 } else if(chroma == "444p16") {
85 pfourths = 24;
86 p1fourths = 8;
87 pnfourths = 8;
88 planes = 3;
89 mode = 2;
90 } else
91 throw std::runtime_error("Unsupported input chroma type '" + chroma + "'");
92 insize = pfourths * inwidth * inheight / 4;
93 outsize = pfourths * outwidth * outheight / 4;
94 inplane1_size = p1fourths * inwidth * inheight / 4;
95 outplane1_size = p1fourths * outwidth * outheight / 4;
96 inplanen_size = pnfourths * inwidth * inheight / 4;
97 outplanen_size = pnfourths * outwidth * outheight / 4;
98 inplane1_stride = p1fourths * inwidth / 4;
99 outplane1_stride = p1fourths * outwidth / 4;
100 inplanen_stride = pnfourths * inwidth / 4;
101 outplanen_stride = pnfourths * outwidth / 4;
102 if(subsample_x && (inwidth | outwidth) & 1)
103 throw std::runtime_error("420 and 422 modes must have even width");
104 if(subsample_y && (inheight | outheight) & 1)
105 throw std::runtime_error("420 modes must have even height");
106 inplanen_width = inwidth / (subsample_x ? 2 : 1);
107 inplanen_height = inheight / (subsample_y ? 2 : 1);
108 outplanen_width = outwidth / (subsample_x ? 2 : 1);
109 outplanen_height = outheight / (subsample_y ? 2 : 1);
111 int mode;
112 size_t outwidth;
113 size_t outheight;
114 size_t insize;
115 size_t outsize;
116 size_t inplane1_size;
117 size_t inplanen_size;
118 size_t outplane1_size;
119 size_t outplanen_size;
120 size_t inplane1_stride;
121 size_t inplanen_stride;
122 size_t outplane1_stride;
123 size_t outplanen_stride;
124 size_t inplanen_width;
125 size_t inplanen_height;
126 size_t outplanen_width;
127 size_t outplanen_height;
128 unsigned planes;
131 void do_resize_rgb(char* out, const char* in, struct scale_params& s)
133 //TODO: Optimize this.
134 for(size_t y = 0; y < s.inheight; y++) {
135 for(size_t x = 0; x < s.inwidth; x++) {
136 for(size_t i = 0; i < s.factor_x; i++) {
137 out[3 * s.factor_x * x + 3 * i + 0] = in[3 * x + 0];
138 out[3 * s.factor_x * x + 3 * i + 1] = in[3 * x + 1];
139 out[3 * s.factor_x * x + 3 * i + 2] = in[3 * x + 2];
142 for(size_t x = 1; x < s.factor_y; x++)
143 memcpy(out + x * s.outplane1_stride, out, s.outplane1_stride);
144 in += s.inplane1_stride;
145 out += s.factor_y * s.outplane1_stride;
149 template<typename T>
150 void do_resize_Y(T* out, const T* in, struct scale_params& s)
152 //TODO: Optimize this.
153 for(size_t y = 0; y < s.inheight; y++) {
154 for(size_t x = 0; x < s.inwidth; x++)
155 for(size_t i = 0; i < s.factor_x; i++)
156 out[s.factor_x * x + i] = in[x];
157 for(size_t x = 1; x < s.factor_y; x++)
158 memcpy(out + x * s.outplane1_stride, out, s.outplane1_stride);
159 in += s.inplane1_stride;
160 out += s.factor_y * s.outplane1_stride;
164 template<typename T>
165 void do_resize_C(T* out, const T* in, struct scale_params& s)
167 //TODO: Optimize this.
168 for(size_t y = 0; y < s.inplanen_height; y++) {
169 for(size_t x = 0; x < s.inplanen_width; x++)
170 for(size_t i = 0; i < s.factor_x; i++)
171 out[s.factor_x * x + i] = in[x];
172 for(size_t x = 1; x < s.factor_y; x++)
173 memcpy(out + x * s.outplanen_stride, out, s.outplanen_stride);
174 in += s.inplanen_stride;
175 out += s.factor_y * s.outplanen_stride;
179 void do_resize(char* out, const char* in, struct scale_params& s)
181 if(s.mode == 0) {
182 do_resize_rgb(out, in, s);
183 } else if(s.mode == 1) {
184 do_resize_Y(reinterpret_cast<uint8_t*>(out), reinterpret_cast<const uint8_t*>(in), s);
185 for(unsigned i = 0; i < s.planes - 1; i++)
186 do_resize_C(reinterpret_cast<uint8_t*>(out + s.outplane1_size + i * s.outplanen_size),
187 reinterpret_cast<const uint8_t*>(in + s.inplane1_size + i * s.inplanen_size),
189 } else if(s.mode == 2) {
190 do_resize_Y(reinterpret_cast<uint16_t*>(out), reinterpret_cast<const uint16_t*>(in), s);
191 for(unsigned i = 0; i < s.planes - 1; i++)
192 do_resize_C(reinterpret_cast<uint16_t*>(out + s.outplane1_size + i *
193 s.outplanen_size), reinterpret_cast<const uint16_t*>(in + s.inplane1_size +
194 i * s.inplanen_size), s);
199 int main(int argc, char** argv)
201 scale_params s;
202 s.inwidth = 0;
203 s.inheight = 0;
204 bool half = false;
205 for(int i = 1; i < argc; i++) {
206 std::string arg = argv[i];
207 if(arg == "--half")
208 half = true;
209 else {
210 std::cerr << "hdify: Unrecognized option '" << arg << "'" << std::endl;
211 return 1;
215 //Open files.
216 FILE* in = stdin;
217 FILE* out = stdout;
218 mark_pipe_as_binary(in);
219 mark_pipe_as_binary(out);
221 //Fixup header.
222 try {
223 double sar = 1;
224 struct yuv4mpeg_stream_header strmh(in);
225 s.inwidth = strmh.width;
226 s.inheight = strmh.height;
228 if(strmh.sar_n && strmh.sar_d)
229 sar = 1.0 * strmh.sar_n / strmh.sar_d;
230 compute_scale_factors(s.inwidth, s.inheight, sar, s.factor_x, s.factor_y);
231 if(half) {
232 s.factor_x >>= 1;
233 s.factor_y >>= 1;
236 s.chroma = strmh.chroma;
237 s.fill_csp();
238 strmh.width = s.outwidth;
239 strmh.height = s.outheight;
240 strmh.sar_n = 1;
241 strmh.sar_d = 1;
243 std::string _strmh = std::string(strmh);
244 write_or_die(out, _strmh);
246 std::vector<char> buffer;
247 std::vector<char> buffer2;
248 buffer.resize(s.insize + 128);
249 buffer2.resize(s.outsize + 128);
250 while(true) {
251 std::string _framh;
252 if(!read_line2(in, _framh))
253 break;
254 read_or_die(in, &buffer[0], s.insize);
255 do_resize(&buffer2[0], &buffer[0], s);
256 write_or_die(out, _framh);
257 write_or_die(out, &buffer2[0], s.outsize);
260 } catch(std::exception& e) {
261 std::cerr << "hdify: Error: " << e.what() << std::endl;
262 return 1;
264 return 0;