├── .gitignore ├── LICENSE.txt ├── README.md ├── assdumper ├── .gitignore ├── Makefile ├── README.md ├── assadjust.rb ├── assdumper.cc └── assdumper.go ├── clean-ts ├── .gitignore ├── CMakeLists.txt ├── README.md └── clean-ts.c ├── encoder ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md ├── aws.tf ├── config.toml ├── main.tf ├── src │ ├── bin │ │ ├── encode.rs │ │ ├── redis-to-sqs.rs │ │ └── sqs-encode.rs │ └── lib.rs └── versions.tf ├── statvfs ├── .gitignore ├── Makefile ├── README.md └── statvfs.c └── tsutils ├── .gitignore ├── Cargo.lock ├── Cargo.toml └── src ├── bin └── tsutils-drop-av.rs ├── lib.rs ├── packet.rs ├── pat.rs ├── pmt.rs └── psi.rs /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Kohei Suzuki 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # eagletmt-recutils 2 | My recutils. 3 | -------------------------------------------------------------------------------- /assdumper/.gitignore: -------------------------------------------------------------------------------- 1 | assdumper 2 | -------------------------------------------------------------------------------- /assdumper/Makefile: -------------------------------------------------------------------------------- 1 | CXX = g++ 2 | CXXFLAGS = -O2 -Wall -W 3 | LDFLAGS = 4 | OBJS = assdumper.o 5 | TARGET = assdumper 6 | 7 | $(TARGET): $(OBJS) 8 | $(CXX) $(LDFLAGS) $< -o $@ 9 | 10 | clean: 11 | $(RM) $(OBJS) $(TARGET) 12 | -------------------------------------------------------------------------------- /assdumper/README.md: -------------------------------------------------------------------------------- 1 | # assdumper 2 | TS の字幕情報を抽出して [.ass](http://en.wikipedia.org/wiki/SubStation_Alpha) の形式で出力する。 3 | 4 | assdumper は実時間で字幕のタイミングを出力します。 5 | 実際に使うときは assadjust.rb に録画開始時刻を与えて相対時間に直す必要があります。 6 | 7 | ``` 8 | % assdumper precure.ts > precure.raw.ass 9 | % assadjust.rb 8:29:45 precure.raw.ass > precure.ass 10 | ``` 11 | -------------------------------------------------------------------------------- /assdumper/assadjust.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | # coding: utf-8 3 | require 'time' 4 | 5 | _, st, _, sc = *ARGV[0].match(/([^.]+)(\.(\d+))?/) 6 | st = Time.strptime st, '%H:%M:%S' 7 | sc = sc.to_i 8 | open(ARGV[1], 'r') do |fin| 9 | started = false 10 | fin.readlines.each do |line| 11 | m = line.match(/^Dialogue: 0,(\d{2}:\d{2}:\d{2}).(\d{2}),(\d{2}:\d{2}:\d{2}).(\d{2}),(.*)$/) rescue nil 12 | if m 13 | _, t1, c1, t2, c2, rest = *m 14 | t1, t2 = *[t1, t2].map { |t| Time.strptime t, '%H:%M:%S' } 15 | c1, c2 = *[c1, c2].map(&:to_i) 16 | c1 -= sc 17 | if c1 < 0 18 | c1 += 100 19 | t1 -= 1 20 | end 21 | c2 -= sc 22 | if c2 < 0 23 | c2 += 100 24 | t2 -= 1 25 | end 26 | d1 = (t1 - st).to_i 27 | if d1 < 0 28 | if started 29 | d1 += 24*60*60 30 | else 31 | next 32 | end 33 | end 34 | started = true 35 | d2 = (t2 - st).to_i 36 | if d2 < 0 37 | d2 += 24*60*60 38 | end 39 | h1 = d1 / 3600 40 | h2 = d2 / 3600 41 | d1 %= 3600 42 | d2 %= 3600 43 | m1 = d1 / 60 44 | m2 = d2 / 60 45 | s1 = d1 % 60 46 | s2 = d2 % 60 47 | printf "Dialogue: 0,%02d:%02d:%02d.%02d,%02d:%02d:%02d.%02d,%s\n", h1, m1, s1, c1, h2, m2, s2, c2, rest 48 | else 49 | puts line 50 | end 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /assdumper/assdumper.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | static std::vector extract_pmt_pids(const unsigned char *payload); 17 | static int extract_caption_pid(const unsigned char *payload); 18 | static int extract_pcr_pid(const unsigned char *payload); 19 | static time_t extract_jst_time(const unsigned char *payload); 20 | static unsigned decode_bcd(uint8_t n); 21 | static std::string try_gaiji(int c); 22 | static void print_prelude(); 23 | static bool blank_p(const std::string& str); 24 | 25 | class system_clock {/*{{{*/ 26 | uint64_t clk; 27 | static const uint64_t K = 27000000; 28 | 29 | system_clock(uint64_t c) : clk(c) {} 30 | 31 | public: 32 | system_clock() : clk(0) {} 33 | 34 | static system_clock clock(uint64_t c) { return system_clock(c); } 35 | static system_clock second(uint64_t sec) { return system_clock(sec * K); } 36 | static system_clock centisecond(uint64_t sec) { return system_clock(sec * K/100); } 37 | 38 | system_clock& operator+=(const system_clock& sc) 39 | { 40 | clk += sc.clk; 41 | return *this; 42 | } 43 | system_clock& operator-=(const system_clock& sc) 44 | { 45 | clk -= sc.clk; 46 | return *this; 47 | } 48 | system_clock operator-(const system_clock& sc) const { system_clock x(*this); x -= sc; return x; } 49 | 50 | uint64_t clock() const { return clk; } 51 | unsigned hour() const { return ((clk/K) % (24*60*60)) / 3600; } 52 | unsigned minute() const { return ((clk/K) % (60*60)) / 60; } 53 | unsigned second() const { return (clk/K) % 60; } 54 | unsigned long long centitime() const { return (clk/(K/100)); } 55 | unsigned centisecond() const { return (clk/(K/100)) % 100; } 56 | };/*}}}*/ 57 | 58 | class AssDumper 59 | { 60 | FILE *fin; 61 | iconv_t cd; 62 | long long clock_offset; 63 | bool prelude_printed; 64 | bool prev_blank; 65 | 66 | system_clock prevts, curts; 67 | std::string prevsub; 68 | public: 69 | AssDumper(const char *path)/*{{{*/ 70 | : fin(fopen(path, "r")) 71 | , cd(iconv_open("UTF-8", "EUC-JP")) 72 | , clock_offset(0) 73 | , prelude_printed(false) 74 | , prev_blank(true) 75 | { 76 | if (!fin) { 77 | throw "cannot open input file"; 78 | } 79 | if (cd == (iconv_t)-1) { 80 | throw "cannot open iconv UTF-8 -> EUC-JP"; 81 | } 82 | }/*}}}*/ 83 | ~AssDumper() { fclose(fin); } 84 | 85 | void run()/*{{{*/ 86 | { 87 | unsigned char buf[188]; 88 | std::vector pmt_pids; 89 | int caption_pid = -1; 90 | int pcr_pid = -1; 91 | 92 | while (fread(buf, 1, 188, fin) == 188) { 93 | // ISO Table 2-2 94 | if (buf[0] != 0x47) { 95 | throw "sync_byte failed"; 96 | } 97 | const bool payload_unit_start_indicator = !!(buf[1]&0x40); 98 | const int pid = (buf[1]&0x1f)<<8 | buf[2]; 99 | const bool has_adaptation = !!(buf[3] & 0x20); 100 | const bool has_payload = !!(buf[3] & 0x10); 101 | const unsigned char *p = buf+4; 102 | 103 | if (has_adaptation) { 104 | // ISO Table 2-6 (p40) 105 | const unsigned adaptation_field_length = *p; 106 | ++p; 107 | const bool pcr_flag = !!(p[0] & 0x10); 108 | if (pcr_flag && pid == pcr_pid) { 109 | const uint64_t pcr_base = uint64_t(p[1]<<25) | (p[2]<<17) | (p[3]<<9) | (p[4]<<1) | ((p[5] & 0x80)>>7); 110 | const uint64_t pcr_ext = (p[5]&0x01) | p[6]; 111 | // ISO 2.4.2.2 112 | curts = system_clock::clock(pcr_base*300 + pcr_ext); 113 | } 114 | p += adaptation_field_length; 115 | } 116 | 117 | if (has_payload) { 118 | if (pmt_pids.empty() && pid == 0) { 119 | // ISO Table 2-3 120 | // PAT section 121 | pmt_pids = extract_pmt_pids(p+1); 122 | fprintf(stderr, "%lu pmt_pids\n", pmt_pids.size()); 123 | for (std::vector::const_iterator it = pmt_pids.begin(); it != pmt_pids.end(); ++it) { 124 | fprintf(stderr, "%u\n", *it); 125 | } 126 | } else if (caption_pid == -1 && find(pmt_pids.begin(), pmt_pids.end(), pid) != pmt_pids.end()) { 127 | // PMT section 128 | if (payload_unit_start_indicator) { 129 | const int r = extract_pcr_pid(p+1); 130 | caption_pid = extract_caption_pid(p+1); 131 | if (caption_pid != -1) { 132 | pcr_pid = r; 133 | fprintf(stderr, "%d caption pid, PCR_PID = %d\n", caption_pid, pcr_pid); 134 | } 135 | } 136 | } else if (pid == 0x0014) { 137 | // Time Offset Table 138 | // B10-2 5.2.9 139 | const time_t t = extract_jst_time(p+1); 140 | if (t != 0) { 141 | clock_offset = t*100 - curts.centitime(); 142 | } 143 | } else if (pid == caption_pid) { 144 | if (payload_unit_start_indicator) { 145 | dump_caption(p); 146 | } 147 | } 148 | } 149 | } 150 | }/*}}}*/ 151 | 152 | void dump_caption(const unsigned char *payload)/*{{{*/ 153 | { 154 | unsigned PES_header_data_length = payload[8]; 155 | unsigned PES_data_packet_header_length = payload[11 + PES_header_data_length] & 0x0F; 156 | const unsigned char *p = payload + 12 + PES_header_data_length + PES_data_packet_header_length; 157 | 158 | // B24 Table 9-1 (p184) 159 | unsigned data_group_id = (*p & 0xFC)>>2; 160 | if (data_group_id == 0x00 || data_group_id == 0x20) { 161 | // B24 Table 9-3 (p186) 162 | // caption_management_data 163 | unsigned num_languages = p[6]; 164 | p += 7 + num_languages * 5; 165 | } else { 166 | // caption_data 167 | p += 6; 168 | } 169 | // B24 Table 9-3 (p186) 170 | unsigned data_unit_loop_length = (p[0]<<16) | (p[1]<<8) | p[2]; 171 | const unsigned char *q = p; 172 | while (q < p + data_unit_loop_length) { 173 | unsigned data_unit_parameter = q[4]; 174 | unsigned data_unit_size = (q[5]<<16) | (q[6]<<8) | q[7]; 175 | if (data_unit_parameter == 0x20) { 176 | if (!prevsub.empty() && !(blank_p(prevsub) && prev_blank)) { 177 | const unsigned long long prev_time_centi = prevts.centitime() + clock_offset; 178 | const unsigned long long cur_time_centi = curts.centitime() + clock_offset; 179 | const time_t prev_time = prev_time_centi/100; 180 | const time_t cur_time = cur_time_centi/100; 181 | const unsigned prev_centi = prev_time_centi%100; 182 | const unsigned cur_centi = cur_time_centi%100; 183 | struct tm prev, cur; 184 | localtime_r(&prev_time, &prev); 185 | localtime_r(&cur_time, &cur); 186 | if (!prelude_printed) { 187 | print_prelude(); 188 | prelude_printed = true; 189 | } 190 | printf("Dialogue: 0,%02u:%02u:%02u.%02u,%02u:%02u:%02u.%02u,Default,,,,,,%s\n", 191 | prev.tm_hour, prev.tm_min, prev.tm_sec, prev_centi, 192 | cur.tm_hour, cur.tm_min, cur.tm_sec, cur_centi, 193 | prevsub.c_str()); 194 | } 195 | prev_blank = blank_p(prevsub); 196 | prevsub = decode_cprofile(q+8, data_unit_size); 197 | prevts = curts; 198 | } 199 | q += 5 + data_unit_size; 200 | } 201 | }/*}}}*/ 202 | 203 | std::string decode_cprofile(const unsigned char *str, unsigned len)/*{{{*/ 204 | { 205 | const unsigned char *end = str + len; 206 | std::string ans; 207 | for (const unsigned char *p = str; p < end; ++p) { 208 | if (0xa0 < *p && *p < 0xff) { 209 | char eucjp[3]; 210 | eucjp[0] = p[0]; 211 | eucjp[1] = p[1]; 212 | eucjp[2] = '\0'; 213 | size_t inbytes = 2, outbytes = 10; 214 | char *e = eucjp; 215 | char buf[10]; 216 | char *b = buf; 217 | size_t r = iconv(cd, &e, &inbytes, &b, &outbytes); 218 | if (r == (size_t)-1) { 219 | if (errno == EILSEQ) { 220 | int gaiji = (p[0]&0x7f)<<8 | (p[1]&0x7f); 221 | if (gaiji != 0x7c21) { 222 | ans += try_gaiji(gaiji); 223 | } 224 | } else { 225 | perror("iconv"); 226 | } 227 | } else if (inbytes == 0) { 228 | buf[10-outbytes] = '\0'; 229 | ans += buf; 230 | //printf("{%02x %02x} -> %s (%lu %lu %lu)\n", p[0], p[1], buf, r, inbytes, outbytes); 231 | } else { 232 | printf("what?: inbytes = %lu, outbytes = %lu, r = %lu\n", inbytes, outbytes, r); 233 | } 234 | ++p; 235 | } else if (0x80 <= *p && *p <= 0x87) { 236 | // color code. ignore 237 | } else if (*p == 0x0d) { 238 | // CR -> LF 239 | ans += "\\n"; 240 | } else if (*p == 0x0c) { 241 | ans += " "; 242 | } else if (*p == 0x20) { 243 | ans += " "; 244 | } else { 245 | //printf("{? %02x}", *p); 246 | } 247 | } 248 | return ans; 249 | }/*}}}*/ 250 | }; 251 | 252 | int main(int argc, char *argv[]) try 253 | { 254 | if (argc < 2) { 255 | fprintf(stderr, "usage: %s path\n", argv[0]); 256 | return 1; 257 | } 258 | 259 | AssDumper dumper(argv[1]); 260 | dumper.run(); 261 | 262 | return 0; 263 | } catch (const char *msg) { 264 | fprintf(stderr, "%s\n", msg); 265 | return 1; 266 | } 267 | 268 | std::vector extract_pmt_pids(const unsigned char *payload)/*{{{*/ 269 | { 270 | // 2.4.4.3 271 | // Table 2-25 272 | std::vector pids; 273 | unsigned table_id = payload[0]; 274 | if (table_id != 0x00) { 275 | //throw "PAT's table_id must be 0"; 276 | return pids; 277 | } 278 | unsigned section_length = (payload[1]&0x0F)<<8 | payload[2]; 279 | const unsigned char *p = payload+8; 280 | while (p < payload+3+section_length-4) { 281 | unsigned program_number = p[0]<<8 | p[1]; 282 | if (program_number != 0) { 283 | unsigned program_map_PID = (p[2]&0x1F)<<8 | p[3]; 284 | fprintf(stderr, "program_number = %u, program_map_PID = %u\n", program_number, program_map_PID); 285 | pids.push_back(program_map_PID); 286 | } 287 | p += 4; 288 | } 289 | return pids; 290 | }/*}}}*/ 291 | 292 | int extract_caption_pid(const unsigned char *payload)/*{{{*/ 293 | { 294 | // 2.4.4.8 Program Map Table 295 | // Table 2-28 296 | unsigned table_id = payload[0]; 297 | if (table_id != 0x02) { 298 | return -1; 299 | //throw "PMT's table_id must be 2"; 300 | } 301 | unsigned section_length = (payload[1]&0x0F)<<8 | payload[2]; 302 | 303 | unsigned program_info_length = (payload[10]&0x0F)<<8 | payload[11]; 304 | const unsigned char *p = payload+12+program_info_length; 305 | while (p < payload+3+section_length-4) { 306 | unsigned stream_type = p[0]; 307 | unsigned ES_info_length = (p[3]&0xF)<<8 | p[4]; 308 | if (stream_type == 0x06) { 309 | unsigned elementary_PID = (p[1]&0x1F)<<8 | p[2]; 310 | const unsigned char *q = p+5; 311 | while (q < p + ES_info_length) { 312 | // 2.6 Program and program element descriptors 313 | unsigned descriptor_tag = q[0]; 314 | unsigned descriptor_length = q[1]; 315 | if (descriptor_tag == 0x52) { 316 | // B10 6.2.16 Stream identifier descriptor 317 | // 表 6-28 318 | unsigned component_tag = q[2]; 319 | if (component_tag == 0x87) { 320 | return elementary_PID; 321 | } 322 | } 323 | q += 2 + descriptor_length; 324 | } 325 | } 326 | p += 5 + ES_info_length; 327 | } 328 | return -1; 329 | }/*}}}*/ 330 | 331 | int extract_pcr_pid(const unsigned char *payload)/*{{{*/ 332 | { 333 | return ((payload[8]&0x1f)<<8) | payload[9]; 334 | }/*}}}*/ 335 | 336 | time_t extract_jst_time(const unsigned char *payload)/*{{{*/ 337 | { 338 | if (payload[0] != 0x73) { 339 | //throw "this is not a Time Offset Table"; 340 | return 0; 341 | } 342 | struct tm t; 343 | // B10-2 Appendix C 344 | uint16_t MJD = (payload[3]<<8) | payload[4]; 345 | unsigned y = (MJD - 15078.2)/365.25; 346 | unsigned m = (MJD - 14956.1 - unsigned(y * 365.25))/30.6001; 347 | unsigned k = m == 14 || m == 15; 348 | t.tm_year = y + k; 349 | t.tm_mon = m - 2 - k*12; 350 | t.tm_mday = MJD - 14956 - unsigned(y * 365.25) - unsigned(m * 30.6001); 351 | t.tm_hour = decode_bcd(payload[5]); 352 | t.tm_min = decode_bcd(payload[6]); 353 | t.tm_sec = decode_bcd(payload[7]); 354 | return mktime(&t); 355 | }/*}}}*/ 356 | 357 | unsigned decode_bcd(uint8_t n)/*{{{*/ 358 | { 359 | return (n>>4)*10 + (n&0x0f); 360 | }/*}}}*/ 361 | 362 | void print_prelude()/*{{{*/ 363 | { 364 | puts("[Script Info]"); 365 | puts("ScriptType: v4.00+"); 366 | puts("Collisions: Normal"); 367 | puts("ScaledBorderAndShadow: yes"); 368 | puts("Timer: 100.0000"); 369 | puts("\n[Events]"); 370 | //PlayResX: 1280 371 | //PlayResY: 720 372 | }/*}}}*/ 373 | 374 | bool blank_p(const std::string& str) 375 | { 376 | for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) { 377 | if (*it != ' ') { 378 | return false; 379 | } 380 | } 381 | return true; 382 | } 383 | 384 | std::string try_gaiji(int c)/*{{{*/ 385 | { 386 | switch (c) { 387 | case 0x7A50: return "【HV】"; 388 | case 0x7A51: return "【SD】"; 389 | case 0x7A52: return "【P】"; 390 | case 0x7A53: return "【W】"; 391 | case 0x7A54: return "【MV】"; 392 | case 0x7A55: return "【手】"; 393 | case 0x7A56: return "【字】"; 394 | case 0x7A57: return "【双】"; 395 | case 0x7A58: return "【デ】"; 396 | case 0x7A59: return "【S】"; 397 | case 0x7A5A: return "【二】"; 398 | case 0x7A5B: return "【多】"; 399 | case 0x7A5C: return "【解】"; 400 | case 0x7A5D: return "【SS】"; 401 | case 0x7A5E: return "【B】"; 402 | case 0x7A5F: return "【N】"; 403 | case 0x7A62: return "【天】"; 404 | case 0x7A63: return "【交】"; 405 | case 0x7A64: return "【映】"; 406 | case 0x7A65: return "【無】"; 407 | case 0x7A66: return "【料】"; 408 | case 0x7A67: return "【年齢制限】"; 409 | case 0x7A68: return "【前】"; 410 | case 0x7A69: return "【後】"; 411 | case 0x7A6A: return "【再】"; 412 | case 0x7A6B: return "【新】"; 413 | case 0x7A6C: return "【初】"; 414 | case 0x7A6D: return "【終】"; 415 | case 0x7A6E: return "【生】"; 416 | case 0x7A6F: return "【販】"; 417 | case 0x7A70: return "【声】"; 418 | case 0x7A71: return "【吹】"; 419 | case 0x7A72: return "【PPV】"; 420 | 421 | case 0x7A60: return "■"; 422 | case 0x7A61: return "●"; 423 | case 0x7A73: return "(秘)"; 424 | case 0x7A74: return "ほか"; 425 | 426 | case 0x7C21: return "→"; 427 | case 0x7C22: return "←"; 428 | case 0x7C23: return "↑"; 429 | case 0x7C24: return "↓"; 430 | case 0x7C25: return "●"; 431 | case 0x7C26: return "○"; 432 | case 0x7C27: return "年"; 433 | case 0x7C28: return "月"; 434 | case 0x7C29: return "日"; 435 | case 0x7C2A: return "円"; 436 | case 0x7C2B: return "㎡"; 437 | case 0x7C2C: return "㎥"; 438 | case 0x7C2D: return "㎝"; 439 | case 0x7C2E: return "㎠"; 440 | case 0x7C2F: return "㎤"; 441 | case 0x7C30: return "0."; 442 | case 0x7C31: return "1."; 443 | case 0x7C32: return "2."; 444 | case 0x7C33: return "3."; 445 | case 0x7C34: return "4."; 446 | case 0x7C35: return "5."; 447 | case 0x7C36: return "6."; 448 | case 0x7C37: return "7."; 449 | case 0x7C38: return "8."; 450 | case 0x7C39: return "9."; 451 | case 0x7C3A: return "氏"; 452 | case 0x7C3B: return "副"; 453 | case 0x7C3C: return "元"; 454 | case 0x7C3D: return "故"; 455 | case 0x7C3E: return "前"; 456 | case 0x7C3F: return "[新]"; 457 | case 0x7C40: return "0,"; 458 | case 0x7C41: return "1,"; 459 | case 0x7C42: return "2,"; 460 | case 0x7C43: return "3,"; 461 | case 0x7C44: return "4,"; 462 | case 0x7C45: return "5,"; 463 | case 0x7C46: return "6,"; 464 | case 0x7C47: return "7,"; 465 | case 0x7C48: return "8,"; 466 | case 0x7C49: return "9,"; 467 | case 0x7C4A: return "(社)"; 468 | case 0x7C4B: return "(財)"; 469 | case 0x7C4C: return "(有)"; 470 | case 0x7C4D: return "(株)"; 471 | case 0x7C4E: return "(代)"; 472 | case 0x7C4F: return "(問)"; 473 | case 0x7C50: return "▶"; 474 | case 0x7C51: return "◀"; 475 | case 0x7C52: return "〖"; 476 | case 0x7C53: return "〗"; 477 | case 0x7C54: return "⟐"; 478 | case 0x7C55: return "^2"; 479 | case 0x7C56: return "^3"; 480 | case 0x7C57: return "(CD)"; 481 | case 0x7C58: return "(vn)"; 482 | case 0x7C59: return "(ob)"; 483 | case 0x7C5A: return "(cb)"; 484 | case 0x7C5B: return "(ce"; 485 | case 0x7C5C: return "mb)"; 486 | case 0x7C5D: return "(hp)"; 487 | case 0x7C5E: return "(br)"; 488 | case 0x7C5F: return "(p)"; 489 | case 0x7C60: return "(s)"; 490 | case 0x7C61: return "(ms)"; 491 | case 0x7C62: return "(t)"; 492 | case 0x7C63: return "(bs)"; 493 | case 0x7C64: return "(b)"; 494 | case 0x7C65: return "(tb)"; 495 | case 0x7C66: return "(tp)"; 496 | case 0x7C67: return "(ds)"; 497 | case 0x7C68: return "(ag)"; 498 | case 0x7C69: return "(eg)"; 499 | case 0x7C6A: return "(vo)"; 500 | case 0x7C6B: return "(fl)"; 501 | case 0x7C6C: return "(ke"; 502 | case 0x7C6D: return "y)"; 503 | case 0x7C6E: return "(sa"; 504 | case 0x7C6F: return "x)"; 505 | case 0x7C70: return "(sy"; 506 | case 0x7C71: return "n)"; 507 | case 0x7C72: return "(or"; 508 | case 0x7C73: return "g)"; 509 | case 0x7C74: return "(pe"; 510 | case 0x7C75: return "r)"; 511 | case 0x7C76: return "(R)"; 512 | case 0x7C77: return "(C)"; 513 | case 0x7C78: return "(箏)"; 514 | case 0x7C79: return "DJ"; 515 | case 0x7C7A: return "[演]"; 516 | case 0x7C7B: return "Fax"; 517 | 518 | case 0x7D21: return "㈪"; 519 | case 0x7D22: return "㈫"; 520 | case 0x7D23: return "㈬"; 521 | case 0x7D24: return "㈭"; 522 | case 0x7D25: return "㈮"; 523 | case 0x7D26: return "㈯"; 524 | case 0x7D27: return "㈰"; 525 | case 0x7D28: return "㈷"; 526 | case 0x7D29: return "㍾"; 527 | case 0x7D2A: return "㍽"; 528 | case 0x7D2B: return "㍼"; 529 | case 0x7D2C: return "㍻"; 530 | case 0x7D2D: return "№"; 531 | case 0x7D2E: return "℡"; 532 | case 0x7D2F: return "〶"; 533 | case 0x7D30: return "○"; 534 | case 0x7D31: return "〔本〕"; 535 | case 0x7D32: return "〔三〕"; 536 | case 0x7D33: return "〔二〕"; 537 | case 0x7D34: return "〔安〕"; 538 | case 0x7D35: return "〔点〕"; 539 | case 0x7D36: return "〔打〕"; 540 | case 0x7D37: return "〔盗〕"; 541 | case 0x7D38: return "〔勝〕"; 542 | case 0x7D39: return "〔敗〕"; 543 | case 0x7D3A: return "〔S〕"; 544 | case 0x7D3B: return "[投]"; 545 | case 0x7D3C: return "[捕]"; 546 | case 0x7D3D: return "[一]"; 547 | case 0x7D3E: return "[二]"; 548 | case 0x7D3F: return "[三]"; 549 | case 0x7D40: return "[遊]"; 550 | case 0x7D41: return "[左]"; 551 | case 0x7D42: return "[中]"; 552 | case 0x7D43: return "[右]"; 553 | case 0x7D44: return "[指]"; 554 | case 0x7D45: return "[走]"; 555 | case 0x7D46: return "[打]"; 556 | case 0x7D47: return "㍑"; 557 | case 0x7D48: return "㎏"; 558 | case 0x7D49: return "㎐"; 559 | case 0x7D4A: return "ha"; 560 | case 0x7D4B: return "㎞"; 561 | case 0x7D4C: return "㎢"; 562 | case 0x7D4D: return "㍱"; 563 | case 0x7D4E: return "・"; 564 | case 0x7D4F: return "・"; 565 | case 0x7D50: return "1/2"; 566 | case 0x7D51: return "0/3"; 567 | case 0x7D52: return "1/3"; 568 | case 0x7D53: return "2/3"; 569 | case 0x7D54: return "1/4"; 570 | case 0x7D55: return "3/4"; 571 | case 0x7D56: return "1/5"; 572 | case 0x7D57: return "2/5"; 573 | case 0x7D58: return "3/5"; 574 | case 0x7D59: return "4/5"; 575 | case 0x7D5A: return "1/6"; 576 | case 0x7D5B: return "5/6"; 577 | case 0x7D5C: return "1/7"; 578 | case 0x7D5D: return "1/8"; 579 | case 0x7D5E: return "1/9"; 580 | case 0x7D5F: return "1/10"; 581 | case 0x7D60: return "☀"; 582 | case 0x7D61: return "☁"; 583 | case 0x7D62: return "☂"; 584 | case 0x7D63: return "☃"; 585 | case 0x7D64: return "☖"; 586 | case 0x7D65: return "☗"; 587 | case 0x7D66: return "▽"; 588 | case 0x7D67: return "▼"; 589 | case 0x7D68: return "♦"; 590 | case 0x7D69: return "♥"; 591 | case 0x7D6A: return "♣"; 592 | case 0x7D6B: return "♠"; 593 | case 0x7D6C: return "⌺"; 594 | case 0x7D6D: return "⦿"; 595 | case 0x7D6E: return "‼"; 596 | case 0x7D6F: return "⁉"; 597 | case 0x7D70: return "(曇/晴)"; 598 | case 0x7D71: return "☔"; 599 | case 0x7D72: return "(雨)"; 600 | case 0x7D73: return "(雪)"; 601 | case 0x7D74: return "(大雪)"; 602 | case 0x7D75: return "⚡"; 603 | case 0x7D76: return "(雷雨)"; 604 | case 0x7D77: return " "; 605 | case 0x7D78: return "・"; 606 | case 0x7D79: return "・"; 607 | case 0x7D7A: return "♬"; 608 | case 0x7D7B: return "☎"; 609 | 610 | case 0x7E21: return "Ⅰ"; 611 | case 0x7E22: return "Ⅱ"; 612 | case 0x7E23: return "Ⅲ"; 613 | case 0x7E24: return "Ⅳ"; 614 | case 0x7E25: return "Ⅴ"; 615 | case 0x7E26: return "Ⅵ"; 616 | case 0x7E27: return "Ⅶ"; 617 | case 0x7E28: return "Ⅷ"; 618 | case 0x7E29: return "Ⅸ"; 619 | case 0x7E2A: return "Ⅹ"; 620 | case 0x7E2B: return "Ⅺ"; 621 | case 0x7E2C: return "Ⅻ"; 622 | case 0x7E2D: return "⑰"; 623 | case 0x7E2E: return "⑱"; 624 | case 0x7E2F: return "⑲"; 625 | case 0x7E30: return "⑳"; 626 | case 0x7E31: return "⑴"; 627 | case 0x7E32: return "⑵"; 628 | case 0x7E33: return "⑶"; 629 | case 0x7E34: return "⑷"; 630 | case 0x7E35: return "⑸"; 631 | case 0x7E36: return "⑹"; 632 | case 0x7E37: return "⑺"; 633 | case 0x7E38: return "⑻"; 634 | case 0x7E39: return "⑼"; 635 | case 0x7E3A: return "⑽"; 636 | case 0x7E3B: return "⑾"; 637 | case 0x7E3C: return "⑿"; 638 | case 0x7E3D: return "㉑"; 639 | case 0x7E3E: return "㉒"; 640 | case 0x7E3F: return "㉓"; 641 | case 0x7E40: return "㉔"; 642 | case 0x7E41: return "(A)"; 643 | case 0x7E42: return "(B)"; 644 | case 0x7E43: return "(C)"; 645 | case 0x7E44: return "(D)"; 646 | case 0x7E45: return "(E)"; 647 | case 0x7E46: return "(F)"; 648 | case 0x7E47: return "(G)"; 649 | case 0x7E48: return "(H)"; 650 | case 0x7E49: return "(I)"; 651 | case 0x7E4A: return "(J)"; 652 | case 0x7E4B: return "(K)"; 653 | case 0x7E4C: return "(L)"; 654 | case 0x7E4D: return "(M)"; 655 | case 0x7E4E: return "(N)"; 656 | case 0x7E4F: return "(O)"; 657 | case 0x7E50: return "(P)"; 658 | case 0x7E51: return "(Q)"; 659 | case 0x7E52: return "(R)"; 660 | case 0x7E53: return "(S)"; 661 | case 0x7E54: return "(T)"; 662 | case 0x7E55: return "(U)"; 663 | case 0x7E56: return "(V)"; 664 | case 0x7E57: return "(W)"; 665 | case 0x7E58: return "(X)"; 666 | case 0x7E59: return "(Y)"; 667 | case 0x7E5A: return "(Z)"; 668 | case 0x7E5B: return "㉕"; 669 | case 0x7E5C: return "㉖"; 670 | case 0x7E5D: return "㉗"; 671 | case 0x7E5E: return "㉘"; 672 | case 0x7E5F: return "㉙"; 673 | case 0x7E60: return "㉚"; 674 | case 0x7E61: return "①"; 675 | case 0x7E62: return "②"; 676 | case 0x7E63: return "③"; 677 | case 0x7E64: return "④"; 678 | case 0x7E65: return "⑤"; 679 | case 0x7E66: return "⑥"; 680 | case 0x7E67: return "⑦"; 681 | case 0x7E68: return "⑧"; 682 | case 0x7E69: return "⑨"; 683 | case 0x7E6A: return "⑩"; 684 | case 0x7E6B: return "⑪"; 685 | case 0x7E6C: return "⑫"; 686 | case 0x7E6D: return "⑬"; 687 | case 0x7E6E: return "⑭"; 688 | case 0x7E6F: return "⑮"; 689 | case 0x7E70: return "⑯"; 690 | case 0x7E71: return "❶"; 691 | case 0x7E72: return "❷"; 692 | case 0x7E73: return "❸"; 693 | case 0x7E74: return "❹"; 694 | case 0x7E75: return "❺"; 695 | case 0x7E76: return "❻"; 696 | case 0x7E77: return "❼"; 697 | case 0x7E78: return "❽"; 698 | case 0x7E79: return "❾"; 699 | case 0x7E7A: return "❿"; 700 | case 0x7E7B: return "⓫"; 701 | case 0x7E7C: return "⓬"; 702 | case 0x7E7D: return "㉛"; 703 | 704 | case 0x7521: return "㐂"; 705 | case 0x7522: return "亭"; 706 | case 0x7523: return "份"; 707 | case 0x7524: return "仿"; 708 | case 0x7525: return "侚"; 709 | case 0x7526: return "俉"; 710 | case 0x7527: return "傜"; 711 | case 0x7528: return "儞"; 712 | case 0x7529: return "冼"; 713 | case 0x752A: return "㔟"; 714 | case 0x752B: return "匇"; 715 | case 0x752C: return "卡"; 716 | case 0x752D: return "卬"; 717 | case 0x752E: return "詹"; 718 | case 0x752F: return "吉"; 719 | case 0x7530: return "呍"; 720 | case 0x7531: return "咖"; 721 | case 0x7532: return "咜"; 722 | case 0x7533: return "咩"; 723 | case 0x7534: return "唎"; 724 | case 0x7535: return "啊"; 725 | case 0x7536: return "噲"; 726 | case 0x7537: return "囤"; 727 | case 0x7538: return "圳"; 728 | case 0x7539: return "圴"; 729 | case 0x753A: return "塚"; 730 | case 0x753B: return "墀"; 731 | case 0x753C: return "姤"; 732 | case 0x753D: return "娣"; 733 | case 0x753E: return "婕"; 734 | case 0x753F: return "寬"; 735 | case 0x7540: return "﨑"; 736 | case 0x7541: return "㟢"; 737 | case 0x7542: return "庬"; 738 | case 0x7543: return "弴"; 739 | case 0x7544: return "彅"; 740 | case 0x7545: return "德"; 741 | case 0x7546: return "怗"; 742 | case 0x7547: return "恵"; 743 | case 0x7548: return "愰"; 744 | case 0x7549: return "昤"; 745 | case 0x754A: return "曈"; 746 | case 0x754B: return "曙"; 747 | case 0x754C: return "曺"; 748 | case 0x754D: return "曻"; 749 | case 0x754E: return "桒"; 750 | case 0x754F: return "・"; 751 | case 0x7550: return "椑"; 752 | case 0x7551: return "椻"; 753 | case 0x7552: return "橅"; 754 | case 0x7553: return "檑"; 755 | case 0x7554: return "櫛"; 756 | case 0x7555: return "・"; 757 | case 0x7556: return "・"; 758 | case 0x7557: return "・"; 759 | case 0x7558: return "毱"; 760 | case 0x7559: return "泠"; 761 | case 0x755A: return "洮"; 762 | case 0x755B: return "海"; 763 | case 0x755C: return "涿"; 764 | case 0x755D: return "淊"; 765 | case 0x755E: return "淸"; 766 | case 0x755F: return "渚"; 767 | case 0x7560: return "潞"; 768 | case 0x7561: return "濹"; 769 | case 0x7562: return "灤"; 770 | case 0x7563: return "・"; 771 | case 0x7564: return "・"; 772 | case 0x7565: return "煇"; 773 | case 0x7566: return "燁"; 774 | case 0x7567: return "爀"; 775 | case 0x7568: return "玟"; 776 | case 0x7569: return "・"; 777 | case 0x756A: return "珉"; 778 | case 0x756B: return "珖"; 779 | case 0x756C: return "琛"; 780 | case 0x756D: return "琡"; 781 | case 0x756E: return "琢"; 782 | case 0x756F: return "琦"; 783 | case 0x7570: return "琪"; 784 | case 0x7571: return "琬"; 785 | case 0x7572: return "琹"; 786 | case 0x7573: return "瑋"; 787 | case 0x7574: return "㻚"; 788 | case 0x7575: return "畵"; 789 | case 0x7576: return "疁"; 790 | case 0x7577: return "睲"; 791 | case 0x7578: return "䂓"; 792 | case 0x7579: return "磈"; 793 | case 0x757A: return "磠"; 794 | case 0x757B: return "祇"; 795 | case 0x757C: return "禮"; 796 | case 0x757D: return "・"; 797 | case 0x757E: return "・"; 798 | 799 | case 0x7621: return "・"; 800 | case 0x7622: return "秚"; 801 | case 0x7623: return "稞"; 802 | case 0x7624: return "筿"; 803 | case 0x7625: return "簱"; 804 | case 0x7626: return "䉤"; 805 | case 0x7627: return "綋"; 806 | case 0x7628: return "羡"; 807 | case 0x7629: return "脘"; 808 | case 0x762A: return "脺"; 809 | case 0x762B: return "・"; 810 | case 0x762C: return "芮"; 811 | case 0x762D: return "葛"; 812 | case 0x762E: return "蓜"; 813 | case 0x762F: return "蓬"; 814 | case 0x7630: return "蕙"; 815 | case 0x7631: return "藎"; 816 | case 0x7632: return "蝕"; 817 | case 0x7633: return "蟬"; 818 | case 0x7634: return "蠋"; 819 | case 0x7635: return "裵"; 820 | case 0x7636: return "角"; 821 | case 0x7637: return "諶"; 822 | case 0x7638: return "跎"; 823 | case 0x7639: return "辻"; 824 | case 0x763A: return "迶"; 825 | case 0x763B: return "郝"; 826 | case 0x763C: return "鄧"; 827 | case 0x763D: return "鄭"; 828 | case 0x763E: return "醲"; 829 | case 0x763F: return "鈳"; 830 | case 0x7640: return "銈"; 831 | case 0x7641: return "錡"; 832 | case 0x7642: return "鍈"; 833 | case 0x7643: return "閒"; 834 | case 0x7644: return "雞"; 835 | case 0x7645: return "餃"; 836 | case 0x7646: return "饀"; 837 | case 0x7647: return "髙"; 838 | case 0x7648: return "鯖"; 839 | case 0x7649: return "鷗"; 840 | case 0x764A: return "麴"; 841 | case 0x764B: return "麵"; 842 | default: 843 | char buf[16]; 844 | sprintf(buf, "{gaiji 0x%x}", c); 845 | return buf; 846 | } 847 | }/*}}}*/ 848 | -------------------------------------------------------------------------------- /assdumper/assdumper.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "crypto/md5" 6 | "encoding/hex" 7 | "fmt" 8 | "golang.org/x/text/encoding/japanese" 9 | "io" 10 | "os" 11 | "strings" 12 | "time" 13 | "unicode/utf8" 14 | ) 15 | 16 | /* 17 | [B10]: ARIB-STD B10 18 | [ISO]: ISO/IEC 13818-1 19 | */ 20 | 21 | const TS_PACKET_SIZE = 188 22 | 23 | type AnalyzerState struct { 24 | pmtPids map[int]bool 25 | pcrPid int 26 | captionPid int 27 | currentTimestamp SystemClock 28 | clockOffset int64 29 | previousSubtitle string 30 | previousIsBlank bool 31 | previousTimestamp SystemClock 32 | preludePrinted bool 33 | captionPayload []byte 34 | } 35 | 36 | type SystemClock int64 37 | 38 | func main() { 39 | if len(os.Args) == 1 { 40 | fmt.Fprintf(os.Stderr, "usage: %s MPEG2-TS-FILE\n", os.Args[0]) 41 | os.Exit(1) 42 | } 43 | fin, err := os.Open(os.Args[1]) 44 | if err != nil { 45 | panic(err) 46 | } 47 | defer func() { 48 | if err := fin.Close(); err != nil { 49 | panic(err) 50 | } 51 | }() 52 | 53 | reader := bufio.NewReader(fin) 54 | 55 | buf := make([]byte, TS_PACKET_SIZE) 56 | state := new(AnalyzerState) 57 | state.pcrPid = -1 58 | state.captionPid = -1 59 | 60 | for { 61 | err := readFull(reader, buf) 62 | if err == io.EOF { 63 | break 64 | } 65 | if err != nil { 66 | panic(err) 67 | } 68 | 69 | analyzePacket(buf, state) 70 | } 71 | } 72 | 73 | func debugMode() bool { 74 | return os.Getenv("ASSDUMPER_DEBUG") == "1" 75 | } 76 | 77 | func isDRCSEnabled() bool { 78 | return os.Getenv("ASSDUMPER_DRCS") == "1" 79 | } 80 | 81 | func assertSyncByte(packet []byte) { 82 | if packet[0] != 0x47 { 83 | panic("sync_byte failed") 84 | } 85 | } 86 | 87 | func readFull(reader *bufio.Reader, buf []byte) error { 88 | for i := 0; i < len(buf); { 89 | n, err := reader.Read(buf[i:]) 90 | if err != nil { 91 | return err 92 | } 93 | i += n 94 | } 95 | return nil 96 | } 97 | 98 | func analyzePacket(packet []byte, state *AnalyzerState) { 99 | assertSyncByte(packet) 100 | 101 | payload_unit_start_indicator := (packet[1] & 0x40) != 0 102 | pid := int(packet[1]&0x1f)<<8 | int(packet[2]) 103 | hasAdaptation := (packet[3] & 0x20) != 0 104 | hasPayload := (packet[3] & 0x10) != 0 105 | p := packet[4:] 106 | 107 | if hasAdaptation { 108 | // [ISO] 2.4.3.4 109 | // Table 2-6 110 | adaptation_field_length := int(p[0]) 111 | p = p[1:] 112 | pcr_flag := (p[0] & 0x10) != 0 113 | if pcr_flag && pid == state.pcrPid { 114 | state.currentTimestamp = extractPcr(p) 115 | } 116 | if adaptation_field_length >= len(p) { 117 | // TODO: adaptation_field_length could be bigger than 118 | // one packet size. We should handle 119 | // payload_unit_start_indicator and pointer_field more 120 | // correctly. 121 | return 122 | } 123 | p = p[adaptation_field_length:] 124 | } 125 | 126 | if hasPayload { 127 | if pid == 0 { 128 | if len(state.pmtPids) == 0 { 129 | state.pmtPids = extractPmtPids(p[1:]) 130 | fmt.Fprintf(os.Stderr, "Found %d pids: %v\n", len(state.pmtPids), state.pmtPids) 131 | } 132 | } else if state.pmtPids != nil && state.pmtPids[pid] { 133 | if state.captionPid == -1 && payload_unit_start_indicator { 134 | // PMT section 135 | pcrPid := extractPcrPid(p[1:]) 136 | captionPid := extractCaptionPid(p[1:]) 137 | if captionPid != -1 { 138 | fmt.Fprintf(os.Stderr, "caption pid = %d, PCR_PID = %d\n", captionPid, pcrPid) 139 | state.pcrPid = pcrPid 140 | state.captionPid = captionPid 141 | } 142 | } 143 | } else if pid == 0x0014 { 144 | // Time Offset Table 145 | // [B10] 5.2.9 146 | t := extractJstTime(p[1:]) 147 | if t != 0 { 148 | state.clockOffset = t*100 - state.currentTimestamp.centitime() 149 | } 150 | } else if pid == state.captionPid { 151 | if payload_unit_start_indicator { 152 | if len(state.captionPayload) != 0 { 153 | dumpCaption(state.captionPayload, state) 154 | } 155 | state.captionPayload = make([]byte, len(p)) 156 | copy(state.captionPayload, p) 157 | } else { 158 | for _, b := range p { 159 | state.captionPayload = append(state.captionPayload, b) 160 | } 161 | } 162 | } 163 | } 164 | } 165 | 166 | func extractPmtPids(payload []byte) map[int]bool { 167 | // [ISO] 2.4.4.3 168 | // Table 2-25 169 | table_id := payload[0] 170 | pids := make(map[int]bool) 171 | if table_id != 0x00 { 172 | return pids 173 | } 174 | section_length := int(payload[1]&0x0F)<<8 | int(payload[2]) 175 | index := 8 176 | for index < 3+section_length-4 { 177 | program_number := int(payload[index+0])<<8 | int(payload[index+1]) 178 | if program_number != 0 { 179 | program_map_PID := int(payload[index+2]&0x1F)<<8 | int(payload[index+3]) 180 | pids[program_map_PID] = true 181 | } 182 | index += 4 183 | } 184 | return pids 185 | } 186 | 187 | func extractPcrPid(payload []byte) int { 188 | return (int(payload[8]&0x1f) << 8) | int(payload[9]) 189 | } 190 | 191 | func extractCaptionPid(payload []byte) int { 192 | // [ISO] 2.4.4.8 Program Map Table 193 | // Table 2-28 194 | table_id := payload[0] 195 | if table_id != 0x02 { 196 | return -1 197 | } 198 | section_length := int(payload[1]&0x0F)<<8 | int(payload[2]) 199 | if section_length >= len(payload) { 200 | return -1 201 | } 202 | 203 | program_info_length := int(payload[10]&0x0F)<<8 | int(payload[11]) 204 | index := 12 + program_info_length 205 | 206 | for index < 3+section_length-4 { 207 | stream_type := payload[index+0] 208 | ES_info_length := int(payload[index+3]&0xF)<<8 | int(payload[index+4]) 209 | if stream_type == 0x06 { 210 | elementary_PID := int(payload[index+1]&0x1F)<<8 | int(payload[index+2]) 211 | subIndex := index + 5 212 | for subIndex < index+ES_info_length { 213 | // [ISO] 2.6 Program and program element descriptors 214 | descriptor_tag := payload[subIndex+0] 215 | descriptor_length := int(payload[subIndex+1]) 216 | if descriptor_tag == 0x52 { 217 | // [B10] 6.2.16 Stream identifier descriptor 218 | // 表 6-28 219 | component_tag := payload[subIndex+2] 220 | if component_tag == 0x87 { 221 | return elementary_PID 222 | } 223 | } 224 | subIndex += 2 + descriptor_length 225 | } 226 | } 227 | index += 5 + ES_info_length 228 | } 229 | return -1 230 | } 231 | 232 | func extractPcr(payload []byte) SystemClock { 233 | pcr_base := (int64(payload[1]) << 25) | 234 | (int64(payload[2]) << 17) | 235 | (int64(payload[3]) << 9) | 236 | (int64(payload[4]) << 1) | 237 | (int64(payload[5]&0x80) >> 7) 238 | pcr_ext := (int64(payload[5] & 0x01)) | int64(payload[6]) 239 | // [ISO] 2.4.2.2 240 | return SystemClock(pcr_base*300 + pcr_ext) 241 | } 242 | 243 | func extractJstTime(payload []byte) int64 { 244 | if payload[0] != 0x73 { 245 | return 0 246 | } 247 | 248 | // [B10] Appendix C 249 | MJD := (int(payload[3]) << 8) | int(payload[4]) 250 | y := int((float64(MJD) - 15078.2) / 365.25) 251 | m := int((float64(MJD) - 14956.1 - float64(int(float64(y)*365.25))) / 30.6001) 252 | k := 0 253 | if m == 14 || m == 15 { 254 | k = 1 255 | } 256 | year := y + k + 1900 257 | month := m - 1 - k*12 258 | day := MJD - 14956 - int(float64(y)*365.25) - int(float64(m)*30.6001) 259 | hour := decodeBcd(payload[5]) 260 | minute := decodeBcd(payload[6]) 261 | second := decodeBcd(payload[7]) 262 | 263 | str := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02d+09:00", year, month, day, hour, minute, second) 264 | t, err := time.Parse(time.RFC3339, str) 265 | if err != nil { 266 | panic(err) 267 | } 268 | return t.Unix() 269 | } 270 | 271 | func decodeBcd(n byte) int { 272 | return (int(n)>>4)*10 + int(n&0x0f) 273 | } 274 | 275 | func dumpCaption(payload []byte, state *AnalyzerState) { 276 | PES_header_data_length := payload[8] 277 | PES_data_packet_header_length := payload[11+PES_header_data_length] & 0x0F 278 | p := payload[12+PES_header_data_length+PES_data_packet_header_length:] 279 | 280 | // [B24] Table 9-1 (p184) 281 | data_group_id := (p[0] & 0xFC) >> 2 282 | if data_group_id == 0x00 || data_group_id == 0x20 { 283 | // [B24] Table 9-3 (p186) 284 | // caption_management_data 285 | num_languages := p[6] 286 | p = p[7+num_languages*5:] 287 | } else { 288 | // caption_data 289 | p = p[6:] 290 | } 291 | // [B24] Table 9-3 (p186) 292 | data_unit_loop_length := (int(p[0]) << 16) | (int(p[1]) << 8) | int(p[2]) 293 | index := 0 294 | for index < data_unit_loop_length { 295 | q := p[index:] 296 | data_unit_parameter := q[4] 297 | data_unit_size := (int(q[5]) << 16) | (int(q[6]) << 8) | int(q[7]) 298 | data := q[8:] 299 | subtitle := "" 300 | subtitleFound := false 301 | switch data_unit_parameter { 302 | case 0x20: 303 | subtitleFound = true 304 | subtitle = decodeString(data, data_unit_size) 305 | case 0x30: 306 | subtitleFound = true 307 | // DRCS 308 | // ARIB STD-B24 第一編 第2部 付録規定D 309 | numberOfCode := int(data[0]) 310 | data = data[1:] 311 | for i := 0; i < numberOfCode; i++ { 312 | // characterCode := uint16(data[0])<<8 | uint16(data[1]) 313 | numberOfFont := int(data[2]) 314 | data = data[3:] 315 | for j := 0; j < numberOfFont; j++ { 316 | // fontId := data[0] >> 4 317 | mode := data[0] & 0x0f 318 | if mode == 0x00 || mode == 0x01 { 319 | // depth := data[1] 320 | width := int(data[2]) 321 | height := int(data[3]) 322 | pat := "" 323 | for h := 0; h < height; h++ { 324 | for w := 0; w < width/8; w++ { 325 | pat += fmt.Sprintf("%08b", data[4+h*(width/8)+w]) 326 | } 327 | pat += "\n" 328 | } 329 | s, md5sum := replaceDRCS(pat) 330 | if s != "" { 331 | if isDRCSEnabled() { 332 | subtitle = s 333 | } 334 | } else if debugMode() { 335 | fmt.Fprintf(os.Stderr, "Unable to replace DRCS bitmap %s\n", md5sum) 336 | fmt.Fprint(os.Stderr, pat) 337 | } 338 | } else { 339 | if debugMode() { 340 | fmt.Fprintf(os.Stderr, "Compressed mode isn't supported (mode=%d)\n", mode) 341 | } 342 | } 343 | } 344 | } 345 | default: 346 | fmt.Fprintf(os.Stderr, "Unknown data_unit_parameter: 0x%02x\n", data_unit_parameter) 347 | } 348 | index += 5 + data_unit_size 349 | 350 | if subtitleFound { 351 | if len(state.previousSubtitle) != 0 && !(isBlank(state.previousSubtitle) && state.previousIsBlank) { 352 | if state.previousTimestamp == state.currentTimestamp { 353 | state.previousSubtitle += subtitle 354 | continue 355 | } else { 356 | prevTimeCenti := state.previousTimestamp.centitime() + state.clockOffset 357 | curTimeCenti := state.currentTimestamp.centitime() + state.clockOffset 358 | prevTime := prevTimeCenti / 100 359 | curTime := curTimeCenti / 100 360 | prevCenti := prevTimeCenti % 100 361 | curCenti := curTimeCenti % 100 362 | prev := time.Unix(prevTime, 0) 363 | cur := time.Unix(curTime, 0) 364 | if !state.preludePrinted { 365 | printPrelude() 366 | state.preludePrinted = true 367 | } 368 | subtitle := strings.Replace(state.previousSubtitle, "\f", "", -1) 369 | fmt.Printf("Dialogue: 0,%02d:%02d:%02d.%02d,%02d:%02d:%02d.%02d,Default,,,,,,%s\n", 370 | prev.Hour(), prev.Minute(), prev.Second(), prevCenti, 371 | cur.Hour(), cur.Minute(), cur.Second(), curCenti, 372 | subtitle) 373 | } 374 | } 375 | state.previousIsBlank = isBlank(state.previousSubtitle) 376 | state.previousSubtitle = subtitle 377 | state.previousTimestamp = state.currentTimestamp 378 | } 379 | } 380 | } 381 | 382 | func isBlank(str string) bool { 383 | for _, c := range str { 384 | if c != ' ' { 385 | return false 386 | } 387 | } 388 | return true 389 | } 390 | 391 | func printPrelude() { 392 | fmt.Println("[Script Info]") 393 | fmt.Println("ScriptType: v4.00+") 394 | fmt.Println("Collisions: Normal") 395 | fmt.Println("ScaledBorderAndShadow: yes") 396 | fmt.Println("Timer: 100.0000") 397 | fmt.Println("\n[Events]") 398 | } 399 | 400 | func decodeString(bytes []byte, length int) string { 401 | eucjpDecoder := japanese.EUCJP.NewDecoder() 402 | decoded := "" 403 | nonDefaultColor := false 404 | 405 | for i := 0; i < length; i++ { 406 | b := bytes[i] 407 | if 0 <= b && b <= 0x20 { 408 | // ARIB STD-B24 第一編 第2部 表 7-14 409 | // ARIB STD-B24 第一編 第2部 表 7-15 410 | // C0 制御集合 411 | switch b { 412 | case 0x0c: 413 | // CS 414 | decoded += "\f" 415 | case 0x0d: 416 | // APR 417 | decoded += "\\n" 418 | case 0x20: 419 | // SP 420 | decoded += " " 421 | default: 422 | fmt.Fprintf(os.Stderr, "Unhandled C0 code: 0x%02x\n", b) 423 | } 424 | } else if 0x20 < b && b < 0x80 { 425 | if debugMode() { 426 | fmt.Fprintf(os.Stderr, "Unhandled GL code: 0x%02x\n", b) 427 | } 428 | } else if 0x80 <= b && b < 0xA0 { 429 | // ARIB STD-B24 第一編 第2部 表 7-14 430 | // ARIB STD-B24 第一編 第2部 表 7-16 431 | // C1 制御集合 432 | switch b { 433 | case 0x80: 434 | // BKF, black 435 | decoded += "{\\c&H000000&}" 436 | nonDefaultColor = true 437 | case 0x81: 438 | // RDF, red 439 | decoded += "{\\c&H0000ff&}" 440 | nonDefaultColor = true 441 | case 0x82: 442 | // GRF, green 443 | decoded += "{\\c&H00ff00&}" 444 | nonDefaultColor = true 445 | case 0x83: 446 | // YLF, yellow 447 | decoded += "{\\c&H00ffff&}" 448 | nonDefaultColor = true 449 | case 0x84: 450 | // BLF, blue 451 | decoded += "{\\c&Hff0000&}" 452 | nonDefaultColor = true 453 | case 0x85: 454 | // MGF, magenta 455 | decoded += "{\\c&Hff00ff&}" 456 | nonDefaultColor = true 457 | case 0x86: 458 | // CNF, cyan 459 | decoded += "{\\c&Hffff00&}" 460 | nonDefaultColor = true 461 | case 0x87: 462 | // WHF, white 463 | if nonDefaultColor { 464 | decoded += "{\\c&HFFFFFF&}" 465 | nonDefaultColor = false 466 | } 467 | case 0x89: 468 | // MSZ 469 | case 0x8a: 470 | // NSZ 471 | case 0x9d: 472 | // TIME 473 | i += 2 474 | default: 475 | fmt.Fprintf(os.Stderr, "Unhandled C1 code: 0x%02x\n", b) 476 | } 477 | } else if 0xa0 < b && b <= 0xff { 478 | eucjp := make([]byte, 3) 479 | eucjp[0] = bytes[i] 480 | eucjp[1] = bytes[i+1] 481 | eucjp[2] = 0 482 | i++ 483 | 484 | if eucjp[0] == 0xfc && eucjp[1] == 0xa1 { 485 | // FIXME 486 | decoded += "➡" 487 | } else { 488 | buf := make([]byte, 10) 489 | ndst, nsrc, err := eucjpDecoder.Transform(buf, eucjp, true) 490 | if err == nil { 491 | if nsrc == 3 { 492 | c, _ := utf8.DecodeRune(buf) 493 | if c == 0xfffd { 494 | gaiji := (int(eucjp[0]&0x7f) << 8) | int(eucjp[1]&0x7f) 495 | if gaiji != 0x7c21 { 496 | decoded += tryGaiji(gaiji) 497 | } 498 | } else { 499 | decoded += string(buf[:ndst-1]) 500 | } 501 | } else { 502 | fmt.Fprintf(os.Stderr, "eucjp decode failed: ndst=%d, nsrc=%d\n", ndst, nsrc) 503 | } 504 | } else { 505 | fmt.Fprintf(os.Stderr, "eucjp decode error: %v\n", err) 506 | } 507 | } 508 | } 509 | } 510 | return decoded 511 | } 512 | 513 | func replaceDRCS(pattern string) (string, string) { 514 | h := md5.New() 515 | io.WriteString(h, pattern) 516 | md5sum := hex.EncodeToString(h.Sum(nil)) 517 | switch md5sum { 518 | case "4447af4c020758d6b615713ad6640fc5": 519 | return "《", md5sum 520 | case "6d6cf86c3f892dc45b68703bb84068a9": 521 | return "》", md5sum 522 | case "6bcc3c66dc1f853e605613fceda9e648": 523 | return "♬", md5sum 524 | case "ec5a85c9f822a0e27847a2d8d31ab73e": 525 | return "📺", md5sum 526 | case "f64c27d6df14074b2e1f92b3a4985c01": 527 | return "➡", md5sum 528 | default: 529 | return "", md5sum 530 | } 531 | } 532 | 533 | func tryGaiji(c int) string { 534 | switch c { 535 | case 0x7A50: 536 | return "【HV】" 537 | case 0x7A51: 538 | return "【SD】" 539 | case 0x7A52: 540 | return "【P】" 541 | case 0x7A53: 542 | return "【W】" 543 | case 0x7A54: 544 | return "【MV】" 545 | case 0x7A55: 546 | return "【手】" 547 | case 0x7A56: 548 | return "【字】" 549 | case 0x7A57: 550 | return "【双】" 551 | case 0x7A58: 552 | return "【デ】" 553 | case 0x7A59: 554 | return "【S】" 555 | case 0x7A5A: 556 | return "【二】" 557 | case 0x7A5B: 558 | return "【多】" 559 | case 0x7A5C: 560 | return "【解】" 561 | case 0x7A5D: 562 | return "【SS】" 563 | case 0x7A5E: 564 | return "【B】" 565 | case 0x7A5F: 566 | return "【N】" 567 | case 0x7A62: 568 | return "【天】" 569 | case 0x7A63: 570 | return "【交】" 571 | case 0x7A64: 572 | return "【映】" 573 | case 0x7A65: 574 | return "【無】" 575 | case 0x7A66: 576 | return "【料】" 577 | case 0x7A67: 578 | return "【年齢制限】" 579 | case 0x7A68: 580 | return "【前】" 581 | case 0x7A69: 582 | return "【後】" 583 | case 0x7A6A: 584 | return "【再】" 585 | case 0x7A6B: 586 | return "【新】" 587 | case 0x7A6C: 588 | return "【初】" 589 | case 0x7A6D: 590 | return "【終】" 591 | case 0x7A6E: 592 | return "【生】" 593 | case 0x7A6F: 594 | return "【販】" 595 | case 0x7A70: 596 | return "【声】" 597 | case 0x7A71: 598 | return "【吹】" 599 | case 0x7A72: 600 | return "【PPV】" 601 | 602 | case 0x7A60: 603 | return "■" 604 | case 0x7A61: 605 | return "●" 606 | case 0x7A73: 607 | return "(秘)" 608 | case 0x7A74: 609 | return "ほか" 610 | 611 | case 0x7C21: 612 | return "→" 613 | case 0x7C22: 614 | return "←" 615 | case 0x7C23: 616 | return "↑" 617 | case 0x7C24: 618 | return "↓" 619 | case 0x7C25: 620 | return "●" 621 | case 0x7C26: 622 | return "○" 623 | case 0x7C27: 624 | return "年" 625 | case 0x7C28: 626 | return "月" 627 | case 0x7C29: 628 | return "日" 629 | case 0x7C2A: 630 | return "円" 631 | case 0x7C2B: 632 | return "㎡" 633 | case 0x7C2C: 634 | return "㎥" 635 | case 0x7C2D: 636 | return "㎝" 637 | case 0x7C2E: 638 | return "㎠" 639 | case 0x7C2F: 640 | return "㎤" 641 | case 0x7C30: 642 | return "0." 643 | case 0x7C31: 644 | return "1." 645 | case 0x7C32: 646 | return "2." 647 | case 0x7C33: 648 | return "3." 649 | case 0x7C34: 650 | return "4." 651 | case 0x7C35: 652 | return "5." 653 | case 0x7C36: 654 | return "6." 655 | case 0x7C37: 656 | return "7." 657 | case 0x7C38: 658 | return "8." 659 | case 0x7C39: 660 | return "9." 661 | case 0x7C3A: 662 | return "氏" 663 | case 0x7C3B: 664 | return "副" 665 | case 0x7C3C: 666 | return "元" 667 | case 0x7C3D: 668 | return "故" 669 | case 0x7C3E: 670 | return "前" 671 | case 0x7C3F: 672 | return "[新]" 673 | case 0x7C40: 674 | return "0," 675 | case 0x7C41: 676 | return "1," 677 | case 0x7C42: 678 | return "2," 679 | case 0x7C43: 680 | return "3," 681 | case 0x7C44: 682 | return "4," 683 | case 0x7C45: 684 | return "5," 685 | case 0x7C46: 686 | return "6," 687 | case 0x7C47: 688 | return "7," 689 | case 0x7C48: 690 | return "8," 691 | case 0x7C49: 692 | return "9," 693 | case 0x7C4A: 694 | return "(社)" 695 | case 0x7C4B: 696 | return "(財)" 697 | case 0x7C4C: 698 | return "(有)" 699 | case 0x7C4D: 700 | return "(株)" 701 | case 0x7C4E: 702 | return "(代)" 703 | case 0x7C4F: 704 | return "(問)" 705 | case 0x7C50: 706 | return "▶" 707 | case 0x7C51: 708 | return "◀" 709 | case 0x7C52: 710 | return "〖" 711 | case 0x7C53: 712 | return "〗" 713 | case 0x7C54: 714 | return "⟐" 715 | case 0x7C55: 716 | return "^2" 717 | case 0x7C56: 718 | return "^3" 719 | case 0x7C57: 720 | return "(CD)" 721 | case 0x7C58: 722 | return "(vn)" 723 | case 0x7C59: 724 | return "(ob)" 725 | case 0x7C5A: 726 | return "(cb)" 727 | case 0x7C5B: 728 | return "(ce" 729 | case 0x7C5C: 730 | return "mb)" 731 | case 0x7C5D: 732 | return "(hp)" 733 | case 0x7C5E: 734 | return "(br)" 735 | case 0x7C5F: 736 | return "(p)" 737 | case 0x7C60: 738 | return "(s)" 739 | case 0x7C61: 740 | return "(ms)" 741 | case 0x7C62: 742 | return "(t)" 743 | case 0x7C63: 744 | return "(bs)" 745 | case 0x7C64: 746 | return "(b)" 747 | case 0x7C65: 748 | return "(tb)" 749 | case 0x7C66: 750 | return "(tp)" 751 | case 0x7C67: 752 | return "(ds)" 753 | case 0x7C68: 754 | return "(ag)" 755 | case 0x7C69: 756 | return "(eg)" 757 | case 0x7C6A: 758 | return "(vo)" 759 | case 0x7C6B: 760 | return "(fl)" 761 | case 0x7C6C: 762 | return "(ke" 763 | case 0x7C6D: 764 | return "y)" 765 | case 0x7C6E: 766 | return "(sa" 767 | case 0x7C6F: 768 | return "x)" 769 | case 0x7C70: 770 | return "(sy" 771 | case 0x7C71: 772 | return "n)" 773 | case 0x7C72: 774 | return "(or" 775 | case 0x7C73: 776 | return "g)" 777 | case 0x7C74: 778 | return "(pe" 779 | case 0x7C75: 780 | return "r)" 781 | case 0x7C76: 782 | return "(R)" 783 | case 0x7C77: 784 | return "(C)" 785 | case 0x7C78: 786 | return "(箏)" 787 | case 0x7C79: 788 | return "DJ" 789 | case 0x7C7A: 790 | return "[演]" 791 | case 0x7C7B: 792 | return "Fax" 793 | 794 | case 0x7D21: 795 | return "㈪" 796 | case 0x7D22: 797 | return "㈫" 798 | case 0x7D23: 799 | return "㈬" 800 | case 0x7D24: 801 | return "㈭" 802 | case 0x7D25: 803 | return "㈮" 804 | case 0x7D26: 805 | return "㈯" 806 | case 0x7D27: 807 | return "㈰" 808 | case 0x7D28: 809 | return "㈷" 810 | case 0x7D29: 811 | return "㍾" 812 | case 0x7D2A: 813 | return "㍽" 814 | case 0x7D2B: 815 | return "㍼" 816 | case 0x7D2C: 817 | return "㍻" 818 | case 0x7D2D: 819 | return "№" 820 | case 0x7D2E: 821 | return "℡" 822 | case 0x7D2F: 823 | return "〶" 824 | case 0x7D30: 825 | return "○" 826 | case 0x7D31: 827 | return "〔本〕" 828 | case 0x7D32: 829 | return "〔三〕" 830 | case 0x7D33: 831 | return "〔二〕" 832 | case 0x7D34: 833 | return "〔安〕" 834 | case 0x7D35: 835 | return "〔点〕" 836 | case 0x7D36: 837 | return "〔打〕" 838 | case 0x7D37: 839 | return "〔盗〕" 840 | case 0x7D38: 841 | return "〔勝〕" 842 | case 0x7D39: 843 | return "〔敗〕" 844 | case 0x7D3A: 845 | return "〔S〕" 846 | case 0x7D3B: 847 | return "[投]" 848 | case 0x7D3C: 849 | return "[捕]" 850 | case 0x7D3D: 851 | return "[一]" 852 | case 0x7D3E: 853 | return "[二]" 854 | case 0x7D3F: 855 | return "[三]" 856 | case 0x7D40: 857 | return "[遊]" 858 | case 0x7D41: 859 | return "[左]" 860 | case 0x7D42: 861 | return "[中]" 862 | case 0x7D43: 863 | return "[右]" 864 | case 0x7D44: 865 | return "[指]" 866 | case 0x7D45: 867 | return "[走]" 868 | case 0x7D46: 869 | return "[打]" 870 | case 0x7D47: 871 | return "㍑" 872 | case 0x7D48: 873 | return "㎏" 874 | case 0x7D49: 875 | return "㎐" 876 | case 0x7D4A: 877 | return "ha" 878 | case 0x7D4B: 879 | return "㎞" 880 | case 0x7D4C: 881 | return "㎢" 882 | case 0x7D4D: 883 | return "㍱" 884 | case 0x7D4E: 885 | return "・" 886 | case 0x7D4F: 887 | return "・" 888 | case 0x7D50: 889 | return "1/2" 890 | case 0x7D51: 891 | return "0/3" 892 | case 0x7D52: 893 | return "1/3" 894 | case 0x7D53: 895 | return "2/3" 896 | case 0x7D54: 897 | return "1/4" 898 | case 0x7D55: 899 | return "3/4" 900 | case 0x7D56: 901 | return "1/5" 902 | case 0x7D57: 903 | return "2/5" 904 | case 0x7D58: 905 | return "3/5" 906 | case 0x7D59: 907 | return "4/5" 908 | case 0x7D5A: 909 | return "1/6" 910 | case 0x7D5B: 911 | return "5/6" 912 | case 0x7D5C: 913 | return "1/7" 914 | case 0x7D5D: 915 | return "1/8" 916 | case 0x7D5E: 917 | return "1/9" 918 | case 0x7D5F: 919 | return "1/10" 920 | case 0x7D60: 921 | return "☀" 922 | case 0x7D61: 923 | return "☁" 924 | case 0x7D62: 925 | return "☂" 926 | case 0x7D63: 927 | return "☃" 928 | case 0x7D64: 929 | return "☖" 930 | case 0x7D65: 931 | return "☗" 932 | case 0x7D66: 933 | return "▽" 934 | case 0x7D67: 935 | return "▼" 936 | case 0x7D68: 937 | return "♦" 938 | case 0x7D69: 939 | return "♥" 940 | case 0x7D6A: 941 | return "♣" 942 | case 0x7D6B: 943 | return "♠" 944 | case 0x7D6C: 945 | return "⌺" 946 | case 0x7D6D: 947 | return "⦿" 948 | case 0x7D6E: 949 | return "‼" 950 | case 0x7D6F: 951 | return "⁉" 952 | case 0x7D70: 953 | return "(曇/晴)" 954 | case 0x7D71: 955 | return "☔" 956 | case 0x7D72: 957 | return "(雨)" 958 | case 0x7D73: 959 | return "(雪)" 960 | case 0x7D74: 961 | return "(大雪)" 962 | case 0x7D75: 963 | return "⚡" 964 | case 0x7D76: 965 | return "(雷雨)" 966 | case 0x7D77: 967 | return " " 968 | case 0x7D78: 969 | return "・" 970 | case 0x7D79: 971 | return "・" 972 | case 0x7D7A: 973 | return "♬" 974 | case 0x7D7B: 975 | return "☎" 976 | 977 | case 0x7E21: 978 | return "Ⅰ" 979 | case 0x7E22: 980 | return "Ⅱ" 981 | case 0x7E23: 982 | return "Ⅲ" 983 | case 0x7E24: 984 | return "Ⅳ" 985 | case 0x7E25: 986 | return "Ⅴ" 987 | case 0x7E26: 988 | return "Ⅵ" 989 | case 0x7E27: 990 | return "Ⅶ" 991 | case 0x7E28: 992 | return "Ⅷ" 993 | case 0x7E29: 994 | return "Ⅸ" 995 | case 0x7E2A: 996 | return "Ⅹ" 997 | case 0x7E2B: 998 | return "Ⅺ" 999 | case 0x7E2C: 1000 | return "Ⅻ" 1001 | case 0x7E2D: 1002 | return "⑰" 1003 | case 0x7E2E: 1004 | return "⑱" 1005 | case 0x7E2F: 1006 | return "⑲" 1007 | case 0x7E30: 1008 | return "⑳" 1009 | case 0x7E31: 1010 | return "⑴" 1011 | case 0x7E32: 1012 | return "⑵" 1013 | case 0x7E33: 1014 | return "⑶" 1015 | case 0x7E34: 1016 | return "⑷" 1017 | case 0x7E35: 1018 | return "⑸" 1019 | case 0x7E36: 1020 | return "⑹" 1021 | case 0x7E37: 1022 | return "⑺" 1023 | case 0x7E38: 1024 | return "⑻" 1025 | case 0x7E39: 1026 | return "⑼" 1027 | case 0x7E3A: 1028 | return "⑽" 1029 | case 0x7E3B: 1030 | return "⑾" 1031 | case 0x7E3C: 1032 | return "⑿" 1033 | case 0x7E3D: 1034 | return "㉑" 1035 | case 0x7E3E: 1036 | return "㉒" 1037 | case 0x7E3F: 1038 | return "㉓" 1039 | case 0x7E40: 1040 | return "㉔" 1041 | case 0x7E41: 1042 | return "(A)" 1043 | case 0x7E42: 1044 | return "(B)" 1045 | case 0x7E43: 1046 | return "(C)" 1047 | case 0x7E44: 1048 | return "(D)" 1049 | case 0x7E45: 1050 | return "(E)" 1051 | case 0x7E46: 1052 | return "(F)" 1053 | case 0x7E47: 1054 | return "(G)" 1055 | case 0x7E48: 1056 | return "(H)" 1057 | case 0x7E49: 1058 | return "(I)" 1059 | case 0x7E4A: 1060 | return "(J)" 1061 | case 0x7E4B: 1062 | return "(K)" 1063 | case 0x7E4C: 1064 | return "(L)" 1065 | case 0x7E4D: 1066 | return "(M)" 1067 | case 0x7E4E: 1068 | return "(N)" 1069 | case 0x7E4F: 1070 | return "(O)" 1071 | case 0x7E50: 1072 | return "(P)" 1073 | case 0x7E51: 1074 | return "(Q)" 1075 | case 0x7E52: 1076 | return "(R)" 1077 | case 0x7E53: 1078 | return "(S)" 1079 | case 0x7E54: 1080 | return "(T)" 1081 | case 0x7E55: 1082 | return "(U)" 1083 | case 0x7E56: 1084 | return "(V)" 1085 | case 0x7E57: 1086 | return "(W)" 1087 | case 0x7E58: 1088 | return "(X)" 1089 | case 0x7E59: 1090 | return "(Y)" 1091 | case 0x7E5A: 1092 | return "(Z)" 1093 | case 0x7E5B: 1094 | return "㉕" 1095 | case 0x7E5C: 1096 | return "㉖" 1097 | case 0x7E5D: 1098 | return "㉗" 1099 | case 0x7E5E: 1100 | return "㉘" 1101 | case 0x7E5F: 1102 | return "㉙" 1103 | case 0x7E60: 1104 | return "㉚" 1105 | case 0x7E61: 1106 | return "①" 1107 | case 0x7E62: 1108 | return "②" 1109 | case 0x7E63: 1110 | return "③" 1111 | case 0x7E64: 1112 | return "④" 1113 | case 0x7E65: 1114 | return "⑤" 1115 | case 0x7E66: 1116 | return "⑥" 1117 | case 0x7E67: 1118 | return "⑦" 1119 | case 0x7E68: 1120 | return "⑧" 1121 | case 0x7E69: 1122 | return "⑨" 1123 | case 0x7E6A: 1124 | return "⑩" 1125 | case 0x7E6B: 1126 | return "⑪" 1127 | case 0x7E6C: 1128 | return "⑫" 1129 | case 0x7E6D: 1130 | return "⑬" 1131 | case 0x7E6E: 1132 | return "⑭" 1133 | case 0x7E6F: 1134 | return "⑮" 1135 | case 0x7E70: 1136 | return "⑯" 1137 | case 0x7E71: 1138 | return "❶" 1139 | case 0x7E72: 1140 | return "❷" 1141 | case 0x7E73: 1142 | return "❸" 1143 | case 0x7E74: 1144 | return "❹" 1145 | case 0x7E75: 1146 | return "❺" 1147 | case 0x7E76: 1148 | return "❻" 1149 | case 0x7E77: 1150 | return "❼" 1151 | case 0x7E78: 1152 | return "❽" 1153 | case 0x7E79: 1154 | return "❾" 1155 | case 0x7E7A: 1156 | return "❿" 1157 | case 0x7E7B: 1158 | return "⓫" 1159 | case 0x7E7C: 1160 | return "⓬" 1161 | case 0x7E7D: 1162 | return "㉛" 1163 | 1164 | case 0x7521: 1165 | return "㐂" 1166 | case 0x7522: 1167 | return "亭" 1168 | case 0x7523: 1169 | return "份" 1170 | case 0x7524: 1171 | return "仿" 1172 | case 0x7525: 1173 | return "侚" 1174 | case 0x7526: 1175 | return "俉" 1176 | case 0x7527: 1177 | return "傜" 1178 | case 0x7528: 1179 | return "儞" 1180 | case 0x7529: 1181 | return "冼" 1182 | case 0x752A: 1183 | return "㔟" 1184 | case 0x752B: 1185 | return "匇" 1186 | case 0x752C: 1187 | return "卡" 1188 | case 0x752D: 1189 | return "卬" 1190 | case 0x752E: 1191 | return "詹" 1192 | case 0x752F: 1193 | return "吉" 1194 | case 0x7530: 1195 | return "呍" 1196 | case 0x7531: 1197 | return "咖" 1198 | case 0x7532: 1199 | return "咜" 1200 | case 0x7533: 1201 | return "咩" 1202 | case 0x7534: 1203 | return "唎" 1204 | case 0x7535: 1205 | return "啊" 1206 | case 0x7536: 1207 | return "噲" 1208 | case 0x7537: 1209 | return "囤" 1210 | case 0x7538: 1211 | return "圳" 1212 | case 0x7539: 1213 | return "圴" 1214 | case 0x753A: 1215 | return "塚" 1216 | case 0x753B: 1217 | return "墀" 1218 | case 0x753C: 1219 | return "姤" 1220 | case 0x753D: 1221 | return "娣" 1222 | case 0x753E: 1223 | return "婕" 1224 | case 0x753F: 1225 | return "寬" 1226 | case 0x7540: 1227 | return "﨑" 1228 | case 0x7541: 1229 | return "㟢" 1230 | case 0x7542: 1231 | return "庬" 1232 | case 0x7543: 1233 | return "弴" 1234 | case 0x7544: 1235 | return "彅" 1236 | case 0x7545: 1237 | return "德" 1238 | case 0x7546: 1239 | return "怗" 1240 | case 0x7547: 1241 | return "恵" 1242 | case 0x7548: 1243 | return "愰" 1244 | case 0x7549: 1245 | return "昤" 1246 | case 0x754A: 1247 | return "曈" 1248 | case 0x754B: 1249 | return "曙" 1250 | case 0x754C: 1251 | return "曺" 1252 | case 0x754D: 1253 | return "曻" 1254 | case 0x754E: 1255 | return "桒" 1256 | case 0x754F: 1257 | return "・" 1258 | case 0x7550: 1259 | return "椑" 1260 | case 0x7551: 1261 | return "椻" 1262 | case 0x7552: 1263 | return "橅" 1264 | case 0x7553: 1265 | return "檑" 1266 | case 0x7554: 1267 | return "櫛" 1268 | case 0x7555: 1269 | return "・" 1270 | case 0x7556: 1271 | return "・" 1272 | case 0x7557: 1273 | return "・" 1274 | case 0x7558: 1275 | return "毱" 1276 | case 0x7559: 1277 | return "泠" 1278 | case 0x755A: 1279 | return "洮" 1280 | case 0x755B: 1281 | return "海" 1282 | case 0x755C: 1283 | return "涿" 1284 | case 0x755D: 1285 | return "淊" 1286 | case 0x755E: 1287 | return "淸" 1288 | case 0x755F: 1289 | return "渚" 1290 | case 0x7560: 1291 | return "潞" 1292 | case 0x7561: 1293 | return "濹" 1294 | case 0x7562: 1295 | return "灤" 1296 | case 0x7563: 1297 | return "・" 1298 | case 0x7564: 1299 | return "・" 1300 | case 0x7565: 1301 | return "煇" 1302 | case 0x7566: 1303 | return "燁" 1304 | case 0x7567: 1305 | return "爀" 1306 | case 0x7568: 1307 | return "玟" 1308 | case 0x7569: 1309 | return "・" 1310 | case 0x756A: 1311 | return "珉" 1312 | case 0x756B: 1313 | return "珖" 1314 | case 0x756C: 1315 | return "琛" 1316 | case 0x756D: 1317 | return "琡" 1318 | case 0x756E: 1319 | return "琢" 1320 | case 0x756F: 1321 | return "琦" 1322 | case 0x7570: 1323 | return "琪" 1324 | case 0x7571: 1325 | return "琬" 1326 | case 0x7572: 1327 | return "琹" 1328 | case 0x7573: 1329 | return "瑋" 1330 | case 0x7574: 1331 | return "㻚" 1332 | case 0x7575: 1333 | return "畵" 1334 | case 0x7576: 1335 | return "疁" 1336 | case 0x7577: 1337 | return "睲" 1338 | case 0x7578: 1339 | return "䂓" 1340 | case 0x7579: 1341 | return "磈" 1342 | case 0x757A: 1343 | return "磠" 1344 | case 0x757B: 1345 | return "祇" 1346 | case 0x757C: 1347 | return "禮" 1348 | case 0x757D: 1349 | return "・" 1350 | case 0x757E: 1351 | return "・" 1352 | 1353 | case 0x7621: 1354 | return "・" 1355 | case 0x7622: 1356 | return "秚" 1357 | case 0x7623: 1358 | return "稞" 1359 | case 0x7624: 1360 | return "筿" 1361 | case 0x7625: 1362 | return "簱" 1363 | case 0x7626: 1364 | return "䉤" 1365 | case 0x7627: 1366 | return "綋" 1367 | case 0x7628: 1368 | return "羡" 1369 | case 0x7629: 1370 | return "脘" 1371 | case 0x762A: 1372 | return "脺" 1373 | case 0x762B: 1374 | return "・" 1375 | case 0x762C: 1376 | return "芮" 1377 | case 0x762D: 1378 | return "葛" 1379 | case 0x762E: 1380 | return "蓜" 1381 | case 0x762F: 1382 | return "蓬" 1383 | case 0x7630: 1384 | return "蕙" 1385 | case 0x7631: 1386 | return "藎" 1387 | case 0x7632: 1388 | return "蝕" 1389 | case 0x7633: 1390 | return "蟬" 1391 | case 0x7634: 1392 | return "蠋" 1393 | case 0x7635: 1394 | return "裵" 1395 | case 0x7636: 1396 | return "角" 1397 | case 0x7637: 1398 | return "諶" 1399 | case 0x7638: 1400 | return "跎" 1401 | case 0x7639: 1402 | return "辻" 1403 | case 0x763A: 1404 | return "迶" 1405 | case 0x763B: 1406 | return "郝" 1407 | case 0x763C: 1408 | return "鄧" 1409 | case 0x763D: 1410 | return "鄭" 1411 | case 0x763E: 1412 | return "醲" 1413 | case 0x763F: 1414 | return "鈳" 1415 | case 0x7640: 1416 | return "銈" 1417 | case 0x7641: 1418 | return "錡" 1419 | case 0x7642: 1420 | return "鍈" 1421 | case 0x7643: 1422 | return "閒" 1423 | case 0x7644: 1424 | return "雞" 1425 | case 0x7645: 1426 | return "餃" 1427 | case 0x7646: 1428 | return "饀" 1429 | case 0x7647: 1430 | return "髙" 1431 | case 0x7648: 1432 | return "鯖" 1433 | case 0x7649: 1434 | return "鷗" 1435 | case 0x764A: 1436 | return "麴" 1437 | case 0x764B: 1438 | return "麵" 1439 | default: 1440 | return fmt.Sprintf("{gaiji 0x%x}", c) 1441 | } 1442 | } 1443 | 1444 | const K int64 = 27000000 1445 | 1446 | func (clock SystemClock) centitime() int64 { 1447 | return int64(clock) / (K / 100) 1448 | } 1449 | -------------------------------------------------------------------------------- /clean-ts/.gitignore: -------------------------------------------------------------------------------- 1 | clean-ts 2 | 3 | CMakeCache.txt 4 | CMakeFiles 5 | Makefile 6 | cmake_install.cmake 7 | install_manifest.txt 8 | -------------------------------------------------------------------------------- /clean-ts/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(clean-ts) 2 | cmake_minimum_required(VERSION 2.8) 3 | 4 | include(FindPkgConfig) 5 | pkg_check_modules(FFMPEG REQUIRED libavcodec libavformat libavutil) 6 | include_directories(${FFMPEG_INCLUDE_DIRS}) 7 | link_directories(${FFMPEG_LIBRARY_DIRS}) 8 | link_libraries(${FFMPEG_LIBRARIES}) 9 | 10 | add_definitions(-Wall -W) 11 | set(CMAKE_C_FLAGS_RELEASE "-O3") 12 | 13 | if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") 14 | set(CMAKE_C_FLAGS_DEBUG "-O1 -g -DCLEAN_TS_DEBUG") 15 | else() 16 | set(CMAKE_C_FLAGS_DEBUG "-Og -g -DCLEAN_TS_DEBUG") 17 | endif() 18 | 19 | add_executable(clean-ts clean-ts.c) 20 | 21 | install(PROGRAMS clean-ts DESTINATION bin) 22 | -------------------------------------------------------------------------------- /clean-ts/README.md: -------------------------------------------------------------------------------- 1 | # clean-ts 2 | FFmpeg や MPlayer でうまく処理できるように MPEG-2 TS ファイルを変換する。 3 | 4 | 基本的には `ffmpeg -i infile.ts -acodec copy -vcodec copy -y outfile.ts` と同じように、主要なビデオストリームとオーディオストリームのみを残した MPEG-2 TS ファイルを生成する。 5 | 6 | 「主要な」ストリームを「id が最も小さい Program に属しているストリーム」としている。 7 | FFmpeg に `av_find_best_stream` という API があり、これは解像度やビットレートから「主要な」ストリームを判断している。 8 | ほとんどの場合 `av_find_best_stream` でうまくいくが、マルチ編成時にサブチャンネルを選択することがあったので、Program id を判断基準にしている。 9 | 10 | このプログラムは多重音声のケースにも対応している。ここでいう多重音声とは複数の音声ストリームが存在するものを指す。 11 | 番組本編が始まる前から音声ストリームが存在するものの、そのときのサンプルレートが0であり、直前になってから正常なサンプルレートのデータになり本編が多重音声で始まる、といったケースがある。 12 | このような切り替えが発生する場合、FFmpeg はうまく扱うことができないので、適切な位置でカットする必要がある。 13 | 14 | ## Requirements 15 | - ffmpeg >= 1.1 16 | 17 | ## Install 18 | ```sh 19 | cmake . -DCMAKE_BUILD_TYPE=release -DCMAKE_INSTALL_PREFIX=/usr 20 | make install 21 | ``` 22 | 23 | あるいは単純に 24 | 25 | ```sh 26 | gcc -o clean-ts -O3 -lavcodec -lavformat -lavutil clean-ts.c 27 | cp clean-ts /usr/bin/clean-ts 28 | ``` 29 | -------------------------------------------------------------------------------- /clean-ts/clean-ts.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Kohei Suzuki 3 | * 4 | * MIT License 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining 7 | * a copy of this software and associated documentation files (the 8 | * "Software"), to deal in the Software without restriction, including 9 | * without limitation the rights to use, copy, modify, merge, publish, 10 | * distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to 12 | * the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be 15 | * included in all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 21 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | static const int TS_PACKET_SIZE = 188; 33 | 34 | #define FAIL_IF_ERROR(s) err = (s); if (err < 0) goto fail 35 | 36 | #ifdef CLEAN_TS_DEBUG 37 | # define DPRINTF(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__) 38 | #else 39 | # define DPRINTF(fmt, ...) 40 | #endif 41 | 42 | static int find_main_streams(const AVFormatContext *ic, AVStream **input_streams, size_t input_stream_size, size_t *num_found_ptr) 43 | { 44 | /* Select audio and video in the most small program id */ 45 | static const int INVALID_PROGRAM_ID = 1000000000; 46 | int program_id = INVALID_PROGRAM_ID; 47 | unsigned i; 48 | 49 | *num_found_ptr = 0; 50 | DPRINTF("nb_programs = %d\n", ic->nb_programs); 51 | for (i = 0; i < ic->nb_programs; i++) { 52 | AVProgram *program = ic->programs[i]; 53 | size_t num_found = 0; 54 | unsigned j; 55 | int audio_found = 0, video_found = 0; 56 | 57 | if (program_id < program->id) { 58 | continue; 59 | } 60 | for (j = 0; j < program->nb_stream_indexes; j++) { 61 | AVStream *stream = ic->streams[program->stream_index[j]]; 62 | const enum AVMediaType media_type = stream->codecpar->codec_type; 63 | switch (media_type) { 64 | case AVMEDIA_TYPE_AUDIO: 65 | case AVMEDIA_TYPE_VIDEO: 66 | DPRINTF("programs[%d]: %s %u [0x%x] duration=%" PRId64 "\n", 67 | program->id, 68 | media_type == AVMEDIA_TYPE_AUDIO ? "audio" : "video", 69 | stream->index, stream->id, stream->duration); 70 | if (stream->duration > 0LL || stream->duration == AV_NOPTS_VALUE) { 71 | if (num_found >= input_stream_size) { 72 | fprintf(stderr, "Too many streams found: %zu\n", num_found); 73 | return AVERROR_STREAM_NOT_FOUND; 74 | } 75 | input_streams[num_found++] = stream; 76 | if (media_type == AVMEDIA_TYPE_AUDIO) { 77 | audio_found = 1; 78 | } else { 79 | video_found = 1; 80 | } 81 | } 82 | break; 83 | default: 84 | break; 85 | } 86 | } 87 | if (audio_found && video_found) { 88 | program_id = program->id; 89 | *num_found_ptr = num_found; 90 | } 91 | } 92 | if (program_id == INVALID_PROGRAM_ID) { 93 | return AVERROR_STREAM_NOT_FOUND; 94 | } else { 95 | return 0; 96 | } 97 | } 98 | 99 | static int clean_ts(const char *infile, const char *outfile, int64_t npackets, 100 | int log_level) { 101 | AVFormatContext *ic = NULL, *oc = NULL; 102 | int err = 0; 103 | AVStream **output_streams = NULL; 104 | 105 | FAIL_IF_ERROR(avformat_open_input(&ic, infile, NULL, NULL)); 106 | avio_seek(ic->pb, npackets * TS_PACKET_SIZE, SEEK_SET); 107 | FAIL_IF_ERROR(avformat_find_stream_info(ic, NULL)); 108 | 109 | av_log_set_level(log_level); 110 | 111 | AVStream *input_streams[8] = { NULL }; 112 | size_t input_stream_size; 113 | FAIL_IF_ERROR(find_main_streams(ic, input_streams, sizeof(input_streams)/sizeof(input_streams[0]), &input_stream_size)); 114 | DPRINTF("%zu streams found\n", input_stream_size); 115 | 116 | FAIL_IF_ERROR(avformat_alloc_output_context2(&oc, NULL, NULL, outfile)); 117 | output_streams = av_mallocz_array(input_stream_size, sizeof(*output_streams)); 118 | size_t i; 119 | for (i = 0; i < input_stream_size; i++) { 120 | const AVCodec *codec = avcodec_find_encoder(input_streams[i]->codecpar->codec_id); 121 | output_streams[i] = avformat_new_stream(oc, codec); 122 | DPRINTF("%d: Copy from [0x%x]\n", output_streams[i]->index, input_streams[i]->index); 123 | FAIL_IF_ERROR(avcodec_parameters_copy(output_streams[i]->codecpar, 124 | input_streams[i]->codecpar)); 125 | output_streams[i]->time_base = input_streams[i]->time_base; 126 | } 127 | 128 | if (!(oc->oformat->flags & AVFMT_NOFILE)) { 129 | FAIL_IF_ERROR(avio_open(&oc->pb, outfile, AVIO_FLAG_WRITE)); 130 | } 131 | 132 | FAIL_IF_ERROR(avformat_write_header(oc, NULL)); 133 | AVPacket packet; 134 | int error_count = 0; 135 | while ((err = av_read_frame(ic, &packet)) >= 0) { 136 | const AVStream *in_stream = ic->streams[packet.stream_index]; 137 | AVStream *out_stream = NULL; 138 | for (i = 0; i < input_stream_size; i++) { 139 | if (in_stream == input_streams[i]) { 140 | out_stream = output_streams[i]; 141 | } 142 | } 143 | if (out_stream != NULL) { 144 | packet.stream_index = out_stream->index; 145 | packet.pts = av_rescale_q_rnd(packet.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX); 146 | packet.dts = av_rescale_q_rnd(packet.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX); 147 | packet.duration = av_rescale_q_rnd(packet.duration, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX); 148 | packet.pos = -1; 149 | err = av_interleaved_write_frame(oc, &packet); 150 | if (err < 0) { 151 | fprintf(stderr, "av_interleaved_write_frame(): %s (at %"PRId64")\n", av_err2str(err), avio_tell(ic->pb)); 152 | ++error_count; 153 | } 154 | } 155 | av_packet_unref(&packet); 156 | if (error_count >= 10) { 157 | goto fail; 158 | } 159 | } 160 | if (err != AVERROR_EOF) { 161 | goto fail; 162 | } 163 | FAIL_IF_ERROR(av_write_trailer(oc)); 164 | 165 | fail: 166 | avformat_close_input(&ic); 167 | if (oc != NULL && oc->pb != NULL) { 168 | avio_close(oc->pb); 169 | } 170 | avformat_free_context(oc); 171 | av_free(output_streams); 172 | return err; 173 | } 174 | 175 | static unsigned count_audio_streams(const char *infile, int64_t npackets) { 176 | AVFormatContext *ic = NULL; 177 | int err = 0; 178 | unsigned i, audio_count = 0; 179 | 180 | FAIL_IF_ERROR(avformat_open_input(&ic, infile, NULL, NULL)); 181 | avio_seek(ic->pb, npackets * TS_PACKET_SIZE, SEEK_SET); 182 | FAIL_IF_ERROR(avformat_find_stream_info(ic, NULL)); 183 | 184 | for (i = 0; i < ic->nb_streams; i++) { 185 | const AVStream *stream = ic->streams[i]; 186 | const AVCodecParameters *params = stream->codecpar; 187 | switch (params->codec_type) { 188 | case AVMEDIA_TYPE_AUDIO: 189 | if ((stream->duration > 0LL || stream->duration == AV_NOPTS_VALUE) && 190 | params->format != AV_SAMPLE_FMT_NONE && params->sample_rate != 0) { 191 | ++audio_count; 192 | } 193 | break; 194 | default: 195 | break; 196 | } 197 | } 198 | 199 | DPRINTF("count_audio_streams: npackets=%" PRId64 ": audio_count=%u\n", 200 | npackets, audio_count); 201 | 202 | fail: 203 | avformat_close_input(&ic); 204 | 205 | return audio_count; 206 | } 207 | 208 | static int64_t find_multi_audio_cutpoint(const char *infile, int64_t lo, int64_t hi) { 209 | unsigned lo_count, hi_count; 210 | 211 | lo_count = count_audio_streams(infile, lo); 212 | hi_count = count_audio_streams(infile, hi); 213 | if (lo_count == hi_count) { 214 | return lo; 215 | } 216 | 217 | while (lo < hi) { 218 | DPRINTF("find_multi_audio_cutpoint: %" PRId64 " - %" PRId64 "\n", lo, hi); 219 | const int64_t mid = (lo + hi) / 2; 220 | const unsigned c = count_audio_streams(infile, mid); 221 | if (c == lo_count) { 222 | lo = mid + 1; 223 | } else { 224 | hi = mid; 225 | } 226 | } 227 | 228 | DPRINTF("find_multi_audio_cutpoint: result=%" PRId64 "\n", lo); 229 | return lo; 230 | } 231 | 232 | int main(int argc, char *argv[]) 233 | { 234 | static const struct option long_options[] = { 235 | { "retry", no_argument, 0, 0 }, 236 | { 0, 0, 0, 0 }, 237 | }; 238 | int option_index = 0; 239 | int enable_retry = 0; 240 | while (getopt_long(argc, argv, "", long_options, &option_index) == 0) { 241 | switch (option_index) { 242 | case 0: 243 | enable_retry = 1; 244 | break; 245 | } 246 | } 247 | if (optind + 2 != argc) { 248 | fprintf(stderr, "Usage: %s [--retry] input.ts output.ts\n", argv[0]); 249 | return 1; 250 | } 251 | 252 | const char *infile = argv[optind], *outfile = argv[optind+1]; 253 | av_register_all(); 254 | av_log_set_level(AV_LOG_FATAL); 255 | 256 | static const int MAX_PACKETS = 200000; 257 | int err; 258 | int64_t npackets = 0; 259 | 260 | npackets = find_multi_audio_cutpoint(infile, npackets, MAX_PACKETS); 261 | 262 | if (npackets < 0) { 263 | err = npackets; 264 | } else { 265 | err = clean_ts(infile, outfile, npackets, AV_LOG_ERROR); 266 | if (err == -EINVAL && enable_retry) { 267 | DPRINTF("Retry clean_ts by binary search\n"); 268 | int lo = npackets, hi = MAX_PACKETS; 269 | while (lo < hi) { 270 | const int mid = (lo + hi) / 2; 271 | DPRINTF(" Try npackets=%d\n", mid); 272 | err = clean_ts(infile, outfile, mid, AV_LOG_FATAL); 273 | if (err == -EINVAL) { 274 | DPRINTF(" Failed\n"); 275 | lo = mid+1; 276 | } else if (err == 0) { 277 | DPRINTF(" Succeeded\n"); 278 | hi = mid; 279 | } else { 280 | DPRINTF(" Error\n"); 281 | break; 282 | } 283 | } 284 | DPRINTF("Determined %d\n", lo); 285 | err = clean_ts(infile, outfile, lo, AV_LOG_ERROR); 286 | } 287 | } 288 | 289 | if (err < 0) { 290 | fprintf(stderr, "ERROR: %s\n", av_err2str(err)); 291 | } 292 | return -err; 293 | } 294 | -------------------------------------------------------------------------------- /encoder/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /.terraform 3 | /tfplan 4 | -------------------------------------------------------------------------------- /encoder/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "aho-corasick" 5 | version = "0.7.15" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" 8 | dependencies = [ 9 | "memchr", 10 | ] 11 | 12 | [[package]] 13 | name = "ansi_term" 14 | version = "0.11.0" 15 | source = "registry+https://github.com/rust-lang/crates.io-index" 16 | checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 17 | dependencies = [ 18 | "winapi 0.3.9", 19 | ] 20 | 21 | [[package]] 22 | name = "anyhow" 23 | version = "1.0.34" 24 | source = "registry+https://github.com/rust-lang/crates.io-index" 25 | checksum = "bf8dcb5b4bbaa28653b647d8c77bd4ed40183b48882e130c1f1ffb73de069fd7" 26 | 27 | [[package]] 28 | name = "arrayref" 29 | version = "0.3.6" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" 32 | 33 | [[package]] 34 | name = "arrayvec" 35 | version = "0.5.2" 36 | source = "registry+https://github.com/rust-lang/crates.io-index" 37 | checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" 38 | 39 | [[package]] 40 | name = "async-channel" 41 | version = "1.5.1" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | checksum = "59740d83946db6a5af71ae25ddf9562c2b176b2ca42cf99a455f09f4a220d6b9" 44 | dependencies = [ 45 | "concurrent-queue", 46 | "event-listener", 47 | "futures-core", 48 | ] 49 | 50 | [[package]] 51 | name = "async-executor" 52 | version = "1.3.0" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "d373d78ded7d0b3fa8039375718cde0aace493f2e34fb60f51cbf567562ca801" 55 | dependencies = [ 56 | "async-task", 57 | "concurrent-queue", 58 | "fastrand", 59 | "futures-lite", 60 | "once_cell", 61 | "vec-arena", 62 | ] 63 | 64 | [[package]] 65 | name = "async-global-executor" 66 | version = "1.4.3" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "73079b49cd26b8fd5a15f68fc7707fc78698dc2a3d61430f2a7a9430230dfa04" 69 | dependencies = [ 70 | "async-executor", 71 | "async-io", 72 | "futures-lite", 73 | "num_cpus", 74 | "once_cell", 75 | ] 76 | 77 | [[package]] 78 | name = "async-io" 79 | version = "1.1.10" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "d54bc4c1c7292475efb2253227dbcfad8fe1ca4c02bc62c510cc2f3da5c4704e" 82 | dependencies = [ 83 | "concurrent-queue", 84 | "fastrand", 85 | "futures-lite", 86 | "libc", 87 | "log", 88 | "nb-connect", 89 | "once_cell", 90 | "parking", 91 | "polling", 92 | "vec-arena", 93 | "waker-fn", 94 | "winapi 0.3.9", 95 | ] 96 | 97 | [[package]] 98 | name = "async-mutex" 99 | version = "1.4.0" 100 | source = "registry+https://github.com/rust-lang/crates.io-index" 101 | checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" 102 | dependencies = [ 103 | "event-listener", 104 | ] 105 | 106 | [[package]] 107 | name = "async-std" 108 | version = "1.7.0" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "a7e82538bc65a25dbdff70e4c5439d52f068048ab97cdea0acd73f131594caa1" 111 | dependencies = [ 112 | "async-global-executor", 113 | "async-io", 114 | "async-mutex", 115 | "blocking", 116 | "crossbeam-utils 0.8.0", 117 | "futures-channel", 118 | "futures-core", 119 | "futures-io", 120 | "futures-lite", 121 | "gloo-timers", 122 | "kv-log-macro", 123 | "log", 124 | "memchr", 125 | "num_cpus", 126 | "once_cell", 127 | "pin-project-lite", 128 | "pin-utils", 129 | "slab", 130 | "wasm-bindgen-futures", 131 | ] 132 | 133 | [[package]] 134 | name = "async-task" 135 | version = "4.0.3" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" 138 | 139 | [[package]] 140 | name = "async-trait" 141 | version = "0.1.41" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | checksum = "b246867b8b3b6ae56035f1eb1ed557c1d8eae97f0d53696138a50fa0e3a3b8c0" 144 | dependencies = [ 145 | "proc-macro2", 146 | "quote", 147 | "syn", 148 | ] 149 | 150 | [[package]] 151 | name = "atomic-waker" 152 | version = "1.0.0" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" 155 | 156 | [[package]] 157 | name = "atty" 158 | version = "0.2.14" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 161 | dependencies = [ 162 | "hermit-abi", 163 | "libc", 164 | "winapi 0.3.9", 165 | ] 166 | 167 | [[package]] 168 | name = "autocfg" 169 | version = "1.0.1" 170 | source = "registry+https://github.com/rust-lang/crates.io-index" 171 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 172 | 173 | [[package]] 174 | name = "base-x" 175 | version = "0.2.7" 176 | source = "registry+https://github.com/rust-lang/crates.io-index" 177 | checksum = "c2734baf8ed08920ccecce1b48a2dfce4ac74a973144add031163bd21a1c5dab" 178 | 179 | [[package]] 180 | name = "base64" 181 | version = "0.11.0" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" 184 | 185 | [[package]] 186 | name = "base64" 187 | version = "0.12.3" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" 190 | 191 | [[package]] 192 | name = "bindgen" 193 | version = "0.55.1" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "75b13ce559e6433d360c26305643803cb52cfbabbc2b9c47ce04a58493dfb443" 196 | dependencies = [ 197 | "bitflags", 198 | "cexpr", 199 | "cfg-if 0.1.10", 200 | "clang-sys", 201 | "clap", 202 | "env_logger", 203 | "lazy_static", 204 | "lazycell", 205 | "log", 206 | "peeking_take_while", 207 | "proc-macro2", 208 | "quote", 209 | "regex", 210 | "rustc-hash", 211 | "shlex", 212 | "which", 213 | ] 214 | 215 | [[package]] 216 | name = "bitflags" 217 | version = "1.2.1" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 220 | 221 | [[package]] 222 | name = "blake2b_simd" 223 | version = "0.5.11" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" 226 | dependencies = [ 227 | "arrayref", 228 | "arrayvec", 229 | "constant_time_eq", 230 | ] 231 | 232 | [[package]] 233 | name = "block-buffer" 234 | version = "0.9.0" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 237 | dependencies = [ 238 | "generic-array", 239 | ] 240 | 241 | [[package]] 242 | name = "blocking" 243 | version = "1.0.2" 244 | source = "registry+https://github.com/rust-lang/crates.io-index" 245 | checksum = "c5e170dbede1f740736619b776d7251cb1b9095c435c34d8ca9f57fcd2f335e9" 246 | dependencies = [ 247 | "async-channel", 248 | "async-task", 249 | "atomic-waker", 250 | "fastrand", 251 | "futures-lite", 252 | "once_cell", 253 | ] 254 | 255 | [[package]] 256 | name = "bumpalo" 257 | version = "3.4.0" 258 | source = "registry+https://github.com/rust-lang/crates.io-index" 259 | checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" 260 | 261 | [[package]] 262 | name = "bytes" 263 | version = "0.5.6" 264 | source = "registry+https://github.com/rust-lang/crates.io-index" 265 | checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" 266 | 267 | [[package]] 268 | name = "cache-padded" 269 | version = "1.1.1" 270 | source = "registry+https://github.com/rust-lang/crates.io-index" 271 | checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" 272 | 273 | [[package]] 274 | name = "cc" 275 | version = "1.0.61" 276 | source = "registry+https://github.com/rust-lang/crates.io-index" 277 | checksum = "ed67cbde08356238e75fc4656be4749481eeffb09e19f320a25237d5221c985d" 278 | 279 | [[package]] 280 | name = "cexpr" 281 | version = "0.4.0" 282 | source = "registry+https://github.com/rust-lang/crates.io-index" 283 | checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" 284 | dependencies = [ 285 | "nom", 286 | ] 287 | 288 | [[package]] 289 | name = "cfg-if" 290 | version = "0.1.10" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 293 | 294 | [[package]] 295 | name = "cfg-if" 296 | version = "1.0.0" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 299 | 300 | [[package]] 301 | name = "chrono" 302 | version = "0.4.19" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" 305 | dependencies = [ 306 | "libc", 307 | "num-integer", 308 | "num-traits", 309 | "serde", 310 | "time 0.1.44", 311 | "winapi 0.3.9", 312 | ] 313 | 314 | [[package]] 315 | name = "clang-sys" 316 | version = "1.0.1" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "fa785e9017cb8e8c8045e3f096b7d1ebc4d7337cceccdca8d678a27f788ac133" 319 | dependencies = [ 320 | "glob", 321 | "libc", 322 | "libloading", 323 | ] 324 | 325 | [[package]] 326 | name = "clap" 327 | version = "2.33.3" 328 | source = "registry+https://github.com/rust-lang/crates.io-index" 329 | checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" 330 | dependencies = [ 331 | "ansi_term", 332 | "atty", 333 | "bitflags", 334 | "strsim", 335 | "textwrap", 336 | "unicode-width", 337 | "vec_map", 338 | ] 339 | 340 | [[package]] 341 | name = "combine" 342 | version = "4.3.2" 343 | source = "registry+https://github.com/rust-lang/crates.io-index" 344 | checksum = "2809f67365382d65fd2b6d9c22577231b954ed27400efeafbe687bda75abcc0b" 345 | dependencies = [ 346 | "bytes", 347 | "futures-util", 348 | "memchr", 349 | "pin-project-lite", 350 | "tokio", 351 | ] 352 | 353 | [[package]] 354 | name = "concurrent-queue" 355 | version = "1.2.2" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" 358 | dependencies = [ 359 | "cache-padded", 360 | ] 361 | 362 | [[package]] 363 | name = "const_fn" 364 | version = "0.4.3" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | checksum = "c478836e029dcef17fb47c89023448c64f781a046e0300e257ad8225ae59afab" 367 | 368 | [[package]] 369 | name = "constant_time_eq" 370 | version = "0.1.5" 371 | source = "registry+https://github.com/rust-lang/crates.io-index" 372 | checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" 373 | 374 | [[package]] 375 | name = "core-foundation" 376 | version = "0.7.0" 377 | source = "registry+https://github.com/rust-lang/crates.io-index" 378 | checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" 379 | dependencies = [ 380 | "core-foundation-sys", 381 | "libc", 382 | ] 383 | 384 | [[package]] 385 | name = "core-foundation-sys" 386 | version = "0.7.0" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" 389 | 390 | [[package]] 391 | name = "cpuid-bool" 392 | version = "0.1.2" 393 | source = "registry+https://github.com/rust-lang/crates.io-index" 394 | checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" 395 | 396 | [[package]] 397 | name = "crc32fast" 398 | version = "1.2.1" 399 | source = "registry+https://github.com/rust-lang/crates.io-index" 400 | checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" 401 | dependencies = [ 402 | "cfg-if 1.0.0", 403 | ] 404 | 405 | [[package]] 406 | name = "crossbeam-utils" 407 | version = "0.7.2" 408 | source = "registry+https://github.com/rust-lang/crates.io-index" 409 | checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" 410 | dependencies = [ 411 | "autocfg", 412 | "cfg-if 0.1.10", 413 | "lazy_static", 414 | ] 415 | 416 | [[package]] 417 | name = "crossbeam-utils" 418 | version = "0.8.0" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "ec91540d98355f690a86367e566ecad2e9e579f230230eb7c21398372be73ea5" 421 | dependencies = [ 422 | "autocfg", 423 | "cfg-if 1.0.0", 424 | "const_fn", 425 | "lazy_static", 426 | ] 427 | 428 | [[package]] 429 | name = "crypto-mac" 430 | version = "0.8.0" 431 | source = "registry+https://github.com/rust-lang/crates.io-index" 432 | checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" 433 | dependencies = [ 434 | "generic-array", 435 | "subtle", 436 | ] 437 | 438 | [[package]] 439 | name = "ct-logs" 440 | version = "0.6.0" 441 | source = "registry+https://github.com/rust-lang/crates.io-index" 442 | checksum = "4d3686f5fa27dbc1d76c751300376e167c5a43387f44bb451fd1c24776e49113" 443 | dependencies = [ 444 | "sct", 445 | ] 446 | 447 | [[package]] 448 | name = "digest" 449 | version = "0.9.0" 450 | source = "registry+https://github.com/rust-lang/crates.io-index" 451 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 452 | dependencies = [ 453 | "generic-array", 454 | ] 455 | 456 | [[package]] 457 | name = "dirs" 458 | version = "2.0.2" 459 | source = "registry+https://github.com/rust-lang/crates.io-index" 460 | checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" 461 | dependencies = [ 462 | "cfg-if 0.1.10", 463 | "dirs-sys", 464 | ] 465 | 466 | [[package]] 467 | name = "dirs-sys" 468 | version = "0.3.5" 469 | source = "registry+https://github.com/rust-lang/crates.io-index" 470 | checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" 471 | dependencies = [ 472 | "libc", 473 | "redox_users", 474 | "winapi 0.3.9", 475 | ] 476 | 477 | [[package]] 478 | name = "discard" 479 | version = "1.0.4" 480 | source = "registry+https://github.com/rust-lang/crates.io-index" 481 | checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" 482 | 483 | [[package]] 484 | name = "dtoa" 485 | version = "0.4.6" 486 | source = "registry+https://github.com/rust-lang/crates.io-index" 487 | checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b" 488 | 489 | [[package]] 490 | name = "encoder" 491 | version = "0.0.0" 492 | dependencies = [ 493 | "anyhow", 494 | "ffmpeg", 495 | "futures", 496 | "redis", 497 | "regex", 498 | "rusoto_sqs", 499 | "serde", 500 | "tempfile", 501 | "tokio", 502 | "toml", 503 | ] 504 | 505 | [[package]] 506 | name = "env_logger" 507 | version = "0.7.1" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" 510 | dependencies = [ 511 | "atty", 512 | "humantime", 513 | "log", 514 | "regex", 515 | "termcolor", 516 | ] 517 | 518 | [[package]] 519 | name = "event-listener" 520 | version = "2.5.1" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" 523 | 524 | [[package]] 525 | name = "fastrand" 526 | version = "1.4.0" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "ca5faf057445ce5c9d4329e382b2ce7ca38550ef3b73a5348362d5f24e0c7fe3" 529 | dependencies = [ 530 | "instant", 531 | ] 532 | 533 | [[package]] 534 | name = "ffmpeg" 535 | version = "0.3.0" 536 | source = "registry+https://github.com/rust-lang/crates.io-index" 537 | checksum = "65fa8441031e0aec713d9e96baeb6aaec4f017640e8dc47551a1a7f977ec7d75" 538 | dependencies = [ 539 | "bitflags", 540 | "ffmpeg-sys", 541 | "libc", 542 | ] 543 | 544 | [[package]] 545 | name = "ffmpeg-sys" 546 | version = "4.2.1" 547 | source = "registry+https://github.com/rust-lang/crates.io-index" 548 | checksum = "682bd88f6c9c524eee7c8eebf22e5b97b23cd9459703ed2009566e4b58a3d805" 549 | dependencies = [ 550 | "bindgen", 551 | "cc", 552 | "libc", 553 | "num_cpus", 554 | "pkg-config", 555 | "vcpkg", 556 | ] 557 | 558 | [[package]] 559 | name = "fnv" 560 | version = "1.0.7" 561 | source = "registry+https://github.com/rust-lang/crates.io-index" 562 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 563 | 564 | [[package]] 565 | name = "fuchsia-zircon" 566 | version = "0.3.3" 567 | source = "registry+https://github.com/rust-lang/crates.io-index" 568 | checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" 569 | dependencies = [ 570 | "bitflags", 571 | "fuchsia-zircon-sys", 572 | ] 573 | 574 | [[package]] 575 | name = "fuchsia-zircon-sys" 576 | version = "0.3.3" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 579 | 580 | [[package]] 581 | name = "futures" 582 | version = "0.3.7" 583 | source = "registry+https://github.com/rust-lang/crates.io-index" 584 | checksum = "95314d38584ffbfda215621d723e0a3906f032e03ae5551e650058dac83d4797" 585 | dependencies = [ 586 | "futures-channel", 587 | "futures-core", 588 | "futures-executor", 589 | "futures-io", 590 | "futures-sink", 591 | "futures-task", 592 | "futures-util", 593 | ] 594 | 595 | [[package]] 596 | name = "futures-channel" 597 | version = "0.3.7" 598 | source = "registry+https://github.com/rust-lang/crates.io-index" 599 | checksum = "0448174b01148032eed37ac4aed28963aaaa8cfa93569a08e5b479bbc6c2c151" 600 | dependencies = [ 601 | "futures-core", 602 | "futures-sink", 603 | ] 604 | 605 | [[package]] 606 | name = "futures-core" 607 | version = "0.3.7" 608 | source = "registry+https://github.com/rust-lang/crates.io-index" 609 | checksum = "18eaa56102984bed2c88ea39026cff3ce3b4c7f508ca970cedf2450ea10d4e46" 610 | 611 | [[package]] 612 | name = "futures-executor" 613 | version = "0.3.7" 614 | source = "registry+https://github.com/rust-lang/crates.io-index" 615 | checksum = "f5f8e0c9258abaea85e78ebdda17ef9666d390e987f006be6080dfe354b708cb" 616 | dependencies = [ 617 | "futures-core", 618 | "futures-task", 619 | "futures-util", 620 | ] 621 | 622 | [[package]] 623 | name = "futures-io" 624 | version = "0.3.7" 625 | source = "registry+https://github.com/rust-lang/crates.io-index" 626 | checksum = "6e1798854a4727ff944a7b12aa999f58ce7aa81db80d2dfaaf2ba06f065ddd2b" 627 | 628 | [[package]] 629 | name = "futures-lite" 630 | version = "1.11.2" 631 | source = "registry+https://github.com/rust-lang/crates.io-index" 632 | checksum = "5e6c079abfac3ab269e2927ec048dabc89d009ebfdda6b8ee86624f30c689658" 633 | dependencies = [ 634 | "fastrand", 635 | "futures-core", 636 | "futures-io", 637 | "memchr", 638 | "parking", 639 | "pin-project-lite", 640 | "waker-fn", 641 | ] 642 | 643 | [[package]] 644 | name = "futures-macro" 645 | version = "0.3.7" 646 | source = "registry+https://github.com/rust-lang/crates.io-index" 647 | checksum = "e36fccf3fc58563b4a14d265027c627c3b665d7fed489427e88e7cc929559efe" 648 | dependencies = [ 649 | "proc-macro-hack", 650 | "proc-macro2", 651 | "quote", 652 | "syn", 653 | ] 654 | 655 | [[package]] 656 | name = "futures-sink" 657 | version = "0.3.7" 658 | source = "registry+https://github.com/rust-lang/crates.io-index" 659 | checksum = "0e3ca3f17d6e8804ae5d3df7a7d35b2b3a6fe89dac84b31872720fc3060a0b11" 660 | 661 | [[package]] 662 | name = "futures-task" 663 | version = "0.3.7" 664 | source = "registry+https://github.com/rust-lang/crates.io-index" 665 | checksum = "96d502af37186c4fef99453df03e374683f8a1eec9dcc1e66b3b82dc8278ce3c" 666 | dependencies = [ 667 | "once_cell", 668 | ] 669 | 670 | [[package]] 671 | name = "futures-util" 672 | version = "0.3.7" 673 | source = "registry+https://github.com/rust-lang/crates.io-index" 674 | checksum = "abcb44342f62e6f3e8ac427b8aa815f724fd705dfad060b18ac7866c15bb8e34" 675 | dependencies = [ 676 | "futures-channel", 677 | "futures-core", 678 | "futures-io", 679 | "futures-macro", 680 | "futures-sink", 681 | "futures-task", 682 | "memchr", 683 | "pin-project 1.0.1", 684 | "pin-utils", 685 | "proc-macro-hack", 686 | "proc-macro-nested", 687 | "slab", 688 | ] 689 | 690 | [[package]] 691 | name = "generic-array" 692 | version = "0.14.4" 693 | source = "registry+https://github.com/rust-lang/crates.io-index" 694 | checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" 695 | dependencies = [ 696 | "typenum", 697 | "version_check", 698 | ] 699 | 700 | [[package]] 701 | name = "getrandom" 702 | version = "0.1.15" 703 | source = "registry+https://github.com/rust-lang/crates.io-index" 704 | checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" 705 | dependencies = [ 706 | "cfg-if 0.1.10", 707 | "libc", 708 | "wasi 0.9.0+wasi-snapshot-preview1", 709 | ] 710 | 711 | [[package]] 712 | name = "glob" 713 | version = "0.3.0" 714 | source = "registry+https://github.com/rust-lang/crates.io-index" 715 | checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" 716 | 717 | [[package]] 718 | name = "gloo-timers" 719 | version = "0.2.1" 720 | source = "registry+https://github.com/rust-lang/crates.io-index" 721 | checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f" 722 | dependencies = [ 723 | "futures-channel", 724 | "futures-core", 725 | "js-sys", 726 | "wasm-bindgen", 727 | "web-sys", 728 | ] 729 | 730 | [[package]] 731 | name = "h2" 732 | version = "0.2.7" 733 | source = "registry+https://github.com/rust-lang/crates.io-index" 734 | checksum = "5e4728fd124914ad25e99e3d15a9361a879f6620f63cb56bbb08f95abb97a535" 735 | dependencies = [ 736 | "bytes", 737 | "fnv", 738 | "futures-core", 739 | "futures-sink", 740 | "futures-util", 741 | "http", 742 | "indexmap", 743 | "slab", 744 | "tokio", 745 | "tokio-util", 746 | "tracing", 747 | "tracing-futures", 748 | ] 749 | 750 | [[package]] 751 | name = "hashbrown" 752 | version = "0.9.1" 753 | source = "registry+https://github.com/rust-lang/crates.io-index" 754 | checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" 755 | 756 | [[package]] 757 | name = "hermit-abi" 758 | version = "0.1.17" 759 | source = "registry+https://github.com/rust-lang/crates.io-index" 760 | checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" 761 | dependencies = [ 762 | "libc", 763 | ] 764 | 765 | [[package]] 766 | name = "hex" 767 | version = "0.4.2" 768 | source = "registry+https://github.com/rust-lang/crates.io-index" 769 | checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" 770 | 771 | [[package]] 772 | name = "hmac" 773 | version = "0.8.1" 774 | source = "registry+https://github.com/rust-lang/crates.io-index" 775 | checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" 776 | dependencies = [ 777 | "crypto-mac", 778 | "digest", 779 | ] 780 | 781 | [[package]] 782 | name = "http" 783 | version = "0.2.1" 784 | source = "registry+https://github.com/rust-lang/crates.io-index" 785 | checksum = "28d569972648b2c512421b5f2a405ad6ac9666547189d0c5477a3f200f3e02f9" 786 | dependencies = [ 787 | "bytes", 788 | "fnv", 789 | "itoa", 790 | ] 791 | 792 | [[package]] 793 | name = "http-body" 794 | version = "0.3.1" 795 | source = "registry+https://github.com/rust-lang/crates.io-index" 796 | checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b" 797 | dependencies = [ 798 | "bytes", 799 | "http", 800 | ] 801 | 802 | [[package]] 803 | name = "httparse" 804 | version = "1.3.4" 805 | source = "registry+https://github.com/rust-lang/crates.io-index" 806 | checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" 807 | 808 | [[package]] 809 | name = "httpdate" 810 | version = "0.3.2" 811 | source = "registry+https://github.com/rust-lang/crates.io-index" 812 | checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" 813 | 814 | [[package]] 815 | name = "humantime" 816 | version = "1.3.0" 817 | source = "registry+https://github.com/rust-lang/crates.io-index" 818 | checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" 819 | dependencies = [ 820 | "quick-error", 821 | ] 822 | 823 | [[package]] 824 | name = "hyper" 825 | version = "0.13.9" 826 | source = "registry+https://github.com/rust-lang/crates.io-index" 827 | checksum = "f6ad767baac13b44d4529fcf58ba2cd0995e36e7b435bc5b039de6f47e880dbf" 828 | dependencies = [ 829 | "bytes", 830 | "futures-channel", 831 | "futures-core", 832 | "futures-util", 833 | "h2", 834 | "http", 835 | "http-body", 836 | "httparse", 837 | "httpdate", 838 | "itoa", 839 | "pin-project 1.0.1", 840 | "socket2", 841 | "tokio", 842 | "tower-service", 843 | "tracing", 844 | "want", 845 | ] 846 | 847 | [[package]] 848 | name = "hyper-rustls" 849 | version = "0.20.0" 850 | source = "registry+https://github.com/rust-lang/crates.io-index" 851 | checksum = "ac965ea399ec3a25ac7d13b8affd4b8f39325cca00858ddf5eb29b79e6b14b08" 852 | dependencies = [ 853 | "bytes", 854 | "ct-logs", 855 | "futures-util", 856 | "hyper", 857 | "log", 858 | "rustls", 859 | "rustls-native-certs", 860 | "tokio", 861 | "tokio-rustls", 862 | "webpki", 863 | ] 864 | 865 | [[package]] 866 | name = "idna" 867 | version = "0.2.0" 868 | source = "registry+https://github.com/rust-lang/crates.io-index" 869 | checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" 870 | dependencies = [ 871 | "matches", 872 | "unicode-bidi", 873 | "unicode-normalization", 874 | ] 875 | 876 | [[package]] 877 | name = "indexmap" 878 | version = "1.6.0" 879 | source = "registry+https://github.com/rust-lang/crates.io-index" 880 | checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2" 881 | dependencies = [ 882 | "autocfg", 883 | "hashbrown", 884 | ] 885 | 886 | [[package]] 887 | name = "instant" 888 | version = "0.1.8" 889 | source = "registry+https://github.com/rust-lang/crates.io-index" 890 | checksum = "cb1fc4429a33e1f80d41dc9fea4d108a88bec1de8053878898ae448a0b52f613" 891 | dependencies = [ 892 | "cfg-if 1.0.0", 893 | ] 894 | 895 | [[package]] 896 | name = "iovec" 897 | version = "0.1.4" 898 | source = "registry+https://github.com/rust-lang/crates.io-index" 899 | checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" 900 | dependencies = [ 901 | "libc", 902 | ] 903 | 904 | [[package]] 905 | name = "itoa" 906 | version = "0.4.6" 907 | source = "registry+https://github.com/rust-lang/crates.io-index" 908 | checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" 909 | 910 | [[package]] 911 | name = "js-sys" 912 | version = "0.3.45" 913 | source = "registry+https://github.com/rust-lang/crates.io-index" 914 | checksum = "ca059e81d9486668f12d455a4ea6daa600bd408134cd17e3d3fb5a32d1f016f8" 915 | dependencies = [ 916 | "wasm-bindgen", 917 | ] 918 | 919 | [[package]] 920 | name = "kernel32-sys" 921 | version = "0.2.2" 922 | source = "registry+https://github.com/rust-lang/crates.io-index" 923 | checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" 924 | dependencies = [ 925 | "winapi 0.2.8", 926 | "winapi-build", 927 | ] 928 | 929 | [[package]] 930 | name = "kv-log-macro" 931 | version = "1.0.7" 932 | source = "registry+https://github.com/rust-lang/crates.io-index" 933 | checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" 934 | dependencies = [ 935 | "log", 936 | ] 937 | 938 | [[package]] 939 | name = "lazy_static" 940 | version = "1.4.0" 941 | source = "registry+https://github.com/rust-lang/crates.io-index" 942 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 943 | 944 | [[package]] 945 | name = "lazycell" 946 | version = "1.3.0" 947 | source = "registry+https://github.com/rust-lang/crates.io-index" 948 | checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" 949 | 950 | [[package]] 951 | name = "libc" 952 | version = "0.2.80" 953 | source = "registry+https://github.com/rust-lang/crates.io-index" 954 | checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" 955 | 956 | [[package]] 957 | name = "libloading" 958 | version = "0.6.5" 959 | source = "registry+https://github.com/rust-lang/crates.io-index" 960 | checksum = "1090080fe06ec2648d0da3881d9453d97e71a45f00eb179af7fdd7e3f686fdb0" 961 | dependencies = [ 962 | "cfg-if 1.0.0", 963 | "winapi 0.3.9", 964 | ] 965 | 966 | [[package]] 967 | name = "log" 968 | version = "0.4.11" 969 | source = "registry+https://github.com/rust-lang/crates.io-index" 970 | checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" 971 | dependencies = [ 972 | "cfg-if 0.1.10", 973 | ] 974 | 975 | [[package]] 976 | name = "matches" 977 | version = "0.1.8" 978 | source = "registry+https://github.com/rust-lang/crates.io-index" 979 | checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" 980 | 981 | [[package]] 982 | name = "md5" 983 | version = "0.7.0" 984 | source = "registry+https://github.com/rust-lang/crates.io-index" 985 | checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" 986 | 987 | [[package]] 988 | name = "memchr" 989 | version = "2.3.4" 990 | source = "registry+https://github.com/rust-lang/crates.io-index" 991 | checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" 992 | 993 | [[package]] 994 | name = "mio" 995 | version = "0.6.22" 996 | source = "registry+https://github.com/rust-lang/crates.io-index" 997 | checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" 998 | dependencies = [ 999 | "cfg-if 0.1.10", 1000 | "fuchsia-zircon", 1001 | "fuchsia-zircon-sys", 1002 | "iovec", 1003 | "kernel32-sys", 1004 | "libc", 1005 | "log", 1006 | "miow 0.2.1", 1007 | "net2", 1008 | "slab", 1009 | "winapi 0.2.8", 1010 | ] 1011 | 1012 | [[package]] 1013 | name = "mio-named-pipes" 1014 | version = "0.1.7" 1015 | source = "registry+https://github.com/rust-lang/crates.io-index" 1016 | checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656" 1017 | dependencies = [ 1018 | "log", 1019 | "mio", 1020 | "miow 0.3.5", 1021 | "winapi 0.3.9", 1022 | ] 1023 | 1024 | [[package]] 1025 | name = "mio-uds" 1026 | version = "0.6.8" 1027 | source = "registry+https://github.com/rust-lang/crates.io-index" 1028 | checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" 1029 | dependencies = [ 1030 | "iovec", 1031 | "libc", 1032 | "mio", 1033 | ] 1034 | 1035 | [[package]] 1036 | name = "miow" 1037 | version = "0.2.1" 1038 | source = "registry+https://github.com/rust-lang/crates.io-index" 1039 | checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" 1040 | dependencies = [ 1041 | "kernel32-sys", 1042 | "net2", 1043 | "winapi 0.2.8", 1044 | "ws2_32-sys", 1045 | ] 1046 | 1047 | [[package]] 1048 | name = "miow" 1049 | version = "0.3.5" 1050 | source = "registry+https://github.com/rust-lang/crates.io-index" 1051 | checksum = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e" 1052 | dependencies = [ 1053 | "socket2", 1054 | "winapi 0.3.9", 1055 | ] 1056 | 1057 | [[package]] 1058 | name = "nb-connect" 1059 | version = "1.0.2" 1060 | source = "registry+https://github.com/rust-lang/crates.io-index" 1061 | checksum = "8123a81538e457d44b933a02faf885d3fe8408806b23fa700e8f01c6c3a98998" 1062 | dependencies = [ 1063 | "libc", 1064 | "winapi 0.3.9", 1065 | ] 1066 | 1067 | [[package]] 1068 | name = "net2" 1069 | version = "0.2.35" 1070 | source = "registry+https://github.com/rust-lang/crates.io-index" 1071 | checksum = "3ebc3ec692ed7c9a255596c67808dee269f64655d8baf7b4f0638e51ba1d6853" 1072 | dependencies = [ 1073 | "cfg-if 0.1.10", 1074 | "libc", 1075 | "winapi 0.3.9", 1076 | ] 1077 | 1078 | [[package]] 1079 | name = "nom" 1080 | version = "5.1.2" 1081 | source = "registry+https://github.com/rust-lang/crates.io-index" 1082 | checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" 1083 | dependencies = [ 1084 | "memchr", 1085 | "version_check", 1086 | ] 1087 | 1088 | [[package]] 1089 | name = "num-integer" 1090 | version = "0.1.44" 1091 | source = "registry+https://github.com/rust-lang/crates.io-index" 1092 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 1093 | dependencies = [ 1094 | "autocfg", 1095 | "num-traits", 1096 | ] 1097 | 1098 | [[package]] 1099 | name = "num-traits" 1100 | version = "0.2.14" 1101 | source = "registry+https://github.com/rust-lang/crates.io-index" 1102 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 1103 | dependencies = [ 1104 | "autocfg", 1105 | ] 1106 | 1107 | [[package]] 1108 | name = "num_cpus" 1109 | version = "1.13.0" 1110 | source = "registry+https://github.com/rust-lang/crates.io-index" 1111 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 1112 | dependencies = [ 1113 | "hermit-abi", 1114 | "libc", 1115 | ] 1116 | 1117 | [[package]] 1118 | name = "once_cell" 1119 | version = "1.4.1" 1120 | source = "registry+https://github.com/rust-lang/crates.io-index" 1121 | checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad" 1122 | 1123 | [[package]] 1124 | name = "opaque-debug" 1125 | version = "0.3.0" 1126 | source = "registry+https://github.com/rust-lang/crates.io-index" 1127 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 1128 | 1129 | [[package]] 1130 | name = "openssl-probe" 1131 | version = "0.1.2" 1132 | source = "registry+https://github.com/rust-lang/crates.io-index" 1133 | checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" 1134 | 1135 | [[package]] 1136 | name = "parking" 1137 | version = "2.0.0" 1138 | source = "registry+https://github.com/rust-lang/crates.io-index" 1139 | checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" 1140 | 1141 | [[package]] 1142 | name = "peeking_take_while" 1143 | version = "0.1.2" 1144 | source = "registry+https://github.com/rust-lang/crates.io-index" 1145 | checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" 1146 | 1147 | [[package]] 1148 | name = "percent-encoding" 1149 | version = "2.1.0" 1150 | source = "registry+https://github.com/rust-lang/crates.io-index" 1151 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 1152 | 1153 | [[package]] 1154 | name = "pin-project" 1155 | version = "0.4.27" 1156 | source = "registry+https://github.com/rust-lang/crates.io-index" 1157 | checksum = "2ffbc8e94b38ea3d2d8ba92aea2983b503cd75d0888d75b86bb37970b5698e15" 1158 | dependencies = [ 1159 | "pin-project-internal 0.4.27", 1160 | ] 1161 | 1162 | [[package]] 1163 | name = "pin-project" 1164 | version = "1.0.1" 1165 | source = "registry+https://github.com/rust-lang/crates.io-index" 1166 | checksum = "ee41d838744f60d959d7074e3afb6b35c7456d0f61cad38a24e35e6553f73841" 1167 | dependencies = [ 1168 | "pin-project-internal 1.0.1", 1169 | ] 1170 | 1171 | [[package]] 1172 | name = "pin-project-internal" 1173 | version = "0.4.27" 1174 | source = "registry+https://github.com/rust-lang/crates.io-index" 1175 | checksum = "65ad2ae56b6abe3a1ee25f15ee605bacadb9a764edaba9c2bf4103800d4a1895" 1176 | dependencies = [ 1177 | "proc-macro2", 1178 | "quote", 1179 | "syn", 1180 | ] 1181 | 1182 | [[package]] 1183 | name = "pin-project-internal" 1184 | version = "1.0.1" 1185 | source = "registry+https://github.com/rust-lang/crates.io-index" 1186 | checksum = "81a4ffa594b66bff340084d4081df649a7dc049ac8d7fc458d8e628bfbbb2f86" 1187 | dependencies = [ 1188 | "proc-macro2", 1189 | "quote", 1190 | "syn", 1191 | ] 1192 | 1193 | [[package]] 1194 | name = "pin-project-lite" 1195 | version = "0.1.11" 1196 | source = "registry+https://github.com/rust-lang/crates.io-index" 1197 | checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b" 1198 | 1199 | [[package]] 1200 | name = "pin-utils" 1201 | version = "0.1.0" 1202 | source = "registry+https://github.com/rust-lang/crates.io-index" 1203 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1204 | 1205 | [[package]] 1206 | name = "pkg-config" 1207 | version = "0.3.19" 1208 | source = "registry+https://github.com/rust-lang/crates.io-index" 1209 | checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" 1210 | 1211 | [[package]] 1212 | name = "polling" 1213 | version = "2.0.2" 1214 | source = "registry+https://github.com/rust-lang/crates.io-index" 1215 | checksum = "a2a7bc6b2a29e632e45451c941832803a18cce6781db04de8a04696cdca8bde4" 1216 | dependencies = [ 1217 | "cfg-if 0.1.10", 1218 | "libc", 1219 | "log", 1220 | "wepoll-sys", 1221 | "winapi 0.3.9", 1222 | ] 1223 | 1224 | [[package]] 1225 | name = "ppv-lite86" 1226 | version = "0.2.10" 1227 | source = "registry+https://github.com/rust-lang/crates.io-index" 1228 | checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" 1229 | 1230 | [[package]] 1231 | name = "proc-macro-hack" 1232 | version = "0.5.19" 1233 | source = "registry+https://github.com/rust-lang/crates.io-index" 1234 | checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" 1235 | 1236 | [[package]] 1237 | name = "proc-macro-nested" 1238 | version = "0.1.6" 1239 | source = "registry+https://github.com/rust-lang/crates.io-index" 1240 | checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" 1241 | 1242 | [[package]] 1243 | name = "proc-macro2" 1244 | version = "1.0.24" 1245 | source = "registry+https://github.com/rust-lang/crates.io-index" 1246 | checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" 1247 | dependencies = [ 1248 | "unicode-xid", 1249 | ] 1250 | 1251 | [[package]] 1252 | name = "quick-error" 1253 | version = "1.2.3" 1254 | source = "registry+https://github.com/rust-lang/crates.io-index" 1255 | checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 1256 | 1257 | [[package]] 1258 | name = "quote" 1259 | version = "1.0.7" 1260 | source = "registry+https://github.com/rust-lang/crates.io-index" 1261 | checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" 1262 | dependencies = [ 1263 | "proc-macro2", 1264 | ] 1265 | 1266 | [[package]] 1267 | name = "rand" 1268 | version = "0.7.3" 1269 | source = "registry+https://github.com/rust-lang/crates.io-index" 1270 | checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" 1271 | dependencies = [ 1272 | "getrandom", 1273 | "libc", 1274 | "rand_chacha", 1275 | "rand_core", 1276 | "rand_hc", 1277 | ] 1278 | 1279 | [[package]] 1280 | name = "rand_chacha" 1281 | version = "0.2.2" 1282 | source = "registry+https://github.com/rust-lang/crates.io-index" 1283 | checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" 1284 | dependencies = [ 1285 | "ppv-lite86", 1286 | "rand_core", 1287 | ] 1288 | 1289 | [[package]] 1290 | name = "rand_core" 1291 | version = "0.5.1" 1292 | source = "registry+https://github.com/rust-lang/crates.io-index" 1293 | checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 1294 | dependencies = [ 1295 | "getrandom", 1296 | ] 1297 | 1298 | [[package]] 1299 | name = "rand_hc" 1300 | version = "0.2.0" 1301 | source = "registry+https://github.com/rust-lang/crates.io-index" 1302 | checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 1303 | dependencies = [ 1304 | "rand_core", 1305 | ] 1306 | 1307 | [[package]] 1308 | name = "redis" 1309 | version = "0.17.0" 1310 | source = "registry+https://github.com/rust-lang/crates.io-index" 1311 | checksum = "95357caf2640abc54651b93c98a8df4fe1ccbf44b8e601ccdf43d5c1451f29ac" 1312 | dependencies = [ 1313 | "async-std", 1314 | "async-trait", 1315 | "bytes", 1316 | "combine", 1317 | "dtoa", 1318 | "futures-util", 1319 | "itoa", 1320 | "percent-encoding", 1321 | "pin-project-lite", 1322 | "sha1", 1323 | "tokio", 1324 | "tokio-util", 1325 | "url", 1326 | ] 1327 | 1328 | [[package]] 1329 | name = "redox_syscall" 1330 | version = "0.1.57" 1331 | source = "registry+https://github.com/rust-lang/crates.io-index" 1332 | checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" 1333 | 1334 | [[package]] 1335 | name = "redox_users" 1336 | version = "0.3.5" 1337 | source = "registry+https://github.com/rust-lang/crates.io-index" 1338 | checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" 1339 | dependencies = [ 1340 | "getrandom", 1341 | "redox_syscall", 1342 | "rust-argon2", 1343 | ] 1344 | 1345 | [[package]] 1346 | name = "regex" 1347 | version = "1.4.2" 1348 | source = "registry+https://github.com/rust-lang/crates.io-index" 1349 | checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" 1350 | dependencies = [ 1351 | "aho-corasick", 1352 | "memchr", 1353 | "regex-syntax", 1354 | "thread_local", 1355 | ] 1356 | 1357 | [[package]] 1358 | name = "regex-syntax" 1359 | version = "0.6.21" 1360 | source = "registry+https://github.com/rust-lang/crates.io-index" 1361 | checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" 1362 | 1363 | [[package]] 1364 | name = "remove_dir_all" 1365 | version = "0.5.3" 1366 | source = "registry+https://github.com/rust-lang/crates.io-index" 1367 | checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" 1368 | dependencies = [ 1369 | "winapi 0.3.9", 1370 | ] 1371 | 1372 | [[package]] 1373 | name = "ring" 1374 | version = "0.16.15" 1375 | source = "registry+https://github.com/rust-lang/crates.io-index" 1376 | checksum = "952cd6b98c85bbc30efa1ba5783b8abf12fec8b3287ffa52605b9432313e34e4" 1377 | dependencies = [ 1378 | "cc", 1379 | "libc", 1380 | "once_cell", 1381 | "spin", 1382 | "untrusted", 1383 | "web-sys", 1384 | "winapi 0.3.9", 1385 | ] 1386 | 1387 | [[package]] 1388 | name = "rusoto_core" 1389 | version = "0.45.0" 1390 | source = "registry+https://github.com/rust-lang/crates.io-index" 1391 | checksum = "e977941ee0658df96fca7291ecc6fc9a754600b21ad84b959eb1dbbc9d5abcc7" 1392 | dependencies = [ 1393 | "async-trait", 1394 | "base64 0.12.3", 1395 | "bytes", 1396 | "crc32fast", 1397 | "futures", 1398 | "http", 1399 | "hyper", 1400 | "hyper-rustls", 1401 | "lazy_static", 1402 | "log", 1403 | "md5", 1404 | "percent-encoding", 1405 | "pin-project 0.4.27", 1406 | "rusoto_credential", 1407 | "rusoto_signature", 1408 | "rustc_version", 1409 | "serde", 1410 | "serde_json", 1411 | "tokio", 1412 | "xml-rs", 1413 | ] 1414 | 1415 | [[package]] 1416 | name = "rusoto_credential" 1417 | version = "0.45.0" 1418 | source = "registry+https://github.com/rust-lang/crates.io-index" 1419 | checksum = "09ac05563f83489b19b4d413607a30821ab08bbd9007d14fa05618da3ef09d8b" 1420 | dependencies = [ 1421 | "async-trait", 1422 | "chrono", 1423 | "dirs", 1424 | "futures", 1425 | "hyper", 1426 | "pin-project 0.4.27", 1427 | "regex", 1428 | "serde", 1429 | "serde_json", 1430 | "shlex", 1431 | "tokio", 1432 | "zeroize", 1433 | ] 1434 | 1435 | [[package]] 1436 | name = "rusoto_signature" 1437 | version = "0.45.0" 1438 | source = "registry+https://github.com/rust-lang/crates.io-index" 1439 | checksum = "97a740a88dde8ded81b6f2cff9cd5e054a5a2e38a38397260f7acdd2c85d17dd" 1440 | dependencies = [ 1441 | "base64 0.12.3", 1442 | "bytes", 1443 | "futures", 1444 | "hex", 1445 | "hmac", 1446 | "http", 1447 | "hyper", 1448 | "log", 1449 | "md5", 1450 | "percent-encoding", 1451 | "pin-project 0.4.27", 1452 | "rusoto_credential", 1453 | "rustc_version", 1454 | "serde", 1455 | "sha2", 1456 | "time 0.2.22", 1457 | "tokio", 1458 | ] 1459 | 1460 | [[package]] 1461 | name = "rusoto_sqs" 1462 | version = "0.45.0" 1463 | source = "registry+https://github.com/rust-lang/crates.io-index" 1464 | checksum = "fcd228a1b4ce3f3a40541ee8cef526ff3702b58a4779fb05c31e739174efda5e" 1465 | dependencies = [ 1466 | "async-trait", 1467 | "bytes", 1468 | "futures", 1469 | "rusoto_core", 1470 | "serde_urlencoded", 1471 | "xml-rs", 1472 | ] 1473 | 1474 | [[package]] 1475 | name = "rust-argon2" 1476 | version = "0.8.2" 1477 | source = "registry+https://github.com/rust-lang/crates.io-index" 1478 | checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19" 1479 | dependencies = [ 1480 | "base64 0.12.3", 1481 | "blake2b_simd", 1482 | "constant_time_eq", 1483 | "crossbeam-utils 0.7.2", 1484 | ] 1485 | 1486 | [[package]] 1487 | name = "rustc-hash" 1488 | version = "1.1.0" 1489 | source = "registry+https://github.com/rust-lang/crates.io-index" 1490 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 1491 | 1492 | [[package]] 1493 | name = "rustc_version" 1494 | version = "0.2.3" 1495 | source = "registry+https://github.com/rust-lang/crates.io-index" 1496 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 1497 | dependencies = [ 1498 | "semver", 1499 | ] 1500 | 1501 | [[package]] 1502 | name = "rustls" 1503 | version = "0.17.0" 1504 | source = "registry+https://github.com/rust-lang/crates.io-index" 1505 | checksum = "c0d4a31f5d68413404705d6982529b0e11a9aacd4839d1d6222ee3b8cb4015e1" 1506 | dependencies = [ 1507 | "base64 0.11.0", 1508 | "log", 1509 | "ring", 1510 | "sct", 1511 | "webpki", 1512 | ] 1513 | 1514 | [[package]] 1515 | name = "rustls-native-certs" 1516 | version = "0.3.0" 1517 | source = "registry+https://github.com/rust-lang/crates.io-index" 1518 | checksum = "a75ffeb84a6bd9d014713119542ce415db3a3e4748f0bfce1e1416cd224a23a5" 1519 | dependencies = [ 1520 | "openssl-probe", 1521 | "rustls", 1522 | "schannel", 1523 | "security-framework", 1524 | ] 1525 | 1526 | [[package]] 1527 | name = "ryu" 1528 | version = "1.0.5" 1529 | source = "registry+https://github.com/rust-lang/crates.io-index" 1530 | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" 1531 | 1532 | [[package]] 1533 | name = "schannel" 1534 | version = "0.1.19" 1535 | source = "registry+https://github.com/rust-lang/crates.io-index" 1536 | checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" 1537 | dependencies = [ 1538 | "lazy_static", 1539 | "winapi 0.3.9", 1540 | ] 1541 | 1542 | [[package]] 1543 | name = "sct" 1544 | version = "0.6.0" 1545 | source = "registry+https://github.com/rust-lang/crates.io-index" 1546 | checksum = "e3042af939fca8c3453b7af0f1c66e533a15a86169e39de2657310ade8f98d3c" 1547 | dependencies = [ 1548 | "ring", 1549 | "untrusted", 1550 | ] 1551 | 1552 | [[package]] 1553 | name = "security-framework" 1554 | version = "0.4.4" 1555 | source = "registry+https://github.com/rust-lang/crates.io-index" 1556 | checksum = "64808902d7d99f78eaddd2b4e2509713babc3dc3c85ad6f4c447680f3c01e535" 1557 | dependencies = [ 1558 | "bitflags", 1559 | "core-foundation", 1560 | "core-foundation-sys", 1561 | "libc", 1562 | "security-framework-sys", 1563 | ] 1564 | 1565 | [[package]] 1566 | name = "security-framework-sys" 1567 | version = "0.4.3" 1568 | source = "registry+https://github.com/rust-lang/crates.io-index" 1569 | checksum = "17bf11d99252f512695eb468de5516e5cf75455521e69dfe343f3b74e4748405" 1570 | dependencies = [ 1571 | "core-foundation-sys", 1572 | "libc", 1573 | ] 1574 | 1575 | [[package]] 1576 | name = "semver" 1577 | version = "0.9.0" 1578 | source = "registry+https://github.com/rust-lang/crates.io-index" 1579 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 1580 | dependencies = [ 1581 | "semver-parser", 1582 | ] 1583 | 1584 | [[package]] 1585 | name = "semver-parser" 1586 | version = "0.7.0" 1587 | source = "registry+https://github.com/rust-lang/crates.io-index" 1588 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 1589 | 1590 | [[package]] 1591 | name = "serde" 1592 | version = "1.0.117" 1593 | source = "registry+https://github.com/rust-lang/crates.io-index" 1594 | checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a" 1595 | dependencies = [ 1596 | "serde_derive", 1597 | ] 1598 | 1599 | [[package]] 1600 | name = "serde_derive" 1601 | version = "1.0.117" 1602 | source = "registry+https://github.com/rust-lang/crates.io-index" 1603 | checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e" 1604 | dependencies = [ 1605 | "proc-macro2", 1606 | "quote", 1607 | "syn", 1608 | ] 1609 | 1610 | [[package]] 1611 | name = "serde_json" 1612 | version = "1.0.59" 1613 | source = "registry+https://github.com/rust-lang/crates.io-index" 1614 | checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95" 1615 | dependencies = [ 1616 | "itoa", 1617 | "ryu", 1618 | "serde", 1619 | ] 1620 | 1621 | [[package]] 1622 | name = "serde_urlencoded" 1623 | version = "0.6.1" 1624 | source = "registry+https://github.com/rust-lang/crates.io-index" 1625 | checksum = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97" 1626 | dependencies = [ 1627 | "dtoa", 1628 | "itoa", 1629 | "serde", 1630 | "url", 1631 | ] 1632 | 1633 | [[package]] 1634 | name = "sha1" 1635 | version = "0.6.0" 1636 | source = "registry+https://github.com/rust-lang/crates.io-index" 1637 | checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" 1638 | 1639 | [[package]] 1640 | name = "sha2" 1641 | version = "0.9.2" 1642 | source = "registry+https://github.com/rust-lang/crates.io-index" 1643 | checksum = "6e7aab86fe2149bad8c507606bdb3f4ef5e7b2380eb92350f56122cca72a42a8" 1644 | dependencies = [ 1645 | "block-buffer", 1646 | "cfg-if 1.0.0", 1647 | "cpuid-bool", 1648 | "digest", 1649 | "opaque-debug", 1650 | ] 1651 | 1652 | [[package]] 1653 | name = "shlex" 1654 | version = "0.1.1" 1655 | source = "registry+https://github.com/rust-lang/crates.io-index" 1656 | checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" 1657 | 1658 | [[package]] 1659 | name = "signal-hook-registry" 1660 | version = "1.2.2" 1661 | source = "registry+https://github.com/rust-lang/crates.io-index" 1662 | checksum = "ce32ea0c6c56d5eacaeb814fbed9960547021d3edd010ded1425f180536b20ab" 1663 | dependencies = [ 1664 | "libc", 1665 | ] 1666 | 1667 | [[package]] 1668 | name = "slab" 1669 | version = "0.4.2" 1670 | source = "registry+https://github.com/rust-lang/crates.io-index" 1671 | checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" 1672 | 1673 | [[package]] 1674 | name = "socket2" 1675 | version = "0.3.15" 1676 | source = "registry+https://github.com/rust-lang/crates.io-index" 1677 | checksum = "b1fa70dc5c8104ec096f4fe7ede7a221d35ae13dcd19ba1ad9a81d2cab9a1c44" 1678 | dependencies = [ 1679 | "cfg-if 0.1.10", 1680 | "libc", 1681 | "redox_syscall", 1682 | "winapi 0.3.9", 1683 | ] 1684 | 1685 | [[package]] 1686 | name = "spin" 1687 | version = "0.5.2" 1688 | source = "registry+https://github.com/rust-lang/crates.io-index" 1689 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 1690 | 1691 | [[package]] 1692 | name = "standback" 1693 | version = "0.2.11" 1694 | source = "registry+https://github.com/rust-lang/crates.io-index" 1695 | checksum = "f4e0831040d2cf2bdfd51b844be71885783d489898a192f254ae25d57cce725c" 1696 | dependencies = [ 1697 | "version_check", 1698 | ] 1699 | 1700 | [[package]] 1701 | name = "stdweb" 1702 | version = "0.4.20" 1703 | source = "registry+https://github.com/rust-lang/crates.io-index" 1704 | checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" 1705 | dependencies = [ 1706 | "discard", 1707 | "rustc_version", 1708 | "stdweb-derive", 1709 | "stdweb-internal-macros", 1710 | "stdweb-internal-runtime", 1711 | "wasm-bindgen", 1712 | ] 1713 | 1714 | [[package]] 1715 | name = "stdweb-derive" 1716 | version = "0.5.3" 1717 | source = "registry+https://github.com/rust-lang/crates.io-index" 1718 | checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" 1719 | dependencies = [ 1720 | "proc-macro2", 1721 | "quote", 1722 | "serde", 1723 | "serde_derive", 1724 | "syn", 1725 | ] 1726 | 1727 | [[package]] 1728 | name = "stdweb-internal-macros" 1729 | version = "0.2.9" 1730 | source = "registry+https://github.com/rust-lang/crates.io-index" 1731 | checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" 1732 | dependencies = [ 1733 | "base-x", 1734 | "proc-macro2", 1735 | "quote", 1736 | "serde", 1737 | "serde_derive", 1738 | "serde_json", 1739 | "sha1", 1740 | "syn", 1741 | ] 1742 | 1743 | [[package]] 1744 | name = "stdweb-internal-runtime" 1745 | version = "0.1.5" 1746 | source = "registry+https://github.com/rust-lang/crates.io-index" 1747 | checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" 1748 | 1749 | [[package]] 1750 | name = "strsim" 1751 | version = "0.8.0" 1752 | source = "registry+https://github.com/rust-lang/crates.io-index" 1753 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 1754 | 1755 | [[package]] 1756 | name = "subtle" 1757 | version = "2.3.0" 1758 | source = "registry+https://github.com/rust-lang/crates.io-index" 1759 | checksum = "343f3f510c2915908f155e94f17220b19ccfacf2a64a2a5d8004f2c3e311e7fd" 1760 | 1761 | [[package]] 1762 | name = "syn" 1763 | version = "1.0.48" 1764 | source = "registry+https://github.com/rust-lang/crates.io-index" 1765 | checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac" 1766 | dependencies = [ 1767 | "proc-macro2", 1768 | "quote", 1769 | "unicode-xid", 1770 | ] 1771 | 1772 | [[package]] 1773 | name = "tempfile" 1774 | version = "3.1.0" 1775 | source = "registry+https://github.com/rust-lang/crates.io-index" 1776 | checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" 1777 | dependencies = [ 1778 | "cfg-if 0.1.10", 1779 | "libc", 1780 | "rand", 1781 | "redox_syscall", 1782 | "remove_dir_all", 1783 | "winapi 0.3.9", 1784 | ] 1785 | 1786 | [[package]] 1787 | name = "termcolor" 1788 | version = "1.1.0" 1789 | source = "registry+https://github.com/rust-lang/crates.io-index" 1790 | checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" 1791 | dependencies = [ 1792 | "winapi-util", 1793 | ] 1794 | 1795 | [[package]] 1796 | name = "textwrap" 1797 | version = "0.11.0" 1798 | source = "registry+https://github.com/rust-lang/crates.io-index" 1799 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 1800 | dependencies = [ 1801 | "unicode-width", 1802 | ] 1803 | 1804 | [[package]] 1805 | name = "thread_local" 1806 | version = "1.0.1" 1807 | source = "registry+https://github.com/rust-lang/crates.io-index" 1808 | checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" 1809 | dependencies = [ 1810 | "lazy_static", 1811 | ] 1812 | 1813 | [[package]] 1814 | name = "time" 1815 | version = "0.1.44" 1816 | source = "registry+https://github.com/rust-lang/crates.io-index" 1817 | checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" 1818 | dependencies = [ 1819 | "libc", 1820 | "wasi 0.10.0+wasi-snapshot-preview1", 1821 | "winapi 0.3.9", 1822 | ] 1823 | 1824 | [[package]] 1825 | name = "time" 1826 | version = "0.2.22" 1827 | source = "registry+https://github.com/rust-lang/crates.io-index" 1828 | checksum = "55b7151c9065e80917fbf285d9a5d1432f60db41d170ccafc749a136b41a93af" 1829 | dependencies = [ 1830 | "const_fn", 1831 | "libc", 1832 | "standback", 1833 | "stdweb", 1834 | "time-macros", 1835 | "version_check", 1836 | "winapi 0.3.9", 1837 | ] 1838 | 1839 | [[package]] 1840 | name = "time-macros" 1841 | version = "0.1.1" 1842 | source = "registry+https://github.com/rust-lang/crates.io-index" 1843 | checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" 1844 | dependencies = [ 1845 | "proc-macro-hack", 1846 | "time-macros-impl", 1847 | ] 1848 | 1849 | [[package]] 1850 | name = "time-macros-impl" 1851 | version = "0.1.1" 1852 | source = "registry+https://github.com/rust-lang/crates.io-index" 1853 | checksum = "e5c3be1edfad6027c69f5491cf4cb310d1a71ecd6af742788c6ff8bced86b8fa" 1854 | dependencies = [ 1855 | "proc-macro-hack", 1856 | "proc-macro2", 1857 | "quote", 1858 | "standback", 1859 | "syn", 1860 | ] 1861 | 1862 | [[package]] 1863 | name = "tinyvec" 1864 | version = "0.3.4" 1865 | source = "registry+https://github.com/rust-lang/crates.io-index" 1866 | checksum = "238ce071d267c5710f9d31451efec16c5ee22de34df17cc05e56cbc92e967117" 1867 | 1868 | [[package]] 1869 | name = "tokio" 1870 | version = "0.2.22" 1871 | source = "registry+https://github.com/rust-lang/crates.io-index" 1872 | checksum = "5d34ca54d84bf2b5b4d7d31e901a8464f7b60ac145a284fba25ceb801f2ddccd" 1873 | dependencies = [ 1874 | "bytes", 1875 | "fnv", 1876 | "futures-core", 1877 | "iovec", 1878 | "lazy_static", 1879 | "libc", 1880 | "memchr", 1881 | "mio", 1882 | "mio-named-pipes", 1883 | "mio-uds", 1884 | "pin-project-lite", 1885 | "signal-hook-registry", 1886 | "slab", 1887 | "tokio-macros", 1888 | "winapi 0.3.9", 1889 | ] 1890 | 1891 | [[package]] 1892 | name = "tokio-macros" 1893 | version = "0.2.5" 1894 | source = "registry+https://github.com/rust-lang/crates.io-index" 1895 | checksum = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389" 1896 | dependencies = [ 1897 | "proc-macro2", 1898 | "quote", 1899 | "syn", 1900 | ] 1901 | 1902 | [[package]] 1903 | name = "tokio-rustls" 1904 | version = "0.13.1" 1905 | source = "registry+https://github.com/rust-lang/crates.io-index" 1906 | checksum = "15cb62a0d2770787abc96e99c1cd98fcf17f94959f3af63ca85bdfb203f051b4" 1907 | dependencies = [ 1908 | "futures-core", 1909 | "rustls", 1910 | "tokio", 1911 | "webpki", 1912 | ] 1913 | 1914 | [[package]] 1915 | name = "tokio-util" 1916 | version = "0.3.1" 1917 | source = "registry+https://github.com/rust-lang/crates.io-index" 1918 | checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" 1919 | dependencies = [ 1920 | "bytes", 1921 | "futures-core", 1922 | "futures-sink", 1923 | "log", 1924 | "pin-project-lite", 1925 | "tokio", 1926 | ] 1927 | 1928 | [[package]] 1929 | name = "toml" 1930 | version = "0.5.7" 1931 | source = "registry+https://github.com/rust-lang/crates.io-index" 1932 | checksum = "75cf45bb0bef80604d001caaec0d09da99611b3c0fd39d3080468875cdb65645" 1933 | dependencies = [ 1934 | "serde", 1935 | ] 1936 | 1937 | [[package]] 1938 | name = "tower-service" 1939 | version = "0.3.0" 1940 | source = "registry+https://github.com/rust-lang/crates.io-index" 1941 | checksum = "e987b6bf443f4b5b3b6f38704195592cca41c5bb7aedd3c3693c7081f8289860" 1942 | 1943 | [[package]] 1944 | name = "tracing" 1945 | version = "0.1.21" 1946 | source = "registry+https://github.com/rust-lang/crates.io-index" 1947 | checksum = "b0987850db3733619253fe60e17cb59b82d37c7e6c0236bb81e4d6b87c879f27" 1948 | dependencies = [ 1949 | "cfg-if 0.1.10", 1950 | "log", 1951 | "pin-project-lite", 1952 | "tracing-core", 1953 | ] 1954 | 1955 | [[package]] 1956 | name = "tracing-core" 1957 | version = "0.1.17" 1958 | source = "registry+https://github.com/rust-lang/crates.io-index" 1959 | checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" 1960 | dependencies = [ 1961 | "lazy_static", 1962 | ] 1963 | 1964 | [[package]] 1965 | name = "tracing-futures" 1966 | version = "0.2.4" 1967 | source = "registry+https://github.com/rust-lang/crates.io-index" 1968 | checksum = "ab7bb6f14721aa00656086e9335d363c5c8747bae02ebe32ea2c7dece5689b4c" 1969 | dependencies = [ 1970 | "pin-project 0.4.27", 1971 | "tracing", 1972 | ] 1973 | 1974 | [[package]] 1975 | name = "try-lock" 1976 | version = "0.2.3" 1977 | source = "registry+https://github.com/rust-lang/crates.io-index" 1978 | checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" 1979 | 1980 | [[package]] 1981 | name = "typenum" 1982 | version = "1.12.0" 1983 | source = "registry+https://github.com/rust-lang/crates.io-index" 1984 | checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" 1985 | 1986 | [[package]] 1987 | name = "unicode-bidi" 1988 | version = "0.3.4" 1989 | source = "registry+https://github.com/rust-lang/crates.io-index" 1990 | checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" 1991 | dependencies = [ 1992 | "matches", 1993 | ] 1994 | 1995 | [[package]] 1996 | name = "unicode-normalization" 1997 | version = "0.1.13" 1998 | source = "registry+https://github.com/rust-lang/crates.io-index" 1999 | checksum = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977" 2000 | dependencies = [ 2001 | "tinyvec", 2002 | ] 2003 | 2004 | [[package]] 2005 | name = "unicode-width" 2006 | version = "0.1.8" 2007 | source = "registry+https://github.com/rust-lang/crates.io-index" 2008 | checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" 2009 | 2010 | [[package]] 2011 | name = "unicode-xid" 2012 | version = "0.2.1" 2013 | source = "registry+https://github.com/rust-lang/crates.io-index" 2014 | checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" 2015 | 2016 | [[package]] 2017 | name = "untrusted" 2018 | version = "0.7.1" 2019 | source = "registry+https://github.com/rust-lang/crates.io-index" 2020 | checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" 2021 | 2022 | [[package]] 2023 | name = "url" 2024 | version = "2.1.1" 2025 | source = "registry+https://github.com/rust-lang/crates.io-index" 2026 | checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb" 2027 | dependencies = [ 2028 | "idna", 2029 | "matches", 2030 | "percent-encoding", 2031 | ] 2032 | 2033 | [[package]] 2034 | name = "vcpkg" 2035 | version = "0.2.10" 2036 | source = "registry+https://github.com/rust-lang/crates.io-index" 2037 | checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c" 2038 | 2039 | [[package]] 2040 | name = "vec-arena" 2041 | version = "1.0.0" 2042 | source = "registry+https://github.com/rust-lang/crates.io-index" 2043 | checksum = "eafc1b9b2dfc6f5529177b62cf806484db55b32dc7c9658a118e11bbeb33061d" 2044 | 2045 | [[package]] 2046 | name = "vec_map" 2047 | version = "0.8.2" 2048 | source = "registry+https://github.com/rust-lang/crates.io-index" 2049 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 2050 | 2051 | [[package]] 2052 | name = "version_check" 2053 | version = "0.9.2" 2054 | source = "registry+https://github.com/rust-lang/crates.io-index" 2055 | checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" 2056 | 2057 | [[package]] 2058 | name = "waker-fn" 2059 | version = "1.1.0" 2060 | source = "registry+https://github.com/rust-lang/crates.io-index" 2061 | checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" 2062 | 2063 | [[package]] 2064 | name = "want" 2065 | version = "0.3.0" 2066 | source = "registry+https://github.com/rust-lang/crates.io-index" 2067 | checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" 2068 | dependencies = [ 2069 | "log", 2070 | "try-lock", 2071 | ] 2072 | 2073 | [[package]] 2074 | name = "wasi" 2075 | version = "0.9.0+wasi-snapshot-preview1" 2076 | source = "registry+https://github.com/rust-lang/crates.io-index" 2077 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 2078 | 2079 | [[package]] 2080 | name = "wasi" 2081 | version = "0.10.0+wasi-snapshot-preview1" 2082 | source = "registry+https://github.com/rust-lang/crates.io-index" 2083 | checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" 2084 | 2085 | [[package]] 2086 | name = "wasm-bindgen" 2087 | version = "0.2.68" 2088 | source = "registry+https://github.com/rust-lang/crates.io-index" 2089 | checksum = "1ac64ead5ea5f05873d7c12b545865ca2b8d28adfc50a49b84770a3a97265d42" 2090 | dependencies = [ 2091 | "cfg-if 0.1.10", 2092 | "wasm-bindgen-macro", 2093 | ] 2094 | 2095 | [[package]] 2096 | name = "wasm-bindgen-backend" 2097 | version = "0.2.68" 2098 | source = "registry+https://github.com/rust-lang/crates.io-index" 2099 | checksum = "f22b422e2a757c35a73774860af8e112bff612ce6cb604224e8e47641a9e4f68" 2100 | dependencies = [ 2101 | "bumpalo", 2102 | "lazy_static", 2103 | "log", 2104 | "proc-macro2", 2105 | "quote", 2106 | "syn", 2107 | "wasm-bindgen-shared", 2108 | ] 2109 | 2110 | [[package]] 2111 | name = "wasm-bindgen-futures" 2112 | version = "0.4.18" 2113 | source = "registry+https://github.com/rust-lang/crates.io-index" 2114 | checksum = "b7866cab0aa01de1edf8b5d7936938a7e397ee50ce24119aef3e1eaa3b6171da" 2115 | dependencies = [ 2116 | "cfg-if 0.1.10", 2117 | "js-sys", 2118 | "wasm-bindgen", 2119 | "web-sys", 2120 | ] 2121 | 2122 | [[package]] 2123 | name = "wasm-bindgen-macro" 2124 | version = "0.2.68" 2125 | source = "registry+https://github.com/rust-lang/crates.io-index" 2126 | checksum = "6b13312a745c08c469f0b292dd2fcd6411dba5f7160f593da6ef69b64e407038" 2127 | dependencies = [ 2128 | "quote", 2129 | "wasm-bindgen-macro-support", 2130 | ] 2131 | 2132 | [[package]] 2133 | name = "wasm-bindgen-macro-support" 2134 | version = "0.2.68" 2135 | source = "registry+https://github.com/rust-lang/crates.io-index" 2136 | checksum = "f249f06ef7ee334cc3b8ff031bfc11ec99d00f34d86da7498396dc1e3b1498fe" 2137 | dependencies = [ 2138 | "proc-macro2", 2139 | "quote", 2140 | "syn", 2141 | "wasm-bindgen-backend", 2142 | "wasm-bindgen-shared", 2143 | ] 2144 | 2145 | [[package]] 2146 | name = "wasm-bindgen-shared" 2147 | version = "0.2.68" 2148 | source = "registry+https://github.com/rust-lang/crates.io-index" 2149 | checksum = "1d649a3145108d7d3fbcde896a468d1bd636791823c9921135218ad89be08307" 2150 | 2151 | [[package]] 2152 | name = "web-sys" 2153 | version = "0.3.45" 2154 | source = "registry+https://github.com/rust-lang/crates.io-index" 2155 | checksum = "4bf6ef87ad7ae8008e15a355ce696bed26012b7caa21605188cfd8214ab51e2d" 2156 | dependencies = [ 2157 | "js-sys", 2158 | "wasm-bindgen", 2159 | ] 2160 | 2161 | [[package]] 2162 | name = "webpki" 2163 | version = "0.21.3" 2164 | source = "registry+https://github.com/rust-lang/crates.io-index" 2165 | checksum = "ab146130f5f790d45f82aeeb09e55a256573373ec64409fc19a6fb82fb1032ae" 2166 | dependencies = [ 2167 | "ring", 2168 | "untrusted", 2169 | ] 2170 | 2171 | [[package]] 2172 | name = "wepoll-sys" 2173 | version = "3.0.1" 2174 | source = "registry+https://github.com/rust-lang/crates.io-index" 2175 | checksum = "0fcb14dea929042224824779fbc82d9fab8d2e6d3cbc0ac404de8edf489e77ff" 2176 | dependencies = [ 2177 | "cc", 2178 | ] 2179 | 2180 | [[package]] 2181 | name = "which" 2182 | version = "3.1.1" 2183 | source = "registry+https://github.com/rust-lang/crates.io-index" 2184 | checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724" 2185 | dependencies = [ 2186 | "libc", 2187 | ] 2188 | 2189 | [[package]] 2190 | name = "winapi" 2191 | version = "0.2.8" 2192 | source = "registry+https://github.com/rust-lang/crates.io-index" 2193 | checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" 2194 | 2195 | [[package]] 2196 | name = "winapi" 2197 | version = "0.3.9" 2198 | source = "registry+https://github.com/rust-lang/crates.io-index" 2199 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 2200 | dependencies = [ 2201 | "winapi-i686-pc-windows-gnu", 2202 | "winapi-x86_64-pc-windows-gnu", 2203 | ] 2204 | 2205 | [[package]] 2206 | name = "winapi-build" 2207 | version = "0.1.1" 2208 | source = "registry+https://github.com/rust-lang/crates.io-index" 2209 | checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" 2210 | 2211 | [[package]] 2212 | name = "winapi-i686-pc-windows-gnu" 2213 | version = "0.4.0" 2214 | source = "registry+https://github.com/rust-lang/crates.io-index" 2215 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2216 | 2217 | [[package]] 2218 | name = "winapi-util" 2219 | version = "0.1.5" 2220 | source = "registry+https://github.com/rust-lang/crates.io-index" 2221 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 2222 | dependencies = [ 2223 | "winapi 0.3.9", 2224 | ] 2225 | 2226 | [[package]] 2227 | name = "winapi-x86_64-pc-windows-gnu" 2228 | version = "0.4.0" 2229 | source = "registry+https://github.com/rust-lang/crates.io-index" 2230 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2231 | 2232 | [[package]] 2233 | name = "ws2_32-sys" 2234 | version = "0.2.1" 2235 | source = "registry+https://github.com/rust-lang/crates.io-index" 2236 | checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" 2237 | dependencies = [ 2238 | "winapi 0.2.8", 2239 | "winapi-build", 2240 | ] 2241 | 2242 | [[package]] 2243 | name = "xml-rs" 2244 | version = "0.8.3" 2245 | source = "registry+https://github.com/rust-lang/crates.io-index" 2246 | checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a" 2247 | 2248 | [[package]] 2249 | name = "zeroize" 2250 | version = "1.1.1" 2251 | source = "registry+https://github.com/rust-lang/crates.io-index" 2252 | checksum = "05f33972566adbd2d3588b0491eb94b98b43695c4ef897903470ede4f3f5a28a" 2253 | -------------------------------------------------------------------------------- /encoder/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "encoder" 3 | version = "0.0.0" 4 | publish = false 5 | authors = ["Kohei Suzuki "] 6 | edition = "2018" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | anyhow = "1.0" 12 | ffmpeg = { version = "0.3", default-features = false, features = ["format"] } 13 | futures = "0.3" 14 | redis = "0.17" 15 | regex = "1.4" 16 | rusoto_sqs = { version = "0.45", default-features = false, features = ["rustls"] } 17 | tempfile = "3.1" 18 | tokio = { version = "0.2", features = ["macros", "process"] } 19 | toml = "0.5" 20 | serde = { version = "1.0", features = ["derive"] } 21 | -------------------------------------------------------------------------------- /encoder/README.md: -------------------------------------------------------------------------------- 1 | # encoder 2 | [kaede](https://github.com/eagletmt/kaede) によって Redis に入れられた TS を 3 | 4 | 1. redis-to-sqs で SQS に入れ直す 5 | 2. sqs-encode でエンコード 6 | 7 | という流れで処理する。適当なリカバリ用に encode がある。 8 | -------------------------------------------------------------------------------- /encoder/aws.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "ap-northeast-1" 3 | } 4 | 5 | terraform { 6 | backend "s3" { 7 | bucket = "terraform-wanko-cc" 8 | key = "eagletmt-recutils.tfstate" 9 | region = "ap-northeast-1" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /encoder/config.toml: -------------------------------------------------------------------------------- 1 | [encoder] 2 | base_dir = "/home/eagletmt/mnt/home/pt/heidemarie" 3 | ffmpeg_args = [ 4 | "-acodec", "aac", "-ac", "2", "-ar", "48000", "-ab", "128k", 5 | "-vcodec", "libx264", "-aspect", "16:9", "-filter:v", "yadif", "-s", "1280x720", 6 | "-crf", "21", "-b_strategy", "2", "-me_method", "umh", "-refs", "8", "-subq", "7", "-trellis", "2", "-deblock", "1:1", 7 | "-f", "mp4", "-map", "0", "-max_muxing_queue_size", "500", 8 | ] 9 | 10 | [redis] 11 | url = "redis://longarch.enospc.tv/1" 12 | 13 | [sqs] 14 | queue_url = "https://sqs.ap-northeast-1.amazonaws.com/274147449864/encode-jobs" 15 | -------------------------------------------------------------------------------- /encoder/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_sqs_queue" "encode-jobs" { 2 | name = "encode-jobs" 3 | } 4 | -------------------------------------------------------------------------------- /encoder/src/bin/encode.rs: -------------------------------------------------------------------------------- 1 | #[tokio::main] 2 | async fn main() -> Result<(), anyhow::Error> { 3 | ffmpeg::init()?; 4 | 5 | let config = encoder::load_config()?; 6 | let ts_path = std::path::PathBuf::from(std::env::args().nth(1).expect("missing file")); 7 | encoder::encode(&config, ts_path).await 8 | } 9 | -------------------------------------------------------------------------------- /encoder/src/bin/redis-to-sqs.rs: -------------------------------------------------------------------------------- 1 | #[tokio::main] 2 | async fn main() -> Result<(), anyhow::Error> { 3 | use redis::Commands as _; 4 | use rusoto_sqs::Sqs as _; 5 | 6 | let config = encoder::load_config()?; 7 | let redis_client = redis::Client::open(config.redis.url)?; 8 | let mut conn = redis_client.get_connection()?; 9 | let sqs_client = rusoto_sqs::SqsClient::new(Default::default()); 10 | 11 | loop { 12 | let job: Vec = conn.blpop(&["jobs", "0"], 5)?; 13 | if job.is_empty() { 14 | break; 15 | } 16 | let fname = job.into_iter().nth(1).unwrap(); 17 | println!("Enqueue {}", fname); 18 | 19 | sqs_client 20 | .send_message(rusoto_sqs::SendMessageRequest { 21 | queue_url: config.sqs.queue_url.clone(), 22 | message_body: fname, 23 | ..Default::default() 24 | }) 25 | .await?; 26 | } 27 | Ok(()) 28 | } 29 | -------------------------------------------------------------------------------- /encoder/src/bin/sqs-encode.rs: -------------------------------------------------------------------------------- 1 | #[tokio::main] 2 | async fn main() -> Result<(), anyhow::Error> { 3 | use anyhow::Context as _; 4 | use futures::StreamExt as _; 5 | use rusoto_sqs::Sqs as _; 6 | 7 | let config = encoder::load_config()?; 8 | let sqs_client = rusoto_sqs::SqsClient::new(Default::default()); 9 | let stop_path = std::path::Path::new("/tmp/stop-encode.txt"); 10 | let base_dir = std::path::Path::new(&config.encoder.base_dir); 11 | 12 | loop { 13 | if stop_path.exists() { 14 | break; 15 | } 16 | let resp = sqs_client 17 | .receive_message(rusoto_sqs::ReceiveMessageRequest { 18 | queue_url: config.sqs.queue_url.clone(), 19 | wait_time_seconds: Some(5), 20 | visibility_timeout: Some(60), 21 | ..Default::default() 22 | }) 23 | .await 24 | .context("failed to call sqs:ReceiveMessage")?; 25 | if let Some(messages) = resp.messages { 26 | let message = messages.into_iter().next().unwrap(); 27 | let fname = message.body.expect("SQS message body is missing"); 28 | let message_id = message.message_id.expect("SQS message_id is missing"); 29 | let receipt_handle = message 30 | .receipt_handle 31 | .expect("SQS receipt_handle is missing"); 32 | println!("[message_id={}] {}", message_id, fname); 33 | 34 | let ts_path = base_dir.join(format!("{}.ts", fname)); 35 | if ts_path.exists() { 36 | let interval = tokio::time::interval(tokio::time::Duration::from_secs(60)) 37 | .map(|_| futures::future::Either::Left(())); 38 | let encode = futures::stream::once(encoder::encode(&config, ts_path)) 39 | .map(futures::future::Either::Right); 40 | tokio::pin!(encode); 41 | let mut stream = futures::stream::select(interval, encode); 42 | 43 | while let Some(item) = stream.next().await { 44 | match item { 45 | futures::future::Either::Left(_) => { 46 | let result = sqs_client 47 | .change_message_visibility( 48 | rusoto_sqs::ChangeMessageVisibilityRequest { 49 | queue_url: config.sqs.queue_url.clone(), 50 | receipt_handle: receipt_handle.clone(), 51 | visibility_timeout: 70, 52 | }, 53 | ) 54 | .await; 55 | if let Err(e) = result { 56 | eprintln!("Failed to change message visibility: {:?}", e); 57 | } 58 | } 59 | futures::future::Either::Right(result) => { 60 | match result { 61 | Ok(_) => { 62 | delete_message_with_retry( 63 | &sqs_client, 64 | &config.sqs.queue_url, 65 | &receipt_handle, 66 | ) 67 | .await?; 68 | } 69 | Err(e) => { 70 | eprintln!("encode failed: {:?}", e); 71 | } 72 | } 73 | break; 74 | } 75 | } 76 | } 77 | } else { 78 | let mp4_path = base_dir.join(format!("{}.mp4", fname)); 79 | if mp4_path.exists() { 80 | println!( 81 | "{} is already encoded to {}", 82 | ts_path.display(), 83 | mp4_path.display() 84 | ); 85 | delete_message_with_retry(&sqs_client, &config.sqs.queue_url, &receipt_handle) 86 | .await?; 87 | } else { 88 | println!("{} does not exist", ts_path.display()); 89 | } 90 | } 91 | } else { 92 | break; 93 | } 94 | } 95 | 96 | Ok(()) 97 | } 98 | 99 | async fn delete_message_with_retry( 100 | sqs_client: &Sqs, 101 | queue_url: &str, 102 | receipt_handle: &str, 103 | ) -> Result<(), anyhow::Error> 104 | where 105 | Sqs: rusoto_sqs::Sqs, 106 | { 107 | for i in 0..3 { 108 | match sqs_client 109 | .delete_message(rusoto_sqs::DeleteMessageRequest { 110 | queue_url: queue_url.to_owned(), 111 | receipt_handle: receipt_handle.to_owned(), 112 | }) 113 | .await 114 | { 115 | Ok(_) => { 116 | return Ok(()); 117 | } 118 | Err(e) => { 119 | eprintln!("[{}] failed to call sqs:DeleteMessage: {}", i, e); 120 | } 121 | } 122 | } 123 | Err(anyhow::anyhow!("sqs:DeleteMessage failed")) 124 | } 125 | -------------------------------------------------------------------------------- /encoder/src/lib.rs: -------------------------------------------------------------------------------- 1 | const EPS: i64 = 1000 * 1000; // 1 second 2 | 3 | #[derive(serde::Deserialize)] 4 | pub struct Config { 5 | pub encoder: EncoderConfig, 6 | pub redis: RedisConfig, 7 | pub sqs: SqsConfig, 8 | } 9 | 10 | #[derive(serde::Deserialize)] 11 | pub struct EncoderConfig { 12 | pub base_dir: String, 13 | pub ffmpeg_args: Vec, 14 | } 15 | 16 | #[derive(serde::Deserialize)] 17 | pub struct RedisConfig { 18 | pub url: String, 19 | } 20 | 21 | #[derive(serde::Deserialize)] 22 | pub struct SqsConfig { 23 | pub queue_url: String, 24 | } 25 | 26 | pub fn load_config() -> Result { 27 | let body = std::fs::read("config.toml")?; 28 | Ok(toml::from_slice(&body)?) 29 | } 30 | 31 | pub async fn encode

(config: &Config, ts_path: P) -> Result<(), anyhow::Error> 32 | where 33 | P: AsRef, 34 | { 35 | let ts_path = ts_path.as_ref(); 36 | let mp4_path = ts_path.with_extension("mp4"); 37 | let ts_duration_micro = ffmpeg::format::input(&ts_path)?.duration(); 38 | 39 | let status = tokio::process::Command::new("ffmpeg") 40 | .arg("-i") 41 | .arg(&ts_path) 42 | .args(&config.encoder.ffmpeg_args) 43 | .arg(&mp4_path) 44 | .status() 45 | .await?; 46 | if !status.success() { 47 | return Err(anyhow::anyhow!("Encode failure!")); 48 | } 49 | 50 | let mp4_duration_micro = ffmpeg::format::input(&ts_path)?.duration(); 51 | if (ts_duration_micro - mp4_duration_micro).abs() > EPS { 52 | return Err(anyhow::anyhow!( 53 | "Duration mismatch: TS {}, MP4 {} (microsecond)", 54 | ts_duration_micro, 55 | mp4_duration_micro 56 | )); 57 | } 58 | verify_audio_and_video(&mp4_path)?; 59 | 60 | let ts_fname = ts_path.file_name().unwrap().to_str().unwrap(); 61 | let orig_fname = regex::Regex::new(r#"\A\d+_\d+"#)? 62 | .find(ts_fname) 63 | .expect("Unexpected filename") 64 | .as_str(); 65 | let orig_path = ts_path 66 | .parent() 67 | .unwrap() 68 | .join(orig_fname) 69 | .with_extension("ts"); 70 | 71 | std::fs::remove_file(ts_path)?; 72 | std::fs::remove_file(orig_path)?; 73 | Ok(()) 74 | } 75 | 76 | fn verify_audio_and_video

(mp4_path: P) -> Result<(), anyhow::Error> 77 | where 78 | P: AsRef, 79 | { 80 | let audio_path = tempfile::NamedTempFile::new()?.into_temp_path(); 81 | let status = std::process::Command::new("ffmpeg") 82 | .args(&["-y", "-i"]) 83 | .arg(mp4_path.as_ref()) 84 | .args(&["-vn", "-acodec", "copy", "-f", "mp4"]) 85 | .arg(&audio_path) 86 | .status()?; 87 | if !status.success() { 88 | return Err(anyhow::anyhow!("ffmpeg -vn failed")); 89 | } 90 | 91 | let video_path = tempfile::NamedTempFile::new()?.into_temp_path(); 92 | let status = std::process::Command::new("ffmpeg") 93 | .args(&["-y", "-i"]) 94 | .arg(mp4_path.as_ref()) 95 | .args(&["-an", "-vcodec", "copy", "-f", "mp4"]) 96 | .arg(&video_path) 97 | .status()?; 98 | if !status.success() { 99 | return Err(anyhow::anyhow!("ffmpeg -an failed")); 100 | } 101 | 102 | let audio_duration_micro = ffmpeg::format::input(&audio_path)?.duration(); 103 | let video_duration_micro = ffmpeg::format::input(&video_path)?.duration(); 104 | if (audio_duration_micro - video_duration_micro).abs() > EPS { 105 | return Err(anyhow::anyhow!( 106 | "Duration mismatch! audio:{} video:{} (microsecond)", 107 | audio_duration_micro, 108 | video_duration_micro 109 | )); 110 | } 111 | Ok(()) 112 | } 113 | -------------------------------------------------------------------------------- /encoder/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | aws = { 4 | source = "hashicorp/aws" 5 | version = "= 3.12.0" 6 | } 7 | } 8 | required_version = ">= 0.13" 9 | } 10 | -------------------------------------------------------------------------------- /statvfs/.gitignore: -------------------------------------------------------------------------------- 1 | statvfs 2 | -------------------------------------------------------------------------------- /statvfs/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -O2 -Wall -W 3 | LDFLAGS = 4 | OBJS = statvfs.o 5 | TARGET = statvfs 6 | 7 | $(TARGET): $(OBJS) 8 | $(CC) $(LDFLAGS) $< -o $@ 9 | 10 | clean: 11 | $(RM) $(OBJS) $(TARGET) 12 | -------------------------------------------------------------------------------- /statvfs/README.md: -------------------------------------------------------------------------------- 1 | # statvfs 2 | df(1) から余計な情報を省いて machine-parsable にしたもの。単なる statvfs(3) のラッパ。 3 | -------------------------------------------------------------------------------- /statvfs/statvfs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Print total disk space and available disk space (in bytes) of the given 3 | * path. It's like df(1) but doesn't display any extra information for 4 | * machine-readability. 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | void print_statvfs(const char *path) 12 | { 13 | struct statvfs buf; 14 | if (statvfs(path, &buf) == 0) { 15 | printf("%lu %lu\n", 16 | (buf.f_bsize) * buf.f_blocks, 17 | buf.f_bsize * buf.f_bavail); 18 | } else { 19 | exit(errno); 20 | } 21 | } 22 | 23 | int main(int argc, char *argv[]) 24 | { 25 | int i; 26 | for (i = 1; i < argc; i++) { 27 | print_statvfs(argv[i]); 28 | } 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /tsutils/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /tsutils/Cargo.lock: -------------------------------------------------------------------------------- 1 | [root] 2 | name = "tsutils" 3 | version = "0.0.0" 4 | dependencies = [ 5 | "env_logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 6 | "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 7 | ] 8 | 9 | [[package]] 10 | name = "aho-corasick" 11 | version = "0.6.1" 12 | source = "registry+https://github.com/rust-lang/crates.io-index" 13 | dependencies = [ 14 | "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 15 | ] 16 | 17 | [[package]] 18 | name = "env_logger" 19 | version = "0.4.0" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | dependencies = [ 22 | "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 23 | "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 24 | ] 25 | 26 | [[package]] 27 | name = "kernel32-sys" 28 | version = "0.2.2" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | dependencies = [ 31 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 32 | "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 33 | ] 34 | 35 | [[package]] 36 | name = "libc" 37 | version = "0.2.20" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | 40 | [[package]] 41 | name = "log" 42 | version = "0.3.6" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | 45 | [[package]] 46 | name = "memchr" 47 | version = "1.0.1" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | dependencies = [ 50 | "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", 51 | ] 52 | 53 | [[package]] 54 | name = "regex" 55 | version = "0.2.1" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | dependencies = [ 58 | "aho-corasick 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", 59 | "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 60 | "regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 61 | "thread_local 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 62 | "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 63 | ] 64 | 65 | [[package]] 66 | name = "regex-syntax" 67 | version = "0.4.0" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | 70 | [[package]] 71 | name = "thread-id" 72 | version = "3.0.0" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | dependencies = [ 75 | "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 76 | "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", 77 | ] 78 | 79 | [[package]] 80 | name = "thread_local" 81 | version = "0.3.2" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | dependencies = [ 84 | "thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 85 | "unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 86 | ] 87 | 88 | [[package]] 89 | name = "unreachable" 90 | version = "0.1.1" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | dependencies = [ 93 | "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 94 | ] 95 | 96 | [[package]] 97 | name = "utf8-ranges" 98 | version = "1.0.0" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | 101 | [[package]] 102 | name = "void" 103 | version = "1.0.2" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | 106 | [[package]] 107 | name = "winapi" 108 | version = "0.2.8" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | 111 | [[package]] 112 | name = "winapi-build" 113 | version = "0.1.1" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | 116 | [metadata] 117 | "checksum aho-corasick 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4f660b942762979b56c9f07b4b36bb559776fbad102f05d6771e1b629e8fd5bf" 118 | "checksum env_logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "99971fb1b635fe7a0ee3c4d065845bb93cca80a23b5613b5613391ece5de4144" 119 | "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" 120 | "checksum libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "684f330624d8c3784fb9558ca46c4ce488073a8d22450415c5eb4f4cfb0d11b5" 121 | "checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054" 122 | "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" 123 | "checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" 124 | "checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457" 125 | "checksum thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4437c97558c70d129e40629a5b385b3fb1ffac301e63941335e4d354081ec14a" 126 | "checksum thread_local 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7793b722f0f77ce716e7f1acf416359ca32ff24d04ffbac4269f44a4a83be05d" 127 | "checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91" 128 | "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" 129 | "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 130 | "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" 131 | "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" 132 | -------------------------------------------------------------------------------- /tsutils/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tsutils" 3 | version = "0.0.0" 4 | authors = ["Kohei Suzuki "] 5 | 6 | [dependencies] 7 | env_logger = "0.4" 8 | log = "0.3" 9 | -------------------------------------------------------------------------------- /tsutils/src/bin/tsutils-drop-av.rs: -------------------------------------------------------------------------------- 1 | extern crate env_logger; 2 | extern crate tsutils; 3 | 4 | #[macro_use] 5 | extern crate log; 6 | 7 | fn main() { 8 | env_logger::init().unwrap(); 9 | 10 | let mut args = std::env::args().skip(1); 11 | if let Some(input_path) = args.next() { 12 | if let Some(output_path) = args.next() { 13 | let input = std::fs::File::open(input_path).unwrap(); 14 | let output = std::fs::File::create(output_path).unwrap(); 15 | drop_av(input, output).unwrap(); 16 | return; 17 | } 18 | } 19 | std::process::exit(1); 20 | } 21 | 22 | #[derive(Debug)] 23 | pub enum Error { 24 | Io(std::io::Error), 25 | PsiParseError(tsutils::psi::ParseError), 26 | Custom(std::borrow::Cow<'static, str>), 27 | } 28 | 29 | impl From for Error { 30 | fn from(e: std::io::Error) -> Self { 31 | Error::Io(e) 32 | } 33 | } 34 | 35 | impl From<&'static str> for Error { 36 | fn from(e: &'static str) -> Self { 37 | Error::Custom(std::borrow::Cow::from(e)) 38 | } 39 | } 40 | 41 | impl From for Error { 42 | fn from(e: String) -> Self { 43 | Error::Custom(std::borrow::Cow::from(e)) 44 | } 45 | } 46 | 47 | impl From for Error { 48 | fn from(e: tsutils::psi::ParseError) -> Self { 49 | Error::PsiParseError(e) 50 | } 51 | } 52 | 53 | fn drop_av(reader: R, mut writer: W) -> Result<(), Error> 54 | where R: std::io::Read, 55 | W: std::io::Write 56 | { 57 | let mut pat = None; 58 | let mut payloads: std::collections::HashMap> = std::collections::HashMap::new(); 59 | let mut av_pids = std::collections::HashSet::new(); 60 | let mut nonav_pids = std::collections::HashSet::new(); 61 | let mut tracking_pids = std::collections::HashSet::new(); 62 | tracking_pids.insert(0); 63 | 64 | for buf in tsutils::packet::ts_packets(reader) { 65 | let buf = try!(buf); 66 | let packet = tsutils::TsPacket::new(&buf); 67 | if !packet.check_sync_byte() { 68 | return Err(Error::from("sync_byte failed")); 69 | } 70 | if packet.transport_error_indicator { 71 | return Err(Error::from("transport_error_indicator is set")); 72 | } 73 | 74 | if packet.payload_unit_start_indicator { 75 | if let Some(payload) = payloads.remove(&packet.pid) { 76 | match packet.pid { 77 | 0x0000 => { 78 | let t = try!(tsutils::ProgramAssociationTable::parse(&payload)); 79 | tracking_pids.extend(t.program_map.keys()); 80 | pat = Some(t); 81 | } 82 | _ => { 83 | if let Some(ref pat) = pat { 84 | if let Some(&program_number) = pat.program_map.get(&packet.pid) { 85 | let pmt = try!(tsutils::ProgramMapTable::parse(&payload)); 86 | if pmt.program_number != program_number { 87 | return Err(Error::from(format!("Inconsistent \ 88 | program_number for PID={}: \ 89 | PAT says {} but PMT says {}", 90 | packet.pid, 91 | program_number, 92 | pmt.program_number))); 93 | } 94 | for es in pmt.es_info { 95 | if !av_pids.contains(&es.elementary_pid) && 96 | !nonav_pids.contains(&es.elementary_pid) { 97 | match es.stream_type { 98 | 0x0f => { 99 | // Audio 100 | av_pids.insert(es.elementary_pid); 101 | } 102 | 0x02 | 0x1b => { 103 | // Video 104 | av_pids.insert(es.elementary_pid); 105 | } 106 | _ => { 107 | debug!("non-AV stream_type={:x} pid={:x}", 108 | es.stream_type, 109 | es.elementary_pid); 110 | nonav_pids.insert(es.elementary_pid); 111 | } 112 | } 113 | } 114 | } 115 | } 116 | } 117 | } 118 | } 119 | } 120 | } 121 | 122 | if tracking_pids.contains(&packet.pid) { 123 | if let Some(data_bytes) = packet.data_bytes { 124 | payloads.entry(packet.pid) 125 | .or_insert(Vec::new()) 126 | .extend_from_slice(data_bytes); 127 | } 128 | } 129 | 130 | if !av_pids.contains(&packet.pid) { 131 | try!(writer.write(&buf)); 132 | } 133 | } 134 | Ok(()) 135 | } 136 | -------------------------------------------------------------------------------- /tsutils/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate log; 3 | 4 | pub mod packet; 5 | pub mod pat; 6 | pub mod pmt; 7 | pub mod psi; 8 | 9 | pub use packet::TsPacket; 10 | pub use pat::ProgramAssociationTable; 11 | pub use pmt::ProgramMapTable; 12 | -------------------------------------------------------------------------------- /tsutils/src/packet.rs: -------------------------------------------------------------------------------- 1 | extern crate std; 2 | 3 | pub struct TsPackets { 4 | reader: R, 5 | buf: [u8; 188], 6 | } 7 | 8 | impl Iterator for TsPackets { 9 | type Item = Result<[u8; 188], std::io::Error>; 10 | 11 | fn next(&mut self) -> Option> { 12 | match self.reader.read_exact(&mut self.buf) { 13 | Ok(()) => Some(Ok(self.buf)), 14 | Err(e) => { 15 | match e.kind() { 16 | std::io::ErrorKind::UnexpectedEof => None, 17 | _ => Some(Err(e)), 18 | } 19 | } 20 | } 21 | } 22 | } 23 | 24 | pub fn ts_packets(reader: R) -> TsPackets { 25 | TsPackets { 26 | reader: reader, 27 | buf: [0; 188], 28 | } 29 | } 30 | 31 | #[derive(Debug)] 32 | pub struct TsPacket<'a> { 33 | pub sync_byte: u8, 34 | pub transport_error_indicator: bool, 35 | pub payload_unit_start_indicator: bool, 36 | pub transport_priority: bool, 37 | pub pid: u16, 38 | pub transport_scrambling_control: u8, 39 | pub adaptation_field_control: u8, 40 | pub continuity_counter: u8, 41 | pub adaptation_field: Option>, 42 | pub data_bytes: Option<&'a [u8]>, 43 | } 44 | 45 | impl<'a> TsPacket<'a> { 46 | pub fn new(packet: &'a [u8]) -> Self { 47 | // ISO/IEC 13818-1 2.4.3.2 Table 2-2 48 | // ISO/IEC 13818-1 2.4.3.3 49 | let sync_byte = packet[0]; 50 | let transport_error_indicator = (packet[1] & 0b10000000) != 0; 51 | let payload_unit_start_indicator = (packet[1] & 0b01000000) != 0; 52 | let transport_priority = (packet[1] & 0b00100000) != 0; 53 | let pid = ((packet[1] & 0b00011111) as u16) << 8 | (packet[2] as u16); 54 | let transport_scrambling_control = (packet[3] & 0b11000000) >> 6; 55 | let adaptation_field_control = (packet[3] & 0b00110000) >> 4; 56 | let continuity_counter = packet[3] & 0b00001111; 57 | 58 | let mut index = 4; 59 | 60 | let adaptation_field = if adaptation_field_control == 0b10 || 61 | adaptation_field_control == 0b11 { 62 | let adaptation_field = AdaptationField::parse(&packet[index..]); 63 | if let Some(ref af) = adaptation_field { 64 | index += af.adaptation_field_length as usize + 1; 65 | } else { 66 | index += 1 67 | } 68 | adaptation_field 69 | } else { 70 | None 71 | }; 72 | 73 | let data_bytes = if adaptation_field_control == 0b01 || adaptation_field_control == 0b11 { 74 | Some(&packet[index..]) 75 | } else { 76 | None 77 | }; 78 | 79 | TsPacket { 80 | sync_byte: sync_byte, 81 | transport_error_indicator: transport_error_indicator, 82 | payload_unit_start_indicator: payload_unit_start_indicator, 83 | transport_priority: transport_priority, 84 | pid: pid, 85 | transport_scrambling_control: transport_scrambling_control, 86 | adaptation_field_control: adaptation_field_control, 87 | continuity_counter: continuity_counter, 88 | adaptation_field: adaptation_field, 89 | data_bytes: data_bytes, 90 | } 91 | } 92 | 93 | pub fn check_sync_byte(&self) -> bool { 94 | self.sync_byte == 0x47 95 | } 96 | } 97 | 98 | #[derive(Debug)] 99 | pub struct AdaptationField<'a> { 100 | pub adaptation_field_length: u8, 101 | pub discontinuity_indicator: bool, 102 | pub random_access_indicator: bool, 103 | pub elementary_stream_priority_indicator: bool, 104 | pub transport_private_data_flag: bool, 105 | pub pcr: Option, 106 | pub opcr: Option, 107 | pub splice_countdown: Option, 108 | pub transport_private_data: Option<&'a [u8]>, 109 | pub adaptation_field_extension: Option>, 110 | } 111 | 112 | impl<'a> AdaptationField<'a> { 113 | fn parse(packet: &'a [u8]) -> Option { 114 | // ISO/IEC 13818-1 2.4.3.4 Table 2-6 115 | // ISO/IEC 13818-1 2.4.3.5 116 | let adaptation_field_length = packet[0]; 117 | if adaptation_field_length == 0 { 118 | None 119 | } else { 120 | let discontinuity_indicator = (packet[1] & 0b100000) != 0; 121 | let random_access_indicator = (packet[1] & 0b010000) != 0; 122 | let elementary_stream_priority_indicator = (packet[1] & 0b00100000) != 0; 123 | let pcr_flag = (packet[1] & 0b00010000) != 0; 124 | let opcr_flag = (packet[1] & 0b00001000) != 0; 125 | let splicing_point_flag = (packet[1] & 0b00000100) != 0; 126 | let transport_private_data_flag = (packet[1] & 0b00000010) != 0; 127 | let adaptation_field_extension_flag = (packet[1] & 0b00000001) != 0; 128 | 129 | let mut index = 2; 130 | 131 | let pcr = if pcr_flag { 132 | let pcr = PCR::new(&packet[index..]); 133 | index += PCR::size(); 134 | Some(pcr) 135 | } else { 136 | None 137 | }; 138 | 139 | let opcr = if opcr_flag { 140 | let opcr = OPCR::new(&packet[index..]); 141 | index += OPCR::size(); 142 | Some(opcr) 143 | } else { 144 | None 145 | }; 146 | 147 | let splice_countdown = if splicing_point_flag { 148 | let splice_countdown = packet[index] as i8; 149 | index += 1; 150 | Some(splice_countdown) 151 | } else { 152 | None 153 | }; 154 | 155 | let transport_private_data = if transport_private_data_flag { 156 | let length = packet[index] as usize; 157 | index += 1; 158 | let data = &packet[index..(index + length)]; 159 | index += length; 160 | Some(data) 161 | } else { 162 | None 163 | }; 164 | 165 | let adaptation_field_extension = if adaptation_field_extension_flag { 166 | let extension = AdaptationFieldExtension::new(&packet[index..]); 167 | index += extension.adaptation_field_extension_length as usize; 168 | Some(extension) 169 | } else { 170 | None 171 | }; 172 | 173 | // Check stuffing_bytes 174 | for &stuffing_byte in &packet[index..(adaptation_field_length as usize + 1)] { 175 | if stuffing_byte != 0xff { 176 | warn!("Invalid stuffing_byte in adaptation field: {}", 177 | stuffing_byte); 178 | } 179 | } 180 | 181 | Some(AdaptationField { 182 | adaptation_field_length: adaptation_field_length, 183 | discontinuity_indicator: discontinuity_indicator, 184 | random_access_indicator: random_access_indicator, 185 | elementary_stream_priority_indicator: elementary_stream_priority_indicator, 186 | transport_private_data_flag: transport_private_data_flag, 187 | pcr: pcr, 188 | opcr: opcr, 189 | splice_countdown: splice_countdown, 190 | transport_private_data: transport_private_data, 191 | adaptation_field_extension: adaptation_field_extension, 192 | }) 193 | } 194 | } 195 | } 196 | 197 | #[derive(Debug)] 198 | pub struct PCR { 199 | pub program_clock_reference_base: u64, 200 | pub reserved: u8, 201 | pub program_clock_reference_extension: u16, 202 | } 203 | 204 | impl PCR { 205 | fn new(packet: &[u8]) -> Self { 206 | PCR { 207 | program_clock_reference_base: ((packet[0] as u64) << 32) | ((packet[1] as u64) << 24) | 208 | ((packet[2] as u64) << 16) | 209 | (packet[3] as u64) << 8 | 210 | (packet[4] & 0b10000000) as u64, 211 | reserved: packet[4] & 0b01111110, 212 | program_clock_reference_extension: ((packet[4] & 0b00000001) as u16) << 8 | 213 | packet[5] as u16, 214 | } 215 | } 216 | 217 | fn size() -> usize { 218 | 6 219 | } 220 | } 221 | 222 | #[derive(Debug)] 223 | pub struct OPCR { 224 | pub original_program_clock_reference_base: u64, 225 | pub reserved: u8, 226 | pub original_program_clock_reference_extension: u16, 227 | } 228 | 229 | impl OPCR { 230 | fn new(packet: &[u8]) -> Self { 231 | OPCR { 232 | original_program_clock_reference_base: ((packet[0] as u64) << 32) | 233 | ((packet[1] as u64) << 24) | 234 | ((packet[2] as u64) << 16) | 235 | (packet[3] as u64) << 8 | 236 | (packet[4] & 0b10000000) as u64, 237 | reserved: packet[4] & 0b01111110, 238 | original_program_clock_reference_extension: ((packet[4] & 0b00000001) as u16) << 8 | 239 | packet[5] as u16, 240 | } 241 | } 242 | 243 | fn size() -> usize { 244 | 6 245 | } 246 | } 247 | 248 | #[derive(Debug)] 249 | pub struct AdaptationFieldExtension<'a> { 250 | pub adaptation_field_extension_length: u8, 251 | pub reserved: u8, 252 | pub ltw: Option, 253 | pub piecewise_rate: Option, 254 | pub seamless_splice: Option, 255 | pub trailing_reserved: &'a [u8], 256 | } 257 | 258 | impl<'a> AdaptationFieldExtension<'a> { 259 | fn new(packet: &'a [u8]) -> Self { 260 | let adaptation_field_extension_length = packet[0]; 261 | let ltw_flag = (packet[1] & 0b10000000) != 0; 262 | let piecewise_rate_flag = (packet[1] & 0b01000000) != 0; 263 | let seamless_splice_flag = (packet[1] & 0b00100000) != 0; 264 | let reserved = packet[1] & 0b00011111; 265 | 266 | let mut index = 2; 267 | 268 | let ltw = if ltw_flag { 269 | let ltw = LegalTimeWindow::new(&packet[index..]); 270 | index += LegalTimeWindow::size(); 271 | Some(ltw) 272 | } else { 273 | None 274 | }; 275 | 276 | let piecewise_rate = if piecewise_rate_flag { 277 | let rate = ((packet[index] & 0b00111111) as u32) << 16 | 278 | ((packet[index + 1] as u32) << 16) | 279 | (packet[index + 1] as u32); 280 | index += 3; 281 | Some(rate) 282 | } else { 283 | None 284 | }; 285 | 286 | let seamless_splice = if seamless_splice_flag { 287 | let splice = SeamlessSplice::new(&packet[index..]); 288 | index += SeamlessSplice::size(); 289 | Some(splice) 290 | } else { 291 | None 292 | }; 293 | 294 | let trailing_reserved = &packet[index..]; 295 | 296 | AdaptationFieldExtension { 297 | adaptation_field_extension_length: adaptation_field_extension_length, 298 | reserved: reserved, 299 | ltw: ltw, 300 | piecewise_rate: piecewise_rate, 301 | seamless_splice: seamless_splice, 302 | trailing_reserved: trailing_reserved, 303 | } 304 | } 305 | } 306 | 307 | #[derive(Debug)] 308 | pub struct LegalTimeWindow { 309 | pub ltw_valid_flag: bool, 310 | pub ltw_offset: u16, 311 | } 312 | 313 | impl LegalTimeWindow { 314 | fn new(packet: &[u8]) -> Self { 315 | LegalTimeWindow { 316 | ltw_valid_flag: (packet[0] & 0b10000000) != 0, 317 | ltw_offset: ((packet[0] & 0b01111111) as u16) << 8 | (packet[1] as u16), 318 | } 319 | } 320 | 321 | fn size() -> usize { 322 | 2 323 | } 324 | } 325 | 326 | #[derive(Debug)] 327 | pub struct SeamlessSplice { 328 | pub splice_type: u8, 329 | pub dts_next_au: u64, 330 | } 331 | 332 | impl SeamlessSplice { 333 | fn new(packet: &[u8]) -> Self { 334 | SeamlessSplice { 335 | splice_type: packet[0] & 0b11110000, 336 | dts_next_au: ((((packet[0] & 0b00001110) >> 1) as u64) << 30 | 337 | ((packet[1] >> 1) as u64) << 15 | 338 | ((packet[2] >> 1) as u64)), 339 | } 340 | } 341 | 342 | fn size() -> usize { 343 | 5 344 | } 345 | } 346 | -------------------------------------------------------------------------------- /tsutils/src/pat.rs: -------------------------------------------------------------------------------- 1 | extern crate std; 2 | 3 | #[derive(Debug)] 4 | pub struct ProgramAssociationTable { 5 | pub table_id: u8, 6 | pub transport_stream_id: u16, 7 | pub version_number: u8, 8 | pub current_next_indicator: bool, 9 | pub section_number: u8, 10 | pub last_section_number: u8, 11 | pub program_map: std::collections::HashMap, 12 | pub crc32: u32, 13 | } 14 | 15 | impl ProgramAssociationTable { 16 | pub fn parse(payload: &[u8]) -> Result { 17 | // ISO/IEC 13818-1 2.4.4.1 Table 2-29 18 | // ISO/IEC 13818-1 2.4.4.2 19 | let pointer_field = payload[0] as usize; 20 | let payload = &payload[(1 + pointer_field)..]; 21 | 22 | // ISO/IEC 13818-1 2.4.4.3 Table 2-30 23 | // ISO/IEC 13818-1 2.4.4.4 24 | let table_id = payload[0]; 25 | if table_id != 0x00 { 26 | return Err(super::psi::ParseError::IncorrectTableId { 27 | expected: 0x00, 28 | actual: table_id, 29 | }); 30 | } 31 | 32 | // ISO/IEC 13818-1 2.4.4.5 33 | let section_syntax_indicator = (payload[1] & 0b10000000) != 0; 34 | if !section_syntax_indicator { 35 | return Err(super::psi::ParseError::IncorrectSectionSyntaxIndicator); 36 | } 37 | let section_length = ((payload[1] & 0b00001111) as usize) << 8 | payload[2] as usize; 38 | let transport_stream_id = ((payload[3] as u16) << 8) | payload[4] as u16; 39 | let version_number = (payload[5] & 0b00111110) >> 1; 40 | let current_next_indicator = (payload[5] & 0b00000001) != 0; 41 | let section_number = payload[6]; 42 | let last_section_number = payload[7]; 43 | 44 | let n = (section_length - 5) / 4; 45 | let mut program_map = std::collections::HashMap::new(); 46 | for i in 0..n { 47 | let index = 8 + i * 4; 48 | let program_number = (payload[index] as u16) << 8 | payload[index + 1] as u16; 49 | let pid = ((payload[index + 2] & 0b00011111) as u16) << 8 | payload[index + 3] as u16; 50 | if program_number == 0 { 51 | // Network_PID 52 | } else { 53 | program_map.insert(pid, program_number); 54 | } 55 | } 56 | let index = 8 + n * 4; 57 | let crc32 = (payload[index] as u32) << 24 | (payload[index + 1] as u32) << 16 | 58 | (payload[index + 2] as u32) << 8 | 59 | payload[index + 3] as u32; 60 | 61 | Ok(ProgramAssociationTable { 62 | table_id: table_id, 63 | transport_stream_id: transport_stream_id, 64 | version_number: version_number, 65 | current_next_indicator: current_next_indicator, 66 | section_number: section_number, 67 | last_section_number: last_section_number, 68 | program_map: program_map, 69 | crc32: crc32, 70 | }) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tsutils/src/pmt.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | pub struct ProgramMapTable<'a> { 3 | pub table_id: u8, 4 | pub program_number: u16, 5 | pub version_number: u8, 6 | pub current_next_indicator: bool, 7 | pub section_number: u8, 8 | pub last_section_number: u8, 9 | pub pcr_pid: u16, 10 | pub program_info: &'a [u8], 11 | pub es_info: Vec>, 12 | pub crc32: u32, 13 | } 14 | 15 | impl<'a> ProgramMapTable<'a> { 16 | pub fn parse(payload: &'a [u8]) -> Result { 17 | // ISO/IEC 13818-1 2.4.4.1 Table 2-29 18 | // ISO/IEC 13818-1 2.4.4.2 19 | let pointer_field = payload[0] as usize; 20 | let payload = &payload[(1 + pointer_field)..]; 21 | 22 | // ISO/IEC 13818-1 2.4.4.8 Table 2-33 23 | // ISO/IEC 13818-1 2.4.4.9 Table 2-33 24 | let table_id = payload[0]; 25 | if table_id != 0x02 { 26 | return Err(super::psi::ParseError::IncorrectTableId { 27 | expected: 0x02, 28 | actual: table_id, 29 | }); 30 | } 31 | let section_syntax_indicator = (payload[1] & 0b10000000) != 0; 32 | if !section_syntax_indicator { 33 | return Err(super::psi::ParseError::IncorrectSectionSyntaxIndicator); 34 | } 35 | let section_length = ((payload[1] & 0b00001111) as usize) << 8 | payload[2] as usize; 36 | let program_number = (payload[3] as u16) << 8 | payload[4] as u16; 37 | let version_number = (payload[5] & 0b00111110) >> 1; 38 | let current_next_indicator = (payload[5] & 0b00000001) != 0; 39 | let section_number = payload[6]; 40 | let last_section_number = payload[7]; 41 | let pcr_pid = ((payload[8] & 0b00011111) as u16) << 8 | payload[9] as u16; 42 | let program_info_length = ((payload[10] & 0b00001111) as usize) << 8 | payload[11] as usize; 43 | let program_info = &payload[12..(12 + program_info_length)]; 44 | 45 | let mut index = 12 + program_info_length; 46 | let mut es_info = vec![]; 47 | while index < 3 + section_length - 4 { 48 | let info = EsInfo::new(&payload[index..]); 49 | index += info.size(); 50 | es_info.push(info); 51 | } 52 | let crc32 = (payload[3 + section_length - 4] as u32) << 24 | 53 | (payload[3 + section_length - 3] as u32) << 16 | 54 | (payload[3 + section_length - 2] as u32) << 8 | 55 | (payload[3 + section_length - 1] as u32); 56 | 57 | Ok(ProgramMapTable { 58 | table_id: table_id, 59 | program_number: program_number, 60 | version_number: version_number, 61 | current_next_indicator: current_next_indicator, 62 | section_number: section_number, 63 | last_section_number: last_section_number, 64 | pcr_pid: pcr_pid, 65 | program_info: program_info, 66 | es_info: es_info, 67 | crc32: crc32, 68 | }) 69 | } 70 | } 71 | 72 | #[derive(Debug)] 73 | pub struct EsInfo<'a> { 74 | pub stream_type: u8, 75 | pub elementary_pid: u16, 76 | pub descriptor: &'a [u8], 77 | } 78 | 79 | impl<'a> EsInfo<'a> { 80 | pub fn new(payload: &'a [u8]) -> Self { 81 | let stream_type = payload[0]; 82 | let elementary_pid = ((payload[1] & 0b00011111) as u16) << 8 | payload[2] as u16; 83 | let es_info_length = ((payload[3] & 0b00001111) as usize) << 8 | payload[4] as usize; 84 | let descriptor = &payload[5..(5 + es_info_length)]; 85 | EsInfo { 86 | stream_type: stream_type, 87 | elementary_pid: elementary_pid, 88 | descriptor: descriptor, 89 | } 90 | } 91 | 92 | pub fn size(&self) -> usize { 93 | 5 + self.descriptor.len() 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /tsutils/src/psi.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | pub enum ParseError { 3 | IncorrectTableId { expected: u8, actual: u8 }, 4 | IncorrectSectionSyntaxIndicator, 5 | } 6 | --------------------------------------------------------------------------------