1 #include "yuv4mpeg.hpp"
9 std::string
extract_tok(const std::string
& str
, size_t& ptr
)
12 size_t strl
= str
.length();
15 if(ch
== '\t' || ch
== '\v' || ch
== '\r' || ch
== ' ')
19 std::string tmp
= str
;
20 tmp
= tmp
.substr(ptr
+ 1, eptr
- ptr
- 1);
26 T
tonumber(const std::string
& str
)
29 size_t strl
= str
.length();
31 throw std::runtime_error("Invalid number '" + str
+ "'");
32 for(size_t i
= 0; i
< strl
; i
++) {
33 if(str
[i
] < '0' || str
[i
] > '9')
34 throw std::runtime_error("Invalid number '" + str
+ "'");
35 if(r
> std::numeric_limits
<T
>::max() / 10)
36 throw std::runtime_error("Invalid number '" + str
+ "'");
38 if(r
+ (str
[i
] - '0') < r
)
39 throw std::runtime_error("Invalid number '" + str
+ "'");
45 void parse_ratio(const std::string
& str
, uint32_t& n
, uint32_t& d
)
47 std::string _str
= str
;
48 size_t p
= str
.find_first_of(':');
50 throw std::runtime_error("Invalid ratio '" + str
+ "'");
51 n
= tonumber
<uint32_t>(_str
.substr(0, p
));
52 d
= tonumber
<uint32_t>(_str
.substr(p
+ 1));
55 std::string
read_line(FILE* pipe
)
61 if(ch
== '\n' || ch
< 0)
63 s
<< static_cast<char>(ch
);
68 yuv4mpeg_stream_header::yuv4mpeg_stream_header()
80 yuv4mpeg_stream_header::yuv4mpeg_stream_header(const std::string
& str
)
82 bool seen_width
= false;
83 bool seen_height
= false;
92 if(str
.length() < 9 || str
.substr(0, 9) != "YUV4MPEG2")
93 throw std::runtime_error("Bad YUV4MPEG2 stream magic");
95 size_t strl
= str
.length();
108 tok
= extract_tok(str
, ptr
);
109 parse_ratio(tok
, sar_n
, sar_d
);
112 chroma
= extract_tok(str
, ptr
);
115 tok
= extract_tok(str
, ptr
);
116 parse_ratio(tok
, fps_n
, fps_d
);
119 tok
= extract_tok(str
, ptr
);
120 height
= tonumber
<size_t>(tok
);
124 tok
= extract_tok(str
, ptr
);
125 if(tok
.length() != 1)
126 throw std::runtime_error("Invalid stream I-token");
130 tok
= extract_tok(str
, ptr
);
131 width
= tonumber
<size_t>(tok
);
135 tok
= extract_tok(str
, ptr
);
137 throw std::runtime_error("Empty extension token not allowed");
138 extension
.push_back(tok
);
141 throw std::runtime_error("Unknown token type '" + std::string(&ch
, 1) + "'");
144 if(!seen_width
|| !seen_height
)
145 throw std::runtime_error("W and H tokens are required");
148 yuv4mpeg_stream_header::yuv4mpeg_stream_header(FILE* pipe
)
150 *this = yuv4mpeg_stream_header(read_line(pipe
));
153 yuv4mpeg_stream_header::operator std::string() const
155 std::ostringstream h
;
156 h
<< "YUV4MPEG2 W" << width
<< " H" << height
;
157 if(chroma
!= "420jpeg")
160 h
<< " I" << interlace
;
162 h
<< " F" << fps_n
<< ":" << fps_d
;
164 h
<< " A" << sar_n
<< ":" << sar_d
;
165 for(auto i
: extension
)
170 yuv4mpeg_frame_header::yuv4mpeg_frame_header()
178 yuv4mpeg_frame_header::yuv4mpeg_frame_header(const std::string
& str
)
184 if(str
.length() < 5 || str
.substr(0, 5) != "FRAME")
185 throw std::runtime_error("Bad YUV4MPEG2 frame magic");
187 size_t strl
= str
.length();
200 tok
= extract_tok(str
, ptr
);
201 if(tok
.length() != 3)
202 throw std::runtime_error("Invalid frame I-token");
203 representation
= tok
[0];
208 tok
= extract_tok(str
, ptr
);
210 throw std::runtime_error("Empty extension token not allowed");
211 if(tok
.length() > 9 && tok
.substr(0, 9) == "duration=")
212 duration
= tonumber
<uint32_t>(tok
.substr(9));
214 extension
.push_back(tok
);
217 throw std::runtime_error("Unknown token type '" + std::string(&ch
, 1) + "'");
222 yuv4mpeg_frame_header::yuv4mpeg_frame_header(FILE* pipe
)
224 *this = yuv4mpeg_frame_header(read_line(pipe
));
227 yuv4mpeg_frame_header::operator std::string() const
229 std::ostringstream h
;
231 if(representation
|| temporal
|| chroma
)
232 h
<< " I" << representation
<< temporal
<< chroma
;
234 h
<< " Xduration=" << duration
;
235 for(auto i
: extension
)
236 if(!regex_match("duration=.*", i
))
241 void mark_pipe_as_binary(FILE* pipe
)
243 #if defined(_WIN32) || defined(_WIN64)
244 setmode(fileno(pipe
), O_BINARY
);
248 void read_or_die(FILE* pipe
, void* data
, size_t datasize
)
250 char* _data
= reinterpret_cast<char*>(data
);
251 while(datasize
> 0) {
253 size_t s
= (datasize
> 4096) ? 4096 : datasize
;
254 r
= fread(_data
, 1, s
, pipe
);
256 throw std::runtime_error("Error reading from file");
262 bool read_or_die2(FILE* pipe
, void* data
, size_t datasize
)
265 char* _data
= reinterpret_cast<char*>(data
);
266 while(datasize
> 0) {
268 size_t s
= (datasize
> 4096) ? 4096 : datasize
;
269 r
= fread(_data
, 1, s
, pipe
);
273 throw std::runtime_error("Error reading from file");
281 void write_or_die(FILE* pipe
, const void* data
, size_t datasize
)
283 const char* _data
= reinterpret_cast<const char*>(data
);
284 while(datasize
> 0) {
286 size_t s
= (datasize
> 4096) ? 4096 : datasize
;
287 r
= fwrite(_data
, 1, s
, pipe
);
289 throw std::runtime_error("Error writing to file");
295 void write_or_die(FILE* pipe
, const std::string
& data
)
298 v
.resize(data
.size() + 1);
299 std::copy(data
.begin(), data
.end(), v
.begin());
300 v
[v
.size() - 1] = '\n';
301 write_or_die(pipe
, &v
[0], v
.size());
304 void get_512_scaling(size_t w
, size_t h
, uint32_t sar_n
, uint32_t sar_d
, size_t& w512
, size_t& h512
)
306 if(!sar_n
|| !sar_d
) {
312 //w / h < sar_n / sar_d, widen the screen.
313 w512
= static_cast<uint64_t>(w
) * sar_n
/ sar_d
;
317 } else if(sar_d
> sar_n
) {
318 //w / h > sar_n / sar_d, tallen the screen.
320 h512
= static_cast<uint64_t>(h
) * sar_d
/ sar_n
;
329 bool read_line2(FILE* pipe
, std::string
& line
)
331 std::ostringstream s
;
336 if(ch
== '\n' || ch
< 0) {
338 return (ch
>= 0 || !first
);
340 s
<< static_cast<char>(ch
);
345 regex_results
yuv4mpeg_find_extension(const std::vector
<std::string
>& exts
, const std::string
& regexp
)
349 if(r
= regex(regexp
, i
))
352 return regex_results();
355 void yuv4mpeg_delete_extensions(std::vector
<std::string
>& exts
, const std::string
& regexp
)
360 for(auto i
= exts
.begin(); i
!= exts
.end(); i
++)
361 if(regex_match(regexp
, *i
)) {