// File: /workspace/github_c_makefile_star2_O3/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, %ebx
movsd %xmm0, (%rsp)
movq %rdi, %r14
callq 0x27a8
testl %eax, %eax
je 0x3dee
movq %r14, %rdi
movl %ebx, %esi
callq 0x2fc3
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), %xmm3
ucomisd %xmm0, %xmm3
movsd %xmm0, 0x58(%rsp)
ja 0x3b25
xorpd %xmm1, %xmm1
ucomisd %xmm3, %xmm1
movapd %xmm3, %xmm0
jbe 0x3b25
xorpd %xmm0, %xmm0
cvttsd2si %xmm2, %rax
movq %rax, 0x30(%rsp)
movsd 0x20(%r14), %xmm1
movsd %xmm1, 0x20(%rsp)
addsd 0x28(%r14), %xmm0
movsd %xmm0, (%rsp)
addq $-0x100, 0x40(%rsp)
movsd 0x56e1(%rip), %xmm0     # 0x9238
movsd %xmm0, 0x28(%rsp)
xorl %ecx, %ecx
movq (%r14), %r12
movq 0x48(%r12), %rax
testq %rax, %rax
movl %ecx, 0xc(%rsp)
je 0x3b8f
movq 0x50(%r12), %rsi
movq %r12, %rdi
callq *%rax
movq (%r12), %rcx
shrq $0x3, %rcx
addq %rax, %rcx
subq 0x10(%r12), %rcx
movq (%r14), %r12
jmp 0x3b97
movq (%r12), %rcx
shrq $0x3, %rcx
movsd (%rsp), %xmm0
subsd 0x20(%rsp), %xmm0
subsd 0x28(%rsp), %xmm0
xorps %xmm1, %xmm1
cvtsi2sdq 0x30(%rsp), %xmm1
mulsd %xmm0, %xmm1
cvttsd2si %xmm1, %rax
movq %rcx, 0x48(%rsp)
addq %rcx, %rax
movq 0x40(%rsp), %r15
cmpq %r15, %rax
cmovlq %rax, %r15
testq %rax, %rax
movl $0x0, %r13d
cmovsq %r13, %r15
movq %r12, %rdi
movq %r15, %rsi
callq 0x4120
movq %r13, 0x60(%r14)
movq %r13, 0x80(%r14)
movl $0xffffffff, 0x38(%r14) # imm = 0xFFFFFFFF
movsd (%rsp), %xmm0
subsd 0x28(%rsp), %xmm0
movsd %xmm0, 0x60(%rsp)
movq $-0x1, 0x10(%rsp)
movb $0x1, %dl
movsd 0x5612(%rip), %xmm0     # 0x9230
movapd %xmm0, %xmm1
movsd %xmm1, 0x50(%rsp)
movl %edx, 0x1c(%rsp)
movq (%r14), %rbp
movq %rbp, %rdi
callq 0x4320
movl %eax, %r13d
cmpl %ebx, %eax
je 0x3c44
cmpl $-0x1, %r13d
jne 0x3c2f
cmpl $-0x1, %r13d
je 0x3d33
movq (%r14), %rbp
movq 0x48(%rbp), %rax
testq %rax, %rax
je 0x3c74
movq 0x50(%rbp), %rsi
movq %rbp, %rdi
callq *%rax
movq (%rbp), %r12
shrq $0x3, %r12
addq %rax, %r12
subq 0x10(%rbp), %r12
jmp 0x3c7c
movq (%rbp), %r12
shrq $0x3, %r12
movq %r14, %rdi
movl %ebx, %esi
callq 0x4559
testq %rax, %rax
je 0x3c2c
movsd 0x8(%rax), %xmm0
ucomisd 0x5598(%rip), %xmm0     # 0x9230
jne 0x3c9c
jnp 0x3c2c
ucomisd (%rsp), %xmm0
ja 0x3dc1
movsd 0x60(%rsp), %xmm1
ucomisd %xmm0, %xmm1
ja 0x3dc1
testb $0x1, 0x1c(%rsp)
jne 0x3cc4
movsd 0x50(%rsp), %xmm0
cmpl $0x0, 0x3c(%rsp)
je 0x3d27
movq 0x10(%rax), %rcx
xorl %edx, %edx
movapd %xmm0, %xmm1
addq $-0x6, %rcx
je 0x3c22
movq 0x18(%rax), %rax
xorl %edx, %edx
cmpb $0x0, (%rax,%rdx)
jne 0x3d00
cmpb $0x0, 0x1(%rax,%rdx)
jne 0x3d00
cmpb $0x1, 0x2(%rax,%rdx)
jne 0x3d00
cmpb $0x0, 0x3(%rax,%rdx)
je 0x3d0f
incq %rdx
cmpq %rdx, %rcx
jne 0x3ce5
xorl %edx, %edx
jmp 0x3c1e
movb 0x5(%rax,%rdx), %al
andb $0x38, %al
cmpb $0x8, %al
movq 0x10(%rsp), %rax
cmoveq %r12, %rax
movq %rax, 0x10(%rsp)
jmp 0x3d08
xorl %edx, %edx
movq %r12, 0x10(%rsp)
jmp 0x3c1e
movsd 0x20(%rsp), %xmm0
movq 0x10(%rsp), %rsi
cmpq $-0x1, %rsi
jne 0x3dff
testb $0x1, 0x1c(%rsp)
je 0x3d8d
cmpl $-0x1, %r13d
jne 0x3d82
subq 0x48(%rsp), %r15
xorps %xmm1, %xmm1
cvtsi2sd %r15, %xmm1
movsd 0x58(%rsp), %xmm3
movapd %xmm3, %xmm2
subsd %xmm0, %xmm2
divsd %xmm2, %xmm1
cvttsd2si %xmm1, %rax
movq %rax, 0x30(%rsp)
movapd %xmm3, %xmm0
movsd (%rsp), %xmm1
movl 0xc(%rsp), %eax
jmp 0x3da7
movsd 0x28(%rsp), %xmm1
addsd %xmm1, %xmm1
movsd %xmm1, 0x28(%rsp)
movl 0xc(%rsp), %eax
movsd 0x50(%rsp), %xmm1
incl %eax
movsd %xmm1, (%rsp)
movsd %xmm0, 0x20(%rsp)
cmpl $0x20, %eax
movl %eax, %ecx
jne 0x3b5f
jmp 0x3dee
movq %r15, %rax
subq 0x48(%rsp), %rax
xorps %xmm1, %xmm1
cvtsi2sd %rax, %xmm1
movapd %xmm0, %xmm2
subsd 0x20(%rsp), %xmm2
divsd %xmm2, %xmm1
cvttsd2si %xmm1, %rax
movq %rax, 0x30(%rsp)
jmp 0x3d39
xorl %eax, %eax
addq $0x68, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq (%r14), %rdi
callq 0x4120
xorl %eax, %eax
movq %rax, 0x60(%r14)
movq %rax, 0x80(%r14)
movl $0xffffffff, 0x38(%r14) # imm = 0xFFFFFFFF
movq %r14, %rdi
movl %ebx, %esi
addq $0x68, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x4559