1 #include "yuv4mpeg.hpp"
2 #include "parseval.hpp"
7 #define UINT64_C(val) val##ULL
9 #include <libswscale/swscale.h>
19 sws_fmt
= (*reinterpret_cast<uint8_t*>(&magic
) == 2) ? PIX_FMT_GRAY16LE
: PIX_FMT_GRAY16BE
;
37 bool subsample_x
= false;
38 bool subsample_y
= false;
45 } else if(chroma
== "420") {
53 } else if(chroma
== "420p16") {
61 } else if(chroma
== "422") {
68 } else if(chroma
== "422p16") {
75 } else if(chroma
== "444") {
81 } else if(chroma
== "444p16") {
88 throw std::runtime_error("Unsupported input chroma type '" + chroma
+ "'");
89 insize
= pfourths
* inwidth
* inheight
/ 4;
90 outsize
= pfourths
* outwidth
* outheight
/ 4;
91 inplane1_size
= p1fourths
* inwidth
* inheight
/ 4;
92 outplane1_size
= p1fourths
* outwidth
* outheight
/ 4;
93 inplanen_size
= pnfourths
* inwidth
* inheight
/ 4;
94 outplanen_size
= pnfourths
* outwidth
* outheight
/ 4;
95 inplane1_stride
= p1fourths
* inwidth
/ 4;
96 outplane1_stride
= p1fourths
* outwidth
/ 4;
97 //Hack: Multiply plane_n strides by 2 if vertically subsampled, so that the values are
99 size_t hack_multiply
= subsample_y
? 2 : 1;
100 inplanen_stride
= hack_multiply
* pnfourths
* inwidth
/ 4;
101 outplanen_stride
= hack_multiply
* 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);
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
;
131 /* Debugging aid, commented out since compiler does not like unused defintions.
132 #define PRINTFIELD(X) << #X "=" << s. X << " "
134 std::ostream& operator<<(std::ostream& os, const scale_params& s)
140 PRINTFIELD(outheight)
147 PRINTFIELD(inplane1_size)
148 PRINTFIELD(inplanen_size)
149 PRINTFIELD(outplane1_size)
150 PRINTFIELD(outplanen_size)
151 PRINTFIELD(inplane1_stride)
152 PRINTFIELD(inplanen_stride)
153 PRINTFIELD(outplane1_stride)
154 PRINTFIELD(outplanen_stride)
155 PRINTFIELD(inplanen_width)
156 PRINTFIELD(outplanen_width)
157 PRINTFIELD(inplanen_height)
158 PRINTFIELD(outplanen_height)
167 void do_resize(char* out
, const char* in
, struct scale_params
& s
)
171 pfmt
= PIX_FMT_RGB24
;
173 pfmt
= PIX_FMT_GRAY8
;
177 static SwsContext
* ctx1
= NULL
;
178 ctx1
= sws_getCachedContext(ctx1
, s
.inwidth
, s
.inheight
, pfmt
, s
.outwidth
, s
.outheight
, pfmt
, s
.flags
,
180 const uint8_t* in_ptr
[1];
184 in_stride
[0] = s
.inplane1_stride
;
185 out_stride
[0] = s
.outplane1_stride
;
186 in_ptr
[0] = reinterpret_cast<const uint8_t*>(in
);
187 out_ptr
[0] = reinterpret_cast<uint8_t*>(out
);
188 sws_scale(ctx1
, in_ptr
, in_stride
, 0, s
.inheight
, out_ptr
, out_stride
);
189 for(unsigned i
= 0; i
< s
.planes
- 1; i
++) {
190 static SwsContext
* ctx2
= NULL
;
191 ctx2
= sws_getCachedContext(ctx2
, s
.inplanen_width
, s
.inplanen_height
, pfmt
,
192 s
.outplanen_width
, s
.outplanen_height
, pfmt
, s
.flags2
, NULL
, NULL
, NULL
);
193 in_stride
[0] = s
.inplanen_stride
;
194 out_stride
[0] = s
.outplanen_stride
;
195 in_ptr
[0] = reinterpret_cast<const uint8_t*>(in
+ s
.inplane1_size
+ i
* s
.inplanen_size
);
196 out_ptr
[0] = reinterpret_cast<uint8_t*>(out
+ s
.outplane1_size
+ i
* s
.outplanen_size
);
197 sws_scale(ctx2
, in_ptr
, in_stride
, 0, s
.inplanen_height
, out_ptr
, out_stride
);
201 void compute_scale(size_t inw
, size_t inh
, size_t& outw
, size_t& outh
, size_t xf
, size_t yf
, bool xd
,
202 bool yd
, bool pc
, uint32_t& sn
, uint32_t& sd
)
205 outw
= xd
? (inw
/ xf
) : (inw
* xf
);
206 outh
= yd
? (inh
/ yf
) : (inh
* yf
);
213 get_512_scaling(outw
, outh
, sn
, sd
, outw
, outh
);
220 int main(int argc
, char** argv
)
233 bool precorrect
= false;
234 for(int i
= 1; i
< argc
; i
++) {
235 std::string arg
= argv
[i
];
237 if(r
= regex("--precorrect", arg
)) {
239 } else if(r
= regex("--resolution=([1-9][0-9]*)x([1-9][0-9]*)", arg
)) {
241 s
.outwidth
= parse_value
<unsigned>(r
[1]);
242 s
.outheight
= parse_value
<unsigned>(r
[2]);
243 } catch(std::exception
& e
) {
244 std::cerr
<< "resize: Bad resolution '" << r
[1] << "x" << r
[2] << "'" << std::endl
;
247 } else if(r
= regex("--factor=([/x])([1-9][0-9]*)", arg
)) {
249 xfactor
= yfactor
= parse_value
<size_t>(r
[2]);
250 xdown
= ydown
= (r
[1] == "/");
251 } catch(std::exception
& e
) {
252 std::cerr
<< "resize: Bad factor '" << arg
<< "'" << std::endl
;
255 } else if(r
= regex("--factor=([/x])([1-9][0-9]*)x([/x])([1-9][0-9]*)", arg
)) {
257 xfactor
= parse_value
<size_t>(r
[2]);
258 yfactor
= parse_value
<size_t>(r
[4]);
259 xdown
= (r
[1] == "/");
260 ydown
= (r
[3] == "/");
261 } catch(std::exception
& e
) {
262 std::cerr
<< "resize: Bad factor '" << arg
<< "'" << std::endl
;
265 } else if(arg
== "--fast-bilinear") {
266 s
.flags
= SWS_FAST_BILINEAR
;
267 } else if(arg
== "--bilinear") {
268 s
.flags
= SWS_BILINEAR
;
269 } else if(arg
== "--bicubic") {
270 s
.flags
= SWS_BICUBIC
;
271 } else if(arg
== "--experimential") {
273 } else if(arg
== "--point") {
275 } else if(arg
== "--area") {
277 } else if(arg
== "--bicubic-linear") {
278 s
.flags
= SWS_BICUBIC
;
279 s
.flags2
= SWS_BILINEAR
;
280 } else if(arg
== "--gauss") {
282 } else if(arg
== "--sinc") {
284 } else if(arg
== "--lanczos") {
285 s
.flags
= SWS_LANCZOS
;
286 } else if(arg
== "--spline") {
287 s
.flags
= SWS_SPLINE
;
289 std::cerr
<< "resize: Unrecognized option '" << arg
<< "'" << std::endl
;
293 if((!s
.outwidth
|| !s
.outheight
) && (!xfactor
|| !yfactor
) && !precorrect
) {
294 std::cerr
<< "resize: Resolution or factor needed if not precorrecting" << std::endl
;
301 mark_pipe_as_binary(in
);
302 mark_pipe_as_binary(out
);
306 struct yuv4mpeg_stream_header
strmh(in
);
307 s
.inwidth
= strmh
.width
;
308 s
.inheight
= strmh
.height
;
309 compute_scale(s
.inwidth
, s
.inheight
, s
.outwidth
, s
.outheight
, xfactor
, yfactor
, xdown
, ydown
,
310 precorrect
, strmh
.sar_n
, strmh
.sar_d
);
311 strmh
.width
= s
.outwidth
;
312 strmh
.height
= s
.outheight
;
314 s
.chroma
= strmh
.chroma
;
317 std::string _strmh
= std::string(strmh
);
318 write_or_die(out
, _strmh
);
320 std::vector
<char> buffer
;
321 std::vector
<char> buffer2
;
322 buffer
.resize(s
.insize
);
323 buffer2
.resize(s
.outsize
);
326 if(!read_line2(in
, _framh
))
328 read_or_die(in
, &buffer
[0], s
.insize
);
329 do_resize(&buffer2
[0], &buffer
[0], s
);
330 write_or_die(out
, _framh
);
331 write_or_die(out
, &buffer2
[0], s
.outsize
);
334 } catch(std::exception
& e
) {
335 std::cerr
<< "resize: Error: " << e
.what() << std::endl
;