// File: lukasz-wiecaszek[P]h264iframedecoder/main.cpp
// Function: main
int main(int argc, char *argv[])
{
    bool status;
    struct {
        bool rtp;
        bool ts;
        bool annex_b;
    } encapsulation = {};
    uint16_t pid = MPEG2TS_PID_INVALID;
    const char* ofile = nullptr;
    ymn::h264_parser_container_e container = ymn::h264_parser_container_e::NONE;
    mpeg2ts_parser_user_data mpeg2ts_user_data;

    static struct option long_options[] = {
        {"rtp",     no_argument,       0, 'r'},
        {"ts",      required_argument, 0, 't'},
        {"annex-b", no_argument,       0, 'a'},
        {"ofile",   required_argument, 0, 'o'},
        {0,         0,                 0,  0 }
    };

    for (;;) {
        int c = getopt_long(argc, argv, "rt:ao:", long_options, 0);
        if (-1 == c)
            break;

        switch(c) {
            case 'r':
                encapsulation.rtp = true;
                break;

            case 't':
                encapsulation.ts = true;
                encapsulation.annex_b = true;
                container = ymn::h264_parser_container_e::ANNEX_B;
                status = (ymn::strtointeger_conversion_status_e::success == ymn::strtointeger(optarg, pid));
                if (!status) {
                    std::cerr << "error: cannot convert '" << optarg << "' to integer" << std::endl;
                    h264iframedecoder_usage(argv[0]);
                    exit(EXIT_FAILURE);
                }
                break;

            case 'a':
                encapsulation.annex_b = true;
                container = ymn::h264_parser_container_e::ANNEX_B;
                break;

            case 'o':
                ofile = optarg;
                break;

            default:
                std::cout << "default option received" << std::endl;
                /* does nothing */
                break;
        }
    }

    std::cout << "encapsulation:"
        << " rtp=" << (encapsulation.rtp ? "y" : "n")
        << " ts=" << (encapsulation.ts ? "y" : "n")
        << " annex-b=" << (encapsulation.annex_b ? "y" : "n")
        << std::endl;
    if (encapsulation.ts)
        std::cout << "pid: " << HEXDEC(pid) << std::endl;
    std::cout << "container: " << to_string(container) << std::endl;

    const char* filename = argv[optind];
    if (!filename) {
         std::cerr << "error: missing input file" << std::endl;
         h264iframedecoder_usage(argv[0]);
         exit(EXIT_FAILURE);
    }

   if (ofile != nullptr) {
      h264_ofile = std::ofstream(ofile, std::ios::out | std::ios::binary);
      if (!h264_ofile.is_open()) {
         std::cerr << "error: could not open '" << ofile << "'" << std::endl;
         h264iframedecoder_usage(argv[0]);
         exit(EXIT_FAILURE);
      }
   }

    h264_decoder = new ymn::h264_decoder(container);
    assert(h264_decoder != nullptr);

    if (encapsulation.ts) {
        mpeg2ts_parser = new ymn::mpeg2ts_parser(TS_PARSER_BUFFER_SIZE);
        assert(mpeg2ts_parser != nullptr);

        mpeg2ts_user_data.pid = pid;
        mpeg2ts_user_data.h264_decoder = h264_decoder;

        mpeg2ts_parser->set_user_data(&mpeg2ts_user_data);
    }

    if (encapsulation.rtp) {
    }

    std::size_t read_bytes = 0;
    std::ifstream file(filename, std::ios::in | std::ios::binary);
    if (file.is_open()) {
        std::streamsize count;
        char* memblock;

        memblock = new char[READ_BUFFER_SIZE];

        do {
            count = file.readsome(memblock, READ_BUFFER_SIZE);
            read_bytes += count;
            if (count > 0) {
                if (encapsulation.rtp)
                    /* to be implemented */;
                else
                if (encapsulation.ts)
                    mpeg2ts_parser_feed(*mpeg2ts_parser, reinterpret_cast<uint8_t*>(memblock), count);
                else
                    h264_decoder_feed(*h264_decoder, reinterpret_cast<uint8_t*>(memblock), count);
            }
        } while (count > 0);

        file.close();
        std::cout << "read " << read_bytes << " bytes from '" << filename << "'" << std::endl;
    }
    else {
        std::cerr << "error: could not open '" << filename << "'" << std::endl;
    }

    if (mpeg2ts_parser)
        delete mpeg2ts_parser;

    if (h264_decoder)
        delete h264_decoder;

    if (h264_ofile.is_open())
        h264_ofile.close();

    return 0;
}

// Assembly:
subq $0x4e8, %rsp            # imm = 0x4E8
movl $0x0, 0x4e4(%rsp)
movl %edi, 0x4e0(%rsp)
movq %rsi, 0x4d8(%rsp)
leaq 0x4d4(%rsp), %rdi
xorl %esi, %esi
movl $0x3, %edx
callq 0x20d0
movw $0x2000, 0x4d2(%rsp)    # imm = 0x2000
movq $0x0, 0x4c8(%rsp)
movl $0x0, 0x4c4(%rsp)
leaq 0x4b0(%rsp), %rdi
callq 0x3910
movl 0x4e0(%rsp), %edi
movq 0x4d8(%rsp), %rsi
leaq 0x211b2(%rip), %rdx     # 0x242db
leaq 0x2b050(%rip), %rcx     # 0x2e180
xorl %eax, %eax
movl %eax, %r8d
callq 0x22a0
movl %eax, 0x4ac(%rsp)
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
cmpl 0x4ac(%rsp), %eax
jne 0x3154
jmp 0x328d
movl 0x4ac(%rsp), %eax
addl $-0x61, %eax
movl %eax, %ecx
movq %rcx, 0x70(%rsp)
subl $0x13, %eax
ja 0x3266
movq 0x70(%rsp), %rax
leaq 0x2001e(%rip), %rcx     # 0x23198
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movb $0x1, 0x4d4(%rsp)
jmp 0x3288
movb $0x1, 0x4d5(%rsp)
movb $0x1, 0x4d6(%rsp)
movl $0x1, 0x4c4(%rsp)
movq 0x2adfe(%rip), %rax     # 0x2dfb0
movq (%rax), %rdi
leaq 0x4d2(%rsp), %rsi
callq 0x10920
movl %eax, %ecx
xorl %eax, %eax
cmpl %ecx, %eax
sete %al
andb $0x1, %al
movb %al, 0x4d7(%rsp)
testb $0x1, 0x4d7(%rsp)
jne 0x323b
movq 0x2ae0b(%rip), %rdi     # 0x2dff0
leaq 0x210f6(%rip), %rsi     # 0x242e2
callq 0x2140
movq %rax, %rdi
movq 0x2adb5(%rip), %rax     # 0x2dfb0
movq (%rax), %rsi
callq 0x2140
movq %rax, %rdi
leaq 0x210ed(%rip), %rsi     # 0x242fa
callq 0x2140
movq %rax, %rdi
movq 0x2ad8c(%rip), %rsi     # 0x2dfa8
callq 0x2180
movq 0x4d8(%rsp), %rax
movq (%rax), %rdi
callq 0x3930
movl $0x1, %edi
callq 0x21d0
jmp 0x3288
movb $0x1, 0x4d6(%rsp)
movl $0x1, 0x4c4(%rsp)
jmp 0x3288
movq 0x2ad57(%rip), %rax     # 0x2dfb0
movq (%rax), %rax
movq %rax, 0x4c8(%rsp)
jmp 0x3288
movq 0x2ad53(%rip), %rdi     # 0x2dfc0
leaq 0x21093(%rip), %rsi     # 0x24307
callq 0x2140
movq %rax, %rdi
movq 0x2ad25(%rip), %rsi     # 0x2dfa8
callq 0x2180
jmp 0x3113
movq 0x2ad2c(%rip), %rdi     # 0x2dfc0
leaq 0x21084(%rip), %rsi     # 0x2431f
callq 0x2140
movq %rax, %rdi
leaq 0x21084(%rip), %rsi     # 0x2432e
callq 0x2140
movq %rax, 0x68(%rsp)
testb $0x1, 0x4d4(%rsp)
je 0x32cc
leaq 0x2196f(%rip), %rax     # 0x24c34
movq %rax, 0x60(%rsp)
jmp 0x32da
leaq 0x20d9e(%rip), %rax     # 0x24071
movq %rax, 0x60(%rsp)
jmp 0x32da
movq 0x68(%rsp), %rdi
movq 0x60(%rsp), %rsi
callq 0x2140
movq %rax, %rdi
leaq 0x21041(%rip), %rsi     # 0x24334
callq 0x2140
movq %rax, 0x58(%rsp)
testb $0x1, 0x4d5(%rsp)
je 0x3315
leaq 0x21926(%rip), %rax     # 0x24c34
movq %rax, 0x50(%rsp)
jmp 0x3323
leaq 0x20d55(%rip), %rax     # 0x24071
movq %rax, 0x50(%rsp)
jmp 0x3323
movq 0x58(%rsp), %rdi
movq 0x50(%rsp), %rsi
callq 0x2140
movq %rax, %rdi
leaq 0x20ffd(%rip), %rsi     # 0x24339
callq 0x2140
movq %rax, 0x48(%rsp)
testb $0x1, 0x4d6(%rsp)
je 0x335e
leaq 0x218dd(%rip), %rax     # 0x24c34
movq %rax, 0x40(%rsp)
jmp 0x336c
leaq 0x20d0c(%rip), %rax     # 0x24071
movq %rax, 0x40(%rsp)
jmp 0x336c
movq 0x48(%rsp), %rdi
movq 0x40(%rsp), %rsi
callq 0x2140
movq %rax, %rdi
movq 0x2ac23(%rip), %rsi     # 0x2dfa8
callq 0x2180
testb $0x1, 0x4d5(%rsp)
je 0x3425
movq 0x2ac21(%rip), %rdi     # 0x2dfc0
leaq 0x20f9d(%rip), %rsi     # 0x24343
callq 0x2140
movq %rax, %rdi
leaq 0x1fe88(%rip), %rsi     # 0x2323d
callq 0x2140
movq %rax, %rdi
leaq 0x126c(%rip), %rsi      # 0x4630
callq 0x20a0
movq %rax, %rdi
movzwl 0x4d2(%rsp), %esi
callq 0x22c0
movq %rax, %rdi
leaq 0x1fe5d(%rip), %rsi     # 0x23240
callq 0x2140
movq %rax, %rdi
leaq 0x125e(%rip), %rsi      # 0x4650
callq 0x20a0
movq %rax, %rdi
movzwl 0x4d2(%rsp), %esi
callq 0x22c0
movq %rax, %rdi
leaq 0x20fac(%rip), %rsi     # 0x243bd
callq 0x2140
movq %rax, %rdi
movq 0x2ab88(%rip), %rsi     # 0x2dfa8
callq 0x2180
movq 0x2ab94(%rip), %rdi     # 0x2dfc0
leaq 0x20f16(%rip), %rsi     # 0x24349
callq 0x2140
movq %rax, 0x38(%rsp)
movl 0x4c4(%rsp), %edi
callq 0x3b30
movq 0x38(%rsp), %rdi
movq %rax, %rsi
callq 0x2140
movq %rax, %rdi
movq 0x2ab48(%rip), %rsi     # 0x2dfa8
callq 0x2180
movq 0x4d8(%rsp), %rax
movq 0x2ab54(%rip), %rcx     # 0x2dfc8
movslq (%rcx), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, 0x4a0(%rsp)
cmpq $0x0, 0x4a0(%rsp)
jne 0x34ca
movq 0x2ab5b(%rip), %rdi     # 0x2dff0
leaq 0x20eb9(%rip), %rsi     # 0x24355
callq 0x2140
movq %rax, %rdi
movq 0x2aafd(%rip), %rsi     # 0x2dfa8
callq 0x2180
movq 0x4d8(%rsp), %rax
movq (%rax), %rdi
callq 0x3930
movl $0x1, %edi
callq 0x21d0
cmpq $0x0, 0x4c8(%rsp)
je 0x3597
movq 0x4c8(%rsp), %rax
movq %rax, 0x30(%rsp)
movl $0x10, %edi
movl $0x4, %esi
callq 0x10950
movq 0x30(%rsp), %rsi
movl %eax, %edx
leaq 0x2a0(%rsp), %rdi
callq 0x2190
leaq 0x2ad28(%rip), %rdi     # 0x2e238
leaq 0x2a0(%rsp), %rsi
callq 0x21c0
leaq 0x2a0(%rsp), %rdi
callq 0x22e8
leaq 0x2ad07(%rip), %rdi     # 0x2e238
callq 0x2100
testb $0x1, %al
jne 0x3595
movq 0x2aaaf(%rip), %rdi     # 0x2dff0
leaq 0x20e27(%rip), %rsi     # 0x2436f
callq 0x2140
movq %rax, %rdi
movq 0x4c8(%rsp), %rsi
callq 0x2140
movq %rax, %rdi
leaq 0x24bd9(%rip), %rsi     # 0x28140
callq 0x2140
movq %rax, %rdi
movq 0x2aa32(%rip), %rsi     # 0x2dfa8
callq 0x2180
movq 0x4d8(%rsp), %rax
movq (%rax), %rdi
callq 0x3930
movl $0x1, %edi
callq 0x21d0
jmp 0x3597
movl $0xa6480, %edi          # imm = 0xA6480
movl $0x40, %esi
callq 0x21a0
movq %rax, %rdi
movq %rdi, 0x28(%rsp)
movl 0x4c4(%rsp), %esi
callq 0x19ee0
movq 0x28(%rsp), %rax
movq %rax, 0x2ae72(%rip)     # 0x2e438
cmpq $0x0, 0x2ae6a(%rip)     # 0x2e438
je 0x35d2
jmp 0x35f1
leaq 0x20dae(%rip), %rdi     # 0x24387
leaq 0x20dbf(%rip), %rsi     # 0x2439f
movl $0xc7, %edx
leaq 0x20dbc(%rip), %rcx     # 0x243a8
callq 0x20f0
testb $0x1, 0x4d5(%rsp)
je 0x369d
movl $0x180, %edi            # imm = 0x180
movl $0x40, %esi
callq 0x21a0
movq %rax, %rdi
movq %rdi, 0x20(%rsp)
movl $0x2000, %esi           # imm = 0x2000
callq 0x10970
movq 0x20(%rsp), %rax
movq %rax, 0x2ae14(%rip)     # 0x2e440
cmpq $0x0, 0x2ae0c(%rip)     # 0x2e440
je 0x3638
jmp 0x3657
leaq 0x20d80(%rip), %rdi     # 0x243bf
leaq 0x20d59(%rip), %rsi     # 0x2439f
movl $0xcb, %edx
leaq 0x20d56(%rip), %rcx     # 0x243a8
callq 0x20f0
movzwl 0x4d2(%rsp), %esi
leaq 0x29c(%rsp), %rdi
callq 0x109e0
movl 0x29c(%rsp), %eax
movl %eax, 0x4b0(%rsp)
movq 0x2adb7(%rip), %rax     # 0x2e438
movq %rax, 0x4b8(%rsp)
movq 0x2adb0(%rip), %rdi     # 0x2e440
leaq 0x4b0(%rsp), %rsi
callq 0x10a00
testb $0x1, 0x4d4(%rsp)
je 0x36a9
jmp 0x36a9
movq $0x0, 0x290(%rsp)
movq 0x4a0(%rsp), %rax
movq %rax, 0x18(%rsp)
movl $0x8, %edi
movl $0x4, %esi
callq 0x10950
movq 0x18(%rsp), %rsi
movl %eax, %edx
leaq 0x88(%rsp), %rdi
callq 0x22d0
leaq 0x88(%rsp), %rdi
callq 0x2280
testb $0x1, %al
jne 0x36fb
jmp 0x381a
movl $0x1000, %edi           # imm = 0x1000
callq 0x2030
movq %rax, 0x78(%rsp)
movq 0x78(%rsp), %rsi
leaq 0x88(%rsp), %rdi
movl $0x1000, %edx           # imm = 0x1000
callq 0x2260
movq %rax, 0x80(%rsp)
movq 0x80(%rsp), %rax
addq 0x290(%rsp), %rax
movq %rax, 0x290(%rsp)
cmpq $0x0, 0x80(%rsp)
jle 0x379a
testb $0x1, 0x4d4(%rsp)
je 0x3758
jmp 0x3798
testb $0x1, 0x4d5(%rsp)
je 0x377d
movq 0x2acd7(%rip), %rdi     # 0x2e440
movq 0x78(%rsp), %rsi
movq 0x80(%rsp), %rdx
callq 0x3b80
jmp 0x3796
movq 0x2acb4(%rip), %rdi     # 0x2e438
movq 0x78(%rsp), %rsi
movq 0x80(%rsp), %rdx
callq 0x3c40
jmp 0x3798
jmp 0x379a
jmp 0x379c
cmpq $0x0, 0x80(%rsp)
jg 0x370a
leaq 0x88(%rsp), %rdi
callq 0x2050
movq 0x2a801(%rip), %rdi     # 0x2dfc0
leaq 0x20c13(%rip), %rsi     # 0x243d9
callq 0x2140
movq %rax, %rdi
movq 0x290(%rsp), %rsi
callq 0x2070
movq %rax, %rdi
leaq 0x20bfa(%rip), %rsi     # 0x243df
callq 0x2140
movq %rax, %rdi
movq 0x4a0(%rsp), %rsi
callq 0x2140
movq %rax, %rdi
leaq 0x2493c(%rip), %rsi     # 0x28140
callq 0x2140
movq %rax, %rdi
movq 0x2a795(%rip), %rsi     # 0x2dfa8
callq 0x2180
jmp 0x385b
movq 0x2a7cf(%rip), %rdi     # 0x2dff0
leaq 0x20b47(%rip), %rsi     # 0x2436f
callq 0x2140
movq %rax, %rdi
movq 0x4a0(%rsp), %rsi
callq 0x2140
movq %rax, %rdi
leaq 0x248f9(%rip), %rsi     # 0x28140
callq 0x2140
movq %rax, %rdi
movq 0x2a752(%rip), %rsi     # 0x2dfa8
callq 0x2180
cmpq $0x0, 0x2abdd(%rip)     # 0x2e440
je 0x3884
movq 0x2abd4(%rip), %rax     # 0x2e440
movq %rax, 0x10(%rsp)
cmpq $0x0, %rax
je 0x3882
movq 0x10(%rsp), %rdi
movq (%rdi), %rax
callq *0x8(%rax)
jmp 0x3884
cmpq $0x0, 0x2abac(%rip)     # 0x2e438
je 0x38c0
movq 0x2aba3(%rip), %rax     # 0x2e438
movq %rax, 0x8(%rsp)
cmpq $0x0, %rax
je 0x38be
movq 0x8(%rsp), %rdi
callq 0x19f40
movq 0x8(%rsp), %rdi
movl $0xa6480, %esi          # imm = 0xA6480
movl $0x40, %edx
callq 0x2060
jmp 0x38c0
leaq 0x2a971(%rip), %rdi     # 0x2e238
callq 0x2100
testb $0x1, %al
jne 0x38d2
jmp 0x38de
leaq 0x2a95f(%rip), %rdi     # 0x2e238
callq 0x2240
movl $0x0, 0x4e4(%rsp)
leaq 0x88(%rsp), %rdi
callq 0x2090
movl 0x4e4(%rsp), %eax
addq $0x4e8, %rsp            # imm = 0x4E8
retq
nopw %cs:(%rax,%rax)