// File: cpearce[P]OggIndex/src/Decoder.cpp
// Function: TheoraDecoder::GetKeyframes()
virtual const vector<KeyFrameInfo>& GetKeyframes() {
    // Construct list of keyframes from page and frame info lists.
    // Need to determine frame start offsets and fill key points array.

    if (mKeyFrames.size() > 0 || mFrames.size() == 0) {
      return mKeyFrames;
    }

    // Packetno of the last packet which has started.
    ogg_int64_t started_packetno = mFirstPacketno - 1;
    // Must at least have header packets.
    assert(started_packetno >= 2);
    ogg_int64_t pageno = 0;
    ogg_int64_t prev_keyframe_pageno = -INT_MAX;
    ogg_int64_t prev_keyframe_start_time = -INT_MAX;
    for (unsigned f=0; f<mFrames.size(); f++) {
      Frame& frame = mFrames[f];
      ogg_int64_t packetno = frame.packetno;

      while (pageno < (ogg_int64_t) mPages.size() &&
             started_packetno + mPages[pageno].num_packets < packetno)
      {
        started_packetno += mPages[pageno].num_packets;
        pageno++;  
      } // pages
      assert(pageno < (ogg_int64_t) mPages.size());
      assert(started_packetno < packetno &&
             started_packetno + mPages[pageno].num_packets >= packetno);

      if (pageno == prev_keyframe_pageno) {
        // Only consider the pages' first key point.
        continue;
      }

      KeyFrameInfo k(mPages[pageno].offset,
                     StartTime(frame.granulepos));
      assert(k.mTime >= 0);

      // Only add the keyframe to the list if it's far enough after the
      // previous keyframe.
      if (k.mTime > prev_keyframe_start_time + gOptions.GetKeyPointInterval()) {
        prev_keyframe_start_time = k.mTime;
        mKeyFrames.push_back(k);
      }
      prev_keyframe_pageno = pageno;

    } // for each frame

    return mKeyFrames;
  }

// Assembly:
subq $0xb8, %rsp
movq %rdi, 0xa8(%rsp)
movq 0xa8(%rsp), %rdi
movq %rdi, 0x58(%rsp)
addq $0x278, %rdi            # imm = 0x278
callq 0xa590
cmpq $0x0, %rax
ja 0x8545
movq 0x58(%rsp), %rdi
addq $0x260, %rdi            # imm = 0x260
callq 0x9050
cmpq $0x0, %rax
jne 0x855d
movq 0x58(%rsp), %rax
addq $0x278, %rax            # imm = 0x278
movq %rax, 0xb0(%rsp)
jmp 0x88d5
movq 0x58(%rsp), %rax
movq 0x240(%rax), %rax
subq $0x1, %rax
movq %rax, 0xa0(%rsp)
cmpq $0x2, 0xa0(%rsp)
jl 0x8582
jmp 0x85a1
leaq 0x15063(%rip), %rdi     # 0x1d5ec
leaq 0x14a7d(%rip), %rsi     # 0x1d00d
movl $0x9f, %edx
leaq 0x15066(%rip), %rcx     # 0x1d602
callq 0x5280
movq $0x0, 0x98(%rsp)
movq $-0x7fffffff, 0x90(%rsp) # imm = 0x80000001
movq $-0x7fffffff, 0x88(%rsp) # imm = 0x80000001
movl $0x0, 0x84(%rsp)
movq 0x58(%rsp), %rdi
movl 0x84(%rsp), %eax
movq %rax, 0x50(%rsp)
addq $0x260, %rdi            # imm = 0x260
callq 0x9050
movq %rax, %rcx
movq 0x50(%rsp), %rax
cmpq %rcx, %rax
jae 0x88c2
movq 0x58(%rsp), %rdi
addq $0x260, %rdi            # imm = 0x260
movl 0x84(%rsp), %eax
movl %eax, %esi
callq 0x9070
movq %rax, 0x78(%rsp)
movq 0x78(%rsp), %rax
movq (%rax), %rax
movq %rax, 0x70(%rsp)
movq 0x58(%rsp), %rdi
movq 0x98(%rsp), %rax
movq %rax, 0x40(%rsp)
addq $0x248, %rdi            # imm = 0x248
callq 0x8f10
movq 0x40(%rsp), %rcx
movq %rax, %rdx
xorl %eax, %eax
cmpq %rdx, %rcx
movb %al, 0x4f(%rsp)
jge 0x869c
movq 0x58(%rsp), %rdi
movq 0xa0(%rsp), %rax
movq %rax, 0x38(%rsp)
addq $0x248, %rdi            # imm = 0x248
movq 0x98(%rsp), %rsi
callq 0xa5b0
movq %rax, %rcx
movq 0x38(%rsp), %rax
movslq 0x8(%rcx), %rcx
addq %rcx, %rax
cmpq 0x70(%rsp), %rax
setl %al
movb %al, 0x4f(%rsp)
movb 0x4f(%rsp), %al
testb $0x1, %al
jne 0x86a6
jmp 0x86ec
movq 0x58(%rsp), %rdi
addq $0x248, %rdi            # imm = 0x248
movq 0x98(%rsp), %rsi
callq 0xa5b0
movslq 0x8(%rax), %rax
addq 0xa0(%rsp), %rax
movq %rax, 0xa0(%rsp)
movq 0x98(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x98(%rsp)
jmp 0x862a
movq 0x58(%rsp), %rdi
movq 0x98(%rsp), %rax
movq %rax, 0x30(%rsp)
addq $0x248, %rdi            # imm = 0x248
callq 0x8f10
movq %rax, %rcx
movq 0x30(%rsp), %rax
cmpq %rcx, %rax
jge 0x8719
jmp 0x8738
leaq 0x14f24(%rip), %rdi     # 0x1d644
leaq 0x148e6(%rip), %rsi     # 0x1d00d
movl $0xad, %edx
leaq 0x14ecf(%rip), %rcx     # 0x1d602
callq 0x5280
movq 0xa0(%rsp), %rcx
xorl %eax, %eax
cmpq 0x70(%rsp), %rcx
movb %al, 0x2f(%rsp)
jge 0x878e
movq 0x58(%rsp), %rdi
movq 0xa0(%rsp), %rax
movq %rax, 0x20(%rsp)
addq $0x248, %rdi            # imm = 0x248
movq 0x98(%rsp), %rsi
callq 0xa5b0
movq %rax, %rcx
movq 0x20(%rsp), %rax
movslq 0x8(%rcx), %rcx
addq %rcx, %rax
cmpq 0x70(%rsp), %rax
setge %al
movb %al, 0x2f(%rsp)
movb 0x2f(%rsp), %al
testb $0x1, %al
jne 0x8798
jmp 0x879a
jmp 0x87b9
leaq 0x14ec8(%rip), %rdi     # 0x1d669
leaq 0x14865(%rip), %rsi     # 0x1d00d
movl $0xaf, %edx
leaq 0x14e4e(%rip), %rcx     # 0x1d602
callq 0x5280
movq 0x98(%rsp), %rax
cmpq 0x90(%rsp), %rax
jne 0x87d0
jmp 0x88ac
movq 0x58(%rsp), %rdi
addq $0x248, %rdi            # imm = 0x248
movq 0x98(%rsp), %rsi
callq 0xa5b0
movq 0x58(%rsp), %rdi
movq (%rax), %rax
movq %rax, 0x18(%rsp)
movq 0x78(%rsp), %rax
movq 0x8(%rax), %rsi
callq 0x90d0
movq 0x18(%rsp), %rsi
movq %rax, %rdx
leaq 0x60(%rsp), %rdi
callq 0x6de0
cmpq $0x0, 0x68(%rsp)
jl 0x8820
jmp 0x883f
leaq 0x14e9b(%rip), %rdi     # 0x1d6c2
leaq 0x147df(%rip), %rsi     # 0x1d00d
movl $0xb8, %edx
leaq 0x14dc8(%rip), %rcx     # 0x1d602
callq 0x5280
movq 0x68(%rsp), %rax
movq %rax, 0x10(%rsp)
movq 0x88(%rsp), %rax
movq %rax, 0x8(%rsp)
leaq 0x1fc83(%rip), %rdi     # 0x284e0
callq 0xa5d0
movq 0x8(%rsp), %rcx
movl %eax, %edx
movq 0x10(%rsp), %rax
movslq %edx, %rdx
addq %rdx, %rcx
cmpq %rcx, %rax
jle 0x889c
movq 0x58(%rsp), %rdi
movq 0x68(%rsp), %rax
movq %rax, 0x88(%rsp)
addq $0x278, %rdi            # imm = 0x278
leaq 0x60(%rsp), %rsi
callq 0xa5e0
movq 0x98(%rsp), %rax
movq %rax, 0x90(%rsp)
movl 0x84(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x84(%rsp)
jmp 0x85d0
movq 0x58(%rsp), %rax
addq $0x278, %rax            # imm = 0x278
movq %rax, 0xb0(%rsp)
movq 0xb0(%rsp), %rax
addq $0xb8, %rsp
retq
nopw %cs:(%rax,%rax)
nop