// File: /workspace/github_cpp_makefile_star2_O2/cpearce[P]OggIndex/src/Validate.cpp
// Function: Theora::Decode(ogg_page*, long&)
virtual ogg_int64_t Decode(ogg_page* page, ogg_int64_t& end_time) {
    end_time = -1;
    if ((ogg_uint32_t)ogg_page_serialno(page) != mSerial) {
      return -1;
    }
    ogg_int64_t start_time = INT_MAX;

    assert(AllBufferedGranuleposInvalid());

    const int shift = mInfo.keyframe_granule_shift;
    ogg_packet op;
    int ret = ogg_stream_pagein(&mStreamState, page);
    assert(ret == 0);
    while ((ret = ogg_stream_packetout(&mStreamState, &op)) != 0) {
      if (ret == -1) {
        cout << "WARNING: Theora decoder out of sync!" << endl;
        continue;
      }
      if (!mReadHeaders) {
        ogg_int32_t ret = th_decode_headerin(&mInfo,
                                             &mComment,
                                             &mSetup,
                                             &op);
        if (ret > 0) {
          mHeaderPacketsRead++;
          mReadHeaders = (mHeaderPacketsRead == 3);
          if (mReadHeaders) {
            mCtx = th_decode_alloc(&mInfo, mSetup);
            assert(mCtx != NULL);
            mFrameDuration = (1000 * mInfo.fps_denominator) / mInfo.fps_numerator;
          }
          continue;
        } else {
          cout << "th_decode_headerin returned " << ret << endl;
          return false;
        }
      }

      PacketInfo p;
      p.granulepos = op.granulepos;
      p.isKeyFrame = th_packet_iskeyframe(&op) != 0;

      mBuffer.push_back(p);

      if (p.granulepos == -1) {
        continue;
      }

      assert(op.granulepos == -1 || op.granulepos == ogg_page_granulepos(page));

      // We've got buffered packets, and the last one has a known
      // granulepos. Use its granulepos to calculate the other granulepos.          
      list<PacketInfo>::reverse_iterator rev_itr = mBuffer.rbegin();
      PacketInfo *prev = &(*rev_itr);
      rev_itr++;
      while (rev_itr != mBuffer.rend()) {
        PacketInfo* p = &(*rev_itr);
        assert(prev->granulepos != -1);
        ogg_int64_t granulepos;
        if (p->isKeyFrame) {
          granulepos =
            (th_granule_frame(mCtx, prev->granulepos) + TheoraVersion(&mInfo,3,2,1) - 1) << shift;
        } else {
          if (prev->isKeyFrame) {
            // The previous frame is a keyframe, so we can't just subtract 1
            // from the "keyframe offset" part of its granulepos, as it
            // doesn't have one! So fake it, take the keyframe offset as the
            // max possible keyframe offset. This means the granulepos claims
            // that it depends on the wrong keyframe, but at least its granule
            // number will be correct, so the times we calculate from this
            // granulepos will also be correct.
            ogg_int64_t frameno = th_granule_frame(mCtx, prev->granulepos);
            ogg_int64_t max_offset = min((frameno - 1), (ogg_int64_t)(1 << shift) - 1);
            ogg_int64_t granule = frameno +
                                  TheoraVersion(&mInfo,3,2,1) - 1 - max_offset;
            assert(granule > 0);
            granulepos = (granule << shift) + max_offset;
          } else {
            assert((prev->granulepos & ((1 << shift) - 1)) > 0);
            granulepos = prev->granulepos - 1;
          }
        }
        p->granulepos = granulepos;
        assert(th_granule_frame(mCtx, p->granulepos) ==
               th_granule_frame(mCtx, prev->granulepos) - 1);
        assert(Time(p->granulepos) < Time(prev->granulepos));
        prev = p;
        rev_itr++;
      }
      assert(mBuffer.front().granulepos != -1);
      assert(mBuffer.size() > 0);

      ogg_int64_t time = NextKeyframeTime();
      if (time != -1) {
        start_time = min(time, start_time);
        end_time = start_time + mFrameDuration;
        ogg_int64_t page_end_time = Time(ogg_page_granulepos(page));
        assert(time <= page_end_time);
      }        
    }
   
    return (start_time != INT_MAX) ? start_time : -1;
  }

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x98, %rsp
movq %rdx, %r14
movq %rsi, %r12
movq %rdi, %r15
orq $-0x1, (%rdx)
movq %rsi, %rdi
callq 0x42c0
cmpl 0x8(%r15), %eax
jne 0xc5be
movq %r15, %rdi
callq 0xc7c2
testb %al, %al
je 0xc6cd
movl 0x1fc(%r15), %r13d
leaq 0x10(%r15), %rbp
movq %rbp, %rdi
movq %r12, %rsi
callq 0x4500
testl %eax, %eax
jne 0xc6ec
leaq 0x1c0(%r15), %rax
movq %rax, (%rsp)
leaq 0x200(%r15), %rax
movq %rax, 0x50(%rsp)
leaq 0x220(%r15), %rax
movq %rax, 0x48(%rsp)
leaq 0x1a8(%r15), %rax
movq %rax, 0x10(%rsp)
pushq $-0x1
popq %rax
movl %r13d, %ecx
shll %cl, %eax
notl %eax
movq %rax, 0x40(%rsp)
pushq $0x1
popq %rax
shll %cl, %eax
cltq
decq %rax
movq %rax, 0x38(%rsp)
movl $0x7fffffff, %eax       # imm = 0x7FFFFFFF
movq %rax, 0x8(%rsp)
movq %rbp, %rdi
leaq 0x68(%rsp), %rsi
callq 0x4550
cmpl $-0x1, %eax
je 0xc366
testl %eax, %eax
je 0xc5c3
cmpb $0x0, 0xc(%r15)
jne 0xc386
movq (%rsp), %rdi
movq 0x50(%rsp), %rsi
movq 0x48(%rsp), %rdx
leaq 0x68(%rsp), %rcx
callq 0x45a0
testl %eax, %eax
jle 0xc5d8
movl 0x230(%r15), %eax
incl %eax
movl %eax, 0x230(%r15)
cmpl $0x3, %eax
sete 0xc(%r15)
jne 0xc2c3
movq 0x220(%r15), %rsi
movq (%rsp), %rdi
callq 0x43f0
movq %rax, 0x228(%r15)
testq %rax, %rax
je 0xc670
imull $0x3e8, 0x1e0(%r15), %eax # imm = 0x3E8
xorl %edx, %edx
divl 0x1dc(%r15)
movq %rax, 0x238(%r15)
jmp 0xc2c3
movq 0x8c63(%rip), %rdi      # 0x14fd0
leaq 0x39aa(%rip), %rsi      # 0xfd1e
callq 0x4340
movq %rax, %rdi
callq 0x41b0
jmp 0xc2c3
movq 0x88(%rsp), %rax
movq %rax, 0x58(%rsp)
leaq 0x68(%rsp), %rdi
callq 0x4290
testl %eax, %eax
setne 0x60(%rsp)
movq 0x10(%rsp), %rdi
leaq 0x58(%rsp), %rsi
callq 0xc7fe
cmpq $-0x1, 0x58(%rsp)
je 0xc2c3
movq %rbp, 0x20(%rsp)
movq %r14, 0x28(%rsp)
movq 0x88(%rsp), %rbx
cmpq $-0x1, %rbx
je 0xc3e8
movq %r12, %rdi
callq 0x45c0
cmpq %rax, %rbx
jne 0xc749
movq %r12, 0x18(%rsp)
movq 0x1b0(%r15), %r14
leaq 0x10(%r14), %rbp
movq %r13, 0x30(%rsp)
movq 0x10(%rsp), %rax
movq (%rax), %rax
cmpq %rax, %r14
je 0xc528
movq (%rbp), %rsi
cmpq $-0x1, %rsi
je 0xc632
movq 0x8(%r14), %r12
cmpb $0x1, 0x18(%r12)
jne 0xc45a
movq 0x228(%r15), %rdi
callq 0x40a0
movq %rax, %rbx
movq (%rsp), %rdi
pushq $0x3
popq %rsi
pushq $0x2
popq %rdx
pushq $0x1
popq %rcx
callq 0xaf6e
cltq
leaq (%rbx,%rax), %rsi
decq %rsi
movl %r13d, %ecx
shlq %cl, %rsi
jmp 0xc4c5
cmpb $0x1, 0x8(%rbp)
jne 0xc4b8
movq 0x228(%r15), %rdi
callq 0x40a0
movq %rax, %rbx
leaq -0x1(%rax), %r13
movq 0x38(%rsp), %rax
cmpq %r13, %rax
cmovlq %rax, %r13
movq (%rsp), %rdi
pushq $0x3
popq %rsi
pushq $0x2
popq %rdx
pushq $0x1
popq %rcx
callq 0xaf6e
cltq
addq %rbx, %rax
movq %r13, %rsi
notq %rsi
addq %rax, %rsi
testq %rsi, %rsi
jle 0xc6ae
movq 0x30(%rsp), %rcx
shlq %cl, %rsi
addq %r13, %rsi
movq %rcx, %r13
jmp 0xc4c5
testl %esi, 0x40(%rsp)
je 0xc68f
decq %rsi
addq $0x10, %r12
movq %rsi, (%r12)
movq 0x228(%r15), %rdi
callq 0x40a0
movq %rax, %rbx
movq 0x228(%r15), %rdi
movq (%rbp), %rsi
callq 0x40a0
decq %rax
cmpq %rax, %rbx
jne 0xc613
movq (%r12), %rsi
movq %r15, %rdi
callq 0xc80a
movq %rax, %rbx
movq (%rbp), %rsi
movq %r15, %rdi
callq 0xc80a
cmpq %rax, %rbx
jge 0xc651
movq 0x8(%r14), %r14
movq %r12, %rbp
jmp 0xc3fd
cmpq $-0x1, 0x10(%rax)
je 0xc72a
cmpq $0x0, 0x1b8(%r15)
movq 0x28(%rsp), %r14
movq 0x18(%rsp), %r12
movq 0x20(%rsp), %rbp
je 0xc70b
movq %r15, %rdi
callq 0xc836
cmpq $-0x1, %rax
je 0xc2c3
movq %rax, %rbx
movq 0x8(%rsp), %rcx
cmpq %rax, %rcx
cmovgeq %rax, %rcx
movq 0x238(%r15), %rax
movq %rcx, 0x8(%rsp)
addq %rcx, %rax
movq %rax, (%r14)
movq %r12, %rdi
callq 0x45c0
movq %r15, %rdi
movq %rax, %rsi
callq 0xc80a
cmpq %rax, %rbx
jle 0xc2c3
leaq 0x38f6(%rip), %rdi      # 0xfe9c
leaq 0x3392(%rip), %rsi      # 0xf93f
leaq 0x372c(%rip), %rcx      # 0xfce0
movl $0xfa, %edx
callq 0x4210
pushq $-0x1
popq %rax
jmp 0xc601
movq 0x8(%rsp), %rcx
cmpq $0x7fffffff, %rcx       # imm = 0x7FFFFFFF
pushq $-0x1
popq %rax
cmovneq %rcx, %rax
jmp 0xc601
movl %eax, %ebx
movq 0x89ef(%rip), %rdi      # 0x14fd0
leaq 0x375b(%rip), %rsi      # 0xfd43
callq 0x4340
movq %rax, %rdi
movl %ebx, %esi
callq 0x4650
movq %rax, %rdi
callq 0x41b0
xorl %eax, %eax
addq $0x98, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x37cb(%rip), %rdi      # 0xfde5
leaq 0x331e(%rip), %rsi      # 0xf93f
leaq 0x36b8(%rip), %rcx      # 0xfce0
movl $0xed, %edx
callq 0x4210
leaq 0x3769(%rip), %rdi      # 0xfda2
leaq 0x32ff(%rip), %rsi      # 0xf93f
leaq 0x3699(%rip), %rcx      # 0xfce0
movl $0xd2, %edx
callq 0x4210
leaq 0x37e3(%rip), %rdi      # 0xfe3b
leaq 0x32e0(%rip), %rsi      # 0xf93f
leaq 0x367a(%rip), %rcx      # 0xfce0
movl $0xee, %edx
callq 0x4210
leaq 0x1d54(%rip), %rdi      # 0xe3cb
leaq 0x32c1(%rip), %rsi      # 0xf93f
leaq 0x365b(%rip), %rcx      # 0xfce0
movl $0xb5, %edx
callq 0x4210
leaq 0x3723(%rip), %rdi      # 0xfdb9
leaq 0x32a2(%rip), %rsi      # 0xf93f
leaq 0x363c(%rip), %rcx      # 0xfce0
movl $0xe7, %edx
callq 0x4210
leaq 0x1dea(%rip), %rdi      # 0xe49f
leaq 0x3283(%rip), %rsi      # 0xf93f
leaq 0x361d(%rip), %rcx      # 0xfce0
movl $0xe4, %edx
callq 0x4210
leaq 0x37ff(%rip), %rdi      # 0xfed3
leaq 0x3264(%rip), %rsi      # 0xf93f
leaq 0x35fe(%rip), %rcx      # 0xfce0
movl $0xa0, %edx
callq 0x4210
leaq 0x1911(%rip), %rdi      # 0xe004
leaq 0x3245(%rip), %rsi      # 0xf93f
leaq 0x35df(%rip), %rcx      # 0xfce0
movl $0xa5, %edx
callq 0x4210
leaq 0x3777(%rip), %rdi      # 0xfe89
leaq 0x3226(%rip), %rsi      # 0xf93f
leaq 0x35c0(%rip), %rcx      # 0xfce0
movl $0xf3, %edx
callq 0x4210
leaq 0x3737(%rip), %rdi      # 0xfe68
leaq 0x3207(%rip), %rsi      # 0xf93f
leaq 0x35a1(%rip), %rcx      # 0xfce0
movl $0xf2, %edx
callq 0x4210
leaq 0x3610(%rip), %rdi      # 0xfd60
leaq 0x31e8(%rip), %rsi      # 0xf93f
leaq 0x3582(%rip), %rcx      # 0xfce0
movl $0xc9, %edx
callq 0x4210