1 2 module decoder; 3 4 import std.array; 5 import std.exception; 6 import std.math; 7 import std.stdio; 8 import std.string; 9 import stdint; 10 import bitstream; 11 import vlc; 12 import macroblock; 13 import matrix; 14 import dct; 15 import fast_dct; 16 import math; 17 18 const MACROBLOCK_SIZE = 16; 19 const ZERO_MV = (short[2]).init; 20 21 class Plane 22 { 23 private short[] _pixels; 24 private size_t _width; 25 private size_t _height; 26 ubyte _scalex; 27 ubyte _scaley; 28 29 this(size_t width, size_t height, ubyte scalex, ubyte scaley) 30 { 31 _width = width; 32 _height = height; 33 _pixels = new short[width * height]; 34 _scalex = scalex; 35 _scaley = scaley; 36 } 37 38 ref short opIndex(size_t x, size_t y) 39 { 40 return _pixels[y * _width + x]; 41 } 42 43 short opIndex(size_t x, size_t y) const 44 { 45 return _pixels[y * _width + x]; 46 } 47 48 const(short)[] pixels() const @property 49 { 50 return _pixels; 51 } 52 53 short[] pixels() @property 54 { 55 return _pixels; 56 } 57 58 ubyte scalex() const @property 59 { 60 return _scalex; 61 } 62 63 ubyte scaley() const @property 64 { 65 return _scaley; 66 } 67 68 size_t width() const @property 69 { 70 return _width; 71 } 72 73 size_t height() const @property 74 { 75 return _height; 76 } 77 } 78 79 class Picture 80 { 81 Plane[3] planes; // YUV 82 83 uint dts; 84 uint pts; 85 size_t width; 86 size_t height; 87 88 this(size_t width, size_t height, ChromaFormat cf) 89 { 90 this.width = width; 91 this.height = height; 92 93 ubyte scalex, scaley; 94 95 final switch(cf) 96 { 97 case ChromaFormat.C444: 98 scalex = 0; 99 scaley = 0; 100 break; 101 case ChromaFormat.C422: 102 scalex = 0; 103 scaley = 1; 104 break; 105 case ChromaFormat.C420: 106 scalex = 1; 107 scaley = 1; 108 break; 109 } 110 111 planes[0] = new Plane(width, height, 0, 0); 112 113 foreach(i; 1..3) 114 { 115 planes[i] = new Plane(width >> scalex, height >> scaley, scalex, scaley); 116 } 117 } 118 119 uint width_in_mb() @property const 120 { 121 return cast(uint) width / MACROBLOCK_SIZE; 122 } 123 124 uint height_in_mb() @property const 125 { 126 return cast(uint) height / MACROBLOCK_SIZE; 127 } 128 129 void dump_block(const short[64] block, int mba, ulong comp, string comment = "") 130 { 131 writefln("MBA #%d block #%d%s: ", mba, comp, comment); 132 133 for(size_t i=0; i<8; ++i) 134 { 135 writef(" "); 136 for(size_t j=0; j<8; ++j) 137 { 138 writef("%3d ", block[i*8+j]); 139 } 140 writeln(); 141 } 142 writeln(); 143 } 144 } 145 146 class PictureBuilder 147 { 148 int previous_macroblock_address = -1; 149 PictureHeader ph; 150 short[3] dct_pred; 151 short[2][2][2] PMV; 152 Picture pic; 153 Picture[] dpb; 154 155 this(PictureHeader ph, Picture[] dpb) 156 { 157 this.ph = ph; 158 this.dpb = dpb; 159 this.pic = new Picture(ph.si.width, ph.si.height, ph.si.chroma_format); 160 } 161 162 void process(const ref MacroBlock mb) 163 { 164 if(mb.incr > 1) 165 { 166 process_skipped_mbs(mb.incr - 1); 167 } 168 169 int mba = previous_macroblock_address + mb.incr; 170 previous_macroblock_address = mba; 171 //mb.dump2(mba, true); 172 //mb.dump(); 173 174 motion_compensate(mb); 175 176 if(ph.picture_coding_type == PictureType.I 177 && (!mb.p.intra || mb.incr > 1)) 178 { 179 reset_dc_predictors(); 180 } 181 uint bx = (mba % pic.width_in_mb) * MACROBLOCK_SIZE; 182 uint by = (mba / pic.width_in_mb) * MACROBLOCK_SIZE; 183 184 foreach(uint bi; 0..mb.block_count) 185 { 186 uint cc = (bi < 4)? 0 : ((bi & 1) + 1); 187 188 short[64] block; 189 190 //dump_block(b.coeffs, mba, bi); 191 192 block = reorder_coefs(mb.blocks[bi].coeffs, ph.alternate_scan); 193 194 block[0] += dct_pred[cc]; 195 dct_pred[cc] = block[0]; 196 197 iquant(block, bi, mb); 198 //dump_block(block, mba, bi, " (dct)"); 199 fast_idct_annexA(block); 200 //dump_block(block, mba, bi, " (rec samples)"); 201 202 add_block(block, cc, bi, bx, by); 203 } 204 205 } 206 207 private void process_skipped_mbs(int num) 208 { 209 if(ph.picture_coding_type == PictureType.P) 210 { 211 reset_mv_predictors(); 212 for(int s = previous_macroblock_address + 1; s<previous_macroblock_address + num + 1; ++s) 213 { 214 apply_mv(s, ZERO_MV); 215 } 216 } 217 } 218 219 private void motion_compensate(const ref MacroBlock mb) 220 { 221 enforce(mb.predinfo.type == PredictionType.Frame); 222 enforce(mb.predinfo.mv_format == MvFormat.Frame); 223 enforce(mb.predinfo.dmv == false); 224 225 if(ph.picture_coding_type == PictureType.P && mb.p.motion_forward == false) 226 { 227 apply_mv(previous_macroblock_address, ZERO_MV); 228 reset_mv_predictors(); 229 return; 230 } 231 232 foreach(r; 0..mb.predinfo.motion_vector_count) 233 { 234 if(mb.p.motion_forward) 235 { 236 motion_compensate(mb, r, 0); 237 } 238 if(mb.p.motion_backward) 239 { 240 motion_compensate(mb, r, 1); 241 } 242 } 243 } 244 245 void motion_compensate(const ref MacroBlock mb, int r, int s) 246 { 247 foreach(t; 0..2) 248 { 249 auto r_size = ph.f_code[s][t] - 1; 250 auto f = (1 << r_size); 251 auto high = 16 * f - 1; 252 auto low = -16 * f; 253 auto range = 32 * f; 254 255 short delta; 256 if(f == 1 || mb.motion_code[r][s][t] == 0) 257 { 258 delta = mb.motion_code[r][s][t]; 259 } 260 else 261 { 262 delta = cast(short)(((abs(mb.motion_code[r][s][t]) - 1) * f) + mb.motion_residual[r][s][t] + 1); 263 if (mb.motion_code[r][s][t] < 0) 264 delta = -delta; 265 } 266 267 short prediction = PMV[r][s][t]; 268 269 auto v = cast(short)(prediction + delta); 270 if(v < low) v += range; 271 if(v > high) v -= range; 272 273 PMV[r][s][t] = v; 274 } 275 276 // form block prediction 277 278 int mba = previous_macroblock_address; 279 280 apply_mv(mba, PMV[r][s]); 281 } 282 283 private void apply_mv(int mba, const ref short[2] mv0) 284 { 285 enforce(dpb.length > 0); 286 auto rf = dpb.back; 287 288 uint bx0 = (mba % pic.width_in_mb) * MACROBLOCK_SIZE; 289 uint by0 = (mba / pic.width_in_mb) * MACROBLOCK_SIZE; 290 //writefln("mv[%s][%s][%d][%d]: %d %d", bx, by, r, s, mvx1, mvy1); 291 292 foreach(cc; 0..3) 293 { 294 auto plane = pic.planes[cc]; 295 296 uint bx = bx0 >> plane.scalex; 297 uint by = by0 >> plane.scaley; 298 299 uint bw = 16 >> plane.scalex; 300 uint bh = 16 >> plane.scaley; 301 302 short[2] mv = mv0; 303 304 mv[0] >>= plane.scalex; 305 mv[1] >>= plane.scaley; 306 307 short[2] mv1 = mv[] / 2; 308 short[2] mv2 = mv1[] + mv[] % 2; 309 310 auto p = plane.pixels.ptr + by * plane.width + bx; 311 auto pp1 = rf.planes[cc].pixels.ptr + (by + mv1[1]) * plane.width + bx + mv1[0]; 312 auto pp2 = rf.planes[cc].pixels.ptr + (by + mv2[1]) * plane.width + bx + mv2[0]; 313 314 for(int y=by; y<by + bh; ++y) 315 { 316 for(int x=bx; x<bx + bw; ++x, ++p, ++pp1, ++pp2) 317 { 318 const auto v = (*pp1 + *pp2) / 2; 319 *p += v; 320 } 321 322 p += plane.width - bw; 323 pp1 += plane.width - bw; 324 pp2 += plane.width - bw; 325 } 326 } 327 } 328 329 void add_block(const ref short[64] block, uint cc, uint comp, uint bx, uint by) 330 { 331 auto plane = pic.planes[cc]; 332 short base = 0; 333 if(ph.picture_coding_type == PictureType.I) 334 { 335 base = 128; 336 } 337 338 if(cc > 0) 339 { 340 bx >>= plane.scalex; 341 by >>= plane.scaley; 342 } 343 344 if(cc == 0 || ph.si.chroma_format == ChromaFormat.C444) 345 { 346 int cx = (comp % 2) * 8; 347 int cy = (comp / 2) * 8; 348 349 for(int i=0; i<8; ++i) 350 { 351 for(int j=0; j<8; ++j) 352 { 353 plane[bx + cx + j, by + cy + i] += cast(short) saturate!(int, 0, 255)(block[i * 8 + j] + base); 354 } 355 } 356 } 357 else if(ph.si.chroma_format == ChromaFormat.C420) 358 { 359 for(int i=0; i<8; ++i) 360 { 361 for(int j=0; j<8; ++j) 362 { 363 const auto v = cast(short) saturate!(int, 0, 255)(block[i * 8 + j] + base); 364 365 plane[bx + j, by + i] += v; 366 } 367 } 368 } 369 else if(ph.si.chroma_format == ChromaFormat.C422) 370 { 371 int cy = (comp / 2) * 8; 372 373 for(int i=0; i<8; ++i) 374 { 375 for(int j=0; j<8; ++j) 376 { 377 const auto v = cast(short) saturate!(int, 0, 255)(block[i * 8 + j] + base); 378 plane[bx + 0 + j, by + cy + i] += v; 379 plane[bx + 8 + j, by + cy + i] += v; 380 } 381 } 382 } 383 } 384 385 private void reset_dc_predictors() 386 { 387 foreach(i; 0..3) 388 { 389 //dct_pred[i] = DCT_PRED_DEFAULT[ph.intra_dc_precision]; 390 dct_pred[i] = 0; 391 } 392 } 393 394 private void reset_mv_predictors() 395 { 396 PMV = PMV.init; 397 } 398 399 void process_new_slice(Slice s) 400 { 401 reset_dc_predictors(); 402 previous_macroblock_address = int(s.slice_vert_pos * pic.width_in_mb) - 1; 403 } 404 405 private short[64] reorder_coefs(short[64] c, int scan_id) 406 { 407 short[64] r; 408 409 for(int i=0; i<64; ++i) 410 { 411 r[SCAN_MATRIX[scan_id][i]] = c[i]; 412 } 413 414 return r; 415 } 416 417 alias quant_saturate = saturate!(short, -2048, 2047); 418 419 private void iquant(ref short[64] b, ulong c, const ref MacroBlock mb) 420 { 421 auto quantiser_scale = QUANTISER_SCALE_MATRIX[ph.q_scale_type][mb.s.quantiser_scale_code]; 422 int cc = ph.si.chroma_format == ChromaFormat.C420? 0: (c >= 4); 423 int w = (mb.p.intra? 0: 1) + 2 * cc; 424 425 b[0] *= INTRA_DC_MULT[ph.intra_dc_precision]; 426 b[0] = quant_saturate(b[0]); 427 428 short sum = b[0]; // for mismatch control 429 for(int i=1; i<64; ++i) 430 { 431 auto k = mb.p.intra?0:sign(b[i]); 432 b[i] = cast(short)((2 * b[i] + k) * DEFAULT_QUANT_MATRIX[w][i] * quantiser_scale / 32); 433 434 b[i] = quant_saturate(b[i]); 435 436 sum |= b[i]; 437 } 438 439 // mismatch control 440 if((sum & 1) == 0) 441 { 442 b[63] += (b[63]&1)? -1: 1; 443 } 444 } 445 } 446 447 enum PictureStructure 448 { 449 Reserved = 0, 450 TopField = 1, 451 BottomField = 2, 452 Frame = 3, 453 } 454 455 enum PictureType 456 { 457 I = 1, 458 P = 2, 459 B = 3, 460 } 461 462 class PictureHeader 463 { 464 SequenceInfo si; 465 466 uint temporal_reference; 467 PictureType picture_coding_type; 468 uint vbv_delay; 469 470 ubyte[2][2] f_code; 471 ubyte intra_dc_precision; 472 ubyte picture_structure; 473 bool top_field_first; 474 bool frame_pred_frame_dct; 475 bool concealment_motion_vectors; 476 bool q_scale_type; 477 bool intra_vlc_format; 478 bool alternate_scan; 479 bool repeat_first_field; 480 bool chroma_420_type; 481 bool progressive_frame; 482 bool composite_display_flag; 483 484 // if composite_display_flag 485 bool v_axis; 486 ubyte field_sequence; 487 bool sub_carrier; 488 ubyte burst_amplitude; 489 ubyte sub_carrier_phase; 490 491 this(SequenceInfo si) 492 { 493 this.si = si; 494 } 495 496 void parse(BitstreamReader bs) 497 { 498 temporal_reference = bs.read_u(10); 499 picture_coding_type = cast(PictureType) bs.read_b(3); 500 vbv_delay = bs.read_u(16); 501 502 if(picture_coding_type == 2 || picture_coding_type == 3) 503 { 504 bs.skip_u(4); 505 } 506 507 if(picture_coding_type == 3) 508 { 509 bs.skip_u(4); 510 } 511 512 ubyte extra_bit = bs.read_u1; 513 while(extra_bit == 1) 514 { 515 bs.skip_u(8); 516 } 517 } 518 519 void parse_extension(BitstreamReader bs) 520 { 521 f_code[0][0] = bs.read_b(4); 522 f_code[0][1] = bs.read_b(4); 523 f_code[1][0] = bs.read_b(4); 524 f_code[1][1] = bs.read_b(4); 525 526 intra_dc_precision = bs.read_b(2); 527 picture_structure = bs.read_b(2); 528 529 top_field_first = bs.read_bool(); 530 frame_pred_frame_dct = bs.read_bool(); 531 concealment_motion_vectors = bs.read_bool(); 532 q_scale_type = bs.read_bool(); 533 intra_vlc_format = bs.read_bool(); 534 alternate_scan = bs.read_bool(); 535 repeat_first_field = bs.read_bool(); 536 chroma_420_type = bs.read_bool(); 537 progressive_frame = bs.read_bool(); 538 composite_display_flag = bs.read_bool(); 539 540 if(composite_display_flag) 541 { 542 v_axis = bs.read_bool; 543 field_sequence = bs.read_b(3); 544 sub_carrier = bs.read_bool; 545 burst_amplitude = bs.read_b(7); 546 sub_carrier_phase = bs.read_b(8); 547 } 548 549 enforce(!concealment_motion_vectors, "concealment_motion_vectors are not implemented"); 550 } 551 552 void dump() 553 { 554 string pictype; 555 final switch(picture_coding_type) 556 { 557 case PictureType.I: pictype = "I"; break; 558 case PictureType.P: pictype = "P"; break; 559 case PictureType.B: pictype = "B"; break; 560 } 561 562 string picstruct; 563 final switch(picture_structure) 564 { 565 case 0b01: picstruct = "Top Field"; break; 566 case 0b10: picstruct = "Bottom Field"; break; 567 case 0b11: picstruct = "Frame"; break; 568 } 569 570 writefln("pic #%04d %s %s", temporal_reference, pictype, picstruct); 571 } 572 } 573 574 enum Profile 575 { 576 Simple, 577 Main, 578 SnrScalable, 579 SpartialyScalable, 580 High, 581 } 582 583 enum Level 584 { 585 Low, 586 Main, 587 High1440, 588 High, 589 } 590 591 enum ChromaFormat 592 { 593 C420 = 1, 594 C422 = 2, 595 C444 = 3, 596 } 597 598 Profile parse_profile(ubyte profile) 599 { 600 final switch(profile) 601 { 602 case 0b101: 603 return Profile.Simple; 604 case 0b100: 605 return Profile.Main; 606 case 0b011: 607 return Profile.SnrScalable; 608 case 0b010: 609 return Profile.SpartialyScalable; 610 case 0b001: 611 return Profile.High; 612 } 613 } 614 615 Level parse_level(ubyte level) 616 { 617 final switch(level) 618 { 619 case 0b1010: 620 return Level.Low; 621 case 0b1000: 622 return Level.Main; 623 case 0b0110: 624 return Level.High1440; 625 case 0b0100: 626 return Level.High; 627 } 628 } 629 630 ChromaFormat parse_chroma_format(ubyte b) 631 { 632 final switch(b) 633 { 634 case 0x01: 635 return ChromaFormat.C420; 636 case 0x02: 637 return ChromaFormat.C422; 638 case 0x03: 639 return ChromaFormat.C444; 640 } 641 } 642 643 class SequenceInfo 644 { 645 int width; 646 int height; 647 int aspect_ratio; 648 int frame_rate; 649 int bitrate; 650 int vbv_buffer_size; 651 652 bool load_intra_quantizer_matrix; 653 bool load_non_intra_quantizer_matrix; 654 ubyte[64] intra_quantizer_matrix; 655 ubyte[64] non_intra_quantizer_matrix; 656 657 Profile profile; 658 Level level; 659 660 bool progressive; 661 bool low_delay; 662 ChromaFormat chroma_format; 663 664 void dump() 665 { 666 writefln("SEQUENCE HEADER:"); 667 writefln("\tsize: %sx%s", width, height); 668 writefln("\tfr: %s", frame_rate); 669 writefln("\tar: %s", aspect_ratio); 670 writefln("\tbitrate: %s Mbps", bitrate * 400 / 1000000); 671 writefln("\tvbv_buffer_size: %s",vbv_buffer_size); 672 673 if(load_intra_quantizer_matrix) 674 { 675 writefln("\tintra qmatrix:"); 676 foreach(i; 0..8) 677 { 678 write("\t\t"); 679 foreach(j; 0..8) 680 { 681 write("%02d ", intra_quantizer_matrix[i*8 + j]); 682 } 683 writeln(""); 684 } 685 686 } 687 688 if(load_non_intra_quantizer_matrix) 689 { 690 writefln("\tnon_intra qmatrix:"); 691 foreach(i; 0..8) 692 { 693 write("\t\t"); 694 foreach(j; 0..8) 695 { 696 write("%02d ", non_intra_quantizer_matrix[i*8 + j]); 697 } 698 writeln(""); 699 } 700 701 } 702 703 writefln("profile: %s", profile); 704 writefln("level: %s", level); 705 writefln("progressive: %s", progressive); 706 writefln("low_delay: %s", low_delay); 707 writefln("chroma_format: %s", chroma_format); 708 } 709 } 710 711 class Slice 712 { 713 this(PictureHeader ph) 714 { 715 this.ph = ph; 716 } 717 718 void parse(BitstreamReader bs, uint start_code) 719 { 720 slice_vert_pos = start_code - 1; 721 722 if(ph.si.height > 2800) 723 { 724 slice_vert_pos = bs.read_u(3) << slice_vert_pos; 725 } 726 727 //TODO: implement priority_breakpoint 728 729 quantiser_scale_code = bs.read_u(5); 730 731 if(bs.peek_u1) 732 { 733 slice_extension_flag = bs.read_bool; 734 intra_slice = bs.read_bool; 735 slice_picture_id_enable = bs.read_bool; 736 slice_picture_id = bs.read_b(6); 737 738 while(bs.peek_u1) 739 { 740 bs.read_u1; 741 bs.skip_u(8); 742 } 743 } 744 745 bs.skip_u1; 746 } 747 748 void dump() 749 { 750 writefln("slice %02d:", slice_vert_pos); 751 writefln("\tquantiser_scale_code: %d", quantiser_scale_code); 752 writefln("\tslice_extension_flag: %d", slice_extension_flag); 753 writefln("\tintra_slice: %d", intra_slice); 754 writefln("\tslice_picture_id_enable: %d", slice_picture_id_enable); 755 writefln("\tslice_picture_id: %d", slice_picture_id); 756 } 757 758 PictureHeader ph; 759 int slice_vert_pos; 760 int quantiser_scale_code; 761 bool slice_extension_flag; 762 bool intra_slice; 763 bool slice_picture_id_enable; 764 ubyte slice_picture_id; 765 766 } 767 768 struct GopInfo 769 { 770 int time_code; 771 bool closed_gop; 772 bool broken_link; 773 } 774 775 class Decoder 776 { 777 this(string filename) 778 { 779 _init_parsers(); 780 781 auto f = File(filename, "rb"); 782 783 auto content = new ubyte[f.size()]; 784 785 content = f.rawRead(content); 786 787 this.bs = new BitstreamReader(content); 788 } 789 790 Picture decode() 791 { 792 while(!bs.eof && !_picture_ready()) 793 { 794 _read_syntax_element(); 795 //_process_syntax_element(se); 796 } 797 798 if(_pics.length == 0) 799 { 800 return null; 801 } 802 803 auto f = _pics[0]; 804 _pics.popFront(); 805 return f; 806 } 807 808 void _read_syntax_element() 809 { 810 bs.align_to_next_byte(); 811 812 int state = 0; 813 int cnt = 0; 814 815 immutable int[][] xlat = [ 816 [1, 0], 817 [2, 0], 818 [0, 3], 819 ]; 820 821 while(state < 3 && !bs.eof) 822 { 823 ubyte b = bs.read_u8(); 824 ++cnt; 825 826 if(b != 0 && b != 1) 827 { 828 state = 0; 829 continue; 830 } 831 832 state = xlat[state][b]; 833 } 834 835 if(bs.eof) 836 { 837 return; 838 } 839 840 if(cnt > 3) writefln("warn: skipped %s bytes to next high level syntax element", cnt - 3); 841 842 auto start_code = bs.read_u8(); 843 844 //writefln("found syntax element %X (%s) at position %s", start_code, start_code_str(start_code), bs.bits_read() / 8); 845 if(start_code !in _parsers) 846 { 847 writefln("unknown syntax element %X (%s) at position %s", start_code, start_code_str(start_code), bs.bits_read() / 8); 848 return; 849 } 850 851 _parsers[start_code](start_code); 852 } 853 854 private void _maybe_flush_picture() 855 { 856 if(picture_builder !is null) 857 { 858 _pics ~= picture_builder.pic; 859 dpb ~= picture_builder.pic; 860 if(dpb.length > 2) 861 { 862 dpb = dpb[$-2..$]; 863 } 864 picture_builder = null; 865 } 866 } 867 868 private void _parse_sequence_header(ubyte start_code) 869 { 870 _maybe_flush_picture(); 871 872 si = new SequenceInfo; 873 874 si.width = bs.read_u(12); 875 si.height = bs.read_u(12); 876 si.aspect_ratio = bs.read_u(4); 877 878 int frame_rate_code = bs.read_u(4); 879 880 si.bitrate = bs.read_u(18); 881 bs.skip_u1(); 882 si.vbv_buffer_size = bs.read_u(10); 883 bs.skip_u1(); 884 885 si.load_intra_quantizer_matrix = cast(bool) bs.read_u1; 886 887 if(si.load_intra_quantizer_matrix) 888 { 889 bs.read_bytes(si.intra_quantizer_matrix); 890 throw new Exception("custom quantizer matrixes are not supported"); 891 } 892 893 si.load_non_intra_quantizer_matrix = cast(bool) bs.read_u1; 894 895 if(si.load_non_intra_quantizer_matrix) 896 { 897 bs.read_bytes(si.non_intra_quantizer_matrix); 898 throw new Exception("custom quantizer matrixes are not supported"); 899 } 900 901 //si.dump(); 902 } 903 904 private void _parse_sequence_extention() 905 { 906 ubyte pal = bs.read_u8(); // profile_and_level 907 908 if(pal & 0x80) 909 { 910 throw new Exception("escape code not implemented"); 911 } 912 else 913 { 914 si.profile = parse_profile((pal & 0x70) >> 4); 915 si.level = parse_level(pal & 0x0f); 916 } 917 918 si.progressive = cast(bool) bs.read_u1; 919 si.chroma_format = parse_chroma_format(cast(ubyte) bs.read_u(2)); 920 921 si.width = (si.width & 0x0fff) | (bs.read_u(2) << 12); 922 si.height = (si.height & 0x0fff) | (bs.read_u(2) << 12); 923 si.bitrate = (si.bitrate & 0x03ffff) | (bs.read_u(12) << 18); 924 enforce(bs.read_u1 == 1, "marker bit"); 925 si.vbv_buffer_size = (si.vbv_buffer_size & 0x03ff) | (bs.read_u(8) << 10); 926 927 si.low_delay = cast(bool) bs.read_u1; 928 929 // frame_rate 930 bs.read_u(2); 931 bs.read_u(5); 932 933 enforce(bs.is_byte_aligned); 934 //si.dump(); 935 } 936 937 private void _parse_extension(ubyte start_code) 938 { 939 ubyte extension_start_code = bs.read_b(4); 940 941 _ext_parsers[extension_start_code](); 942 } 943 944 private void _parse_picture_extension() 945 { 946 ph.parse_extension(bs); 947 //writefln("================== pic #%03d =======================", ph.temporal_reference); 948 //ph.dump(); 949 //expected_extension = ExpectedExtension.ExtensionAndUserData; 950 //extension_i = 2; 951 } 952 953 private void _parse_slice(ubyte start_code) 954 { 955 auto s = new Slice(ph); 956 957 s.parse(bs, start_code); 958 //s.dump(); 959 960 picture_builder.process_new_slice(s); 961 962 do { 963 auto mb = MacroBlock(s); 964 auto oldp = bs.bits_read; 965 mb.parse(bs); 966 auto newp = bs.bits_read; 967 //writefln("mb: %d -> %d (%d)", oldp, newp, newp - oldp); 968 picture_builder.process(mb); 969 } while( bs.nextbits(23) != 0); 970 } 971 972 private void _parse_picture_header(ubyte start_code) 973 { 974 _maybe_flush_picture(); 975 ph = new PictureHeader(si); 976 ph.parse(bs); 977 picture_builder = new PictureBuilder(ph, dpb); 978 } 979 980 private void _parse_extension_and_user_data(int i) 981 { 982 writefln("extension_and_user_data(%d)", i); 983 } 984 985 private void _parse_group_of_picture_header(ubyte start_code) 986 { 987 gopi.time_code = bs.read_u(25); 988 gopi.closed_gop = bs.read_bool; 989 gopi.broken_link = bs.read_bool; 990 991 //expected_extension = ExpectedExtension.ExtensionAndUserData; 992 //extension_i = 1; 993 } 994 995 private bool _picture_ready() 996 { 997 return _pics.length > 0; 998 } 999 1000 private void _init_parsers() 1001 { 1002 _parsers[0x00] = &_parse_picture_header; 1003 _parsers[0xb3] = &_parse_sequence_header; 1004 _parsers[0xb5] = &_parse_extension; 1005 _parsers[0xb8] = &_parse_group_of_picture_header; 1006 1007 foreach(ubyte sc; 0x01..0xaf) 1008 { 1009 _parsers[sc] = &this._parse_slice; 1010 } 1011 1012 _ext_parsers[0x01] = &_parse_sequence_extention; 1013 _ext_parsers[0x08] = &_parse_picture_extension; 1014 } 1015 1016 private alias Parser = void delegate (ubyte); 1017 private alias ExtParser = void delegate (); 1018 1019 private BitstreamReader bs; 1020 private Parser[ubyte] _parsers; 1021 private ExtParser[ubyte] _ext_parsers; 1022 private SequenceInfo si; 1023 private GopInfo gopi; 1024 private PictureHeader ph; 1025 private PictureBuilder picture_builder; 1026 private Picture[] _pics; 1027 private Picture[] dpb; 1028 } 1029 1030 enum ExpectedExtension 1031 { 1032 Sequence, 1033 Picture, 1034 ExtensionAndUserData, 1035 } 1036 1037 extern string start_code_str(ubyte start_code) 1038 { 1039 byte number; 1040 string str = null; 1041 switch (start_code) 1042 { 1043 // H.262 start codes 1044 case 0x00: str = "Picture"; break; 1045 case 0xB0: str = "Reserved"; break; 1046 case 0xB1: str = "Reserved"; break; 1047 case 0xB2: str = "User data"; break; 1048 case 0xB3: str = "SEQUENCE HEADER"; break; 1049 case 0xB4: str = "Sequence error"; break; 1050 case 0xB5: str = "Extension start"; break; 1051 case 0xB6: str = "Reserved"; break; 1052 case 0xB7: str = "SEQUENCE END"; break; 1053 case 0xB8: str = "Group start"; break; 1054 1055 // System start codes - 13818-1 p32 Table 2-18 stream_id 1056 // If these occur, then we're seeing PES headers 1057 // - maybe we're looking at transport stream data? 1058 case 0xBC: str = "SYSTEM START: Program stream map"; break; 1059 case 0xBD: str = "SYSTEM START: Private stream 1"; break; 1060 case 0xBE: str = "SYSTEM START: Padding stream"; break; 1061 case 0xBF: str = "SYSTEM START: Private stream 2"; break; 1062 case 0xF0: str = "SYSTEM START: ECM stream"; break; 1063 case 0xF1: str = "SYSTEM START: EMM stream"; break; 1064 case 0xF2: str = "SYSTEM START: DSMCC stream"; break; 1065 case 0xF3: str = "SYSTEM START: 13522 stream"; break; 1066 case 0xF4: str = "SYSTEM START: H.222 A stream"; break; 1067 case 0xF5: str = "SYSTEM START: H.222 B stream"; break; 1068 case 0xF6: str = "SYSTEM START: H.222 C stream"; break; 1069 case 0xF7: str = "SYSTEM START: H.222 D stream"; break; 1070 case 0xF8: str = "SYSTEM START: H.222 E stream"; break; 1071 case 0xF9: str = "SYSTEM START: Ancillary stream"; break; 1072 case 0xFF: str = "SYSTEM START: Program stream directory"; break; 1073 1074 default: str = null; break; 1075 } 1076 1077 if (str != null) 1078 { 1079 1080 } 1081 else if (start_code == 0x47) 1082 str = "TRANSPORT STREAM sync byte"; 1083 else if (start_code >= 0x01 && start_code <= 0xAF) 1084 str = format("Slice, vertical posn %d", start_code); 1085 else if (start_code >= 0xC0 && start_code <=0xDF) 1086 { 1087 number = start_code & 0x1F; 1088 str = format("SYSTEM START: Audio stream %02x",number); 1089 } 1090 else if (start_code >= 0xE0 && start_code <= 0xEF) 1091 { 1092 number = start_code & 0x0F; 1093 str = format("SYSTEM START: Video stream %x",number); 1094 } 1095 else if (start_code >= 0xFC && start_code <= 0xFE) 1096 str = "SYSTEM START: Reserved data stream"; 1097 else 1098 str = "SYSTEM START: Unrecognised stream id"; 1099 1100 return str; 1101 }