Fix integer overflow in ft_rendered_size_line
[ilaris-y4m-tools.git] / redup.cpp
blob41954548faeb3f46b35bc013e608d8ab6b77c068
1 #include "yuv4mpeg.hpp"
2 #include "parseval.hpp"
3 #include <iostream>
5 uint64_t not_valid = 0xFFFFFFFFFFFFFFFFULL;
7 uint64_t nscale[7] = {1000000, 100000, 10000, 1000, 100, 10, 1};
9 struct redup_logic
11 redup_logic(FILE* _tc, uint32_t _fps_n, uint64_t _fps_d)
13 char buffer[512];
14 tc = _tc;
15 fps_n = _fps_n;
16 fps_d = _fps_d;
17 fgets(buffer, 512, tc);
18 if(!regex_match(buffer, "# timecode format v2\r?\n"))
19 throw std::runtime_error("Not valid TC file (header)");
20 current_frame = not_valid;
21 next_frame = 0;
23 size_t get()
25 current_frame = next_frame;
26 next_frame = read_framenum();
27 return (next_frame > current_frame) ? (next_frame - current_frame) : 0;
29 private:
30 uint64_t read_framenum()
32 char buffer[512];
33 if(fgets(buffer, 512, tc) && buffer[0])
34 return _read_framenum(buffer);
35 else
36 return current_frame + 1;
38 uint64_t _read_framenum(const char* buf)
40 regex_results r = regex("([0-9]+)(\\.([0-9]+))?\r?\n", buf);
41 if(!r)
42 throw std::runtime_error("Not valid TC file (value)");
43 uint64_t nanosec = parse_value<uint64_t>(r[1]) * 1000000ULL;
44 if(r[3].length() > 6)
45 nanosec += parse_value<uint64_t>(r[3].substr(0, 6));
46 else if(r[3].length() > 0)
47 nanosec += parse_value<uint64_t>(r[3]) * nscale[r[3].length()];
48 uint64_t blocklen = fps_d * 1000000000ULL;
49 uint64_t blocks = nanosec / blocklen;
50 nanosec %= blocklen;
51 return blocks * fps_n + (nanosec / 1000000000.0 * fps_n / fps_d);
53 FILE* tc;
54 uint32_t fps_n;
55 uint32_t fps_d;
56 uint64_t current_frame;
57 uint64_t next_frame;
60 int main(int argc, char** argv)
62 uint64_t infr = 0;
63 uint64_t outfr = 0;
64 uint64_t lost = 0;
65 uint32_t ofps_n = 25;
66 uint32_t ofps_d = 1;
67 uint32_t fps_n = 0;
68 uint32_t fps_d = 0;
69 size_t framesize = 0;
70 std::string tcfile;
71 for(int i = 1; i < argc; i++) {
72 std::string arg = argv[i];
73 regex_results r;
74 if(r = regex("--fps=([1-9][0-9]*)", arg)) {
75 try {
76 fps_n = parse_value<unsigned>(r[1]);
77 fps_d = 1;
78 } catch(std::exception& e) {
79 std::cerr << "redup: Bad fps '" << r[1] << "'" << std::endl;
80 return 1;
82 } else if(r = regex("--fps=([1-9][0-9]*)/([1-9][0-9]*)", arg)) {
83 try {
84 fps_n = parse_value<unsigned>(r[1]);
85 fps_d = parse_value<unsigned>(r[2]);
86 } catch(std::exception& e) {
87 std::cerr << "redup: Bad fps '" << r[1] << "/" << r[2] << "'" << std::endl;
88 return 1;
90 } else if(r = regex("--.*", arg)) {
91 std::cerr << "redup: Unrecognized option '" << arg << "'" << std::endl;
92 return 1;
93 } else {
94 if(tcfile != "") {
95 std::cerr << "redup: Only one TC file may be specified." << std::endl;
96 return 1;
98 tcfile = arg;
102 if(tcfile == "") {
103 std::cerr << "redup: TC file must be specified." << std::endl;
104 return 1;
107 //Open files.
108 FILE* in = stdin;
109 FILE* out = stdout;
110 FILE* tc = fopen(tcfile.c_str(), "r");
111 mark_pipe_as_binary(in);
112 mark_pipe_as_binary(out);
114 if(!tc) {
115 std::cerr << "redup: Can't open TC file '" << tcfile << "'." << std::endl;
116 return 1;
119 //Fixup header.
120 try {
121 regex_results r;
122 struct yuv4mpeg_stream_header strmh(in);
123 if(strmh.chroma == "rgb")
124 framesize = 3 * strmh.width * strmh.height;
125 else if(strmh.chroma == "420")
126 framesize = 3 * strmh.width * strmh.height / 2;
127 else if(strmh.chroma == "420p16")
128 framesize = 6 * strmh.width * strmh.height / 2;
129 else if(strmh.chroma == "422")
130 framesize = 2 * strmh.width * strmh.height;
131 else if(strmh.chroma == "422p16")
132 framesize = 4 * strmh.width * strmh.height;
133 else if(strmh.chroma == "444")
134 framesize = 3 * strmh.width * strmh.height;
135 else if(strmh.chroma == "444p16")
136 framesize = 6 * strmh.width * strmh.height;
137 else
138 throw std::runtime_error("Unsupported input chroma type '" + strmh.chroma + "'");
139 if(strmh.fps_n && strmh.fps_d) {
140 ofps_n = strmh.fps_n;
141 ofps_d = strmh.fps_d;
143 if(fps_n && fps_d) {
144 strmh.fps_n = fps_n;
145 strmh.fps_d = fps_d;
146 } else {
147 fps_n = ofps_n;
148 fps_d = ofps_d;
150 strmh.delete_extensions("VFR");
151 std::string _strmh = std::string(strmh);
152 write_or_die(out, _strmh);
155 std::string _framh, _framh2;
156 std::vector<char> buffer;
157 buffer.resize(framesize);
158 struct yuv4mpeg_frame_header framh;
159 struct redup_logic rdl(tc, fps_n, fps_d);
161 size_t count = 0;
163 //Initial black frame.
164 count = rdl.get();
165 for(size_t i = 0; i < count; i++) {
166 outfr++;
167 std::string _framh2 = framh;
168 write_or_die(out, _framh2);
169 write_or_die(out, &buffer[0], framesize);
172 //Frame loop.
173 next_input:
174 if(!read_line2(in, _framh))
175 goto out; //End.
176 framh = yuv4mpeg_frame_header(_framh);
177 infr++;
178 read_or_die(in, &buffer[0], buffer.size());
180 count = rdl.get();
181 framh.duration = 1;
182 if(!count) lost++;
183 for(size_t i = 0; i < count; i++) {
184 outfr++;
185 std::string _framh2 = framh;
186 write_or_die(out, _framh2);
187 write_or_die(out, &buffer[0], framesize);
189 goto next_input;
190 } catch(std::exception& e) {
191 std::cerr << "redup: Error: " << e.what() << std::endl;
192 return 1;
194 out:
195 std::cerr << "redup: Read " << infr << " frames, wrote " << outfr << " frames." << std::endl;
196 std::cerr << "redup: Lost " << lost << " frames." << std::endl;
197 return 0;