// File: /workspace/github_c_makefile_star2_O1/phoboslab[P]pl_mpeg/./pl_mpeg.h
// Function: plm_demux_seek
plm_packet_t *plm_demux_seek(plm_demux_t *self, double seek_time, int type, int force_intra) {
	if (!plm_demux_has_headers(self)) {
		return NULL;
	}

	// Using the current time, current byte position and the average bytes per
	// second for this file, try to jump to a byte position that hopefully has
	// packets containing timestamps within one second before to the desired 
	// seek_time.

	// If we hit close to the seek_time scan through all packets to find the
	// last one (just before the seek_time) containing an intra frame.
	// Otherwise we should at least be closer than before. Calculate the bytes
	// per second for the jumped range and jump again.

	// The number of retries here is hard-limited to a generous amount. Usually
	// the correct range is found after 1--5 jumps, even for files with very 
	// variable bitrates. If significantly more jumps are needed, there's
	// probably something wrong with the file and we just avoid getting into an
	// infinite loop. 32 retries should be enough for anybody.

	double duration = plm_demux_get_duration(self, type);
	long file_size = plm_buffer_get_size(self->buffer);
	long byterate = file_size / duration;

	double cur_time = self->last_decoded_pts;
	double scan_span = 1;

	if (seek_time > duration) {
		seek_time = duration;
	}
	else if (seek_time < 0) {
		seek_time = 0;
	}
	seek_time += self->start_time;

	for (int retry = 0; retry < 32; retry++) {
		int found_packet_with_pts = FALSE;
		int found_packet_in_range = FALSE;
		long last_valid_packet_start = -1;
		double first_packet_time = PLM_PACKET_INVALID_TS;

		long cur_pos = plm_buffer_tell(self->buffer);

		// Estimate byte offset and jump to it.
		long offset = (seek_time - cur_time - scan_span) * byterate;
		long seek_pos = cur_pos + offset;
		if (seek_pos < 0) {
			seek_pos = 0;
		}
		else if (seek_pos > file_size - 256) {
			seek_pos = file_size - 256;
		}

		plm_demux_buffer_seek(self, seek_pos);

		// Scan through all packets up to the seek_time to find the last packet
		// containing an intra frame.
		while (plm_buffer_find_start_code(self->buffer, type) != -1) {
			long packet_start = plm_buffer_tell(self->buffer);
			plm_packet_t *packet = plm_demux_decode_packet(self, type);

			// Skip packet if it has no PTS
			if (!packet || packet->pts == PLM_PACKET_INVALID_TS) {
				continue;
			}

			// Bail scanning through packets if we hit one that is outside
			// seek_time - scan_span.
			// We also adjust the cur_time and byterate values here so the next 
			// iteration can be a bit more precise.
			if (packet->pts > seek_time || packet->pts < seek_time - scan_span) {
				found_packet_with_pts = TRUE;
				byterate = (seek_pos - cur_pos) / (packet->pts - cur_time);
				cur_time = packet->pts;
				break;
			}

			// If we are still here, it means this packet is in close range to
			// the seek_time. If this is the first packet for this jump position
			// record the PTS. If we later have to back off, when there was no
			// intra frame in this range, we can lower the seek_time to not scan
			// this range again.
			if (!found_packet_in_range) {
				found_packet_in_range = TRUE;
				first_packet_time = packet->pts;
			}

			// Check if this is an intra frame packet. If so, record the buffer
			// position of the start of this packet. We want to jump back to it 
			// later, when we know it's the last intra frame before desired
			// seek time.
			if (force_intra) {
				for (size_t i = 0; i < packet->length - 6; i++) {
					// Find the START_PICTURE code
					if (
						packet->data[i] == 0x00 &&
						packet->data[i + 1] == 0x00 &&
						packet->data[i + 2] == 0x01 &&
						packet->data[i + 3] == 0x00
					) {
						// Bits 11--13 in the picture header contain the frame 
						// type, where 1=Intra
						if ((packet->data[i + 5] & 0x38) == 8) {
							last_valid_packet_start = packet_start;
						}
						break;
					}
				}
			}

			// If we don't want intra frames, just use the last PTS found.
			else {
				last_valid_packet_start = packet_start;
			}
		}

		// If there was at least one intra frame in the range scanned above,
		// our search is over. Jump back to the packet and decode it again.
		if (last_valid_packet_start != -1) {
			plm_demux_buffer_seek(self, last_valid_packet_start);
			return plm_demux_decode_packet(self, type);
		}

		// If we hit the right range, but still found no intra frame, we have
		// to increases the scan_span. This is done exponentially to also handle
		// video files with very few intra frames.
		else if (found_packet_in_range) {
			scan_span *= 2;
			seek_time = first_packet_time;
		}

		// If we didn't find any packet with a PTS, it probably means we reached
		// the end of the file. Estimate byterate and cur_time accordingly.
		else if (!found_packet_with_pts) {
			byterate = (seek_pos - cur_pos) / (duration - cur_time);
			cur_time = duration;
		}
	}

	return NULL;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x68, %rsp
movl %edx, 0x3c(%rsp)
movl %esi, %ebp
movsd %xmm0, (%rsp)
movq %rdi, %r14
callq 0x2894
testl %eax, %eax
je 0x3fbd
movq %r14, %rdi
movl %ebp, %esi
callq 0x30d8
movq (%r14), %rax
xorl %ecx, %ecx
cmpl $0x0, 0x60(%rax)
sete %cl
movq 0x10(%rax,%rcx,8), %rax
movq %rax, 0x40(%rsp)
cvtsi2sd %rax, %xmm2
divsd %xmm0, %xmm2
movsd (%rsp), %xmm4
ucomisd %xmm0, %xmm4
movsd %xmm0, 0x50(%rsp)
movapd %xmm0, %xmm3
ja 0x3ca7
xorpd %xmm1, %xmm1
ucomisd %xmm4, %xmm1
movapd %xmm4, %xmm3
jbe 0x3ca7
xorpd %xmm3, %xmm3
cvttsd2si %xmm2, %rax
movq %rax, 0x30(%rsp)
movsd 0x20(%r14), %xmm0
movsd %xmm0, (%rsp)
addsd 0x28(%r14), %xmm3
addq $-0x100, 0x40(%rsp)
movsd 0x533d(%rip), %xmm0     # 0x9010
movsd %xmm0, 0x28(%rsp)
xorl %ecx, %ecx
movq (%r14), %r12
movq 0x48(%r12), %rax
testq %rax, %rax
movsd %xmm3, 0x20(%rsp)
movl %ecx, 0xc(%rsp)
je 0x3d14
movq 0x50(%r12), %rsi
movq %r12, %rdi
callq *%rax
movsd 0x20(%rsp), %xmm3
movq (%r12), %r15
shrq $0x3, %r15
addq %rax, %r15
subq 0x10(%r12), %r15
jmp 0x3d1c
movq (%r12), %r15
shrq $0x3, %r15
movapd %xmm3, %xmm0
subsd (%rsp), %xmm0
subsd 0x28(%rsp), %xmm0
xorps %xmm1, %xmm1
cvtsi2sdq 0x30(%rsp), %xmm1
mulsd %xmm0, %xmm1
cvttsd2si %xmm1, %rax
addq %r15, %rax
movq 0x40(%rsp), %r12
cmpq %r12, %rax
cmovlq %rax, %r12
xorl %ebx, %ebx
testq %rax, %rax
cmovsq %rbx, %r12
movq (%r14), %rdi
movq %r12, %rsi
callq 0x430a
movq %rbx, 0x60(%r14)
movq %rbx, 0x80(%r14)
movl $0xffffffff, 0x38(%r14) # imm = 0xFFFFFFFF
movsd 0x20(%rsp), %xmm1
subq %r15, %r12
xorps %xmm0, %xmm0
cvtsi2sd %r12, %xmm0
movsd %xmm0, 0x48(%rsp)
subsd 0x28(%rsp), %xmm1
movsd %xmm1, 0x60(%rsp)
movq $-0x1, 0x10(%rsp)
xorl %r12d, %r12d
movsd 0x525d(%rip), %xmm0     # 0x9008
movsd %xmm0, 0x18(%rsp)
movq (%r14), %r13
movq %r13, %rdi
callq 0x4500
cmpl %ebp, %eax
je 0x3dc5
cmpl $-0x1, %eax
jne 0x3db4
cmpl $-0x1, %eax
je 0x3efb
movq (%r14), %r13
movq 0x48(%r13), %rax
testq %rax, %rax
je 0x3df4
movq 0x50(%r13), %rsi
movq %r13, %rdi
callq *%rax
movq (%r13), %r15
shrq $0x3, %r15
addq %rax, %r15
subq 0x10(%r13), %r15
jmp 0x3dfc
movq (%r13), %r15
shrq $0x3, %r15
movq %r14, %rdi
movl %ebp, %esi
callq 0x4739
testq %rax, %rax
je 0x3e29
movsd 0x8(%rax), %xmm2
ucomisd 0x51f0(%rip), %xmm2     # 0x9008
movsd 0x20(%rsp), %xmm3
jne 0x3e3b
jp 0x3e3b
xorl %eax, %eax
jmp 0x3ecf
xorl %eax, %eax
movsd (%rsp), %xmm2
movsd 0x20(%rsp), %xmm3
jmp 0x3ed4
ucomisd %xmm3, %xmm2
ja 0x3e9c
movsd 0x60(%rsp), %xmm0
ucomisd %xmm2, %xmm0
ja 0x3e9c
testl %r12d, %r12d
je 0x3e58
movsd 0x18(%rsp), %xmm2
movl $0x1, %r12d
cmpl $0x0, 0x3c(%rsp)
je 0x3ec2
movq 0x10(%rax), %rcx
addq $-0x6, %rcx
je 0x3e98
movq 0x18(%rax), %rax
xorl %edx, %edx
cmpb $0x0, (%rax,%rdx)
jne 0x3e90
cmpb $0x0, 0x1(%rax,%rdx)
jne 0x3e90
cmpb $0x1, 0x2(%rax,%rdx)
jne 0x3e90
cmpb $0x0, 0x3(%rax,%rdx)
je 0x3ee3
incq %rdx
cmpq %rdx, %rcx
jne 0x3e75
xorl %eax, %eax
jmp 0x3ec9
movapd %xmm2, %xmm0
subsd (%rsp), %xmm0
movsd 0x48(%rsp), %xmm1
divsd %xmm0, %xmm1
cvttsd2si %xmm1, %rax
movq %rax, 0x30(%rsp)
movl $0x1, %ebx
movb $0x1, %al
jmp 0x3ed4
xorl %eax, %eax
movq %r15, 0x10(%rsp)
movsd %xmm2, 0x18(%rsp)
movsd (%rsp), %xmm2
movsd %xmm2, (%rsp)
testb %al, %al
je 0x3db1
jmp 0x3f06
movb 0x5(%rax,%rdx), %al
andb $0x38, %al
cmpb $0x8, %al
movq 0x10(%rsp), %rax
cmoveq %r15, %rax
movq %rax, 0x10(%rsp)
jmp 0x3e98
movsd (%rsp), %xmm2
movsd 0x20(%rsp), %xmm3
movq 0x10(%rsp), %rsi
cmpq $-0x1, %rsi
je 0x3f4f
movq (%r14), %rdi
movsd %xmm2, (%rsp)
callq 0x430a
xorl %eax, %eax
movq %rax, 0x60(%r14)
movq %rax, 0x80(%r14)
movl $0xffffffff, 0x38(%r14) # imm = 0xFFFFFFFF
movq %r14, %rdi
movl %ebp, %esi
callq 0x4739
movsd 0x20(%rsp), %xmm3
movq %rax, 0x58(%rsp)
movq 0x10(%rsp), %rsi
jmp 0x3fa8
testl %r12d, %r12d
je 0x3f71
movsd 0x28(%rsp), %xmm0
addsd %xmm0, %xmm0
movsd %xmm0, 0x28(%rsp)
movsd %xmm2, (%rsp)
movsd 0x18(%rsp), %xmm3
jmp 0x3fa8
testl %ebx, %ebx
je 0x3f7c
movsd %xmm2, (%rsp)
jmp 0x3fa8
movsd 0x50(%rsp), %xmm1
movapd %xmm1, %xmm0
subsd %xmm2, %xmm0
movsd 0x48(%rsp), %xmm2
divsd %xmm0, %xmm2
cvttsd2si %xmm2, %rax
movq %rax, 0x30(%rsp)
movq 0x10(%rsp), %rsi
movsd %xmm1, (%rsp)
movl 0xc(%rsp), %ecx
cmpq $-0x1, %rsi
jne 0x3fc1
incl %ecx
cmpl $0x20, %ecx
jne 0x3cdb
xorl %eax, %eax
jmp 0x3fc6
movq 0x58(%rsp), %rax
addq $0x68, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq