// File: /workspace/github_c_makefile_star2_O2/phoboslab[P]pl_mpeg/./pl_mpeg.h
// Function: plm_video_decode_macroblock
void plm_video_decode_macroblock(plm_video_t *self) {
	// Decode increment
	int increment = 0;
	int t = plm_buffer_read_vlc(self->buffer, PLM_VIDEO_MACROBLOCK_ADDRESS_INCREMENT);

	while (t == 34) {
		// macroblock_stuffing
		t = plm_buffer_read_vlc(self->buffer, PLM_VIDEO_MACROBLOCK_ADDRESS_INCREMENT);
	}
	while (t == 35) {
		// macroblock_escape
		increment += 33;
		t = plm_buffer_read_vlc(self->buffer, PLM_VIDEO_MACROBLOCK_ADDRESS_INCREMENT);
	}
	increment += t;

	// Process any skipped macroblocks
	if (self->slice_begin) {
		// The first increment of each slice is relative to beginning of the
		// previous row, not the previous macroblock
		self->slice_begin = FALSE;
		self->macroblock_address += increment;
	}
	else {
		if (self->macroblock_address + increment >= self->mb_size) {
			return; // invalid
		}
		if (increment > 1) {
			// Skipped macroblocks reset DC predictors
			self->dc_predictor[0] = 128;
			self->dc_predictor[1] = 128;
			self->dc_predictor[2] = 128;

			// Skipped macroblocks in P-pictures reset motion vectors
			if (self->picture_type == PLM_VIDEO_PICTURE_TYPE_PREDICTIVE) {
				self->motion_forward.h = 0;
				self->motion_forward.v = 0;
			}
		}

		// Predict skipped macroblocks
		while (increment > 1) {
			self->macroblock_address++;
			self->mb_row = self->macroblock_address / self->mb_width;
			self->mb_col = self->macroblock_address % self->mb_width;

			plm_video_predict_macroblock(self);
			increment--;
		}
		self->macroblock_address++;
	}

	self->mb_row = self->macroblock_address / self->mb_width;
	self->mb_col = self->macroblock_address % self->mb_width;

	if (self->mb_col >= self->mb_width || self->mb_row >= self->mb_height) {
		return; // corrupt stream;
	}

	// Process the current macroblock
	const plm_vlc_t *table = PLM_VIDEO_MACROBLOCK_TYPE[self->picture_type];
	self->macroblock_type = plm_buffer_read_vlc(self->buffer, table);

	self->macroblock_intra = (self->macroblock_type & 0x01);
	self->motion_forward.is_set = (self->macroblock_type & 0x08);
	self->motion_backward.is_set = (self->macroblock_type & 0x04);

	// Quantizer scale
	if ((self->macroblock_type & 0x10) != 0) {
		self->quantizer_scale = plm_buffer_read(self->buffer, 5);
	}

	if (self->macroblock_intra) {
		// Intra-coded macroblocks reset motion vectors
		self->motion_backward.h = self->motion_forward.h = 0;
		self->motion_backward.v = self->motion_forward.v = 0;
	}
	else {
		// Non-intra macroblocks reset DC predictors
		self->dc_predictor[0] = 128;
		self->dc_predictor[1] = 128;
		self->dc_predictor[2] = 128;

		plm_video_decode_motion_vectors(self);
		plm_video_predict_macroblock(self);
	}

	// Decode blocks
	int cbp = ((self->macroblock_type & 0x02) != 0)
		? plm_buffer_read_vlc(self->buffer, PLM_VIDEO_CODE_BLOCK_PATTERN)
		: (self->macroblock_intra ? 0x3f : 0);

	for (int block = 0, mask = 0x20; block < 6; block++) {
		if ((cbp & mask) != 0) {
			plm_video_decode_block(self, block);
		}
		mask >>= 1;
	}
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %rbx
pushq %rax
movq %rdi, %rbx
leaq 0x3df6(%rip), %r14      # 0x8390
movq 0xa0(%rbx), %rdi
movq %r14, %rsi
callq 0x3df2
cmpw $0x22, %ax
je 0x459a
xorl %r15d, %r15d
leaq 0x3dd7(%rip), %r14      # 0x8390
cmpw $0x23, %ax
jne 0x45d4
addl $0x21, %r15d
movq 0xa0(%rbx), %rdi
movq %r14, %rsi
callq 0x3df2
jmp 0x45b9
movswl %ax, %ebp
cmpl $0x0, 0x78(%rbx)
movabsq $0x8000000080, %r14     # imm = 0x8000000080
je 0x45f8
andl $0x0, 0x78(%rbx)
addl 0x7c(%rbx), %ebp
addl %r15d, %ebp
movl %ebp, 0x7c(%rbx)
movl %ebp, %eax
jmp 0x4656
movl 0x7c(%rbx), %eax
addl %ebp, %eax
addl %r15d, %eax
cmpl 0x2c(%rbx), %eax
jge 0x4759
addl %r15d, %ebp
cmpl $0x2, %ebp
jl 0x4649
movq %r14, 0x90(%rbx)
movl $0x80, 0x98(%rbx)
cmpl $0x2, 0x44(%rbx)
jne 0x4649
andq $0x0, 0x54(%rbx)
jmp 0x4649
cltd
idivl 0x24(%rbx)
movl %eax, 0x80(%rbx)
movl %edx, 0x84(%rbx)
movq %rbx, %rdi
callq 0x4764
decl %ebp
movl 0x7c(%rbx), %eax
incl %eax
movl %eax, 0x7c(%rbx)
cmpl $0x2, %ebp
jge 0x462f
movl 0x24(%rbx), %ecx
cltd
idivl %ecx
movl %eax, 0x80(%rbx)
movl %edx, 0x84(%rbx)
testl %ecx, %ecx
js 0x4759
cmpl 0x28(%rbx), %eax
jge 0x4759
movslq 0x44(%rbx), %rax
leaq 0x873c(%rip), %rcx      # 0xcdc0
movq (%rcx,%rax,8), %rsi
movq 0xa0(%rbx), %rdi
callq 0x3df2
movswl %ax, %ecx
movl %ecx, 0x88(%rbx)
movl %ecx, %eax
andl $0x1, %eax
movl %eax, 0x8c(%rbx)
movl %ecx, %edx
andl $0x8, %edx
movl %edx, 0x4c(%rbx)
movl %ecx, %edx
andl $0x4, %edx
movl %edx, 0x60(%rbx)
testb $0x10, %cl
je 0x46d5
movq 0xa0(%rbx), %rdi
pushq $0x5
popq %rsi
callq 0x3c08
movl %eax, 0x74(%rbx)
movl 0x8c(%rbx), %eax
testl %eax, %eax
je 0x46e5
andq $0x0, 0x54(%rbx)
andq $0x0, 0x68(%rbx)
jmp 0x4706
movq %r14, 0x90(%rbx)
movl $0x80, 0x98(%rbx)
movq %rbx, %rdi
callq 0x47f5
movq %rbx, %rdi
callq 0x4764
testb $0x2, 0x88(%rbx)
jne 0x4721
movl 0x8c(%rbx), %eax
testl %eax, %eax
pushq $0x3f
popq %r14
cmovel %eax, %r14d
jmp 0x4738
movq 0xa0(%rbx), %rdi
leaq 0x3da1(%rip), %rsi      # 0x84d0
callq 0x3df2
movzwl %ax, %r14d
pushq $0x20
popq %r15
xorl %ebp, %ebp
cmpl $0x6, %ebp
je 0x4759
testl %r14d, %r15d
je 0x4752
movq %rbx, %rdi
movl %ebp, %esi
callq 0x4861
shrl %r15d
incl %ebp
jmp 0x473e
addq $0x8, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
retq