This is video.c in view mode; [Download] [Up]
/* * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ #include <stdio.h> #include <sys/time.h> #include "video.h" #include "util.h" /* Declarations of functions. */ static void ReconIMBlock(); static void ReconPMBlock(); static void ReconBMBlock(); static void ReconBiMBlock(); static void ReconSkippedBlock(); static void DoPictureDisplay(); static int ParseSeqHead(); static int ParseGOP(); static int ParsePicture(); static int ParseSlice(); static int ParseMacroBlock(); static int ProcessSkippedPFrameMBlocks(); static int ProcessSkippedBFrameMBlocks(); /* 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; /* Set up array for fast conversion from zig zag order to row/column coordinates. */ int zigzag[64][2] = { 0, 0, 1, 0, 0, 1, 0, 2, 1, 1, 2, 0, 3, 0, 2, 1, 1, 2, 0, 3, 0, 4, 1, 3, 2, 2, 3, 1, 4, 0, 5, 0, 4, 1, 3, 2, 2, 3, 1, 4, 0, 5, 0, 6, 1, 5, 2, 4, 3, 3, 4, 2, 5, 1, 6, 0, 7, 0, 6, 1, 5, 2, 4, 3, 3, 4, 2, 5, 1, 6, 0, 7, 1, 7, 2, 6, 3, 5, 4, 4, 5, 3, 6, 2, 7, 1, 7, 2, 6, 3, 5, 4, 4, 5, 3, 6, 2, 7, 3, 7, 4, 6, 5, 5, 6, 4, 7, 3, 7, 4, 6, 5, 5, 6, 4, 7, 5, 7, 6, 6, 7, 5, 7, 6, 6, 7, 7, 7 }; /* 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}; /* Set up array for fast conversion from row/column coordinates to zig zag order. */ int scan[8][8] = { { 0, 1, 5, 6, 14, 15, 27, 28}, { 2, 4, 7, 13, 16, 26, 29, 42}, { 3, 8, 12, 17, 25, 30, 41, 43}, { 9, 11, 18, 24, 31, 40, 44, 53}, { 10, 19, 23, 32, 39, 45, 52, 54}, { 20, 22, 33, 38, 46, 51, 55, 60}, { 21, 34, 37, 47, 50, 56, 59, 61}, { 35, 36, 48, 49, 57, 58, 62, 63}}; /* Initialize P and B skip flags. */ static int No_P_Flag = 0; static int No_B_Flag = 0; double realTimeStart; int totNumFrames = 0; double ReadSysClock () { struct timeval tv; (void) gettimeofday(&tv, NULL); return (tv.tv_sec + tv.tv_usec / 1000000.0); } extern int writeToStdout; void PrintTimeInfo() { double spent; if(!writeToStdout) { spent = ReadSysClock()-realTimeStart; printf( "\nReal Time Spent (After Initializations): %f secs.\n", spent); printf( "Avg. Frames/Sec: %f\n", ((double) totNumFrames) / spent); } } /* *-------------------------------------------------------------- * * 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(bufLength) int bufLength; { int i, j; 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; /* Copy default intra matrix. */ for (i=0; i<8; i++) { for (j = 0; j<8; j++) { new->intra_quant_matrix[j][i] = default_intra_matrix[i*8+j]; } } /* Initialize non intra quantization matrix. */ for (i=0; i<8; i++) { for (j=0; j<8; j++) { new->non_intra_quant_matrix[j][i] = 16; } } /* 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; /* Return structure. */ return new; } /* *-------------------------------------------------------------- * * DestroyVidStream -- * * Deallocates a VidStream structure. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void DestroyVidStream(astream) VidStream *astream; { int i; if (astream->ext_data != NULL) free(astream->ext_data); if (astream->user_data != NULL) free(astream->user_data); if (astream->group.ext_data != NULL) free(astream->group.ext_data); if (astream->group.user_data != NULL) free(astream->group.user_data); if (astream->picture.extra_info != NULL) free(astream->picture.extra_info); if (astream->picture.ext_data != NULL) free(astream->picture.ext_data); if (astream->picture.user_data != NULL) free(astream->picture.user_data); if (astream->slice.extra_info != NULL) free(astream->slice.extra_info); if (astream->buf_start != NULL) free(astream->buf_start); for (i=0; i<RING_BUF_SIZE; i++) { if (astream->ring[i] != NULL) { DestroyPictImage(astream->ring[i]); } } 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(width, height) int width, height; { PictImage *new; /* Allocate memory space for new structure. */ new = (PictImage *) malloc(sizeof(PictImage)); /* Allocate memory for image spaces. */ { shmemerror: new->display = (unsigned char *) malloc(width*height*4); } new->luminance = (unsigned char *) malloc(width*height); new->Cr = (unsigned char *) malloc(width*height/4); new->Cb = (unsigned char *) malloc(width*height/4); /* 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(apictimage) PictImage *apictimage; { if (apictimage->luminance != NULL) { free(apictimage->luminance); } if (apictimage->Cr != NULL) { free(apictimage->Cr); } if (apictimage->Cb != NULL) { free(apictimage->Cb); } if (apictimage->display != NULL) { free(apictimage->display); } } /* *-------------------------------------------------------------- * * 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 pointer to the video stream structure used. * * Side effects: * Bit stream is irreversibly parsed. If a picture is completed, * a function is called to display the frame at the correct time. * *-------------------------------------------------------------- */ VidStream *mpegVidRsrc(time_stamp, vid_stream) TimeStamp time_stamp; VidStream *vid_stream; { static int first = 1; unsigned int data; int i, status; /* If vid_stream is null, create new VidStream structure. */ if (vid_stream == NULL) { return NULL; } /* 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; curBits = *curVidStream->buffer; 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(); show_bits32(&data); if (data != SEQ_START_CODE) { fprintf(stderr, "This is not an MPEG stream."); DestroyVidStream(curVidStream); exit(1); } first = 0; } /* Get next 32 bits (size of start codes). */ show_bits32(&data); /* Process according to start code (or parse macroblock if not a start code at all. */ switch (data) { case SEQ_END_CODE: /*Sequence done. Do the right thing. For right now, exit. */ fprintf(stderr, "\nDone!\n"); PrintTimeInfo(); if (loopFlag) longjmp(env, 1); DestroyVidStream(curVidStream); exit(); 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 (!next_bits(32, PICTURE_START_CODE)) { if (next_bits(32, GOP_START_CODE)) break; else if (next_bits(32, 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; default: /* Check for slice start code. */ if ((data >= SLICE_MIN_START_CODE) && (data <= SLICE_MAX_START_CODE)) { /* Slice start code. Parse slice header. */ if (ParseSlice(vid_stream) != PARSE_OK) 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 (!next_bits(23, 0x00000000)) { /* Not start code. Parse Macroblock. */ if (ParseMacroBlock(vid_stream) != PARSE_OK) goto error; } 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)) { 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 vid_stream; } /* *-------------------------------------------------------------- * * 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(vid_stream) VidStream *vid_stream; { unsigned int data; int i; /* Flush off sequence start code. */ flush_bits(32); /* Get horizontal size of image space. */ get_bits12(&data); vid_stream->h_size = data; /* Get vertical size of image space. */ get_bits12(&data); vid_stream->v_size = data; /* Calculate macroblock width and height of image space. */ vid_stream->mb_width = (vid_stream->h_size+15)/16; vid_stream->mb_height = (vid_stream->v_size+15)/16; /* 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*16, vid_stream->mb_height*16); } } /* Parse of aspect ratio code. */ get_bits4(&data); vid_stream->aspect_ratio = (unsigned char) data; /* Parse off picture rate code. */ get_bits4(&data); vid_stream->picture_rate = (unsigned char) data; /* Parse off bit rate. */ get_bits18(&data); vid_stream->bit_rate = data; /* Flush marker bit. */ flush_bits(1); /* Parse off vbv buffer size. */ get_bits10(&data); vid_stream->vbv_buffer_size = data; /* Parse off contrained parameter flag. */ get_bits1(&data); if (data) { vid_stream->const_param_flag = TRUE; } else vid_stream->const_param_flag = FALSE; /* If intra_quant_matrix_flag set, parse off intra quant matrix values. */ get_bits1(&data); if (data) { for(i=0; i<64; i++) { get_bits8(&data); vid_stream->intra_quant_matrix[zigzag[i][1]][zigzag[i][0]] = (unsigned char) data; } } /* If non intra quant matrix flag set, parse off non intra quant matrix values. */ get_bits1(&data); if (data) { for (i=0; i<64; i++) { get_bits8(&data); vid_stream->non_intra_quant_matrix[zigzag[i][1]][zigzag[i][0]] = (unsigned char) data; } } /* Go to next start code. */ next_start_code(); /* If next start code is extension start code, parse off extension data. */ if (next_bits(32, EXT_START_CODE)) { flush_bits(32); if (vid_stream->ext_data != NULL) { free(vid_stream->ext_data); vid_stream->ext_data = NULL; } vid_stream->ext_data = get_ext_data(); } /* If next start code is user start code, parse off user data. */ if (next_bits(32, USER_START_CODE)) { flush_bits(32); if (vid_stream->user_data != NULL) { 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(vid_stream) VidStream *vid_stream; { unsigned int data; /* Flush group of pictures start code. WWWWWWOOOOOOOSSSSSSHHHHH!!! */ flush_bits(32); /* Parse off drop frame flag. */ get_bits1(&data); if(data) { vid_stream->group.drop_flag = TRUE; } else vid_stream->group.drop_flag = FALSE; /* Parse off hour component of time code. */ get_bits5(&data); vid_stream->group.tc_hours = data; /* Parse off minute component of time code. */ get_bits6(&data); vid_stream->group.tc_minutes = data; /* Flush marker bit. */ flush_bits(1); /* Parse off second component of time code. */ get_bits6(&data); vid_stream->group.tc_seconds = data; /* Parse off picture count component of time code. */ get_bits6(&data); vid_stream->group.tc_pictures = data; /* Parse off closed gop and broken link flags. */ get_bits2(&data); if (data > 1) { vid_stream->group.closed_gop = TRUE; if (data > 2) { vid_stream->group.broken_link = TRUE; } else vid_stream->group.broken_link = FALSE; } else { vid_stream->group.closed_gop = FALSE; if (data) { vid_stream->group.broken_link = TRUE; } else vid_stream->group.broken_link = FALSE; } /* Goto next start code. */ next_start_code(); /* If next start code is extension data, parse off extension data. */ if (next_bits(32, EXT_START_CODE)) { flush_bits(32); if (vid_stream->group.ext_data != NULL) { free(vid_stream->group.ext_data); vid_stream->group.ext_data = NULL; } vid_stream->group.ext_data = get_ext_data(); } /* If next start code is user data, parse off user data. */ if (next_bits(32, USER_START_CODE)) { flush_bits(32); if (vid_stream->group.user_data != NULL) { 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(vid_stream, time_stamp) VidStream *vid_stream; TimeStamp time_stamp; { unsigned int data; int i; /* Flush header start code. */ flush_bits(32); /* Parse off temporal reference. */ get_bits10(&data); vid_stream->picture.temp_ref = data; /* Parse of picture type. */ get_bits3(&data); vid_stream->picture.code_type = data; 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; /* Parse off vbv buffer delay value. */ get_bits16(&data); vid_stream->picture.vbv_delay = data; /* 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(&data); if (data) vid_stream->picture.full_pel_forw_vector = TRUE; else vid_stream->picture.full_pel_forw_vector = FALSE; /* Parse of forw_r_code. */ get_bits3(&data); /* Decode forw_r_code into forw_r_size and forw_f. */ vid_stream->picture.forw_r_size = data - 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(&data); if (data) vid_stream->picture.full_pel_back_vector = TRUE; else vid_stream->picture.full_pel_back_vector = FALSE; /* Parse off back_r_code. */ get_bits3(&data); /* Decode back_r_code into back_r_size and back_f. */ vid_stream->picture.back_r_size = data -1; vid_stream->picture.back_f = (1 << vid_stream->picture.back_r_size); } /* Get extra bit picture info. */ if (vid_stream->picture.extra_info != NULL) { 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 (next_bits(32, EXT_START_CODE)) { flush_bits(32); if (vid_stream->picture.ext_data != NULL) { free(vid_stream->picture.ext_data); vid_stream->picture.ext_data = NULL; } vid_stream->picture.ext_data = get_ext_data(); } /* If start code is user start code, parse off user data. */ if (next_bits(32, USER_START_CODE)) { flush_bits(32); if (vid_stream->picture.user_data != NULL) { 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(vid_stream) VidStream *vid_stream; { unsigned int data; /* Flush slice start code. */ flush_bits(24); /* Parse off slice vertical position. */ get_bits8(&data); vid_stream->slice.vert_pos = data; /* Parse off quantization scale. */ get_bits5(&data); vid_stream->slice.quant_scale = data; /* Parse off extra bit slice info. */ if (vid_stream->slice.extra_info != NULL) { 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 = ((vid_stream->slice.vert_pos-1) * 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(vid_stream) VidStream *vid_stream; { int addr_incr; unsigned int data; int i, recon_right_for, recon_down_for, recon_right_back, recon_down_back; int zero_block_flag; BOOLEAN mb_quant, mb_motion_forw, mb_motion_back, mb_pattern; int sparseFlag; /* 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 > (vid_stream->mb_height * 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_quant, &mb_motion_forw, &mb_motion_back, &mb_pattern, &(vid_stream->mblock.mb_intra)); break; case P_TYPE: DecodeMBTypeP(&mb_quant, &mb_motion_forw, &mb_motion_back, &mb_pattern, &(vid_stream->mblock.mb_intra)); break; case B_TYPE: DecodeMBTypeB(&mb_quant, &mb_motion_forw, &mb_motion_back, &mb_pattern, &(vid_stream->mblock.mb_intra)); break; } /* If quantization flag set, parse off new quantization scale. */ if (mb_quant == TRUE) { get_bits5(&data); vid_stream->slice.quant_scale = data; } /* If forward motion vectors exist... */ if (mb_motion_forw == TRUE) { /* 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, &data); vid_stream->mblock.motion_h_forw_r = data; } /* 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, &data); vid_stream->mblock.motion_v_forw_r = data; } } /* If back motion vectors exist... */ if (mb_motion_back == TRUE) { /* 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, &data); vid_stream->mblock.motion_h_back_r = data; } /* 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, &data); vid_stream->mblock.motion_v_back_r = data; } } /* If mblock pattern flag set, parse and decode CBP (code block pattern). */ if (mb_pattern == TRUE) { DecodeCBP(&vid_stream->mblock.cbp); } /* Otherwise, set CBP to zero. */ else vid_stream->mblock.cbp = 0; /* 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_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_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_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. */ vid_stream->mblock.bpict_past_forw = mb_motion_forw; vid_stream->mblock.bpict_past_back = mb_motion_back; } } /* For each possible block in macroblock. */ for (i=0; i<6; i++) { /* If block exists... */ if ((vid_stream->mblock.mb_intra) || (vid_stream->mblock.cbp & (1<<(5-i)))) { /* Unset Zero Block Flag. */ zero_block_flag = 0; /* Parse and reconstruct block. */ ParseReconBlock(i, &sparseFlag); /* Run through inverse DCT. */ j_rev_dct(vid_stream->block.dct_recon, sparseFlag); } /* Otherwise, set zero block flag. */ else { zero_block_flag = 1; } /* If macroblock is intra coded... */ if (vid_stream->mblock.mb_intra) { ReconIMBlock(vid_stream, i); } else if (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_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_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; return PARSE_OK; } /* *-------------------------------------------------------------- * * ReconIMBlock -- * * Reconstructs intra coded macroblock. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void ReconIMBlock(vid_stream, bnum) VidStream *vid_stream; int bnum; { int mb_row, mb_col, row, col, row_size, rr, cc; unsigned char *dest; /* Calculate macroblock row and column from address. */ mb_row = vid_stream->mblock.mb_address / vid_stream->mb_width; mb_col = vid_stream->mblock.mb_address % vid_stream->mb_width; /* If block is luminance block... */ if (bnum<4) { /* Calculate row and col values for upper left pixel of block. */ row = mb_row * 16; col = mb_col * 16; if (bnum>1) row += 8; if (bnum%2) col += 8; /* Set dest to luminance plane of current pict image. */ dest = vid_stream->current->luminance; /* Establish row size. */ row_size = vid_stream->mb_width*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 = vid_stream->mb_width*8; /* Calculate row,col for upper left pixel of block. */ row = mb_row*8; col = mb_col*8; } /* 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 = vid_stream->mb_width*8; /* Calculate row,col for upper left pixel value of block. */ row = mb_row*8; col = mb_col*8; } /* For each pixel in block, set to cropped reconstructed value from inverse dct. */ /* old code */ /* for (rr =0; rr < 8; rr++) { for (cc = 0; cc < 8; cc++) { if (vid_stream->block.dct_recon[rr][cc] < 0) { dest[row*row_size+col] = 0; } else if (vid_stream->block.dct_recon[rr][cc] > 255) { dest[row*row_size+col] = 255; } else { dest[row*row_size+col] = vid_stream->block.dct_recon[rr][cc]; } col++; } col -= 8; row++;*/ /* patch -pk */ { short *sp = &vid_stream->block.dct_recon[0][0], sv; dest += row * row_size + col; for(rr = 0; rr < 8; rr++, sp += 8, dest += row_size){ if((sv = sp[0]) < 0){ dest[0] = 0; } else if(sv > 255){ dest[0] = 255; } else { dest[0] = sv; } if((sv = sp[1]) < 0){ dest[1] = 0; } else if(sv > 255){ dest[1] = 255; } else { dest[1] = sv; } if((sv = sp[2]) < 0){ dest[2] = 0; } else if(sv > 255){ dest[2] = 255; } else { dest[2] = sv; } if((sv = sp[3]) < 0){ dest[3] = 0; } else if(sv > 255){ dest[3] = 255; } else { dest[3] = sv; } if((sv = sp[4]) < 0){ dest[4] = 0; } else if(sv > 255){ dest[4] = 255; } else { dest[4] = sv; } if((sv = sp[5]) < 0){ dest[5] = 0; } else if(sv > 255){ dest[5] = 255; } else { dest[5] = sv; } if((sv = sp[6]) < 0){ dest[6] = 0; } else if(sv > 255){ dest[6] = 255; } else { dest[6] = sv; } if((sv = sp[7]) < 0){ dest[7] = 0; } else if(sv > 255){ dest[7] = 255; } else { dest[7] = sv; } } } } /* *-------------------------------------------------------------- * * ReconPMBlock -- * * Reconstructs forward predicted macroblocks. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void ReconPMBlock(vid_stream, bnum, recon_right_for, recon_down_for, zflag) VidStream * vid_stream; int bnum, recon_right_for, recon_down_for, zflag; { int mb_row, mb_col, row, col, row_size, rr, cc; unsigned char *dest, *past; int right_for, down_for, right_half_for, down_half_for; unsigned char *rindex1, *rindex2; unsigned char *index; int val; short int *blockvals; /* Calculate macroblock row and column from address. */ mb_row = vid_stream->mblock.mb_address / vid_stream->mb_width; mb_col = vid_stream->mblock.mb_address % vid_stream->mb_width; if (bnum<4) { /* Calculate right_for, down_for motion vectors. */ right_for = recon_right_for >> 1; down_for = recon_down_for >> 1; right_half_for = recon_right_for & 0x1; down_half_for = recon_down_for & 0x1; /* 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 != NULL) past = vid_stream->past->luminance; } else { /* Set predicitive frame to current future frame. */ if (vid_stream->future != NULL) past = vid_stream->future->luminance; } /* Establish row size. */ row_size = vid_stream->mb_width << 4; /* Calculate row,col of upper left pixel in block. */ row = mb_row << 4; col = mb_col << 4; if (bnum>1) row += 8; if (bnum%2) col += 8; } /* Otherwise, block is NOT luminance block, ... */ else { /* Construct motion vectors. */ right_for = recon_right_for >> 2; down_for = recon_down_for >> 2; right_half_for = recon_right_for & 0x2; down_half_for = recon_down_for & 0x2; /* Establish row size. */ row_size = vid_stream->mb_width << 3; /* Calculate row,col of upper left pixel in block. */ row = mb_row << 3; col = mb_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 != NULL) past = vid_stream->past->Cr; } else { if (vid_stream->future != NULL) 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 != NULL) past = vid_stream->past->Cb; } else { if (vid_stream->future != NULL) past = vid_stream->future->Cb; } } } /* For each pixel in block... */ index = dest+(row*row_size)+col; rindex1 = past+(row+down_for)*row_size+col+right_for; blockvals = &(vid_stream->block.dct_recon[0][0]); /* Calculate predictive pixel value based on motion vectors and copy to dest plane. */ if ((!down_half_for) && (!right_half_for)) { for (rr = 0; rr < 8; rr++) { for (cc = 0; cc < 8; cc++) { val = (int)(*rindex1++); if (!zflag) { val += (int)(*blockvals++); } if (val > 255) val = 255; else if (val < 0) val = 0; *index++ = val; } index += row_size - 8; rindex1 += row_size - 8; } } else { rindex2 = rindex1 + right_half_for + (down_half_for * row_size); for (rr = 0; rr < 8; rr++) { for (cc = 0; cc < 8; cc++) { val = ((*rindex1++) + (*rindex2++)) >> 1; if (!zflag) { val += *blockvals++; } if (val > 255) val = 255; else if (val < 0) val = 0; *index++ = val; } index += row_size - 8; rindex1 += row_size - 8; rindex2 += row_size - 8; } } } /* *-------------------------------------------------------------- * * ReconBMBlock -- * * Reconstructs back predicted macroblocks. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void ReconBMBlock(vid_stream, bnum, recon_right_back, recon_down_back, zflag) VidStream *vid_stream; int bnum, recon_right_back, recon_down_back, zflag; { int mb_row, mb_col, row, col, row_size, rr, cc; unsigned char *dest, *future; int right_back, down_back, right_half_back, down_half_back; unsigned char *rindex1, *rindex2; unsigned char *index; int val; short int *blockvals; /* Calculate macroblock row and column from address. */ mb_row = vid_stream->mblock.mb_address / vid_stream->mb_width; mb_col = vid_stream->mblock.mb_address % vid_stream->mb_width; /* If block is luminance block... */ if (bnum<4) { /* Calculate right_back, down_bakc motion vectors. */ right_back = recon_right_back >> 1; down_back = recon_down_back >> 1; right_half_back = recon_right_back & 0x1; down_half_back = recon_down_back & 0x1; /* 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 != NULL) future = vid_stream->future->luminance; /* Establish row size. */ row_size = vid_stream->mb_width << 4; /* Calculate row,col of upper left pixel in block. */ row = mb_row << 4; col = mb_col << 4; if (bnum>1) row += 8; if (bnum%2) col += 8; } /* Otherwise, block is NOT luminance block, ... */ else { /* Construct motion vectors. */ right_back = recon_right_back >> 2; down_back = recon_down_back >> 2; right_half_back = recon_right_back & 0x2; down_half_back = recon_down_back & 0x2; /* Establish row size. */ row_size = vid_stream->mb_width << 3; /* Calculate row,col of upper left pixel in block. */ row = mb_row << 3; col = mb_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 != NULL) 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 != NULL) future = vid_stream->future->Cb; } } /* For each pixel in block do... */ index = dest + (row*row_size)+col; rindex1 = future + (row+down_back)*row_size+col+right_back; blockvals = &(vid_stream->block.dct_recon[0][0]); if ((!right_half_back)&&(!down_half_back)) { for (rr = 0; rr < 8; rr++) { for (cc = 0; cc < 8; cc++) { val = *rindex1++; if (!zflag) { val += *blockvals++; } if (val > 255) val = 255; else if (val < 0) val = 0; *index++ = val; } index += row_size - 8; rindex1 += row_size - 8; } } else { rindex2 = rindex1 + right_half_back + (down_half_back*row_size); for (rr = 0; rr < 8; rr++) { for (cc = 0; cc < 8; cc++) { val = ((*rindex1++) + (*rindex2++)) >> 1; if (!zflag) { val += *blockvals++; } if (val > 255) val = 255; else if (val < 0) val = 0; *index++ = val; } index += row_size - 8; rindex1 += row_size - 8; rindex2 += row_size - 8; } } } /* *-------------------------------------------------------------- * * ReconBiMBlock -- * * Reconstructs bidirectionally predicted macroblocks. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void ReconBiMBlock(vid_stream, bnum, recon_right_for, recon_down_for, recon_right_back, recon_down_back, zflag) VidStream *vid_stream; int bnum, recon_right_for, recon_down_for, recon_right_back, recon_down_back; int zflag; { int mb_row, mb_col, row, col, row_size, rr, cc; unsigned char *dest, *past, *future; int right_for, down_for, right_half_for, down_half_for; int right_back, down_back, right_half_back, down_half_back; unsigned char *indexptr, *rindex1ptr, *bindex1ptr, *rindex2ptr, *bindex2ptr; short int *dct_reconptr; int val; /* Calculate macroblock row and column from address. */ mb_row = vid_stream->mblock.mb_address / vid_stream->mb_width; mb_col = vid_stream->mblock.mb_address % vid_stream->mb_width; /* If block is luminance block... */ if (bnum<4) { /* Calculate right_for, down_for, right_half_for, down_half_for, right_back, down_bakc, right_half_back, and down_half_back, motion vectors. */ right_for = recon_right_for >> 1; down_for = recon_down_for >> 1; right_half_for = recon_right_for & 0x1; down_half_for = recon_down_for & 0x1; right_back = recon_right_back >> 1; down_back = recon_down_back >> 1; right_half_back = recon_right_back & 0x1; down_half_back = recon_down_back & 0x1; /* 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 != NULL) past = vid_stream->past->luminance; /* If future frame exists, set future to luminance plane of future frame. */ if (vid_stream->future != NULL) future = vid_stream->future->luminance; /* Establish row size. */ row_size = (vid_stream->mb_width << 4); /* Calculate row,col of upper left pixel in block. */ row = (mb_row << 4); col = (mb_col << 4); if (bnum>1) row += 8; if (bnum & 0x01) col += 8; } /* Otherwise, block is NOT luminance block, ... */ else { /* Construct motion vectors. */ right_for = recon_right_for >> 2; down_for = recon_down_for >> 2; right_half_for = recon_right_for & 0x2; down_half_for = recon_down_for & 0x2; right_back = recon_right_back >> 2; down_back = recon_down_back >> 2; right_half_back = recon_right_back & 0x2; down_half_back = recon_down_back & 0x2; /* Establish row size. */ row_size = (vid_stream->mb_width << 3); /* Calculate row,col of upper left pixel in block. */ row = (mb_row << 3); col = (mb_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 past frame exists, set past to Cr plane of past image. */ if (vid_stream->past != NULL) past = vid_stream->past->Cr; /* If future frame exists, set future to Cr plane of future image. */ if (vid_stream->future != NULL) 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 != NULL) past = vid_stream->past->Cb; /* If future frame exists, set future to Cb plane of future frame. */ if (vid_stream->future != NULL) future = vid_stream->future->Cb; } } /* For each pixel in block... */ indexptr = dest+(row*row_size)+col; rindex1ptr = past+(row+down_for)*row_size+col+right_for; bindex1ptr = future+(row+down_back)*row_size+col+right_back; dct_reconptr = (short int *) &( vid_stream->block.dct_recon[0][0]); if ((!down_half_for) && (!right_half_for) && (!down_half_back) && (!right_half_back)) { row_size -= 8; for (rr = 0; rr < 8; rr++) { for (cc = 0; cc < 8; cc++) { val = (((*rindex1ptr++) + (*bindex1ptr++)) >> 1); if (!zflag) { val += *dct_reconptr++; } if (val > 255) val = 255; else if (val < 0) val = 0; *indexptr++ = val; } indexptr += row_size; rindex1ptr += row_size; bindex1ptr += row_size; } } else { rindex2ptr = rindex1ptr + right_half_for + (row_size * down_half_for); bindex2ptr = bindex1ptr + right_half_back + (row_size * down_half_back); row_size -= 8; for (rr = 0; rr < 8; rr++) { for (cc = 0; cc < 8; cc++) { val = (((*rindex1ptr++) + (*bindex1ptr++) + (*rindex2ptr++) + (*bindex2ptr++)) >> 2); if (!zflag) { val += *dct_reconptr++; } if (val > 255) val = 255; else if (val < 0) val = 0; *indexptr++ = val; } indexptr += row_size; rindex1ptr += row_size; bindex1ptr += row_size; rindex2ptr += row_size; bindex2ptr += row_size; } } } /* *-------------------------------------------------------------- * * 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 int ProcessSkippedPFrameMBlocks(vid_stream) VidStream *vid_stream; { int row_size, half_row, mb_row, mb_col, row, col, rr; int addr; unsigned char *dest, *src, *dest1, *src1; /* Calculate row sizes for luminance and Cr/Cb macroblock areas. */ row_size = vid_stream->mb_width << 4; half_row = (row_size >> 1); /* For each skipped macroblock, do... */ for(addr = vid_stream->mblock.past_mb_addr+1; addr < vid_stream->mblock.mb_address; addr++) { /* Calculate macroblock row and col. */ mb_row = addr / vid_stream->mb_width; mb_col = addr % vid_stream->mb_width; /* Calculate upper left pixel row,col for luminance plane. */ row = mb_row << 4; col = mb_col << 4; /* For each row in macroblock luminance plane... */ dest = vid_stream->current->luminance+(row*row_size)+col; src = vid_stream->future->luminance+(row*row_size)+col; for (rr = 0; rr < 16; rr++) { /* Copy pixel values from last I or P picture. */ memcpy(dest, src, 16); dest += row_size; src += row_size; } /* Divide row,col to get upper left pixel of macroblock in Cr and Cb planes. */ row = row >> 1; col = col >> 1; /* For each row in Cr, and Cb planes... */ dest = vid_stream->current->Cr+(row*half_row)+col; src = vid_stream->future->Cr+(row*half_row)+col; dest1 = vid_stream->current->Cb+(row*half_row)+col; src1 = vid_stream->future->Cb+(row*half_row)+col; for (rr = 0; rr < 8; rr++) { /* Copy pixel values from last I or P picture. */ memcpy(dest, src, 8); memcpy(dest1, src1, 8); dest += half_row; src += half_row; dest1 += half_row; src1 += half_row; } } vid_stream->mblock.recon_right_for_prev = 0; vid_stream->mblock.recon_down_for_prev = 0; return PARSE_OK; } /* *-------------------------------------------------------------- * * 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 int ProcessSkippedBFrameMBlocks(vid_stream) VidStream *vid_stream; { int row_size, half_row, mb_row, mb_col, row, col, rr, cc; 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, right_for, down_for; int recon_right_for, recon_down_for; int recon_right_back, recon_down_back; int right_back, down_back; int c_right_for, c_down_for; int 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]; unsigned char *src1, *src2, *src1a, *src2a; unsigned char *dest, *dest1; /* Calculate row sizes for luminance and Cr/Cb macroblock areas. */ row_size = vid_stream->mb_width << 4; half_row = (row_size >> 1); /* Establish motion vector codes based on full pixel flag. */ if (vid_stream->picture.full_pel_forw_vector) { recon_right_for = vid_stream->mblock.recon_right_for_prev << 1; recon_down_for = vid_stream->mblock.recon_down_for_prev << 1; } else { 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_back_vector) { recon_right_back = vid_stream->mblock.recon_right_back_prev << 1; recon_down_back = vid_stream->mblock.recon_down_back_prev << 1; } else { recon_right_back = vid_stream->mblock.recon_right_back_prev; recon_down_back = vid_stream->mblock.recon_down_back_prev; } /* Calculate motion vectors. */ if (vid_stream->mblock.bpict_past_forw) { right_for = recon_right_for >> 1; down_for = recon_down_for >> 1; right_half_for = recon_right_for & 0x1; down_half_for = recon_down_for & 0x1; c_right_for = recon_right_for >> 2; c_down_for = recon_down_for >> 2; c_right_half_for = recon_right_for & 0x2; c_down_half_for = recon_down_for & 0x2; } if (vid_stream->mblock.bpict_past_back) { right_back = recon_right_back >> 1; down_back = recon_down_back >> 1; right_half_back = recon_right_back & 0x1; down_half_back = recon_down_back & 0x1; c_right_back = recon_right_back >> 2; c_down_back = recon_down_back >> 2; c_right_half_back = recon_right_back & 0x2; c_down_half_back = recon_down_back & 0x2; } /* For each skipped macroblock, do... */ for(addr = vid_stream->mblock.past_mb_addr+1; addr < vid_stream->mblock.mb_address; addr++) { /* Calculate macroblock row and col. */ mb_row = addr / vid_stream->mb_width; mb_col = addr % vid_stream->mb_width; /* Calculate upper left pixel row,col for luminance plane. */ row = mb_row << 4; col = mb_col << 4; /* If forward predicted, calculate prediction values. */ if (vid_stream->mblock.bpict_past_forw) { ReconSkippedBlock(vid_stream->past->luminance, forw_lum, row, col, row_size, right_for, down_for, right_half_for, down_half_for, 16); ReconSkippedBlock(vid_stream->past->Cr, forw_cr, (row>>1), (col>>1), (row_size>>1), c_right_for, c_down_for, c_right_half_for, c_down_half_for, 8); ReconSkippedBlock(vid_stream->past->Cb, forw_cb, (row>>1), (col>>1), (row_size>>1), c_right_for, c_down_for, c_right_half_for, c_down_half_for, 8); } /* If back predicted, calculate prediction values. */ if (vid_stream->mblock.bpict_past_back) { ReconSkippedBlock(vid_stream->future->luminance, back_lum, row, col, row_size, right_back, down_back, right_half_back, down_half_back, 16); ReconSkippedBlock(vid_stream->future->Cr, back_cr, (row>>1), (col>>1), (row_size>>1), c_right_back, c_down_back, c_right_half_back, c_down_half_back, 8); ReconSkippedBlock(vid_stream->future->Cb, back_cb, (row>>1), (col>>1), (row_size>>1), c_right_back, c_down_back, c_right_half_back, c_down_half_back, 8); } if (vid_stream->mblock.bpict_past_forw && (!vid_stream->mblock.bpict_past_back)) { dest = vid_stream->current->luminance+(row*row_size)+col; for (rr = 0; rr < 16; rr++) { memcpy(dest, forw_lum+(rr<<4), 16); dest += row_size; } row /= 2; col /= 2; dest = vid_stream->current->Cr+(row*half_row)+col; dest1 = vid_stream->current->Cb+(row*half_row)+col; for (rr = 0; rr < 8; rr++) { memcpy(dest, forw_cr+(rr<<3), 8); memcpy(dest1, forw_cb+(rr<<3), 8); dest += half_row; dest1 += half_row; } } else if (vid_stream->mblock.bpict_past_back && (!vid_stream->mblock.bpict_past_forw)) { dest = vid_stream->current->luminance+(row*row_size)+col; for (rr = 0; rr < 16; rr++) { memcpy(dest, back_lum+(rr<<4), 16); dest += row_size; } row /= 2; col /= 2; dest = vid_stream->current->Cr+(row*half_row)+col; dest1 = vid_stream->current->Cb+(row*half_row)+col; for (rr = 0; rr < 8; rr++) { memcpy(dest, back_cr+(rr<<3), 8); memcpy(dest1, back_cb+(rr<<3), 8); dest += half_row; dest1 += half_row; } } else { dest = vid_stream->current->luminance+(row*row_size)+col; src1 = forw_lum; src2 = back_lum; for (rr = 0; rr < 16; rr++) { for (cc = 0; cc < 16; cc++) { *dest++ = ((*src1++) + (*src2++)) >> 1; } dest += row_size - 16; } row /= 2; col /= 2; dest = vid_stream->current->Cr+(row*half_row)+col; dest1 = vid_stream->current->Cb+(row*half_row)+col; src1 = forw_cr; src2 = back_cr; src1a = forw_cb; src2a = back_cb; for (rr = 0; rr < 8; rr++) { for (cc = 0; cc < 8; cc++) { *dest++ = ((*src1++) + (*src2++)) >> 1; *dest1++ = ((*src1a++) + (*src2a++)) >> 1; } dest += half_row - 8; dest1 += half_row - 8; } } } return PARSE_OK; } /* *-------------------------------------------------------------- * * ReconSkippedBlock -- * * Reconstructs predictive block for skipped macroblocks * in B Frames. * * Results: * No return values. * * Side effects: * None. * *-------------------------------------------------------------- */ static void ReconSkippedBlock(source, dest, row, col, row_size, right, down, right_half, down_half, width) unsigned char *source; unsigned char *dest; int row, col, row_size, right, down, right_half, down_half, width; { int rr, cc; unsigned char *source2; source += ((row+down)*row_size)+col+right; if ((!right_half) && (!down_half)) { row_size -= width; for (rr =0 ; rr < width; rr++) { for (cc = 0; cc < width; cc++) { *dest++ = *source++; } source += row_size; } } else { source2 = source + right_half + (row_size * down_half); row_size -= width; for (rr =0 ; rr < width; rr++) { for (cc = 0; cc < width; cc++) { *dest++ = ((*source++) + (*source2++)) >> 1; } source += row_size; source2 += 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(vid_stream) VidStream *vid_stream; { /* Convert to colormap space and dither. */ ColorDitherImage(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); /* 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); } return; } /* *-------------------------------------------------------------- * * 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() { if (No_B_Flag) { No_B_Flag = 0; } else No_B_Flag = 1; } /* *-------------------------------------------------------------- * * 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() { if (No_P_Flag) { No_P_Flag = 0; } else No_P_Flag = 1; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.