Fix integer overflow in ft_rendered_size_line
[ilaris-y4m-tools.git] / concatenate.cpp
blobd36dcf621edba4e9503475b424e86b8dcdab420c
1 #include "yuv4mpeg.hpp"
2 #include "parseval.hpp"
3 #include "fpschanger.hpp"
4 #include <iostream>
6 int main(int argc, char** argv)
8 std::vector<std::string> files;
9 std::vector<FILE*> in;
10 bool stdin_used = false;
11 unsigned headernum = 0;
12 size_t framesize = 0;
13 for(int i = 1; i < argc; i++) {
14 std::string arg = argv[i];
15 regex_results r;
16 if(r = regex("--primary-header=(0|[1-9][0-9]*)", arg)) {
17 try {
18 headernum = parse_value<unsigned>(r[1]);
19 } catch(std::exception& e) {
20 std::cerr << "concatenate: Bad end '" << r[1] << "'" << std::endl;
21 return 1;
23 } else if(r = regex("--.*", arg)) {
24 std::cerr << "concatenate: Unrecognized option '" << arg << "'" << std::endl;
25 return 1;
26 } else {
27 files.push_back(arg);
31 if(headernum >= files.size()) {
32 std::cerr << "concatenate: Invalid primary header number" << std::endl;
33 return 1;
36 //Open files.
37 FILE* out = stdout;
38 mark_pipe_as_binary(out);
39 for(auto i : files) {
40 if(i == "-") {
41 if(stdin_used) {
42 std::cerr << "concatenate: Stdin can only be used once" << std::endl;
43 return 1;
45 stdin_used = true;
46 in.push_back(stdin);
47 mark_pipe_as_binary(stdin);
48 } else {
49 FILE* _in = fopen(i.c_str(), "rb");
50 if(!_in) {
51 std::cerr << "concatenate: Can't open '" << i << "'" << std::endl;
52 return 1;
54 in.push_back(_in);
58 //Fixup header.
59 try {
60 regex_results r;
61 //Read all stream headers.
62 std::vector<yuv4mpeg_stream_header> strmhs;
63 yuv4mpeg_stream_header phdr;
64 for(auto i : in) {
65 struct yuv4mpeg_stream_header strmh(i);
66 strmhs.push_back(strmh);
68 phdr = strmhs[headernum];
70 //Check that all headers are compatible.
71 for(auto i : strmhs) {
72 if(i.width != phdr.width || i.height != phdr.height)
73 throw std::runtime_error("Streams must all have the same size");
74 if(i.chroma != phdr.chroma)
75 throw std::runtime_error("Streams must all have the same chroma");
76 if(i.interlace != phdr.interlace)
77 throw std::runtime_error("Streams must all have the same interlace");
80 //Get frame size.
81 if(phdr.chroma == "rgb")
82 framesize = 3 * phdr.width * phdr.height;
83 else if(phdr.chroma == "420")
84 framesize = 3 * phdr.width * phdr.height / 2;
85 else if(phdr.chroma == "420p16")
86 framesize = 6 * phdr.width * phdr.height / 2;
87 else if(phdr.chroma == "422")
88 framesize = 2 * phdr.width * phdr.height;
89 else if(phdr.chroma == "422p16")
90 framesize = 4 * phdr.width * phdr.height;
91 else if(phdr.chroma == "444")
92 framesize = 3 * phdr.width * phdr.height;
93 else if(phdr.chroma == "444p16")
94 framesize = 6 * phdr.width * phdr.height;
95 else
96 throw std::runtime_error("Unsupported input chroma type '" + phdr.chroma + "'");
98 write_or_die(out, static_cast<std::string>(phdr));
100 std::string _framh;
101 std::vector<char> buffer;
102 buffer.resize(framesize);
104 fpschanger timer(phdr.fps_n, phdr.fps_d, phdr.fps_n, phdr.fps_d);
105 bool tvfr = phdr.find_extension("VFR");
107 //Frame loop.
108 size_t index = 0;
109 for(auto i : in) {
110 timer.change_source_rate(strmhs[index].fps_n, strmhs[index].fps_d);
111 bool svfr = strmhs[index].find_extension("VFR");
112 while(true) {
113 uint64_t duration = 1;
114 if(!read_line2(i, _framh))
115 break; //Next!
116 read_or_die(i, &buffer[0], buffer.size());
117 struct yuv4mpeg_frame_header framh(_framh);
118 if(svfr)
119 duration = framh.duration;
120 duration = timer.duration(duration);
121 if(tvfr) {
122 framh.duration = duration;
123 write_or_die(out, framh);
124 write_or_die(out, &buffer[0], buffer.size());
125 } else {
126 framh.duration = 1;
127 for(uint64_t i = 0; i < duration; i++) {
128 write_or_die(out, framh);
129 write_or_die(out, &buffer[0], buffer.size());
133 index++;
135 } catch(std::exception& e) {
136 std::cerr << "concatenate: Error: " << e.what() << std::endl;
137 return 1;
139 return 0;