// File: /workspace/github_cpp_makefile_star2_O3/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 $0x88, %rsp
movq %rdx, %rbx
movq %rsi, %r13
movq %rdi, %r15
movq $-0x1, (%rdx)
movq %rsi, %rdi
callq 0x42d0
movl %eax, %ecx
movq $-0x1, %rax
cmpl 0x8(%r15), %ecx
jne 0xe52f
leaq 0x1a8(%r15), %rbp
movq %rbp, %rax
movq (%rax), %rax
cmpq %rbp, %rax
je 0xe098
cmpq $-0x1, 0x10(%rax)
je 0xe06a
leaq 0x3e38(%rip), %rdi      # 0x11eb8
leaq 0x38be(%rip), %rsi      # 0x11945
leaq 0x3e3e(%rip), %rcx      # 0x11ecc
movl $0x7b, %edx
callq 0x4210
movq %rbx, 0x28(%rsp)
movl 0x1fc(%r15), %ebx
leaq 0x10(%r15), %rdi
movq %rdi, 0x50(%rsp)
movq %r13, %rsi
callq 0x4540
testl %eax, %eax
jne 0xe5fb
leaq 0x1c0(%r15), %rdx
leaq 0x200(%r15), %rax
movq %rax, 0x48(%rsp)
movl $0xffffffff, %esi       # imm = 0xFFFFFFFF
movl %ebx, %ecx
shll %cl, %esi
movl $0x1, %eax
movq %rbx, 0x10(%rsp)
movq %rdx, %rbx
shll %cl, %eax
leaq 0x220(%r15), %rcx
movq %rcx, 0x40(%rsp)
notl %esi
movq %rsi, 0x38(%rsp)
cltq
decq %rax
movq %rax, 0x30(%rsp)
movl $0x7fffffff, %eax       # imm = 0x7FFFFFFF
movq %rax, 0x8(%rsp)
leaq 0x58(%rsp), %r14
movq 0x50(%rsp), %rdi
movq %r14, %rsi
callq 0x4590
cmpl $-0x1, %eax
je 0xe1b8
testl %eax, %eax
je 0xe4c1
cmpb $0x0, 0xc(%r15)
jne 0xe200
movq %rbx, %rdi
movq 0x48(%rsp), %rsi
movq 0x40(%rsp), %rdx
movq %r14, %rcx
callq 0x45f0
testl %eax, %eax
jle 0xe4da
movl 0x230(%r15), %eax
incl %eax
movl %eax, 0x230(%r15)
cmpl $0x3, %eax
sete 0xc(%r15)
leaq 0x58(%rsp), %r14
jne 0xe114
movq 0x220(%r15), %rsi
movq %rbx, %rdi
callq 0x4440
movq %rax, 0x228(%r15)
testq %rax, %rax
je 0xe541
imull $0x3e8, 0x1e0(%r15), %eax # imm = 0x3E8
xorl %edx, %edx
divl 0x1dc(%r15)
movq %rax, 0x238(%r15)
jmp 0xe114
movl $0x24, %edx
movq 0x8e0c(%rip), %r12      # 0x16fd0
movq %r12, %rdi
leaq 0x3b56(%rip), %rsi      # 0x11d24
callq 0x4410
movq (%r12), %rax
movq -0x18(%rax), %rdi
addq %r12, %rdi
movl $0xa, %esi
callq 0x4360
movsbl %al, %esi
movq %r12, %rdi
callq 0x4040
movq %rax, %rdi
callq 0x4250
jmp 0xe114
movq %rbx, (%rsp)
movq 0x78(%rsp), %rbx
movq %r14, %rdi
callq 0x42a0
movl %eax, %r14d
movl $0x20, %edi
callq 0x4380
testl %r14d, %r14d
leaq 0x58(%rsp), %r14
movq %rbx, 0x10(%rax)
setne 0x18(%rax)
movq %rax, %rdi
movq %rbp, %rsi
callq 0x4060
incq 0x1b8(%r15)
cmpq $-0x1, %rbx
movq (%rsp), %rbx
je 0xe114
movq %rbp, 0x18(%rsp)
movq 0x78(%rsp), %rbx
cmpq $-0x1, %rbx
je 0xe26f
movq %r13, %rdi
callq 0x4610
cmpq %rax, %rbx
jne 0xe658
movq %r13, 0x20(%rsp)
movq 0x1a8(%r15), %rax
movq 0x1b0(%r15), %rbx
cmpq %rax, %rbx
movq 0x10(%rsp), %r12
je 0xe408
leaq 0x10(%rbx), %r13
movq (%r13), %rsi
cmpq $-0x1, %rsi
je 0xe59e
movq 0x8(%rbx), %rbp
cmpb $0x1, 0x18(%rbp)
jne 0xe2e4
movq 0x228(%r15), %rdi
callq 0x40b0
movq %rax, %r14
movq (%rsp), %rdi
movl $0x3, %esi
movl $0x2, %edx
movl $0x1, %ecx
callq 0xc826
cltq
leaq (%r14,%rax), %rsi
decq %rsi
movl %r12d, %ecx
shlq %cl, %rsi
jmp 0xe356
cmpb $0x1, 0x8(%r13)
jne 0xe349
movq 0x228(%r15), %rdi
callq 0x40b0
movq %rax, %r14
leaq -0x1(%rax), %r12
movq 0x30(%rsp), %rax
cmpq %r12, %rax
cmovlq %rax, %r12
movq (%rsp), %rdi
movl $0x3, %esi
movl $0x2, %edx
movl $0x1, %ecx
callq 0xc826
cltq
addq %r14, %rax
movq %r12, %rsi
notq %rsi
addq %rax, %rsi
testq %rsi, %rsi
jle 0xe5dc
movq 0x10(%rsp), %rcx
shlq %cl, %rsi
addq %r12, %rsi
movq %rcx, %r12
jmp 0xe356
testl %esi, 0x38(%rsp)
je 0xe5bd
decq %rsi
addq $0x10, %rbp
movq %rsi, (%rbp)
movq 0x228(%r15), %rdi
callq 0x40b0
movq %rax, %r14
movq 0x228(%r15), %rdi
movq (%r13), %rsi
callq 0x40b0
decq %rax
cmpq %rax, %r14
jne 0xe560
movq (%rbp), %rsi
movq 0x228(%r15), %rdi
callq 0x40b0
imull $0x3e8, 0x1e0(%r15), %ecx # imm = 0x3E8
imulq %rcx, %rax
movl 0x1dc(%r15), %ecx
cqto
idivq %rcx
movq %rax, %r14
movq (%r13), %rsi
movq 0x228(%r15), %rdi
callq 0x40b0
imull $0x3e8, 0x1e0(%r15), %ecx # imm = 0x3E8
imulq %rcx, %rax
movl 0x1dc(%r15), %ecx
cqto
idivq %rcx
cmpq %rax, %r14
jge 0xe57f
movq 0x8(%rbx), %rbx
movq 0x18(%rsp), %rax
movq (%rax), %rax
movq %rbp, %r13
cmpq %rax, %rbx
leaq 0x58(%rsp), %r14
jne 0xe294
cmpq $-0x1, 0x10(%rax)
je 0xe639
cmpq $0x0, 0x1b8(%r15)
movq 0x20(%rsp), %r13
movq 0x18(%rsp), %rbp
movq (%rsp), %rbx
je 0xe61a
movq %r15, %rdi
callq 0xe6a6
cmpq $-0x1, %rax
je 0xe114
movq %rax, %r12
movq 0x8(%rsp), %rcx
cmpq %rax, %rcx
cmovgeq %rax, %rcx
movq 0x238(%r15), %rax
movq %rcx, 0x8(%rsp)
addq %rcx, %rax
movq 0x28(%rsp), %rcx
movq %rax, (%rcx)
movq %r13, %rdi
callq 0x4610
movq 0x228(%r15), %rdi
movq %rax, %rsi
callq 0x40b0
imull $0x3e8, 0x1e0(%r15), %ecx # imm = 0x3E8
imulq %rcx, %rax
movl 0x1dc(%r15), %ecx
cqto
idivq %rcx
cmpq %rax, %r12
jle 0xe114
leaq 0x39f9(%rip), %rdi      # 0x11ea2
leaq 0x3495(%rip), %rsi      # 0x11945
leaq 0x382f(%rip), %rcx      # 0x11ce6
movl $0xfa, %edx
callq 0x4210
movq 0x8(%rsp), %rcx
cmpq $0x7fffffff, %rcx       # imm = 0x7FFFFFFF
movq $-0x1, %rax
cmovneq %rcx, %rax
jmp 0xe52f
movl %eax, %r14d
movq 0x8aec(%rip), %rbx      # 0x16fd0
leaq 0x385e(%rip), %rsi      # 0x11d49
movl $0x1c, %edx
movq %rbx, %rdi
callq 0x4410
movq %rbx, %rdi
movl %r14d, %esi
callq 0x4690
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x4360
movsbl %al, %esi
movq %rbx, %rdi
callq 0x4040
movq %rax, %rdi
callq 0x4250
xorl %eax, %eax
addq $0x88, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x1e83(%rip), %rdi      # 0x103cb
leaq 0x33f6(%rip), %rsi      # 0x11945
leaq 0x3790(%rip), %rcx      # 0x11ce6
movl $0xb5, %edx
callq 0x4210
leaq 0x3884(%rip), %rdi      # 0x11deb
leaq 0x33d7(%rip), %rsi      # 0x11945
leaq 0x3771(%rip), %rcx      # 0x11ce6
movl $0xed, %edx
callq 0x4210
leaq 0x38bb(%rip), %rdi      # 0x11e41
leaq 0x33b8(%rip), %rsi      # 0x11945
leaq 0x3752(%rip), %rcx      # 0x11ce6
movl $0xee, %edx
callq 0x4210
leaq 0x3803(%rip), %rdi      # 0x11da8
leaq 0x3399(%rip), %rsi      # 0x11945
leaq 0x3733(%rip), %rcx      # 0x11ce6
movl $0xd2, %edx
callq 0x4210
leaq 0x37fb(%rip), %rdi      # 0x11dbf
leaq 0x337a(%rip), %rsi      # 0x11945
leaq 0x3714(%rip), %rcx      # 0x11ce6
movl $0xe7, %edx
callq 0x4210
leaq 0x1ebc(%rip), %rdi      # 0x1049f
leaq 0x335b(%rip), %rsi      # 0x11945
leaq 0x36f5(%rip), %rcx      # 0x11ce6
movl $0xe4, %edx
callq 0x4210
leaq 0x1a02(%rip), %rdi      # 0x10004
leaq 0x333c(%rip), %rsi      # 0x11945
leaq 0x36d6(%rip), %rcx      # 0x11ce6
movl $0xa5, %edx
callq 0x4210
leaq 0x386e(%rip), %rdi      # 0x11e8f
leaq 0x331d(%rip), %rsi      # 0x11945
leaq 0x36b7(%rip), %rcx      # 0x11ce6
movl $0xf3, %edx
callq 0x4210
leaq 0x382e(%rip), %rdi      # 0x11e6e
leaq 0x32fe(%rip), %rsi      # 0x11945
leaq 0x3698(%rip), %rcx      # 0x11ce6
movl $0xf2, %edx
callq 0x4210
leaq 0x3707(%rip), %rdi      # 0x11d66
leaq 0x32df(%rip), %rsi      # 0x11945
leaq 0x3679(%rip), %rcx      # 0x11ce6
movl $0xc9, %edx
callq 0x4210
nop