// File: /workspace/github_c_makefile_star2_O0/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
movq %rsp, %rbp
subq $0xa0, %rsp
movq %rdi, -0x10(%rbp)
movsd %xmm0, -0x18(%rbp)
movl %esi, -0x1c(%rbp)
movl %edx, -0x20(%rbp)
movq -0x10(%rbp), %rdi
callq 0x2880
cmpl $0x0, %eax
jne 0x47f5
movq $0x0, -0x8(%rbp)
jmp 0x4bcb
movq -0x10(%rbp), %rdi
movl -0x1c(%rbp), %esi
callq 0x3700
movsd %xmm0, -0x28(%rbp)
movq -0x10(%rbp), %rax
movq (%rax), %rdi
callq 0x5000
movq %rax, -0x30(%rbp)
cvtsi2sdq -0x30(%rbp), %xmm0
divsd -0x28(%rbp), %xmm0
cvttsd2si %xmm0, %rax
movq %rax, -0x38(%rbp)
movq -0x10(%rbp), %rax
movsd 0x20(%rax), %xmm0
movsd %xmm0, -0x40(%rbp)
movsd 0x87d0(%rip), %xmm0     # 0xd010
movsd %xmm0, -0x48(%rbp)
movsd -0x18(%rbp), %xmm0
ucomisd -0x28(%rbp), %xmm0
jbe 0x485d
movsd -0x28(%rbp), %xmm0
movsd %xmm0, -0x18(%rbp)
jmp 0x4871
xorps %xmm0, %xmm0
ucomisd -0x18(%rbp), %xmm0
jbe 0x486f
xorps %xmm0, %xmm0
movsd %xmm0, -0x18(%rbp)
jmp 0x4871
movq -0x10(%rbp), %rax
movsd 0x28(%rax), %xmm0
addsd -0x18(%rbp), %xmm0
movsd %xmm0, -0x18(%rbp)
movl $0x0, -0x4c(%rbp)
cmpl $0x20, -0x4c(%rbp)
jge 0x4bc3
movl $0x0, -0x50(%rbp)
movl $0x0, -0x54(%rbp)
movq $-0x1, -0x60(%rbp)
movsd 0x8755(%rip), %xmm0     # 0xd008
movsd %xmm0, -0x68(%rbp)
movq -0x10(%rbp), %rax
movq (%rax), %rdi
callq 0x51e0
movq %rax, -0x70(%rbp)
movsd -0x18(%rbp), %xmm0
subsd -0x40(%rbp), %xmm0
subsd -0x48(%rbp), %xmm0
cvtsi2sdq -0x38(%rbp), %xmm1
mulsd %xmm1, %xmm0
cvttsd2si %xmm0, %rax
movq %rax, -0x78(%rbp)
movq -0x70(%rbp), %rax
addq -0x78(%rbp), %rax
movq %rax, -0x80(%rbp)
cmpq $0x0, -0x80(%rbp)
jge 0x4907
movq $0x0, -0x80(%rbp)
jmp 0x492b
movq -0x80(%rbp), %rax
movq -0x30(%rbp), %rcx
subq $0x100, %rcx            # imm = 0x100
cmpq %rcx, %rax
jle 0x4929
movq -0x30(%rbp), %rax
subq $0x100, %rax            # imm = 0x100
movq %rax, -0x80(%rbp)
jmp 0x492b
movq -0x10(%rbp), %rdi
movq -0x80(%rbp), %rsi
callq 0x5850
movq -0x10(%rbp), %rax
movq (%rax), %rdi
movl -0x1c(%rbp), %esi
callq 0x55f0
cmpl $-0x1, %eax
je 0x4b31
movq -0x10(%rbp), %rax
movq (%rax), %rdi
callq 0x51e0
movq %rax, -0x88(%rbp)
movq -0x10(%rbp), %rdi
movl -0x1c(%rbp), %esi
callq 0x58a0
movq %rax, -0x90(%rbp)
cmpq $0x0, -0x90(%rbp)
je 0x499c
movq -0x90(%rbp), %rax
movsd 0x8(%rax), %xmm0
movsd 0x8674(%rip), %xmm1     # 0xd008
ucomisd %xmm1, %xmm0
jne 0x499e
jp 0x499e
jmp 0x4938
movq -0x90(%rbp), %rax
movsd 0x8(%rax), %xmm0
ucomisd -0x18(%rbp), %xmm0
ja 0x49cd
movq -0x90(%rbp), %rax
movsd 0x8(%rax), %xmm1
movsd -0x18(%rbp), %xmm0
subsd -0x48(%rbp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x4a15
movl $0x1, -0x50(%rbp)
movq -0x80(%rbp), %rax
subq -0x70(%rbp), %rax
cvtsi2sd %rax, %xmm0
movq -0x90(%rbp), %rax
movsd 0x8(%rax), %xmm1
subsd -0x40(%rbp), %xmm1
divsd %xmm1, %xmm0
cvttsd2si %xmm0, %rax
movq %rax, -0x38(%rbp)
movq -0x90(%rbp), %rax
movsd 0x8(%rax), %xmm0
movsd %xmm0, -0x40(%rbp)
jmp 0x4b31
cmpl $0x0, -0x54(%rbp)
jne 0x4a33
movl $0x1, -0x54(%rbp)
movq -0x90(%rbp), %rax
movsd 0x8(%rax), %xmm0
movsd %xmm0, -0x68(%rbp)
cmpl $0x0, -0x20(%rbp)
je 0x4b21
movq $0x0, -0x98(%rbp)
movq -0x98(%rbp), %rax
movq -0x90(%rbp), %rcx
movq 0x10(%rcx), %rcx
subq $0x6, %rcx
cmpq %rcx, %rax
jae 0x4b1f
movq -0x90(%rbp), %rax
movq 0x18(%rax), %rax
movq -0x98(%rbp), %rcx
movzbl (%rax,%rcx), %eax
cmpl $0x0, %eax
jne 0x4b06
movq -0x90(%rbp), %rax
movq 0x18(%rax), %rax
movq -0x98(%rbp), %rcx
movzbl 0x1(%rax,%rcx), %eax
cmpl $0x0, %eax
jne 0x4b06
movq -0x90(%rbp), %rax
movq 0x18(%rax), %rax
movq -0x98(%rbp), %rcx
movzbl 0x2(%rax,%rcx), %eax
cmpl $0x1, %eax
jne 0x4b06
movq -0x90(%rbp), %rax
movq 0x18(%rax), %rax
movq -0x98(%rbp), %rcx
movzbl 0x3(%rax,%rcx), %eax
cmpl $0x0, %eax
jne 0x4b06
movq -0x90(%rbp), %rax
movq 0x18(%rax), %rax
movq -0x98(%rbp), %rcx
movzbl 0x5(%rax,%rcx), %eax
andl $0x38, %eax
cmpl $0x8, %eax
jne 0x4b04
movq -0x88(%rbp), %rax
movq %rax, -0x60(%rbp)
jmp 0x4b1f
jmp 0x4b08
movq -0x98(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x98(%rbp)
jmp 0x4a48
jmp 0x4b2c
movq -0x88(%rbp), %rax
movq %rax, -0x60(%rbp)
jmp 0x4938
cmpq $-0x1, -0x60(%rbp)
je 0x4b57
movq -0x10(%rbp), %rdi
movq -0x60(%rbp), %rsi
callq 0x5850
movq -0x10(%rbp), %rdi
movl -0x1c(%rbp), %esi
callq 0x58a0
movq %rax, -0x8(%rbp)
jmp 0x4bcb
cmpl $0x0, -0x54(%rbp)
je 0x4b7b
movsd 0x84b3(%rip), %xmm0     # 0xd018
mulsd -0x48(%rbp), %xmm0
movsd %xmm0, -0x48(%rbp)
movsd -0x68(%rbp), %xmm0
movsd %xmm0, -0x18(%rbp)
jmp 0x4bb1
cmpl $0x0, -0x50(%rbp)
jne 0x4baf
movq -0x80(%rbp), %rax
subq -0x70(%rbp), %rax
cvtsi2sd %rax, %xmm0
movsd -0x28(%rbp), %xmm1
subsd -0x40(%rbp), %xmm1
divsd %xmm1, %xmm0
cvttsd2si %xmm0, %rax
movq %rax, -0x38(%rbp)
movsd -0x28(%rbp), %xmm0
movsd %xmm0, -0x40(%rbp)
jmp 0x4bb1
jmp 0x4bb3
jmp 0x4bb5
movl -0x4c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4c(%rbp)
jmp 0x488b
movq $0x0, -0x8(%rbp)
movq -0x8(%rbp), %rax
addq $0xa0, %rsp
popq %rbp
retq
nopl (%rax,%rax)