#include "mpeg3private.h"
#include "mpeg3protos.h"
#include "vlc.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int mpeg3video_get_cbp(mpeg3_slice_t *slice)
{
  	int code;
	mpeg3_slice_buffer_t *slice_buffer = slice->slice_buffer;

  	if((code = mpeg3slice_showbits9(slice_buffer)) >= 128)
	{
    	code >>= 4;
    	mpeg3slice_flushbits(slice_buffer, mpeg3_CBPtab0[code].len);
    	return mpeg3_CBPtab0[code].val;
  	}

  	if(code >= 8)
	{
    	code >>= 1;
    	mpeg3slice_flushbits(slice_buffer, mpeg3_CBPtab1[code].len);
    	return mpeg3_CBPtab1[code].val;
  	}

  	if(code < 1)
	{
/*    	fprintf(stderr,"mpeg3video_get_cbp: invalid coded_block_pattern code\n"); */
    	slice->fault = 1;
    	return 0;
  	}

  	mpeg3slice_flushbits(slice_buffer, mpeg3_CBPtab2[code].len);
  	return mpeg3_CBPtab2[code].val;
}


/* set block to zero */
int mpeg3video_clearblock(mpeg3_slice_t *slice, int comp, int size)
{
	slice->sparse[comp] = 1;

/* Compiler error with 2.95 required hard coding the size to 6 */

	bzero(slice->block[comp], sizeof(short) * 64 * size);
//	memset(slice->block[comp], 0, sizeof(short) * 64 * size);
	return 0;
}

static inline int mpeg3video_getdclum(mpeg3_slice_buffer_t *slice_buffer)
{
	int code, size, val;
/* decode length */
	code = mpeg3slice_showbits5(slice_buffer);

	if(code < 31)
	{
    	size = mpeg3_DClumtab0[code].val;
    	mpeg3slice_flushbits(slice_buffer, mpeg3_DClumtab0[code].len);
	}
	else 
	{
    	code = mpeg3slice_showbits9(slice_buffer) - 0x1f0;
    	size = mpeg3_DClumtab1[code].val;
    	mpeg3slice_flushbits(slice_buffer, mpeg3_DClumtab1[code].len);
	}

	if(size == 0) val = 0;
	else 
	{
    	val = mpeg3slice_getbits(slice_buffer, size);
    	if((val & (1 << (size - 1))) == 0)  val -= (1 << size) - 1;
	}

	return val;
}


int mpeg3video_getdcchrom(mpeg3_slice_buffer_t *slice_buffer)
{
	int code, size, val;

/* decode length */
	code = mpeg3slice_showbits5(slice_buffer);

	if(code < 31)
	{
    	size = mpeg3_DCchromtab0[code].val;
    	mpeg3slice_flushbits(slice_buffer, mpeg3_DCchromtab0[code].len);
	}
	else 
	{
    	code = mpeg3slice_showbits(slice_buffer, 10) - 0x3e0;
    	size = mpeg3_DCchromtab1[code].val;
    	mpeg3slice_flushbits(slice_buffer, mpeg3_DCchromtab1[code].len);
	}

	if(size == 0) val = 0;
	else 
	{
      val = mpeg3slice_getbits(slice_buffer, size);
      if((val & (1 << (size - 1))) == 0) val -= (1 << size) - 1;
	}

	return val;
}


/* decode one intra coded MPEG-1 block */

int mpeg3video_getintrablock(mpeg3_slice_t *slice, 
		mpeg3video_t *video,
		int comp, 
		int dc_dct_pred[])
{
	int val, i, j = 8, sign;
	unsigned int code;
	mpeg3_DCTtab_t *tab = 0;
	short *bp = slice->block[comp];
	mpeg3_slice_buffer_t *slice_buffer = slice->slice_buffer;

/* decode DC coefficients */
  	if(comp < 4)         
  		bp[0] = (dc_dct_pred[0] += mpeg3video_getdclum(slice_buffer)) << 3;
  	else 
  	if(comp == 4)   
  		bp[0] = (dc_dct_pred[1] += mpeg3video_getdcchrom(slice_buffer)) << 3;
	else                
  		bp[0] = (dc_dct_pred[2] += mpeg3video_getdcchrom(slice_buffer)) << 3;

#ifdef HAVE_MMX
	if(video->have_mmx)
  		bp[0] <<= 4;
#endif

  	if(slice->fault) return 1;

/* decode AC coefficients */
  	for(i = 1; ; i++)
	{
    	code = mpeg3slice_showbits16(slice_buffer);
    	if(code >= 16384)
			tab = &mpeg3_DCTtabnext[(code >> 12) - 4];
    	else 
		if(code >= 1024) tab = &mpeg3_DCTtab0[(code >> 8) - 4];
    	else 
		if(code >= 512) tab = &mpeg3_DCTtab1[(code >> 6) - 8];
    	else 
		if(code >= 256) tab = &mpeg3_DCTtab2[(code >> 4) - 16];
    	else 
		if(code >= 128) tab = &mpeg3_DCTtab3[(code >> 3) - 16];
    	else 
		if(code >= 64) tab = &mpeg3_DCTtab4[(code >> 2) - 16];
    	else 
		if(code >= 32) tab = &mpeg3_DCTtab5[(code >> 1) - 16];
    	else 
		if(code >= 16) tab = &mpeg3_DCTtab6[code - 16];
    	else 
		{
/*    	  	fprintf(stderr, "mpeg3video_getintrablock: invalid Huffman code\n"); */
    	  	slice->fault = 1;
    	  	return 0;
    	}

    	mpeg3slice_flushbits(slice_buffer, tab->len);

    	if(tab->run == 64) break;  /* end_of_block */

    	if(tab->run == 65)
		{
/* escape */
    		i += mpeg3slice_getbits(slice_buffer, 6);

    		if((val = mpeg3slice_getbits(slice_buffer, 8)) == 0) 
				val = mpeg3slice_getbits(slice_buffer, 8);
    		else 
			if(val == 128)         
				val = mpeg3slice_getbits(slice_buffer, 8) - 256;
    		else 
			if(val > 128)          
				val -= 256;

    		if((sign = (val < 0)) != 0) val= -val;
    	}
    	else 
		{
    		i += tab->run;
    		val = tab->level;
    		sign = mpeg3slice_getbit(slice_buffer);
    	}

		if(i < 64)
	    	j = video->mpeg3_zigzag_scan_table[i];
		else
		{
    	  	slice->fault = 1;
    	  	return 0;
		}
			

#ifdef HAVE_MMX
		if(video->have_mmx)
		{
    		val = (val * slice->quant_scale * video->intra_quantizer_matrix[j]) << 1;
    		val = (val - 16) | 16;
		}
		else
#endif
		{
    		val = (val * slice->quant_scale * video->intra_quantizer_matrix[j]) >> 3;
    		val = (val - 1) | 1;
		}

    	bp[j] = sign ? -val : val;
	}

	if(j != 0) 
	{
/* not a sparse matrix ! */
       slice->sparse[comp] = 0;
	}
	return 0;
}


/* decode one non-intra coded MPEG-1 block */

int mpeg3video_getinterblock(mpeg3_slice_t *slice, 
		mpeg3video_t *video, 
		int comp)
{
	int val, i, j, sign;
	unsigned int code;
	mpeg3_DCTtab_t *tab; 
	short *bp = slice->block[comp];
	mpeg3_slice_buffer_t *slice_buffer = slice->slice_buffer;

/* decode AC coefficients */
	for(i = 0; ; i++)
	{
    	code = mpeg3slice_showbits16(slice_buffer);
    	if(code >= 16384)
		{
    	    if(i == 0) 
				tab = &mpeg3_DCTtabfirst[(code >> 12) - 4];
    	    else      
				tab = &mpeg3_DCTtabnext[(code >> 12) - 4];
    	}
    	else 
		if(code >= 1024) tab = &mpeg3_DCTtab0[(code >> 8) - 4];
    	else 
		if(code >= 512)  tab = &mpeg3_DCTtab1[(code >> 6) - 8];
    	else 
		if(code >= 256)  tab = &mpeg3_DCTtab2[(code >> 4) - 16];
    	else 
		if(code >= 128)  tab = &mpeg3_DCTtab3[(code >> 3) - 16];
    	else 
		if(code >= 64)   tab = &mpeg3_DCTtab4[(code >> 2) - 16];
    	else 
		if(code >= 32)   tab = &mpeg3_DCTtab5[(code >> 1) - 16];
    	else 
		if(code >= 16)   tab = &mpeg3_DCTtab6[code - 16];
    	else 
		{
// invalid Huffman code
    		slice->fault = 1;
    		return 1;
    	}

    	mpeg3slice_flushbits(slice_buffer, tab->len);

/* end of block */
    	if(tab->run == 64)
    	   break;   

    	if(tab->run == 65)
		{          
/* escape  */
    		i += mpeg3slice_getbits(slice_buffer, 6);
    		if((val = mpeg3slice_getbits(slice_buffer, 8)) == 0) 
				val = mpeg3slice_getbits(slice_buffer, 8);
    		else 
			if(val == 128)  
				val = mpeg3slice_getbits(slice_buffer, 8) - 256;
    		else 
			if(val > 128) 
				val -= 256;

    		if((sign = (val < 0)) != 0) val = -val;
    	}
    	else 
		{
    		i += tab->run;
    		val = tab->level;
    		sign = mpeg3slice_getbit(slice_buffer);
    	}

    	j = video->mpeg3_zigzag_scan_table[i];

#ifdef HAVE_MMX
		if(video->have_mmx)
		{
    		val = (((val << 1)+1) * slice->quant_scale * video->non_intra_quantizer_matrix[j]);
    		val = (val - 16) | 16;
		}
		else
#endif
		{
    		val = (((val << 1)+1) * slice->quant_scale * video->non_intra_quantizer_matrix[j]) >> 4;
    		val = (val - 1) | 1;
		}

    	bp[j] = sign ? -val : val;
	}

	if(j != 0) 
	{
/* not a sparse matrix ! */
       slice->sparse[comp] = 0;
	}
	return 0;
}


/* decode one intra coded MPEG-2 block */
int mpeg3video_getmpg2intrablock(mpeg3_slice_t *slice, 
		mpeg3video_t *video, 
		int comp, 
		int dc_dct_pred[])
{
	int val, i, j, sign, nc;
	unsigned int code;
	mpeg3_DCTtab_t *tab;
	short *bp;
	int *qmat;
	mpeg3_slice_buffer_t *slice_buffer = slice->slice_buffer;

/* with data partitioning, data always goes to base layer */
  	bp = slice->block[comp];

  	qmat = (comp < 4 || video->chroma_format == CHROMA420)
         ? video->intra_quantizer_matrix
         : video->chroma_intra_quantizer_matrix;

/* decode DC coefficients */
	if(comp < 4)           
		val = (dc_dct_pred[0] += mpeg3video_getdclum(slice_buffer));
	else 
	if((comp & 1) == 0) 
		val = (dc_dct_pred[1] += mpeg3video_getdcchrom(slice_buffer));
	else                  
		val = (dc_dct_pred[2] += mpeg3video_getdcchrom(slice_buffer));

  	if(slice->fault) return 0;
#ifdef HAVE_MMX
	if(video->have_mmx)
  		bp[0] = val << (7 - video->dc_prec);
	else
#endif
  		bp[0] = val << (3 - video->dc_prec);

  	nc = 0;

/* decode AC coefficients */
  	for(i = 1; ; i++)
	{
    	code = mpeg3slice_showbits16(slice_buffer);

    	if(code >= 16384 && !video->intravlc)
			tab = &mpeg3_DCTtabnext[(code >> 12) - 4];
    	else 
		if(code >= 1024)
		{
    		if(video->intravlc) 
				tab = &mpeg3_DCTtab0a[(code >> 8) - 4];
    		else 
				tab = &mpeg3_DCTtab0[(code >> 8) - 4];
    	}
    	else 
		if(code >= 512)
		{
    		if(video->intravlc)     
		  	  	tab = &mpeg3_DCTtab1a[(code >> 6) - 8];
    		else              
				tab = &mpeg3_DCTtab1[(code >> 6) - 8];
    	}
    	else 
		if(code >= 256) tab = &mpeg3_DCTtab2[(code >> 4) - 16];
    	else 
		if(code >= 128) tab = &mpeg3_DCTtab3[(code >> 3) - 16];
    	else 
		if(code >= 64)  tab = &mpeg3_DCTtab4[(code >> 2) - 16];
    	else 
		if(code >= 32)  tab = &mpeg3_DCTtab5[(code >> 1) - 16];
    	else 
		if(code >= 16)  tab = &mpeg3_DCTtab6[code - 16];
    	else 
		{
/*    		fprintf(stderr,"mpeg3video_getmpg2intrablock: invalid Huffman code\n"); */
    		slice->fault = 1;
    		return 1;
    	}

    	mpeg3slice_flushbits(slice_buffer, tab->len);

/* end_of_block */
    	if(tab->run == 64)
    	   	break; 

    	if(tab->run == 65)
		{
/* escape */
    	  	i += mpeg3slice_getbits(slice_buffer, 6);

    	  	val = mpeg3slice_getbits(slice_buffer, 12);
    	  	if((val & 2047) == 0)
			{
// invalid signed_level (escape)
        		slice->fault = 1;
        		return 0;
    	  	}
    	  	if((sign = (val >= 2048)) != 0) val = 4096 - val;
    	}
    	else 
		{
    		i += tab->run;
    		val = tab->level;
    		sign = mpeg3slice_getbit(slice_buffer);
    	}

    	j = (video->altscan ? video->mpeg3_alternate_scan_table : video->mpeg3_zigzag_scan_table)[i];

#ifdef HAVE_MMX
		if(video->have_mmx)
	    	val = (val * slice->quant_scale * qmat[j]);
		else
#endif
    		val = (val * slice->quant_scale * qmat[j]) >> 4;

    	bp[j] = sign ? -val : val;
    	nc++;
	}

	if(j != 0)
	{
/* not a sparse matrix ! */
    	 slice->sparse[comp] = 0;
	}
	return 1;
}


/* decode one non-intra coded MPEG-2 block */

int mpeg3video_getmpg2interblock(mpeg3_slice_t *slice, 
		mpeg3video_t *video, 
		int comp)
{
	int val, i, j, sign, nc;
	unsigned int code;
	mpeg3_DCTtab_t *tab;
	short *bp;
	int *qmat;
	mpeg3_slice_buffer_t *slice_buffer = slice->slice_buffer;

/* with data partitioning, data always goes to base layer */
  	bp = slice->block[comp];

  	qmat = (comp < 4 || video->chroma_format == CHROMA420)
         ? video->non_intra_quantizer_matrix
         : video->chroma_non_intra_quantizer_matrix;

  	nc = 0;

/* decode AC coefficients */
  	for(i = 0; ; i++)
	{
    	code = mpeg3slice_showbits16(slice_buffer);
    	if(code >= 16384)
		{
    	  if(i == 0) tab = &mpeg3_DCTtabfirst[(code >> 12) - 4];
    	  else      tab = &mpeg3_DCTtabnext[(code >> 12) - 4];
    	}
    	else 
		if(code >= 1024) tab = &mpeg3_DCTtab0[(code >> 8) - 4];
    	else 
		if(code >= 512)  tab = &mpeg3_DCTtab1[(code >> 6) - 8];
    	else 
		if(code >= 256)  tab = &mpeg3_DCTtab2[(code >> 4) - 16];
    	else 
		if(code >= 128)  tab = &mpeg3_DCTtab3[(code >> 3) - 16];
    	else 
		if(code >= 64)   tab = &mpeg3_DCTtab4[(code >> 2) - 16];
    	else 
		if(code >= 32)   tab = &mpeg3_DCTtab5[(code >> 1) - 16];
    	else 
		if(code >= 16)   tab = &mpeg3_DCTtab6[code - 16];
    	else 
		{
// invalid Huffman code
    		slice->fault = 1;
    		return 0;
    	}

    	mpeg3slice_flushbits(slice_buffer, tab->len);

/* end_of_block */
    	if(tab->run == 64)
       		break;          

    	if(tab->run == 65)
		{                 
/* escape */
    		i += mpeg3slice_getbits(slice_buffer, 6);
    		val = mpeg3slice_getbits(slice_buffer, 12);
    		if((val & 2047) == 0)
			{
/*        		fprintf(stderr, "mpeg3video_getmpg2interblock: invalid signed_level (escape)\n"); */
        		slice->fault = 1;
        		return 1;
    		}
    		if((sign = (val >= 2048)) != 0) val = 4096 - val;
    	}
    	else 
		{
    		i += tab->run;
    		val = tab->level;
    		sign = mpeg3slice_getbit(slice_buffer);
    	}

    	j = (video->altscan ? video->mpeg3_alternate_scan_table : video->mpeg3_zigzag_scan_table)[i];

#ifdef HAVE_MMX
 		if(video->have_mmx)
    		val = (((val << 1)+1) * slice->quant_scale * qmat[j]) >> 1;
		else
#endif
     		val = (((val << 1)+1) * slice->quant_scale * qmat[j]) >> 5;

    	bp[j] = sign ? (-val) : val ;
    	nc++;
	}

	if(j != 0) 
	{
      	slice->sparse[comp] = 0;
	}
	return 0;
}


/* decode all macroblocks of the current picture */
int mpeg3video_get_macroblocks(mpeg3video_t *video, int framenum)
{
	unsigned int code;
	mpeg3_slice_buffer_t *slice_buffer; /* Buffer being loaded */
	int i;
	int current_buffer;
	mpeg3_bits_t *vstream = video->vstream;

/* Load every slice into a buffer array */
	video->total_slice_buffers = 0;
	current_buffer = 0;
	while(!mpeg3bits_eof(vstream) && 
		mpeg3bits_showbits32_noptr(vstream) >= MPEG3_SLICE_MIN_START && 
		mpeg3bits_showbits32_noptr(vstream) <= MPEG3_SLICE_MAX_START &&
		video->total_slice_buffers < MPEG3_MAX_CPUS)
	{
/* Initialize the buffer */
		if(current_buffer >= video->slice_buffers_initialized)
			mpeg3_new_slice_buffer(&(video->slice_buffers[video->slice_buffers_initialized++]));
		slice_buffer = &(video->slice_buffers[current_buffer]);
		slice_buffer->buffer_size = 0;
		slice_buffer->current_position = 0;
		slice_buffer->bits_size = 0;
		slice_buffer->done = 0;

/* Read the slice into the buffer including the slice start code */
		do
		{
/* Expand buffer */
			if(slice_buffer->buffer_allocation <= slice_buffer->buffer_size)
				mpeg3_expand_slice_buffer(slice_buffer);

/* Load 1 char into buffer */
			slice_buffer->data[slice_buffer->buffer_size++] = mpeg3bits_getbyte_noptr(vstream);
		}while(!mpeg3bits_eof(vstream) &&
			mpeg3bits_showbits24_noptr(vstream) != MPEG3_PACKET_START_CODE_PREFIX);

/* Pad the buffer to get the last macroblock */
		if(slice_buffer->buffer_allocation <= slice_buffer->buffer_size + 4)
			mpeg3_expand_slice_buffer(slice_buffer);

		slice_buffer->data[slice_buffer->buffer_size++] = 0;
		slice_buffer->data[slice_buffer->buffer_size++] = 0;
		slice_buffer->data[slice_buffer->buffer_size++] = 1;
		slice_buffer->data[slice_buffer->buffer_size++] = 0;
		slice_buffer->bits_size = 0;

		pthread_mutex_lock(&(slice_buffer->completion_lock)); fflush(stdout);
		current_buffer++;
		video->total_slice_buffers++;
	}

/* Run the slice decoders */
	if(video->total_slice_buffers > 0)
	{
		for(i = 0; i < video->total_slice_decoders; i++)
		{
			if(i == 0 && video->total_slice_decoders > 1)
			{
				video->slice_decoders[i].current_buffer = 0;
				video->slice_decoders[i].buffer_step = 1;
				video->slice_decoders[i].last_buffer = (video->total_slice_buffers - 1);
			}
			else
			if(i == 1)
			{
				video->slice_decoders[i].current_buffer = video->total_slice_buffers - 1;
				video->slice_decoders[i].buffer_step = -1;
				video->slice_decoders[i].last_buffer = 0;
			}
			else
			{
				video->slice_decoders[i].current_buffer = i;
				video->slice_decoders[i].buffer_step = 1;
				video->slice_decoders[i].last_buffer = video->total_slice_buffers - 1;
			}
			pthread_mutex_unlock(&(video->slice_decoders[i].input_lock));
		}
	}

/* Wait for the slice buffers to finish */
	if(video->total_slice_buffers > 0)
	{
		for(i = 0; i < video->total_slice_buffers; i++)
		{
			pthread_mutex_lock(&(video->slice_buffers[i].completion_lock));
			pthread_mutex_unlock(&(video->slice_buffers[i].completion_lock));
		}

/* Wait for decoders to finish so packages aren't overwritten */
		for(i = 0; i < video->total_slice_decoders; i++)
		{
			pthread_mutex_lock(&(video->slice_decoders[i].completion_lock));
		}
	}
	return 0;
}

int mpeg3video_allocate_decoders(mpeg3video_t *video, int decoder_count)
{
	int i;
	mpeg3_t *file = video->file;
/* Get the slice decoders */
	if(video->total_slice_decoders != file->cpus)
	{
		for(i = 0; i < video->total_slice_decoders; i++)
		{
			mpeg3_delete_slice_decoder(&(video->slice_decoders[i]));
		}

		for(i = 0; i < file->cpus && i < MPEG3_MAX_CPUS; i++)
		{
			mpeg3_new_slice_decoder(video, &(video->slice_decoders[i]));
			video->slice_decoders[i].thread_number = i;
		}

		video->total_slice_decoders = file->cpus;
	}
	return 0;
}

/* decode one frame or field picture */

int mpeg3video_getpicture(mpeg3video_t *video, int framenum)
{
	int i, result = 0;
	mpeg3_t *file = video->file;

	if(video->pict_struct == FRAME_PICTURE && video->secondfield)
	{
/* recover from illegal number of field pictures */
    	video->secondfield = 0;
	}

	if(!video->mpeg2)
	{
		video->current_repeat = video->repeat_count = 0;
	}

	mpeg3video_allocate_decoders(video, file->cpus);

  	for(i = 0; i < 3; i++)
	{
    	if(video->pict_type == B_TYPE)
		{
			video->newframe[i] = video->auxframe[i];
		}
    	else 
		{
    	  	if(!video->secondfield && !video->current_repeat)
			{
/* Swap refframes for I frames */
        		unsigned char* tmp = video->oldrefframe[i];
        		video->oldrefframe[i] = video->refframe[i];
        		video->refframe[i] = tmp;
    	  	}

    	 	video->newframe[i] = video->refframe[i];
    	}

    	if(video->pict_struct == BOTTOM_FIELD)
		{
/* Only used if fields are in different pictures */
    	    video->newframe[i] += (i == 0) ? 
				video->coded_picture_width : 
				video->chrom_width;
		}
	}


/* The problem is when a B frame lands on the first repeat and is skipped, */
/* the second repeat goes for the same bitmap as the skipped repeat, */
/* so it picks up a frame from 3 frames back. */
/* The first repeat must consititutively read a B frame if its B frame is going to be */
/* used in a later repeat. */
	if(!video->current_repeat)
		if(!(video->skip_bframes && video->pict_type == B_TYPE) || 
			(video->repeat_count >= 100 + 100 * video->skip_bframes))
  			result = mpeg3video_get_macroblocks(video, framenum);

/* Set the frame to display */
	video->output_src = 0;
	if(framenum > -1 && !result)
	{
    	if(video->pict_struct == FRAME_PICTURE || video->secondfield)
		{
     	  	if(video->pict_type == B_TYPE)
			{
				video->output_src = video->auxframe;
			}
     	  	else
			{
				video->output_src = video->oldrefframe;
			}
    	}
    	else 
		{
			mpeg3video_display_second_field(video);
		}
	}

	if(video->mpeg2)
	{
		video->current_repeat += 100;
	}

  	if(video->pict_struct != FRAME_PICTURE) 
		video->secondfield = !video->secondfield;
	return result;
}
