📄 video.c
字号:
/* * 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. *//* This file contains C code that implements * the video decoder model. */#include <config.h>#include <stdio.h>#include <stdlib.h>#include <assert.h>#ifndef MIPS# ifdef _MSC_VER# include <sys/utime.h># else# ifdef __BORLANDC__# include <utime.h># else# include <sys/time.h># endif# endif#else# include <sys/types.h># include <sys/system.h>#endif#include "globals.h"#include "decoders.h"#include "video.h"#include "util.h"#include "proto.h"#include "my_dmalloc.h"/* Declarations of functions. */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);static void ReconSkippedBlock(unsigned char *,unsigned char *,int,int,int,int,int,int,int,int);static void DoPictureDisplay(VidStream *);static int ParseSeqHead(VidStream *);static int ParseGOP(VidStream *);static int ParsePicture(VidStream *,TimeStamp);static int ParseSlice(VidStream *);static int ParseMacroBlock(VidStream *);static void ProcessSkippedPFrameMBlocks(VidStream *);static void ProcessSkippedBFrameMBlocks(VidStream *);char *ditherFlags;/* 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;/* Max lum, chrom indices for illegal block checking. */static int lmaxx;static int lmaxy;static int cmaxx;static int cmaxy;/* * We use a lookup table to make sure values stay in the 0..255 range. * Since this is cropping (ie, x = (x < 0)?0:(x>255)?255:x; ), wee call this * table the "crop table". * MAX_NEG_CROP is the maximum neg/pos value we can handle. */#define MAX_NEG_CROP 384#define NUM_CROP_ENTRIES (256+2*MAX_NEG_CROP)#define assertCrop(x) assert(((x) >= -MAX_NEG_CROP) && \ ((x) <= 256+MAX_NEG_CROP))static unsigned char cropTbl[NUM_CROP_ENTRIES];/* *-------------------------------------------------------------- * * 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 crop table. */ for (i = (-MAX_NEG_CROP); i < NUM_CROP_ENTRIES - MAX_NEG_CROP; i++) { if (i <= 0) { cropTbl[i + MAX_NEG_CROP] = 0; } else if (i >= 255) { cropTbl[i + MAX_NEG_CROP] = 255; } else { cropTbl[i + MAX_NEG_CROP] = i; } } /* 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. * *-------------------------------------------------------------- */voidDestroyVidStream(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]); astream->ring[i] = NULL; } } 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) unsigned int width, height;{ PictImage *new; /* Allocate memory space for new structure. */ new = (PictImage *) malloc(sizeof(PictImage)); /* Allocate memory for image spaces. */ if ((ditherType == Twox2_DITHER) || (ditherType == FULL_COLOR_DITHER)) { new->display = (unsigned char *) malloc(width * height * 4); } else { new->display = (unsigned char *) malloc(width * height); } 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. * *-------------------------------------------------------------- */voidDestroyPictImage(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); } free(apictimage);}/* *-------------------------------------------------------------- * * 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. * * Note that multiple calls to mpegVidRsrc are required * decode each frame in the movie. When mpegVidRsrc has * determined that it has decoded a single frame, it calls * DoPictureDisplay(), which converts from YUV space to RGB * space and then calls ExecuteDisplay(). ExecuteDisplay() * is passed the currently-being-decoded video stream, which * has a field called current (a pointer to a PictImage) * which in turn points to the raw image data in some * X-friendly RGB format. * * When the last frame has been decoded, mpegVidRsrc calls * ExecuteDisplay() one last time (if necessary), destroys * the video stream, and returns NULL. * * Results: * A pointer to the video stream structure used, or NULL * if the last frame has just been finished. * * 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 num_calls = 0; unsigned int data; int i, status; long int ftell (FILE *stream); /* 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; bitOffset = curVidStream->bit_offset;#ifdef UTIL2 curBits = *curVidStream->buffer << bitOffset;#else curBits = *curVidStream->buffer;#endif 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 (num_calls == 0) { next_start_code(); show_bits32(data); if (data != SEQ_START_CODE) { fprintf(stderr, "This is not an MPEG stream."); DestroyVidStream(curVidStream); exit(1); } num_calls++; } /* 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. */ mpeg_debug (("mpegVidRsrc: offset %6ld: found ", ftell (input))); switch (data) { case SEQ_END_CODE: /* Display last frame. */ mpeg_debug (("SEQ_END_CODE\n"));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -