// File: cpearce[P]OggIndex/src/SkeletonEncoder.cpp
// Function: SkeletonEncoder::ConstructIndexPackets()
void
SkeletonEncoder::ConstructIndexPackets() {
  assert(mIndexPackets.size() > 0);
  for (ogg_uint32_t i=0; i<mDecoders.size(); i++) {
    ogg_packet* packet = new ogg_packet();
    memset(packet, 0, sizeof(ogg_packet));
    
    Decoder* decoder = mDecoders[i];
    const vector<KeyFrameInfo>& keyframes = decoder->GetKeyframes();
    
    const ogg_int32_t uncompressed_size = INDEX_KEYPOINT_OFFSET +
                                  (int)keyframes.size() * 20;

    ogg_int64_t compressed_size =
      INDEX_KEYPOINT_OFFSET + compressed_length(keyframes);

    double savings = ((double)compressed_size / (double)uncompressed_size) * 100.0;
    cout << sStreamType[mDecoders[i]->Type()] << "/" << mDecoders[i]->GetSerial()
         << " index uses " << uncompressed_size 
         << " bytes, compresses to " << compressed_size << " (" << savings << "%),"
         << " duration [" << decoder->GetStartTime() << "," << decoder->GetEndTime() << "] ms"
         << endl;

    packet->bytes = compressed_size;
    unsigned char* p = new unsigned char[compressed_size];
    memset(p, 0, compressed_size);
    packet->packet = p;

    // Identifier bytes.
    memcpy(packet->packet, HEADER_MAGIC, HEADER_MAGIC_LEN);

    // Stream serialno.
    WriteLEUint32(packet->packet + INDEX_SERIALNO_OFFSET,
                  mDecoders[i]->GetSerial());
    
    // Number of key points.
    assert(keyframes.size() < UINT_MAX);
    WriteLEUint64(packet->packet + INDEX_NUM_KEYPOINTS_OFFSET,
                  (ogg_uint64_t)keyframes.size());
    
    // Write start time and end time.
    WriteLEInt64(packet->packet + INDEX_FIRST_NUMER_OFFSET, decoder->GetStartTime());
    WriteLEInt64(packet->packet + INDEX_LAST_NUMER_OFFSET, decoder->GetEndTime());

    // Timestamp denominator.
    WriteLEInt64(packet->packet + INDEX_TIME_DENOM_OFFSET, 1000);

    p = packet->packet + INDEX_KEYPOINT_OFFSET;

    ogg_int64_t prev_offset = 0;
    ogg_int64_t prev_time = 0;
    const unsigned char* limit = packet->packet + compressed_size;
    for (ogg_uint32_t j=0; j<keyframes.size(); j++) {
      const KeyFrameInfo& k = keyframes[j];

      ogg_int64_t off_diff = k.mOffset - prev_offset;
      ogg_int64_t time_diff = k.mTime - prev_time;

      unsigned char* expected = p + bytes_required(off_diff);
      p = WriteVariableLength(p, limit, off_diff);
      assert(p == expected);

      expected = p + bytes_required(time_diff);
      p = WriteVariableLength(p, limit, time_diff);
      assert(p == expected);

      prev_offset = k.mOffset;
      prev_time = k.mTime;

    }
    
    assert(p == packet->packet + compressed_size);

    packet->packetno = mPacketCount;
    mPacketCount++;

    assert(packet->e_o_s == 0);
    assert(packet->b_o_s == 0);
    mIndexPackets.push_back(packet);
  }
}

// Assembly:
subq $0xf8, %rsp
movq %rdi, 0xf0(%rsp)
movq 0xf0(%rsp), %rdi
movq %rdi, 0x68(%rsp)
addq $0x38, %rdi
callq 0x6980
cmpq $0x0, %rax
jbe 0x11cdd
jmp 0x11cfc
leaq 0xc36d(%rip), %rdi      # 0x1e051
leaq 0xc2f9(%rip), %rsi      # 0x1dfe4
movl $0x117, %edx            # imm = 0x117
leaq 0xc373(%rip), %rcx      # 0x1e06a
callq 0x5280
movl $0x0, 0xec(%rsp)
movq 0x68(%rsp), %rdi
movl 0xec(%rsp), %eax
movq %rax, 0x60(%rsp)
callq 0x140a0
movq %rax, %rcx
movq 0x60(%rsp), %rax
cmpq %rcx, %rax
jae 0x123d4
movl $0x30, %edi
callq 0x53e0
movq %rax, %rdi
movq %rdi, 0x38(%rsp)
xorl %esi, %esi
movl $0x30, %edx
callq 0x5230
movq 0x38(%rsp), %rax
movq %rax, 0xe0(%rsp)
movq 0xe0(%rsp), %rdi
xorl %esi, %esi
movl $0x30, %edx
callq 0x5230
movq 0x68(%rsp), %rdi
movl 0xec(%rsp), %eax
movl %eax, %esi
callq 0x140c0
movq (%rax), %rax
movq %rax, 0xd8(%rsp)
movq 0xd8(%rsp), %rdi
movq (%rdi), %rax
callq *0x20(%rax)
movq %rax, 0xd0(%rsp)
movq 0xd0(%rsp), %rdi
callq 0xa590
imull $0x14, %eax, %eax
addl $0x2a, %eax
movl %eax, 0xcc(%rsp)
movq 0xd0(%rsp), %rdi
callq 0x12f40
movq 0x68(%rsp), %rdi
addq $0x2a, %rax
movq %rax, 0xc0(%rsp)
cvtsi2sdq 0xc0(%rsp), %xmm0
cvtsi2sdl 0xcc(%rsp), %xmm1
divsd %xmm1, %xmm0
movsd 0xba90(%rip), %xmm1     # 0x1d888
mulsd %xmm1, %xmm0
movsd %xmm0, 0xb8(%rsp)
movl 0xec(%rsp), %eax
movl %eax, %esi
callq 0x140c0
movq (%rax), %rdi
movq (%rdi), %rax
callq *0x28(%rax)
movl %eax, %eax
movl %eax, %ecx
leaq 0x16679(%rip), %rax     # 0x284a0
movq (%rax,%rcx,8), %rsi
movq 0x1619e(%rip), %rdi     # 0x27fd0
callq 0x53d0
movq %rax, %rdi
leaq 0xc257(%rip), %rsi      # 0x1e098
callq 0x53d0
movq 0x68(%rsp), %rdi
movq %rax, 0x40(%rsp)
movl 0xec(%rsp), %eax
movl %eax, %esi
callq 0x140c0
movq (%rax), %rdi
callq 0x13f80
movq 0x40(%rsp), %rdi
movl %eax, %esi
callq 0x5560
movq %rax, %rdi
leaq 0xc21e(%rip), %rsi      # 0x1e09a
callq 0x53d0
movq %rax, %rdi
movl 0xcc(%rsp), %esi
callq 0x57a0
movq %rax, %rdi
leaq 0xc20d(%rip), %rsi      # 0x1e0a7
callq 0x53d0
movq %rax, %rdi
movq 0xc0(%rsp), %rsi
callq 0x5810
movq %rax, %rdi
leaq 0xcba6(%rip), %rsi      # 0x1ea5f
callq 0x53d0
movq %rax, %rdi
movsd 0xb8(%rsp), %xmm0
callq 0x5860
movq %rax, %rdi
leaq 0xc1e5(%rip), %rsi      # 0x1e0be
callq 0x53d0
movq %rax, %rdi
leaq 0xc1da(%rip), %rsi      # 0x1e0c2
callq 0x53d0
movq %rax, 0x48(%rsp)
movq 0xd8(%rsp), %rdi
callq 0x140e0
movq 0x48(%rsp), %rdi
movq %rax, %rsi
callq 0x5810
movq %rax, %rdi
leaq 0xc1aa(%rip), %rsi      # 0x1e0c0
callq 0x53d0
movq %rax, 0x50(%rsp)
movq 0xd8(%rsp), %rdi
callq 0x14100
movq 0x50(%rsp), %rdi
movq %rax, %rsi
callq 0x5810
movq %rax, %rdi
leaq 0xc18a(%rip), %rsi      # 0x1e0ce
callq 0x53d0
movq %rax, %rdi
movq 0x1606d(%rip), %rsi     # 0x27fc0
callq 0x5430
movq 0xc0(%rsp), %rcx
movq 0xe0(%rsp), %rax
movq %rcx, 0x8(%rax)
movq 0xc0(%rsp), %rdi
callq 0x5030
movq %rax, 0xb0(%rsp)
movq 0xb0(%rsp), %rdi
movq 0xc0(%rsp), %rdx
xorl %esi, %esi
callq 0x5230
movq 0x68(%rsp), %rdi
movq 0xb0(%rsp), %rcx
movq 0xe0(%rsp), %rax
movq %rcx, (%rax)
movq 0xe0(%rsp), %rax
movq (%rax), %rax
movl 0xc112(%rip), %ecx      # 0x1e0d3
movl %ecx, (%rax)
movw 0xc10d(%rip), %cx       # 0x1e0d7
movw %cx, 0x4(%rax)
movq 0xe0(%rsp), %rax
movq (%rax), %rax
addq $0x6, %rax
movq %rax, 0x58(%rsp)
movl 0xec(%rsp), %eax
movl %eax, %esi
callq 0x140c0
movq (%rax), %rdi
callq 0x13f80
movq 0x58(%rsp), %rdi
movl %eax, %esi
callq 0x16d10
movq 0xd0(%rsp), %rdi
callq 0xa590
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
cmpq %rcx, %rax
jae 0x1201d
jmp 0x1203c
leaq 0xc0b5(%rip), %rdi      # 0x1e0d9
leaq 0xbfb9(%rip), %rsi      # 0x1dfe4
movl $0x139, %edx            # imm = 0x139
leaq 0xc033(%rip), %rcx      # 0x1e06a
callq 0x5280
movq 0xe0(%rsp), %rax
movq (%rax), %rax
addq $0xa, %rax
movq %rax, 0x20(%rsp)
movq 0xd0(%rsp), %rdi
callq 0xa590
movq 0x20(%rsp), %rdi
movq %rax, %rsi
callq 0x16ad0
movq 0xe0(%rsp), %rax
movq (%rax), %rax
addq $0x1a, %rax
movq %rax, 0x28(%rsp)
movq 0xd8(%rsp), %rdi
callq 0x140e0
movq 0x28(%rsp), %rdi
movq %rax, %rsi
callq 0x16bf0
movq 0xe0(%rsp), %rax
movq (%rax), %rax
addq $0x22, %rax
movq %rax, 0x30(%rsp)
movq 0xd8(%rsp), %rdi
callq 0x14100
movq 0x30(%rsp), %rdi
movq %rax, %rsi
callq 0x16bf0
movq 0xe0(%rsp), %rax
movq (%rax), %rdi
addq $0x12, %rdi
movl $0x3e8, %esi            # imm = 0x3E8
callq 0x16bf0
movq 0xe0(%rsp), %rax
movq (%rax), %rax
addq $0x2a, %rax
movq %rax, 0xb0(%rsp)
movq $0x0, 0xa8(%rsp)
movq $0x0, 0xa0(%rsp)
movq 0xe0(%rsp), %rax
movq (%rax), %rax
addq 0xc0(%rsp), %rax
movq %rax, 0x98(%rsp)
movl $0x0, 0x94(%rsp)
movl 0x94(%rsp), %eax
movq %rax, 0x18(%rsp)
movq 0xd0(%rsp), %rdi
callq 0xa590
movq %rax, %rcx
movq 0x18(%rsp), %rax
cmpq %rcx, %rax
jae 0x122e9
movq 0xd0(%rsp), %rdi
movl 0x94(%rsp), %eax
movl %eax, %esi
callq 0x14120
movq %rax, 0x88(%rsp)
movq 0x88(%rsp), %rax
movq (%rax), %rax
subq 0xa8(%rsp), %rax
movq %rax, 0x80(%rsp)
movq 0x88(%rsp), %rax
movq 0x8(%rax), %rax
subq 0xa0(%rsp), %rax
movq %rax, 0x78(%rsp)
movq 0xb0(%rsp), %rax
movq %rax, 0x10(%rsp)
movq 0x80(%rsp), %rdi
callq 0x130b0
movl %eax, %ecx
movq 0x10(%rsp), %rax
movslq %ecx, %rcx
addq %rcx, %rax
movq %rax, 0x70(%rsp)
movq 0xb0(%rsp), %rdi
movq 0x98(%rsp), %rsi
movq 0x80(%rsp), %rdx
callq 0x14140
movq %rax, 0xb0(%rsp)
movq 0xb0(%rsp), %rax
cmpq 0x70(%rsp), %rax
jne 0x12212
jmp 0x12231
leaq 0xbedc(%rip), %rdi      # 0x1e0f5
leaq 0xbdc4(%rip), %rsi      # 0x1dfe4
movl $0x151, %edx            # imm = 0x151
leaq 0xbe3e(%rip), %rcx      # 0x1e06a
callq 0x5280
movq 0xb0(%rsp), %rax
movq %rax, 0x8(%rsp)
movq 0x78(%rsp), %rdi
callq 0x130b0
movl %eax, %ecx
movq 0x8(%rsp), %rax
movslq %ecx, %rcx
addq %rcx, %rax
movq %rax, 0x70(%rsp)
movq 0xb0(%rsp), %rdi
movq 0x98(%rsp), %rsi
movq 0x78(%rsp), %rdx
callq 0x14140
movq %rax, 0xb0(%rsp)
movq 0xb0(%rsp), %rax
cmpq 0x70(%rsp), %rax
jne 0x1228d
jmp 0x122ac
leaq 0xbe61(%rip), %rdi      # 0x1e0f5
leaq 0xbd49(%rip), %rsi      # 0x1dfe4
movl $0x155, %edx            # imm = 0x155
leaq 0xbdc3(%rip), %rcx      # 0x1e06a
callq 0x5280
movq 0x88(%rsp), %rax
movq (%rax), %rax
movq %rax, 0xa8(%rsp)
movq 0x88(%rsp), %rax
movq 0x8(%rax), %rax
movq %rax, 0xa0(%rsp)
movl 0x94(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x94(%rsp)
jmp 0x12134
movq 0xb0(%rsp), %rax
movq 0xe0(%rsp), %rcx
movq (%rcx), %rcx
addq 0xc0(%rsp), %rcx
cmpq %rcx, %rax
jne 0x1230b
jmp 0x1232a
leaq 0xbdf1(%rip), %rdi      # 0x1e103
leaq 0xbccb(%rip), %rsi      # 0x1dfe4
movl $0x15c, %edx            # imm = 0x15C
leaq 0xbd45(%rip), %rcx      # 0x1e06a
callq 0x5280
movq 0x68(%rsp), %rax
movslq 0x34(%rax), %rdx
movq 0xe0(%rsp), %rcx
movq %rdx, 0x28(%rcx)
movl 0x34(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x34(%rax)
movq 0xe0(%rsp), %rax
cmpq $0x0, 0x18(%rax)
jne 0x12359
jmp 0x12378
leaq 0xbdc9(%rip), %rdi      # 0x1e129
leaq 0xbc7d(%rip), %rsi      # 0x1dfe4
movl $0x161, %edx            # imm = 0x161
leaq 0xbcf7(%rip), %rcx      # 0x1e06a
callq 0x5280
movq 0xe0(%rsp), %rax
cmpq $0x0, 0x10(%rax)
jne 0x12389
jmp 0x123a8
leaq 0xbdac(%rip), %rdi      # 0x1e13c
leaq 0xbc4d(%rip), %rsi      # 0x1dfe4
movl $0x162, %edx            # imm = 0x162
leaq 0xbcc7(%rip), %rcx      # 0x1e06a
callq 0x5280
movq 0x68(%rsp), %rdi
addq $0x38, %rdi
leaq 0xe0(%rsp), %rsi
callq 0x14030
movl 0xec(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xec(%rsp)
jmp 0x11d07
addq $0xf8, %rsp
retq
nopl (%rax)