/* * This file contains C code that implements the video decoder model. */ #include "video.h" #include "proto.h" #include "decoders.h" #include "util.h" #include #define MYRECON /* Declarations of functions. */ //static void init_stat_struct(Statval *); //static void PrintOneStat(void); //static void CollectStats(void); //static unsigned int bitCountRead(void); //static void StartTime(void); //static void EndTime(void); static int ParseSeqHead(VidStream *); static int ParseGOP(VidStream *); static int ParsePicture(VidStream *, TimeStamp); static int ParseSlice(VidStream *); static int ParseMacroBlock(VidStream *); static void DoPictureDisplay(VidStream *); #ifndef MYRECON static void ReconIMBlock(VidStream *, int); static void ReconPMBlock(VidStream *, int, int, int, int); static void ReconBMBlock(VidStream *, int, int, int, int); static void ReconBiMBlock(VidStream *, int, int, int, int, int, int); #endif static void ProcessSkippedPFrameMBlocks(VidStream *); static void ProcessSkippedBFrameMBlocks(VidStream *); static void ReconSkippedBlock16(unsigned char *, unsigned char *, int, int, int, int, int, int, int); static void ReconSkippedBlock8(unsigned char *, unsigned char *, int, int, int, int, int, int, int); extern int ditherType; /* Macro for returning 1 if num is positive, -1 if negative, 0 if 0. */ //#define Sign(num) ((num > 0) ? 1 : ((num == 0) ? 0 : -1)) /* Declare global pointer to vid stream used for current decoding. */ VidStream *curVidStream = NULL; /* Array mapping zigzag to array pointer offset. */ int zigzag_direct[64] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63}; /* Initialize P and B skip flags. */ static int No_P_Flag = 0; static int No_B_Flag = 0; /* Max lum, chrom indices for illegal block checking. */ static int lmaxx, lmaxy, cmaxx, cmaxy; /* The following accounts for time and size spent in various parsing acitivites if ANALYSIS has been defined. */ #ifdef ANALYSIS #include "analysis.h" #endif double realTimeStart; int totNumFrames = 0; double ReadSysClock(void) { unsigned int clock[2]; (void) timer(clock); return clock[0] + clock[1] / 1000000.0; } void PrintTimeInfo(void) { if (!quietFlag) { double spent = ReadSysClock() - realTimeStart; printf("\nReal Time Spent (After Initializations): %f secs.\n", spent); printf("Avg. Frames/Sec: %f\n", ((double) totNumFrames) / spent); printf("Frame size: %i*%i pixels\n", curVidStream->h_size, curVidStream->v_size); if(modeid != 0xffffffff) printf("ModeID of CyberGraphX screen: 0x%X\n", modeid); } } /* *-------------------------------------------------------------- * * NewVidStream -- * * Allocates and initializes a VidStream structure. Takes * as parameter requested size for buffer length. * * Results: * A pointer to the new VidStream structure. * * Side effects: * None. * *-------------------------------------------------------------- */ VidStream * NewVidStream(int bufLength) { int i,j; short *intra_quant_matrix, *intra_quant_matrix0, *intra_quant_matrix1; VidStream *new; static unsigned char default_intra_matrix[64] = { 8, 16, 19, 22, 26, 27, 29, 34, 16, 16, 22, 24, 27, 29, 34, 37, 19, 22, 26, 27, 29, 34, 34, 38, 22, 22, 26, 27, 29, 34, 37, 40, 22, 26, 27, 29, 32, 35, 40, 48, 26, 27, 29, 32, 35, 40, 48, 58, 26, 27, 29, 34, 38, 46, 56, 69, 27, 29, 35, 38, 46, 56, 69, 83}; /* Check for legal buffer length. */ if (bufLength < 4) return NULL; /* Make buffer length multiple of 4. */ bufLength = (bufLength + 3) >> 2; /* Allocate memory for new structure. */ new = (VidStream *) malloc(sizeof(VidStream)); /* Initialize pointers to extension and user data. */ new->group.ext_data = new->group.user_data = new->picture.extra_info = new->picture.user_data = new->picture.ext_data = new->slice.extra_info = new->ext_data = new->user_data = NULL; /* Create default intra matrix and qscale multiplication tables. */ new->intra_quant_matrix_ptr[0] = (short*) malloc(32 * 8*8 * sizeof(short)); clear64words(intra_quant_matrix = new->intra_quant_matrix_ptr[0]); for(j=1; j<32; j++) new->intra_quant_matrix_ptr[j] = (intra_quant_matrix+=64); intra_quant_matrix0 = intra_quant_matrix = new->intra_quant_matrix_ptr[1]; for(i=0; i<64; i++) *intra_quant_matrix++ = default_intra_matrix[zigzag_direct[i]]; for(j=2; j<32; j++) { intra_quant_matrix1 = new->intra_quant_matrix_ptr[1]; for(i=0; i<64; i++) *intra_quant_matrix++ = (*intra_quant_matrix0++) + (*intra_quant_matrix1++); } /* Initialize non intra quantization matrix. */ new->non_intra_default = TRUE; new->non_intra_quant_matrix_ptr[0] = NULL; /* Initialize pointers to image spaces. */ new->current = new->past = new->future = NULL; for (i = 0; i < RING_BUF_SIZE; i++) new->ring[i] = NULL; /* Create buffer. */ new->buf_start = (unsigned int *) malloc(bufLength * 4); /* * Set max_buf_length to one less than actual length to deal with messy * data without proper seq. end codes. */ new->max_buf_length = bufLength - 1; /* Initialize bitstream i/o fields. */ new->bit_offset = 0; new->buf_length = 0; new->buffer = new->buf_start; /* display stuff */ new->display_is_initialized = FALSE; /* Return structure. */ return new; } /* *-------------------------------------------------------------- * * DestroyVidStream -- * * Deallocates a VidStream structure. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void DestroyVidStream(VidStream *astream) { int i; if (astream->ext_data) free(astream->ext_data); if (astream->user_data) free(astream->user_data); if (astream->group.ext_data) free(astream->group.ext_data); if (astream->group.user_data) free(astream->group.user_data); if (astream->picture.extra_info) free(astream->picture.extra_info); if (astream->picture.ext_data) free(astream->picture.ext_data); if (astream->picture.user_data) free(astream->picture.user_data); if (astream->slice.extra_info) free(astream->slice.extra_info); if (astream->buf_start) free(astream->buf_start); for (i = 0; i < RING_BUF_SIZE; i++) { if (astream->ring[i]) { DestroyPictImage(astream->ring[i]); astream->ring[i] = NULL; } } if (!astream->non_intra_default) free(astream->non_intra_quant_matrix_ptr[0]); if (astream->intra_quant_matrix_ptr[0]) free(astream->intra_quant_matrix_ptr[0]); free((char *) astream); } /* *-------------------------------------------------------------- * * NewPictImage -- * * Allocates and initializes a PictImage structure. * The width and height of the image space are passed in * as parameters. * * Results: * A pointer to the new PictImage structure. * * Side effects: * None. * *-------------------------------------------------------------- */ PictImage * NewPictImage(unsigned int width, unsigned int height) { extern int lores, ham6; PictImage *new; int size = (short)width * (short)height; /* Allocate memory space for new structure. */ new = (PictImage *) malloc(sizeof(PictImage)); /* Allocate memory for image spaces. */ if (ditherType == FULL_COLOR_DITHER) { new->display = (unsigned char *) malloc(ham6 ? size : (lores ? (size << 1) : (size << 2))); } else if (ditherType == CYBERGFX_DITHER) { new->display = (unsigned char *) malloc(size * 4); /* one byte for each of R, G and B and A :)*/ } else { new->display = (unsigned char *) malloc(size); } new->luminance = (unsigned char *) malloc(size); new->Cr = (unsigned char *) malloc(size >> 2); new->Cb = (unsigned char *) malloc(size >> 2); /* Reset locked flag. */ new->locked = 0; /* Return pointer to new structure. */ return new; } /* *-------------------------------------------------------------- * * DestroyPictImage -- * * Deallocates a PictImage structure. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void DestroyPictImage(PictImage *apictimage) { if (apictimage->luminance) free(apictimage->luminance); if (apictimage->Cr) free(apictimage->Cr); if (apictimage->Cb) free(apictimage->Cb); if (apictimage->display) free(apictimage->display); free(apictimage); } /* *-------------------------------------------------------------- * * mpegInitVidRsrc -- * * reset first to 1 * * gonna check this thingy out !!!! * *-------------------------------------------------------------- */ static int first = 1; void mpegInitVidRsrc(void) { first = 1; } /* *-------------------------------------------------------------- * * mpegVidRsrc -- * * Parses bit stream until MB_QUANTUM number of * macroblocks have been decoded or current slice or * picture ends, whichever comes first. If the start * of a frame is encountered, the frame is time stamped * with the value passed in time_stamp. If the value * passed in buffer is not null, the video stream buffer * is set to buffer and the length of the buffer is * expected in value passed in through length. The current * video stream is set to vid_stream. If vid_stream * is passed as NULL, a new VidStream structure is created * and initialized and used as the current video stream. * * Results: * A Boolean value is returned - 0 is end of picture or error * * Side effects: * Bit stream is irreversibly parsed. If a picture is completed, * a function is called to display the frame at the correct time. * *-------------------------------------------------------------- */ int mpegVidRsrc(TimeStamp time_stamp, VidStream *vid_stream) { unsigned int data; int i, status; /* If vid_stream is null, create new VidStream structure. MR: ????? */ if(!handle_window()) return 0; if (vid_stream == NULL) return 0; /* * Set global curVidStream to vid_stream. Necessary because bit i/o use * curVidStream and are not passed vid_stream. Also set global bitstream * parameters. */ curVidStream = vid_stream; bitOffset = curVidStream->bit_offset; bufLength = curVidStream->buf_length; bitBuffer = curVidStream->buffer; /* * If called for the first time, find start code, make sure it is a * sequence start code. */ if (first) { next_start_code(); if (show_bits32(data) != SEQ_START_CODE) { fprintf(stderr, "This is not an MPEG stream.\n"); DestroyVidStream(curVidStream); exit(1); } first = 0; } /* * Process according to start code (or parse macroblock if not a start code * at all. */ switch (show_bits32(data)) { case SEQ_END_CODE: /* Display last frame. */ if (vid_stream->future != NULL) { vid_stream->current = vid_stream->future; ExecuteDisplay(vid_stream); } /* Sequence done. Do the right thing. return False. */ if (!quietFlag) { fprintf(stderr, "\nDone!\n"); } #ifdef ANALYSIS PrintAllStats(); #endif PrintTimeInfo(); if (loopFlag) longjmp(env, 1); DestroyVidStream(curVidStream); return 0; break; case SEQ_START_CODE: /* Sequence start code. Parse sequence header. */ if (ParseSeqHead(vid_stream) != PARSE_OK) goto error; /* * Return after sequence start code so that application above can use * info in header. */ goto done; case GOP_START_CODE: /* Group of Pictures start code. Parse gop header. */ if (ParseGOP(vid_stream) != PARSE_OK) goto error; case PICTURE_START_CODE: /* Picture start code. Parse picture header and first slice header. */ status = ParsePicture(vid_stream, time_stamp); if (status == SKIP_PICTURE) { next_start_code(); fprintf(stderr, "Skipping picture..."); while ((show_bits32(data)) != PICTURE_START_CODE) { if (data == GOP_START_CODE || data == SEQ_END_CODE) break; flush_bits(24); next_start_code(); } fprintf(stderr, "Done.\n"); goto done; } else if (status != PARSE_OK) goto error; if (ParseSlice(vid_stream) != PARSE_OK) goto error; break; case USER_START_CODE: // there has been one stream with an error in a GOP header flush_bits32; if (vid_stream->group.user_data) { free(vid_stream->group.user_data); vid_stream->group.user_data = NULL; } vid_stream->group.user_data = get_ext_data(); break; case EXT_START_CODE: flush_bits32; if (vid_stream->group.ext_data) { free(vid_stream->group.ext_data); vid_stream->group.ext_data = NULL; } vid_stream->group.ext_data = get_ext_data(); break; default: /* Check for slice start code. */ if ((data >= SLICE_MIN_START_CODE) && (data <= SLICE_MAX_START_CODE)) if (ParseSlice(vid_stream) != PARSE_OK) /* Slice start code. Parse slice header. */ goto error; break; } /* Parse next MB_QUANTUM macroblocks. */ for (i = 0; i < MB_QUANTUM; i++) { /* Check to see if actually a startcode and not a macroblock. */ if ((show_bitsn(23,data)) != 0x00000000) { /* Not start code. Parse Macroblock. */ if (ParseMacroBlock(vid_stream) != PARSE_OK) goto error; #ifdef ANALYSIS if (showmb_flag) { DoDitherImage(vid_stream->current->luminance, vid_stream->current->Cr, vid_stream->current->Cb, vid_stream->current->display, vid_stream->mb_height * 16, vid_stream->mb_width * 16); ExecuteDisplay(vid_stream); } #endif } else { /* Not macroblock, actually start code. Get start code. */ next_start_code(); show_bits32(data); /* * If start code is outside range of slice start codes, frame is * complete, display frame. */ if ((data < SLICE_MIN_START_CODE) || (data > SLICE_MAX_START_CODE)) { #ifdef ANALYSIS EndTime(); stat_a[0].totsize += bitCountRead() - pictureSizeCount; if (showEachFlag) PrintOneStat(); CollectStats(); #endif DoPictureDisplay(vid_stream); } break; } } /* Return pointer to video stream structure. */ goto done; error: fprintf(stderr, "Error!!!!\n"); next_start_code(); goto done; done: /* Copy global bit i/o variables back into vid_stream. */ vid_stream->buffer = bitBuffer; vid_stream->buf_length = bufLength; vid_stream->bit_offset = bitOffset; return 1; } /* *-------------------------------------------------------------- * * ParseSeqHead -- * * Assumes bit stream is at the begining of the sequence * header start code. Parses off the sequence header. * * Results: * Fills the vid_stream structure with values derived and * decoded from the sequence header. Allocates the pict image * structures based on the dimensions of the image space * found in the sequence header. * * Side effects: * Bit stream irreversibly parsed off. * *-------------------------------------------------------------- */ static int ParseSeqHead(VidStream *vid_stream) { unsigned int data; int i; /* Flush off sequence start code. */ flush_bits32; /* Get horizontal size of image space. */ get_bits12(vid_stream->h_size); /* Get vertical size of image space. */ get_bits12(vid_stream->v_size); /* Calculate macroblock width and height of image space. */ vid_stream->mb_width = (vid_stream->h_size + 15) >> 4; vid_stream->mb_height = (vid_stream->v_size + 15) >> 4; /* Initialize lmaxx, lmaxy, cmaxx, cmaxy. */ lmaxx = (vid_stream->mb_width<<4)-1; lmaxy = (vid_stream->mb_height<<4)-1; cmaxx = (vid_stream->mb_width<<3)-1; cmaxy = (vid_stream->mb_height<<3)-1; /* * Initialize ring buffer of pict images now that dimensions of image space * are known. */ if (vid_stream->ring[0] == NULL) { for (i = 0; i < RING_BUF_SIZE; i++) vid_stream->ring[i] = NewPictImage(vid_stream->mb_width << 4, vid_stream->mb_height << 4); } /* Parse of aspect ratio code. */ get_bits4(vid_stream->aspect_ratio); /* Parse off picture rate code. */ get_bits4(vid_stream->picture_rate); /* Parse off bit rate. */ get_bits18(vid_stream->bit_rate); /* Flush marker bit. */ flush_bits(1); /* Parse off vbv buffer size. */ get_bits10(vid_stream->vbv_buffer_size); /* Parse off contrained parameter flag. */ get_bits1(vid_stream->const_param_flag); /* * If intra_quant_matrix_flag set, parse off intra quant matrix values. */ if (get_bits1(data)) new_matrix(vid_stream->intra_quant_matrix_ptr[1]); /* * If non intra quant matrix flag set, parse off non intra quant matrix * values. */ if (get_bits1(data)) { if(vid_stream->non_intra_default) { unsigned short *intra_quant_matrix; vid_stream->non_intra_quant_matrix_ptr[0] = (short*) malloc(32 * 8*8 * sizeof(short)); clear64words(intra_quant_matrix = vid_stream->non_intra_quant_matrix_ptr[0]); for(i=1; i<32; i++) vid_stream->non_intra_quant_matrix_ptr[i] = (intra_quant_matrix+=64); vid_stream->non_intra_default = FALSE; } new_matrix(vid_stream->non_intra_quant_matrix_ptr[1]); } /* Go to next start code. */ next_start_code(); /* If next start code is extension start code, parse off extension data. */ if ((show_bits32(data)) == EXT_START_CODE) { flush_bits32; if (vid_stream->ext_data) { free(vid_stream->ext_data); vid_stream->ext_data = NULL; } vid_stream->ext_data = get_ext_data(); show_bits32(data); } /* If next start code is user start code, parse off user data. */ if (data == USER_START_CODE) { flush_bits32; if (vid_stream->user_data) { free(vid_stream->user_data); vid_stream->user_data = NULL; } vid_stream->user_data = get_ext_data(); } return PARSE_OK; } /* *-------------------------------------------------------------- * * ParseGOP -- * * Parses of group of pictures header from bit stream * associated with vid_stream. * * Results: * Values in gop header placed into video stream structure. * * Side effects: * Bit stream irreversibly parsed. * *-------------------------------------------------------------- */ static int ParseGOP(VidStream *vid_stream) { unsigned int data; /* Flush group of pictures start code. WWWWWWOOOOOOOSSSSSSHHHHH!!! */ flush_bits32; /* Parse off drop frame flag. */ get_bits1(vid_stream->group.drop_flag); /* Parse off hour component of time code. */ get_bits5(vid_stream->group.tc_hours); /* Parse off minute component of time code. */ get_bits6(vid_stream->group.tc_minutes); /* Flush marker bit. */ flush_bits(1); /* Parse off second component of time code. */ get_bits6(vid_stream->group.tc_seconds); /* Parse off picture count component of time code. */ get_bits6(vid_stream->group.tc_pictures); /* Parse off closed gop and broken link flags. */ get_bits1(vid_stream->group.closed_gop); get_bits1(vid_stream->group.broken_link); /* Goto next start code. */ next_start_code(); /* If next start code is extension data, parse off extension data. */ if ((show_bits32(data)) == EXT_START_CODE) { flush_bits32; if (vid_stream->group.ext_data) { free(vid_stream->group.ext_data); vid_stream->group.ext_data = NULL; } vid_stream->group.ext_data = get_ext_data(); show_bits32(data); } /* If next start code is user data, parse off user data. */ if (data == USER_START_CODE) { flush_bits32; if (vid_stream->group.user_data) { free(vid_stream->group.user_data); vid_stream->group.user_data = NULL; } vid_stream->group.user_data = get_ext_data(); } return PARSE_OK; } /* *-------------------------------------------------------------- * * ParsePicture -- * * Parses picture header. Marks picture to be presented * at particular time given a time stamp. * * Results: * Values from picture header put into video stream structure. * * Side effects: * Bit stream irreversibly parsed. * *-------------------------------------------------------------- */ static int ParsePicture(VidStream *vid_stream, TimeStamp time_stamp) { unsigned int data; int i; /* Flush header start code. */ flush_bits32; /* Parse off temporal reference. */ get_bits10(vid_stream->picture.temp_ref); /* Parse of picture type. */ get_bits3(vid_stream->picture.code_type); if ((vid_stream->picture.code_type == B_TYPE) && (No_B_Flag || (vid_stream->past == NULL) || (vid_stream->future == NULL))) return SKIP_PICTURE; if ((vid_stream->picture.code_type == P_TYPE) && (No_P_Flag || (vid_stream->future == NULL))) return SKIP_PICTURE; #ifdef ANALYSIS StartTime(); stat_a[0].frametype = vid_stream->picture.code_type; stat_a[0].number = 1; stat_a[0].totsize = 45; pictureSizeCount = bitCountRead(); #endif /* Parse off vbv buffer delay value. */ get_bits16(vid_stream->picture.vbv_delay); /* If P or B type frame... */ if ((vid_stream->picture.code_type == 2) || (vid_stream->picture.code_type == 3)) { /* Parse off forward vector full pixel flag. */ get_bits1(vid_stream->picture.full_pel_forw_vector); /* Parse of and decode forw_r_code into forw_r_size and forw_f. */ get_bits3(vid_stream->picture.forw_r_size) - 1; vid_stream->picture.forw_f = (1 << vid_stream->picture.forw_r_size); } /* If B type frame... */ if (vid_stream->picture.code_type == 3) { /* Parse off back vector full pixel flag. */ get_bits1(vid_stream->picture.full_pel_back_vector); /* Parse off and decode back_r_code into back_r_size and back_f. */ get_bits3(vid_stream->picture.back_r_size) - 1; vid_stream->picture.back_f = (1 << vid_stream->picture.back_r_size); } /* Get extra bit picture info. */ if (vid_stream->picture.extra_info) { free(vid_stream->picture.extra_info); vid_stream->picture.extra_info = NULL; } vid_stream->picture.extra_info = get_extra_bit_info(); /* Goto next start code. */ next_start_code(); /* If start code is extension start code, parse off extension data. */ if ((show_bits32(data)) == EXT_START_CODE) { flush_bits32; if (vid_stream->picture.ext_data) { free(vid_stream->picture.ext_data); vid_stream->picture.ext_data = NULL; } vid_stream->picture.ext_data = get_ext_data(); show_bits32(data); } /* If start code is user start code, parse off user data. */ if (data == USER_START_CODE) { flush_bits32; if (vid_stream->picture.user_data) { free(vid_stream->picture.user_data); vid_stream->picture.user_data = NULL; } vid_stream->picture.user_data = get_ext_data(); } /* Find a pict image structure in ring buffer not currently locked. */ i = 0; while (vid_stream->ring[i]->locked != 0) { if (++i >= RING_BUF_SIZE) { perror("Fatal error. Ring buffer full."); exit(1); } } /* Set current pict image structure to the one just found in ring. */ vid_stream->current = vid_stream->ring[i]; /* Set time stamp. */ vid_stream->current->show_time = time_stamp; /* Reset past macroblock address field. */ vid_stream->mblock.past_mb_addr = -1; return PARSE_OK; } /* *-------------------------------------------------------------- * * ParseSlice -- * * Parses off slice header. * * Results: * Values found in slice header put into video stream structure. * * Side effects: * Bit stream irreversibly parsed. * *-------------------------------------------------------------- */ static int ParseSlice(VidStream *vid_stream) { /* Flush slice start code. */ flush_bits(24); /* Parse off slice vertical position. */ get_bits8(vid_stream->slice.vert_pos); /* Parse off quantization scale. */ get_bits5(vid_stream->slice.quant_scale); /* Parse off extra bit slice info. */ if (vid_stream->slice.extra_info) { free(vid_stream->slice.extra_info); vid_stream->slice.extra_info = NULL; } vid_stream->slice.extra_info = get_extra_bit_info(); /* Reset past intrablock address. */ vid_stream->mblock.past_intra_addr = -2; /* Reset previous recon motion vectors. */ vid_stream->mblock.recon_right_for_prev = 0; vid_stream->mblock.recon_down_for_prev = 0; vid_stream->mblock.recon_right_back_prev = 0; vid_stream->mblock.recon_down_back_prev = 0; /* Reset macroblock address. */ vid_stream->mblock.mb_address = ((short)(vid_stream->slice.vert_pos - 1) * (short)vid_stream->mb_width) - 1; /* Reset past dct dc y, cr, and cb values. */ vid_stream->block.dct_dc_y_past = 1024; vid_stream->block.dct_dc_cr_past = 1024; vid_stream->block.dct_dc_cb_past = 1024; return PARSE_OK; } /* *-------------------------------------------------------------- * * ParseMacroBlock -- * * Parseoff macroblock. Reconstructs DCT values. Applies * inverse DCT, reconstructs motion vectors, calculates and * set pixel values for macroblock in current pict image * structure. * * Results: * Here's where everything really happens. Welcome to the * heart of darkness. * * Side effects: * Bit stream irreversibly parsed off. * *-------------------------------------------------------------- */ static int ParseMacroBlock(VidStream *vid_stream) { int addr_incr, mask, i; int recon_right_for, recon_down_for, recon_right_back, recon_down_back, zero_block_flag; int mb_data; #ifdef ANALYSIS mbSizeCount = bitCountRead(); #endif /* * Parse off macroblock address increment and add to macroblock address. */ do { DecodeMBAddrInc(addr_incr); if (addr_incr == MB_ESCAPE) { vid_stream->mblock.mb_address += 33; addr_incr = MB_STUFFING; } } while (addr_incr == MB_STUFFING); vid_stream->mblock.mb_address += addr_incr; if (vid_stream->mblock.mb_address > ((short)vid_stream->mb_height * (short)vid_stream->mb_width - 1)) return SKIP_TO_START_CODE; /* * If macroblocks have been skipped, process skipped macroblocks. */ if (vid_stream->mblock.mb_address - vid_stream->mblock.past_mb_addr > 1) { if (vid_stream->picture.code_type == P_TYPE) ProcessSkippedPFrameMBlocks(vid_stream); else if (vid_stream->picture.code_type == B_TYPE) ProcessSkippedBFrameMBlocks(vid_stream); } /* Set past macroblock address to current macroblock address. */ vid_stream->mblock.past_mb_addr = vid_stream->mblock.mb_address; /* Based on picture type decode macroblock type. */ switch (vid_stream->picture.code_type) { case I_TYPE: DecodeMBTypeI(mb_data, vid_stream->mblock.mb_intra); break; case P_TYPE: DecodeMBTypeP(mb_data, vid_stream->mblock.mb_intra); break; case B_TYPE: DecodeMBTypeB(mb_data, vid_stream->mblock.mb_intra); break; } /* If quantization flag set, parse off new quantization scale. */ if (mb_data&MB_quant) { get_bits5(vid_stream->slice.quant_scale); } /* If forward motion vectors exist... */ if (mb_data&MB_motion_forw) { /* Parse off and decode horizontal forward motion vector. */ DecodeMotionVectors(vid_stream->mblock.motion_h_forw_code); /* If horiz. forward r data exists, parse off. */ if ((vid_stream->picture.forw_f != 1) && (vid_stream->mblock.motion_h_forw_code != 0)) { get_bitsn(vid_stream->picture.forw_r_size, vid_stream->mblock.motion_h_forw_r); } /* Parse off and decode vertical forward motion vector. */ DecodeMotionVectors(vid_stream->mblock.motion_v_forw_code); /* If vert. forw. r data exists, parse off. */ if ((vid_stream->picture.forw_f != 1) && (vid_stream->mblock.motion_v_forw_code != 0)) { get_bitsn(vid_stream->picture.forw_r_size, vid_stream->mblock.motion_v_forw_r); } } /* If back motion vectors exist... */ if (mb_data&MB_motion_back) { /* Parse off and decode horiz. back motion vector. */ DecodeMotionVectors(vid_stream->mblock.motion_h_back_code); /* If horiz. back r data exists, parse off. */ if ((vid_stream->picture.back_f != 1) && (vid_stream->mblock.motion_h_back_code != 0)) { get_bitsn(vid_stream->picture.back_r_size, vid_stream->mblock.motion_h_back_r); } /* Parse off and decode vert. back motion vector. */ DecodeMotionVectors(vid_stream->mblock.motion_v_back_code); /* If vert. back r data exists, parse off. */ if ((vid_stream->picture.back_f != 1) && (vid_stream->mblock.motion_v_back_code != 0)) { get_bitsn(vid_stream->picture.back_r_size, vid_stream->mblock.motion_v_back_r); } } #ifdef ANALYSIS if (vid_stream->mblock.mb_intra) { stat_a[0].i_mbnum++; mbCBPPtr = stat_a[0].i_mbcbp; mbCoeffPtr = stat_a[0].i_mbcoeff; mbSizePtr = &(stat_a[0].i_mbsize); } else if ((mb_data&(MB_motion_back | MB_motion_forw)) == (MB_motion_back | MB_motion_forw)) { stat_a[0].bi_mbnum++; mbCBPPtr = stat_a[0].bi_mbcbp; mbCoeffPtr = stat_a[0].bi_mbcoeff; mbSizePtr = &(stat_a[0].bi_mbsize); } else if (mb_data&MB_motion_back) { stat_a[0].b_mbnum++; mbCBPPtr = stat_a[0].b_mbcbp; mbCoeffPtr = stat_a[0].b_mbcoeff; mbSizePtr = &(stat_a[0].b_mbsize); } else { stat_a[0].p_mbnum++; mbCBPPtr = stat_a[0].p_mbcbp; mbCoeffPtr = stat_a[0].p_mbcoeff; mbSizePtr = &(stat_a[0].p_mbsize); } #endif /* If mblock pattern flag set, parse and decode CBP (code block pattern). */ if (mb_data&MB_pattern) { DecodeCBP(vid_stream->mblock.cbp); } else /* Otherwise, set CBP to zero. */ vid_stream->mblock.cbp = 0; #ifdef ANALYSIS mbCBPPtr[vid_stream->mblock.cbp]++; #endif /* Reconstruct motion vectors depending on picture type. */ if (vid_stream->picture.code_type == P_TYPE) { /* * If no forw motion vectors, reset previous and current vectors to 0. */ if (!(mb_data&MB_motion_forw)) { recon_right_for = 0; recon_down_for = 0; vid_stream->mblock.recon_right_for_prev = 0; vid_stream->mblock.recon_down_for_prev = 0; } /* * Otherwise, compute new forw motion vectors. Reset previous vectors to * current vectors. */ else { ComputeForwVector(&recon_right_for, &recon_down_for); } } if (vid_stream->picture.code_type == B_TYPE) { /* Reset prev. and current vectors to zero if mblock is intracoded. */ if (vid_stream->mblock.mb_intra) { vid_stream->mblock.recon_right_for_prev = 0; vid_stream->mblock.recon_down_for_prev = 0; vid_stream->mblock.recon_right_back_prev = 0; vid_stream->mblock.recon_down_back_prev = 0; } else { /* If no forw vectors, current vectors equal prev. vectors. */ if (!(mb_data&MB_motion_forw)) { recon_right_for = vid_stream->mblock.recon_right_for_prev; recon_down_for = vid_stream->mblock.recon_down_for_prev; } /* * Otherwise compute forw. vectors. Reset prev vectors to new values. */ else { ComputeForwVector(&recon_right_for, &recon_down_for); } /* If no back vectors, set back vectors to prev back vectors. */ if (!(mb_data&MB_motion_back)) { recon_right_back = vid_stream->mblock.recon_right_back_prev; recon_down_back = vid_stream->mblock.recon_down_back_prev; } /* Otherwise compute new vectors and reset prev. back vectors. */ else { ComputeBackVector(&recon_right_back, &recon_down_back); } /* * Store vector existance flags in structure for possible skipped * macroblocks to follow. */ if(mb_data<0) vid_stream->mblock.bpict_past_forw = vid_stream->mblock.bpict_past_back = -1; else { vid_stream->mblock.bpict_past_forw = mb_data&MB_motion_forw; vid_stream->mblock.bpict_past_back = mb_data&MB_motion_back; } } } /* For each possible block in macroblock. */ if (ditherType == GRAY_DITHER || ditherType == CYBERGFXGRAY_DITHER) { for (mask = 32, i = 0; i < 4; mask >>= 1, i++) { /* If block exists... */ if ((vid_stream->mblock.mb_intra) || (vid_stream->mblock.cbp & mask)) { zero_block_flag = 0; ParseReconBlock(i); } else zero_block_flag = 1; /* If macroblock is intra coded... */ if (vid_stream->mblock.mb_intra) { ReconIMBlock(vid_stream, i); } else if ((mb_data&(MB_motion_forw | MB_motion_back)) == (MB_motion_forw | MB_motion_back)) { ReconBiMBlock(vid_stream, i, recon_right_for, recon_down_for, recon_right_back, recon_down_back, zero_block_flag); } else if ((mb_data&MB_motion_forw) || (vid_stream->picture.code_type == P_TYPE)) { ReconPMBlock(vid_stream, i, recon_right_for, recon_down_for, zero_block_flag); } else if (mb_data&MB_motion_back) { ReconBMBlock(vid_stream, i, recon_right_back, recon_down_back, zero_block_flag); } } /* Kill the Chrominace blocks... */ if ((vid_stream->mblock.mb_intra) || (vid_stream->mblock.cbp & 0x2)) ParseAwayBlock(4); if ((vid_stream->mblock.mb_intra) || (vid_stream->mblock.cbp & 0x1)) ParseAwayBlock(5); } else { for (mask = 32, i = 0; i < 6; mask >>= 1, i++) { /* If block exists... */ if ((vid_stream->mblock.mb_intra) || (vid_stream->mblock.cbp & mask)) { zero_block_flag = 0; ParseReconBlock(i); } else zero_block_flag = 1; /* If macroblock is intra coded... */ if (vid_stream->mblock.mb_intra) { ReconIMBlock(vid_stream, i); } else if ((mb_data&(MB_motion_forw | MB_motion_back)) == (MB_motion_forw | MB_motion_back)) { ReconBiMBlock(vid_stream, i, recon_right_for, recon_down_for, recon_right_back, recon_down_back, zero_block_flag); } else if ((mb_data&MB_motion_forw) || (vid_stream->picture.code_type == P_TYPE)) { ReconPMBlock(vid_stream, i, recon_right_for, recon_down_for, zero_block_flag); } else if (mb_data&MB_motion_back) { ReconBMBlock(vid_stream, i, recon_right_back, recon_down_back, zero_block_flag); } } } /* If D Type picture, flush marker bit. */ if (vid_stream->picture.code_type == 4) flush_bits(1); /* If macroblock was intracoded, set macroblock past intra address. */ if (vid_stream->mblock.mb_intra) vid_stream->mblock.past_intra_addr = vid_stream->mblock.mb_address; #ifdef ANALYSIS *mbSizePtr += bitCountRead() - mbSizeCount; #endif return PARSE_OK; } #ifndef MYRECON /*MR *-------------------------------------------------------------- * * ReconIMBlock -- * * Reconstructs intra coded macroblock. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void ReconIMBlock(VidStream *vid_stream, int bnum) { int row, col, row_size; unsigned char *dest; row_size = vid_stream->mb_width; /* Calculate macroblock row and column from address. */ row = vid_stream->mblock.mb_address / row_size; col = vid_stream->mblock.mb_address % row_size; /* If block is luminance block... */ if (bnum < 4) { /* Calculate row and col values for upper left pixel of block. */ row <<= 4; col <<= 4; if (bnum > 1) row += 8; if (bnum & 1) col += 8; /* Set dest to luminance plane of current pict image. */ dest = vid_stream->current->luminance; /* Establish row size. */ row_size *= 16; } /* Otherwise if block is Cr block... */ else if (bnum == 4) { /* Set dest to Cr plane of current pict image. */ dest = vid_stream->current->Cr; /* Establish row size. */ row_size <<= 3; /* Calculate row,col for upper left pixel of block. */ row <<= 3; col <<= 3; } /* Otherwise block is Cb block, and ... */ else { /* Set dest to Cb plane of current pict image. */ dest = vid_stream->current->Cb; /* Establish row size. */ row_size <<= 3; /* Calculate row,col for upper left pixel value of block. */ row <<= 3; col <<= 3; } /* * For each pixel in block, set to cropped reconstructed value from inverse dct. */ IM_reconstruct(dest + row * row_size + col, &vid_stream->block.dct_recon[0][0], row_size); } /* MR *-------------------------------------------------------------- * * ReconPMBlock -- * * Reconstructs forward predicted macroblocks. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void ReconPMBlock(VidStream *vid_stream, int bnum, int recon_right_for, int recon_down_for, int zflag) { int row, col, row_size; unsigned char *dest, *past, *rindex2; int right_half_for, down_half_for; row_size = vid_stream->mb_width; /* Calculate macroblock row and column from address. */ row = vid_stream->mblock.mb_address / row_size; col = vid_stream->mblock.mb_address % row_size; if (bnum < 4) { /* Calculate right_for, down_for motion vectors. */ right_half_for = recon_right_for & 0x1; down_half_for = recon_down_for & 0x1; recon_right_for >>= 1; recon_down_for >>= 1; /* Set dest to luminance plane of current pict image. */ dest = vid_stream->current->luminance; if (vid_stream->picture.code_type == B_TYPE) { if (vid_stream->past) past = vid_stream->past->luminance; } else { /* Set predicitive frame to current future frame. */ if (vid_stream->future) past = vid_stream->future->luminance; } /* Establish row size. */ row_size <<= 4; /* Calculate row,col of upper left pixel in block. */ row <<= 4; col <<= 4; if (bnum > 1) row += 8; if (bnum & 1) col += 8; } /* Otherwise, block is NOT luminance block, ... */ else { /* Construct motion vectors. */ right_half_for = (recon_right_for & 0x2)>>1; down_half_for = recon_down_for & 0x2; recon_right_for >>= 2; recon_down_for >>= 2; /* Establish row size. */ row_size <<= 3; /* Calculate row,col of upper left pixel in block. */ row <<= 3; col <<= 3; /* If block is Cr block... */ if (bnum == 4) { /* Set dest to Cr plane of current pict image. */ dest = vid_stream->current->Cr; if (vid_stream->picture.code_type == B_TYPE) { if (vid_stream->past) past = vid_stream->past->Cr; } else { if (vid_stream->future) past = vid_stream->future->Cr; } } /* Otherwise, block is Cb block... */ else { /* Set dest to Cb plane of current pict image. */ dest = vid_stream->current->Cb; if (vid_stream->picture.code_type == B_TYPE) { if (vid_stream->past) past = vid_stream->past->Cb; } else { if (vid_stream->future) past = vid_stream->future->Cb; } } } /* For each pixel in block... */ dest += ((short)row * (short)row_size) + col; past += (short)(row + recon_down_for) * (short)row_size + col + recon_right_for; /* * Calculate predictive pixel value based on motion vectors and copy to * dest plane. */ if ((!down_half_for) && (!right_half_for)) { if (!zflag) BMcm_reconstruct(dest, past, &(vid_stream->block.dct_recon[0][0]), row_size); else BM_reconstruct(dest, past, row_size); } else { rindex2 = past + right_half_for + (down_half_for?row_size:0); if (!zflag) BIMcm_reconstruct(dest, past, rindex2, &(vid_stream->block.dct_recon[0][0]), row_size); else BIM_reconstruct(dest, past, rindex2, row_size); } } /* MR *-------------------------------------------------------------- * * ReconBMBlock -- * * Reconstructs back predicted macroblocks. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void ReconBMBlock(VidStream *vid_stream, int bnum, int recon_right_back, int recon_down_back, int zflag) { int row, col, row_size; unsigned char *dest, *future, *rindex2; int right_half_back, down_half_back; row_size = vid_stream->mb_width; /* Calculate macroblock row and column from address. */ row = vid_stream->mblock.mb_address / row_size; col = vid_stream->mblock.mb_address % row_size; /* If block is luminance block... */ if (bnum < 4) { /* Calculate right_back, down_back motion vectors. */ right_half_back = recon_right_back & 0x1; down_half_back = recon_down_back & 0x1; recon_right_back >>= 1; recon_down_back >>= 1; /* Set dest to luminance plane of current pict image. */ dest = vid_stream->current->luminance; /* If future frame exists, set future to luminance plane of future frame. */ if (vid_stream->future) future = vid_stream->future->luminance; /* Establish row size. */ row_size <<= 4; /* Calculate row,col of upper left pixel in block. */ row <<= 4; col <<= 4; if (bnum > 1) row += 8; if (bnum & 1) col += 8; } /* Otherwise, block is NOT luminance block, ... */ else { /* Construct motion vectors. */ right_half_back = (recon_right_back & 0x2)>>1; /* used as integer down there */ down_half_back = recon_down_back & 0x2; recon_right_back >>= 2; recon_down_back >>= 2; /* Establish row size. */ row_size <<= 3; /* Calculate row,col of upper left pixel in block. */ row <<= 3; col <<= 3; /* If block is Cr block... */ if (bnum == 4) { /* Set dest to Cr plane of current pict image. */ dest = vid_stream->current->Cr; /* If future frame exists, set future to Cr plane of future image. */ if (vid_stream->future) future = vid_stream->future->Cr; } /* Otherwise, block is Cb block... */ else { /* Set dest to Cb plane of current pict image. */ dest = vid_stream->current->Cb; /* If future frame exists, set future to Cb plane of future frame. */ if (vid_stream->future) future = vid_stream->future->Cb; } } /* For each pixel in block do... */ dest += ((short)row * (short)row_size) + col; future += (short)(row + recon_down_back) * (short)row_size + col + recon_right_back; if ((!right_half_back) && (!down_half_back)) { if (!zflag) BMcm_reconstruct(dest, future, &(vid_stream->block.dct_recon[0][0]), row_size); else BM_reconstruct(dest, future, row_size); } else { rindex2 = future + right_half_back + (down_half_back?row_size:0); if (!zflag) BIMcm_reconstruct(dest, future, rindex2, &(vid_stream->block.dct_recon[0][0]), row_size); else BIM_reconstruct(dest, future, rindex2, row_size); } } /* MR *-------------------------------------------------------------- * * ReconBiMBlock -- * * Reconstructs bidirectionally predicted macroblocks. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void ReconBiMBlock(VidStream *vid_stream, int bnum, int forw_col_start, int forw_row_start, int back_col_start, int back_row_start, int zflag) { int row, col, row_size; unsigned char *dest, *past, *future; row_size = vid_stream->mb_width; /* Calculate macroblock row and column from address. */ row = vid_stream->mblock.mb_address / row_size; col = vid_stream->mblock.mb_address % row_size; /* If block is luminance block... */ if (bnum < 4) { /* Set dest to luminance plane of current pict image. */ dest = vid_stream->current->luminance; /* If past frame exists, set past to luminance plane of past frame. */ if (vid_stream->past) past = vid_stream->past->luminance; /*If future frame exists, set future to luminance plane of future frame. */ if (vid_stream->future) future = vid_stream->future->luminance; /* Establish row size. */ row_size <<= 4; /* Calculate row,col of upper left pixel in block. */ row <<= 4; col <<= 4; if (bnum > 1) row += 8; if (bnum & 1) col += 8; forw_col_start = (forw_col_start>>1) + col; forw_row_start = (forw_row_start>>1) + row; back_col_start = (back_col_start>>1) + col; back_row_start = (back_row_start>>1) + row; } /* Otherwise, block is NOT luminance block, ... */ else { /* Establish row size. */ row_size <<= 3; /* Calculate row,col of upper left pixel in block. */ row <<= 3; col <<= 3; forw_col_start = (forw_col_start>>2) + col; forw_row_start = (forw_row_start>>2) + row; back_col_start = (back_col_start>>2) + col; back_row_start = (back_row_start>>2) + row; /* If block is Cr block... */ if (bnum == 4) { /* Set dest to Cr plane of current pict image. */ dest = vid_stream->current->Cr; /* If past frame exists, set past to Cr plane of past image. */ if (vid_stream->past) past = vid_stream->past->Cr; /* If future frame exists, set future to Cr plane of future image. */ if (vid_stream->future) future = vid_stream->future->Cr; } /* Otherwise, block is Cb block... */ else { /* Set dest to Cb plane of current pict image. */ dest = vid_stream->current->Cb; /* If past frame exists, set past to Cb plane of past frame. */ if (vid_stream->past) past = vid_stream->past->Cb; /* If future frame exists, set future to Cb plane of future frame. */ if (vid_stream->future) future = vid_stream->future->Cb; } } dest += (short)row * (short)row_size + col; past += (short)forw_row_start * (short)row_size + forw_col_start; future += (short)back_row_start * (short)row_size + back_col_start; if (!zflag) BIMcm_reconstruct(dest, past, future, &(vid_stream->block.dct_recon[0][0]), row_size); else BIM_reconstruct(dest, past, future, row_size); } #endif /* MR *-------------------------------------------------------------- * * ProcessSkippedPFrameMBlocks -- * * Processes skipped macroblocks in P frames. * * Results: * Calculates pixel values for luminance, Cr, and Cb planes * in current pict image for skipped macroblocks. * * Side effects: * Pixel values in pict image changed. * *-------------------------------------------------------------- */ static void ProcessSkippedPFrameMBlocks(VidStream *vid_stream) { int row_size, row, col, addr, off; /* Calculate row sizes for luminance and Cr/Cb macroblock areas. */ row_size = vid_stream->mb_width << 4; /* For each skipped macroblock, do... */ addr = vid_stream->mblock.past_mb_addr + 1; row = (addr / vid_stream->mb_width)<<4; col = (addr % vid_stream->mb_width)<<4; for (; addr < vid_stream->mblock.mb_address; addr++, col+=16) { /* Calculate macroblock row and col. */ if(col>=row_size) col=0, row+=16; /* For each row in macroblock luminance plane... */ off = ((short)row * (short)row_size); PMB1_reconstruct(vid_stream->current->luminance + off + col, vid_stream->future->luminance + off + col, row_size >> 2); /* For each row in Cr, and Cb planes... */ off >>= 2; off += (col>>1); PMB2_reconstruct(vid_stream->current->Cr + off, vid_stream->current->Cb + off, vid_stream->future->Cr + off, vid_stream->future->Cb + off, row_size >> 3); } vid_stream->mblock.recon_right_for_prev = 0; vid_stream->mblock.recon_down_for_prev = 0; } /* MR *-------------------------------------------------------------- * * ProcessSkippedBFrameMBlocks -- * * Processes skipped macroblocks in B frames. * * Results: * Calculates pixel values for luminance, Cr, and Cb planes * in current pict image for skipped macroblocks. * * Side effects: * Pixel values in pict image changed. * *-------------------------------------------------------------- */ static void ProcessSkippedBFrameMBlocks(VidStream *vid_stream) { int row_size, half_row, row, col, ccol, crow; int right_half_for, down_half_for, c_right_half_for, c_down_half_for; int right_half_back, down_half_back, c_right_half_back, c_down_half_back; int addr; int recon_right_for, recon_down_for, recon_right_back, recon_down_back; int c_right_for, c_down_for, c_right_back, c_down_back; unsigned char forw_lum[256]; unsigned char forw_cr[64], forw_cb[64]; unsigned char back_lum[256], back_cr[64], back_cb[64]; int row_incr, half_row_incr; int h; char *lum; /* Calculate row sizes for luminance and Cr/Cb macroblock areas. */ row_size = vid_stream->mb_width << 4; half_row = row_size >> 1; row_incr = row_size >> 2; half_row_incr = half_row >> 2; /* Establish motion vector codes based on full pixel flag. */ recon_right_for = vid_stream->mblock.recon_right_for_prev; recon_down_for = vid_stream->mblock.recon_down_for_prev; if (vid_stream->picture.full_pel_forw_vector) { recon_right_for <<= 1; recon_down_for <<= 1; } recon_right_back = vid_stream->mblock.recon_right_back_prev; recon_down_back = vid_stream->mblock.recon_down_back_prev; if (vid_stream->picture.full_pel_back_vector) { recon_right_back <<= 1; recon_down_back <<= 1; } /* If only one motion vector, do display copy, else do full calculation. */ /* Calculate motion vectors. */ if (vid_stream->mblock.bpict_past_forw) { right_half_for = recon_right_for & 0x1; down_half_for = recon_down_for & 0x1; recon_right_for >>= 1; recon_down_for >>= 1; c_right_for = recon_right_for >> 1; c_down_for = recon_down_for >> 1; c_right_half_for = recon_right_for & 0x1; c_down_half_for = recon_down_for & 0x1; } if (vid_stream->mblock.bpict_past_back) { right_half_back = recon_right_back & 0x1; down_half_back = recon_down_back & 0x1; recon_right_back >>= 1; recon_down_back >>= 1; c_right_back = recon_right_back >> 1; c_down_back = recon_down_back >> 1; c_right_half_back = recon_right_back & 0x1; c_down_half_back = recon_down_back & 0x1; } /* For each skipped macroblock, do... */ addr = vid_stream->mblock.past_mb_addr + 1; row = (addr / vid_stream->mb_width)<<4; col = (addr % vid_stream->mb_width)<<4; for (; addr < vid_stream->mblock.mb_address; addr++, col+=16) { /* Calculate macroblock row and col. */ if(col>=row_size) col=0, row+=16; /* Calculate upper left pixel row,col for luminance plane. */ crow = row >> 1; ccol = col >> 1; /* If forward predicted, calculate prediction values. */ if (vid_stream->mblock.bpict_past_forw) { ReconSkippedBlock16(vid_stream->past->luminance, forw_lum, row, col, row_size, recon_right_for, recon_down_for, right_half_for, down_half_for); ReconSkippedBlock8(vid_stream->past->Cr, forw_cr, crow, ccol, half_row, c_right_for, c_down_for, c_right_half_for, c_down_half_for); ReconSkippedBlock8(vid_stream->past->Cb, forw_cb, crow, ccol, half_row, c_right_for, c_down_for, c_right_half_for, c_down_half_for); } /* If back predicted, calculate prediction values. */ if (vid_stream->mblock.bpict_past_back) { ReconSkippedBlock16(vid_stream->future->luminance, back_lum, row, col, row_size, recon_right_back, recon_down_back, right_half_back, down_half_back); ReconSkippedBlock8(vid_stream->future->Cr, back_cr, crow, ccol, half_row, c_right_back, c_down_back, c_right_half_back, c_down_half_back); ReconSkippedBlock8(vid_stream->future->Cb, back_cb, crow, ccol, half_row, c_right_back, c_down_back, c_right_half_back, c_down_half_back); } h = ((short)crow * (short)half_row) + ccol; lum = (vid_stream->current->luminance + ((short)row * (short)row_size) + col); if (vid_stream->mblock.bpict_past_forw && !vid_stream->mblock.bpict_past_back) { PSB1_reconstruct(lum, forw_lum, row_incr); PSB2_reconstruct(vid_stream->current->Cr + h, vid_stream->current->Cb + h, forw_cr, forw_cb, half_row_incr); } else if (vid_stream->mblock.bpict_past_back && !vid_stream->mblock.bpict_past_forw) { PSB1_reconstruct(lum, back_lum, row_incr); PSB2_reconstruct(vid_stream->current->Cr + h, vid_stream->current->Cb + h, back_cr, back_cb, half_row_incr); } else { PSB3_reconstruct(lum, forw_lum, back_lum, row_size); PSB4_reconstruct(vid_stream->current->Cr + h, vid_stream->current->Cb + h, forw_cr, back_cr, forw_cb, back_cb, half_row); } } } /* MR *-------------------------------------------------------------- * * ReconSkippedBlock -- width 16 * * Reconstructs predictive block for skipped macroblocks * in B Frames. * * Results: * No return values. * * Side effects: * None. * *-------------------------------------------------------------- */ static void ReconSkippedBlock16(unsigned char *source, unsigned char *dest, int row, int col, int row_size, int right, int down, int right_half, int down_half) { source += ((short)(row + down) * (short)row_size) + col + right; if ((!right_half) && (!down_half)) RSB1_reconstruct(dest, source, row_size); else RSB2_reconstruct(dest, source, source + right_half + ((short)row_size * (short)down_half), row_size); } /* MR *-------------------------------------------------------------- * * ReconSkippedBlock -- width 8 * * Reconstructs predictive block for skipped macroblocks * in B Frames. * * Results: * No return values. * * Side effects: * None. * *-------------------------------------------------------------- */ static void ReconSkippedBlock8(unsigned char *source, unsigned char *dest, int row, int col, int row_size, int right, int down, int right_half, int down_half) { source += ((short)(row + down) * (short)row_size) + col + right; if ((!right_half) && (!down_half)) RSB3_reconstruct(dest, source, row_size); else RSB4_reconstruct(dest, source, source + right_half + ((short)row_size * (short)down_half), row_size); } /* *-------------------------------------------------------------- * * DoPictureDisplay -- * * Converts image from Lum, Cr, Cb to colormap space. Puts * image in lum plane. Updates past and future frame * pointers. Dithers image. Sends to display mechanism. * * Results: * Pict image structure locked if displaying or if frame * is needed as past or future reference. * * Side effects: * Lum plane pummelled. * *-------------------------------------------------------------- */ static void DoPictureDisplay(VidStream *vid_stream) { /* init display, if needed */ if(!vid_stream->display_is_initialized) { ResizeDisplay(vid_stream->h_size, vid_stream->v_size); vid_stream->display_is_initialized = TRUE; } /* Convert to colormap space and dither. */ if(ditherType == CYBERGFXGRAY_DITHER) vid_stream->current->display = vid_stream->current->luminance; else DoDitherImage(vid_stream->current->luminance, vid_stream->current->Cr, vid_stream->current->Cb, vid_stream->current->display, vid_stream->mb_height <<4, vid_stream->mb_width <<4); /* Update past and future references if needed. */ if ((vid_stream->picture.code_type == I_TYPE) || (vid_stream->picture.code_type == P_TYPE)) { if (vid_stream->future == NULL) { vid_stream->future = vid_stream->current; vid_stream->future->locked |= FUTURE_LOCK; } else { if (vid_stream->past != NULL) { vid_stream->past->locked &= ~PAST_LOCK; } vid_stream->past = vid_stream->future; vid_stream->past->locked &= ~FUTURE_LOCK; vid_stream->past->locked |= PAST_LOCK; vid_stream->future = vid_stream->current; vid_stream->future->locked |= FUTURE_LOCK; vid_stream->current = vid_stream->past; ExecuteDisplay(vid_stream); } } else ExecuteDisplay(vid_stream); } /* *-------------------------------------------------------------- * * ToggleBFlag -- * * Called to set no b frame processing flag. * * Results: * No_B_Flag flag is toggled from present value to opposite value. * * Side effects: * None. * *-------------------------------------------------------------- */ void ToggleBFlag(void) { No_B_Flag ^= 0xffff; } /* *-------------------------------------------------------------- * * TogglePFlag -- * * Called to set no p frame processing flag. * * Results: * No_P_Flag flag is toggled from present value to opposite value. * * Side effects: * None. * *-------------------------------------------------------------- */ void TogglePFlag(void) { No_P_Flag ^= 0xffff; }