// File: /workspace/github_c_makefile_star2_O2/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, 0x8(%rsp)
movq %rdi, %r14
callq 0x2619
testl %eax, %eax
je 0x3889
movq %r14, %rdi
movl %ebx, %esi
callq 0x2cc3
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 0x8(%rsp), %xmm3
ucomisd %xmm0, %xmm3
movsd %xmm0, 0x58(%rsp)
ja 0x3641
xorpd %xmm1, %xmm1
ucomisd %xmm3, %xmm1
movapd %xmm3, %xmm0
jbe 0x3641
xorpd %xmm0, %xmm0
cvttsd2si %xmm2, %rax
movq %rax, 0x28(%rsp)
movsd 0x20(%r14), %xmm1
movsd %xmm1, 0x20(%rsp)
addsd 0x28(%r14), %xmm0
addq $-0x100, 0x40(%rsp)
xorl %eax, %eax
movapd %xmm0, %xmm1
movsd 0x4b74(%rip), %xmm0     # 0x81e8
movsd %xmm0, 0x18(%rsp)
movapd %xmm1, %xmm0
cmpl $0x20, %eax
je 0x3889
movq %rax, 0x50(%rsp)
movq (%r14), %rdi
movsd %xmm0, 0x8(%rsp)
callq 0x3b67
movsd 0x8(%rsp), %xmm0
subsd 0x20(%rsp), %xmm0
subsd 0x18(%rsp), %xmm0
cvtsi2sdq 0x28(%rsp), %xmm1
mulsd %xmm0, %xmm1
cvttsd2si %xmm1, %rdx
movq %rax, 0x48(%rsp)
addq %rax, %rdx
movq 0x40(%rsp), %rcx
cmpq %rcx, %rdx
cmovlq %rdx, %rcx
testq %rdx, %rdx
movl $0x0, %r12d
cmovnsq %rcx, %r12
movq %r14, %rdi
movq %r12, %rsi
callq 0x3eb7
movsd 0x8(%rsp), %xmm0
subsd 0x18(%rsp), %xmm0
movsd %xmm0, 0x60(%rsp)
movb $0x1, %bpl
pushq $-0x1
popq %rax
movq %rax, 0x10(%rsp)
movsd 0x4ad3(%rip), %xmm0     # 0x81e0
movsd %xmm0, 0x30(%rsp)
movq (%r14), %rdi
movl %ebx, %esi
callq 0x3d76
movl %eax, %r15d
cmpl $-0x1, %eax
je 0x37df
movq (%r14), %rdi
callq 0x3b67
movq %rax, %r13
movq %r14, %rdi
movl %ebx, %esi
callq 0x3ed6
testq %rax, %rax
je 0x3713
movsd 0x8(%rax), %xmm0
ucomisd 0x4a90(%rip), %xmm0     # 0x81e0
jne 0x3754
jnp 0x3713
ucomisd 0x8(%rsp), %xmm0
ja 0x385f
movsd 0x60(%rsp), %xmm1
ucomisd %xmm0, %xmm1
ja 0x385f
testb $0x1, %bpl
jne 0x377c
movsd 0x30(%rsp), %xmm0
cmpl $0x0, 0x3c(%rsp)
je 0x37d3
movq 0x10(%rax), %rcx
addq $-0x6, %rcx
xorl %edx, %edx
cmpq %rdx, %rcx
je 0x37cc
movq 0x18(%rax), %rsi
cmpb $0x0, (%rsi,%rdx)
jne 0x37b1
cmpb $0x0, 0x1(%rsi,%rdx)
jne 0x37b1
cmpb $0x1, 0x2(%rsi,%rdx)
jne 0x37b1
cmpb $0x0, 0x3(%rsi,%rdx)
je 0x37b6
incq %rdx
jmp 0x378d
movb 0x5(%rsi,%rdx), %al
andb $0x38, %al
cmpb $0x8, %al
movq 0x10(%rsp), %rax
cmoveq %r13, %rax
movq %rax, 0x10(%rsp)
xorl %ebp, %ebp
jmp 0x370d
xorl %ebp, %ebp
movq %r13, 0x10(%rsp)
jmp 0x370d
movsd 0x20(%rsp), %xmm0
movq 0x10(%rsp), %rsi
cmpq $-0x1, %rsi
jne 0x389a
testb $0x1, %bpl
je 0x3837
cmpl $-0x1, %r15d
movq 0x50(%rsp), %rax
jne 0x382f
subq 0x48(%rsp), %r12
cvtsi2sd %r12, %xmm1
movsd 0x58(%rsp), %xmm3
movapd %xmm3, %xmm2
subsd %xmm0, %xmm2
divsd %xmm2, %xmm1
cvttsd2si %xmm1, %rcx
movq %rcx, 0x28(%rsp)
movapd %xmm3, %xmm0
movsd 0x8(%rsp), %xmm1
jmp 0x3852
movsd 0x18(%rsp), %xmm1
addsd %xmm1, %xmm1
movsd %xmm1, 0x18(%rsp)
movq 0x50(%rsp), %rax
movsd 0x30(%rsp), %xmm1
incl %eax
movsd %xmm0, 0x20(%rsp)
jmp 0x367a
movq %r12, %rax
subq 0x48(%rsp), %rax
cvtsi2sd %rax, %xmm1
movapd %xmm0, %xmm2
subsd 0x20(%rsp), %xmm2
divsd %xmm2, %xmm1
cvttsd2si %xmm1, %rax
movq %rax, 0x28(%rsp)
jmp 0x37e5
xorl %eax, %eax
addq $0x68, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %r14, %rdi
callq 0x3eb7
movq %r14, %rdi
movl %ebx, %esi
addq $0x68, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x3ed6