blob: a34a7a0872210c80065679926bbb4c41a260cbb1 [file] [log] [blame]
/* #define DEBUG */
/* subspic.c, Frame buffer substitution routines */
/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */
/*
* Disclaimer of Warranty
*
* These software programs are available to the user without any license fee or
* royalty on an "as is" basis. The MPEG Software Simulation Group disclaims
* any and all warranties, whether express, implied, or statuary, including any
* implied warranties or merchantability or of fitness for a particular
* purpose. In no event shall the copyright-holder be liable for any
* incidental, punitive, or consequential damages of any kind whatsoever
* arising from the use of these programs.
*
* This disclaimer of warranty extends to the user of these programs and user's
* customers, employees, agents, transferees, successors, and assigns.
*
* The MPEG Software Simulation Group does not represent or warrant that the
* programs furnished hereunder are free of infringement of any third-party
* patents.
*
* Commercial implementations of MPEG-1 and MPEG-2 video, including shareware,
* are subject to royalty fees to patent holders. Many of these patents are
* general enough such that they are unavoidable regardless of implementation
* design.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include "config.h"
#include "global.h"
/* private prototypes*/
static void Read_Frame _ANSI_ARGS_((char *filename,
unsigned char *frame_buffer[], int framenum));
static void Copy_Frame _ANSI_ARGS_((unsigned char *src, unsigned char *dst,
int width, int height, int parity, int incr));
static int Read_Components _ANSI_ARGS_ ((char *filename,
unsigned char *frame[3], int framenum));
static int Read_Component _ANSI_ARGS_ ((char *fname, unsigned char *frame,
int width, int height));
static int Extract_Components _ANSI_ARGS_ ((char *filename,
unsigned char *frame[3], int framenum));
/* substitute frame buffer routine */
void Substitute_Frame_Buffer (bitstream_framenum, sequence_framenum)
int bitstream_framenum;
int sequence_framenum;
{
/* static tracking variables */
static int previous_temporal_reference;
static int previous_bitstream_framenum;
static int previous_anchor_temporal_reference;
static int previous_anchor_bitstream_framenum;
static int previous_picture_coding_type;
static int bgate;
/* local temporary variables */
int substitute_display_framenum;
#ifdef DEBUG
printf("SUB: seq fn(%d) bitfn(%d) tempref(%d) picstr(%d) type(%d)\n",
sequence_framenum, bitstream_framenum, temporal_reference,
picture_structure, picture_coding_type);
#endif
/* we don't substitute at the first picture of a sequence */
if((sequence_framenum!=0)||(Second_Field))
{
/* only at the start of the frame */
if ((picture_structure==FRAME_PICTURE)||(!Second_Field))
{
if(picture_coding_type==P_TYPE)
{
/* the most recently decoded reference frame needs substituting */
substitute_display_framenum = bitstream_framenum - 1;
Read_Frame(Substitute_Picture_Filename, forward_reference_frame,
substitute_display_framenum);
}
/* only the first B frame in a consequitve set of B pictures
loads a substitute backward_reference_frame since all subsequent
B frames predict from the same reference pictures */
else if((picture_coding_type==B_TYPE)&&(bgate!=1))
{
substitute_display_framenum =
(previous_temporal_reference - temporal_reference)
+ bitstream_framenum - 1;
Read_Frame(Substitute_Picture_Filename, backward_reference_frame,
substitute_display_framenum);
}
} /* P fields can predict from the two most recently decoded fields, even
from the first field of the same frame being decoded */
else if(Second_Field && (picture_coding_type==P_TYPE))
{
/* our favourite case: the IP field picture pair */
if((previous_picture_coding_type==I_TYPE)&&(picture_coding_type==P_TYPE))
{
substitute_display_framenum = bitstream_framenum;
}
else /* our more generic P field picture pair */
{
substitute_display_framenum =
(temporal_reference - previous_anchor_temporal_reference)
+ bitstream_framenum - 1;
}
Read_Frame(Substitute_Picture_Filename, current_frame, substitute_display_framenum);
}
#ifdef DEBUG
else if((picture_coding_type!=B_TYPE)||(picture_coding_type!=D_TYPE))
{
printf("NO SUBS FOR THIS PICTURE\n");
}
#endif
}
/* set b gate so we don't redundantly load next time around */
if(picture_coding_type==B_TYPE)
bgate = 1;
else
bgate = 0;
/* update general tracking variables */
if((picture_structure==FRAME_PICTURE)||(!Second_Field))
{
previous_temporal_reference = temporal_reference;
previous_bitstream_framenum = bitstream_framenum;
}
/* update reference frame tracking variables */
if((picture_coding_type!=B_TYPE) &&
((picture_structure==FRAME_PICTURE)||Second_Field))
{
previous_anchor_temporal_reference = temporal_reference;
previous_anchor_bitstream_framenum = bitstream_framenum;
}
previous_picture_coding_type = picture_coding_type;
}
/* Note: fields are only read to serve as the same-frame reference for
a second field */
static void Read_Frame(fname,frame,framenum)
char *fname;
unsigned char *frame[];
int framenum;
{
int parity;
int rerr = 0;
int field_mode;
if(framenum<0)
printf("ERROR: framenum (%d) is less than zero\n", framenum);
if(Big_Picture_Flag)
rerr = Extract_Components(fname, substitute_frame, framenum);
else
rerr = Read_Components(fname, substitute_frame, framenum);
if(rerr!=0)
{
printf("was unable to substitute frame\n");
}
/* now copy to the appropriate buffer */
/* first field (which we are attempting to substitute) must be
of opposite field parity to the current one */
if((Second_Field)&&(picture_coding_type==P_TYPE))
{
parity = (picture_structure==TOP_FIELD ? 1:0);
field_mode = (picture_structure==FRAME_PICTURE ? 0:1);
}
else
{
/* Like frame structued pictures, B pictures only substitute an entire frame
since both fields always predict from the same frame (with respect
to forward/backwards directions) */
parity = 0;
field_mode = 0;
}
Copy_Frame(substitute_frame[0], frame[0], Coded_Picture_Width,
Coded_Picture_Height, parity, field_mode);
Copy_Frame(substitute_frame[1], frame[1], Chroma_Width, Chroma_Height,
parity, field_mode);
Copy_Frame(substitute_frame[2], frame[2], Chroma_Width, Chroma_Height,
parity, field_mode);
#ifdef VERBOSE
if(Verbose_Flag > NO_LAYER)
printf("substituted %s %d\n",
(field_mode ? (parity?"bottom field":"bottom field"):"frame"), framenum);
#endif
}
static int Read_Components(filename, frame, framenum)
char *filename;
unsigned char *frame[3];
int framenum;
{
int err = 0;
char outname[FILENAME_LENGTH];
char name[FILENAME_LENGTH];
sprintf(outname,filename,framenum);
sprintf(name,"%s.Y",outname);
err += Read_Component(name, frame[0], Coded_Picture_Width,
Coded_Picture_Height);
sprintf(name,"%s.U",outname);
err += Read_Component(name, frame[1], Chroma_Width, Chroma_Height);
sprintf(name,"%s.V",outname);
err += Read_Component(name, frame[2], Chroma_Width, Chroma_Height);
return(err);
}
static int Read_Component(Filename, Frame, Width, Height)
char *Filename;
unsigned char *Frame;
int Width;
int Height;
{
int Size;
int Bytes_Read;
int Infile;
Size = Width*Height;
#ifdef DEBUG
printf("SUBS: reading %s\n", filename);
#endif
if(!(Infile=open(Filename,O_RDONLY|O_BINARY))<0)
{
printf("ERROR: unable to open reference filename (%s)\n", Filename);
return(-1);
}
Bytes_Read = read(Infile, Frame, Size);
if(Bytes_Read!=Size)
{
printf("was able to read only %d bytes of %d of file %s\n",
Bytes_Read, Size, Filename);
}
close(Infile);
return(0);
}
/* optimization: do not open the big file each time. Open once at start
of decoder, and close at the very last frame */
/* Note: "big" files were used in E-mail exchanges almost exclusively by the
MPEG Committee's syntax validation and conformance ad-hoc groups from
the year 1993 until 1995 */
static int Extract_Components(filename, frame, framenum)
char *filename;
unsigned char *frame[3];
int framenum;
{
/* int err = 0; */
FILE *fd;
int line;
int size, offset;
if (!(fd = fopen(filename,"rb")))
{
sprintf(Error_Text,"Couldn't open %s\n",filename);
return(-1);
}
/* compute size of each frame (in bytes) */
size = (Coded_Picture_Width*Coded_Picture_Height);
if(chroma_format==CHROMA444)
size = (size * 3);
else if(chroma_format==CHROMA422)
size = (size * 2);
else if(chroma_format==CHROMA420)
size = ((size*3)>>1);
else
printf("ERROR: chroma_format (%d) not recognized\n", chroma_format);
/* compute distance into "big" file */
offset = size*framenum;
#ifdef DEBUG
printf("EXTRACTING: frame(%d) offset(%d), size (%d) from %s\n",
framenum, offset, size, filename);
#endif
/* seek to location in big file where desired frame begins */
/* note: this offset cannot exceed a few billion bytes due to the */
/* obvious limitations of 32-bit integers */
fseek(fd, offset, 0);
/* Y */
for (line=0; line<Coded_Picture_Height; line++)
{
fread(frame[0]+(line*Coded_Picture_Width),1,Coded_Picture_Width,fd);
}
/* Cb */
for (line=0; line<Chroma_Height; line++)
{
fread(frame[1]+(line*Chroma_Width),1,Chroma_Width,fd);
}
/* Cr */
for (line=0; line<Chroma_Height; line++)
{
fread(frame[2]+(line*Chroma_Width),1,Chroma_Width,fd);
}
fclose(fd);
return(0);
}
static void Copy_Frame(src, dst, width, height, parity, field_mode)
unsigned char *src;
unsigned char *dst;
int width;
int height;
int parity; /* field parity (top or bottom) to overwrite */
int field_mode; /* 0 = frame, 1 = field */
{
int row, col;
int s, d;
int incr;
s = d = 0;
#ifdef DEBUG
printf("COPYING (w=%d, h=%d, parity=%d, field_mode=%d)\n",
width,height,parity,field_mode);
#endif /* DEBUG */
if(field_mode)
{
incr = 2;
if(parity==0)
s += width;
}
else
{
incr = 1;
}
for(row=0; row<height; row+=incr)
{
for(col=0; col<width; col++)
{
dst[d+col] = src[s+col];
}
d += (width*incr);
s += (width*incr);
}
}