APPENDIX G

Appendix G contains the code listing for the test program referred to in Chapter 6.

//****************************************************************

// Written by Hu Imm Lee

// Filename: FrameDropper.c

// Program name: FrameDropper --

// + Intentionally drops frames of type specified by user

// + Significantly alters the MPEG stream to exclude a picture-type

// + Program DOES NOT allow you to DROP the I-FRAME picture

// type

// + MPEG stream is consequently sped up due to the loss of frames

//

// Input: input filename, picture type

// Output: new (altered) MPEG file, "output.mpg"

//

// Last Modified: September 16, 1997

//****************************************************************

#include <windows.h>

#include <stdio.h>

#include <errno.h> // errno

#include <io.h> // _open

#include <fcntl.h> // _open

#include <sys/stat.h> // _open

// system start codes

#define PACK_START_CODE 0x000001ba

#define SYSTEM_HEADER_START_CODE 0x000001bb

#define ISO_11172_END_CODE 0x000001b9

// video start codes

#define PICTURE_START_CODE 0x00000100

#define SEQUENCE_HEADER_CODE 0x000001b3

#define SEQUENCE_END_CODE 0x000001b7

#define GROUP_START_CODE 0x000001b8

// frame types

#define FORBIDDEN_FRAME 0

#define I_FRAME 1

#define P_FRAME 2

#define B_FRAME 3

#define D_FRAME 4

// prototypes

void docheck(unsigned int drop_frame_type);

void drop();

int getbits(int n);

int nextbits(int n);

void next_start_code(int outstream);

// globals

int fd;

BYTE byteword;

int bit_ptr=0; //bits manipulation var, 'pointer' to curBits

unsigned int curBits=0x00000000; //buffer for 'leftover' bits during bits manipulation

BOOLEAN end_of_file = FALSE;

// debugging purposes

int framecount=0,droppedframe=0;

void main(int argc, char *argv[]) {

unsigned frame_type;

char filepath[20];

if (argc <= 1) {

printf("usage: FrameDropper [filename] [frame_type] \n");

return;

}

else {

strcpy(filepath, argv[1]);

if ( strcmp(argv[2], "B") == 0 ) {

printf("Program will drop B frames from MPEG file\n");

frame_type = B_FRAME;

}

else if ( strcmp(argv[2], "P") == 0 ) {

printf("Program will drop B frames from MPEG file\n");

frame_type = P_FRAME;

}

else printf("Invalid frame type!\n");

}

fd = _open(filepath, _O_RDONLY|_O_BINARY);

if (fd < 0) {

printf("ERRNO: %d\n", errno);

return;

}

docheck(frame_type);

printf("Dropped [%d] frames of a total of [%d] frames\n",

droppedframe, framecount);

}

// =========================================================

// docheck --

// + locates a frame in the stream

// + determines whether a frame gets dropped or not

// + ignores "unwanted" frames and writes the rest to file in

// in original stream order

// =========================================================

void docheck(unsigned int drop_frame_type) {

unsigned int frame_type = 0x00000000, code;

int outfd, nwrite, i;

unsigned short stor; // 16 bits

BYTE bytecode;

// open an output file

outfd = _open("output.mpg", _O_WRONLY|_O_BINARY|_O_CREAT,

_S_IREAD|_S_IWRITE);

if (outfd < 0) {

printf("ERRNO: %d\n", errno);

return;

}

while (!end_of_file) {

// stumble onto a new start_code ...

// next_start_code should copy "unwanted" bytes into output stream

next_start_code(outfd);

// flush 32 bits and check for a frame

if ( (code = getbits(32)) == PICTURE_START_CODE ) {

framecount++;

// which frame?

stor = nextbits(16); // read word from left to right

// |__temporal ref 10-bits__|_pic-type 3-bits_|_remainder 3-

// bits_|

stor >>= 3;

frame_type = stor & 0x00000007;

if (frame_type == drop_frame_type) {

// don't write to output

droppedframe++;

drop();

}

else {

// write to output

// write in terms of BYTEs to simulate

// big-endian order

for (i=0; i < 4; i++) {

bytecode =

(BYTE) ( (code & 0xff000000) >> 24 );

code <<= 8;

nwrite = write( outfd, (char *)&bytecode,

sizeof(BYTE) );

if (nwrite < 0) {

printf("docheck: write errno [%d]\n",

errno);

return;

}

}

}

}

else { // if not picture_start_code, write to output

for (i=0; i < 4; i++) {

bytecode = (BYTE) ( (code & 0xff000000) >> 24 );

code <<= 8;

nwrite = write( outfd, (char *)&bytecode,

sizeof(BYTE) );

if (nwrite < 0) {

printf("docheck: write errno [%d]\n", errno);

return;

}

}

}

} // end while

}

// =========================================================

// drop --

// + Drops a frame

// - look for next picture_start_code/group_start_code without

// copying bytes (belonging to specified frame) into output

// =========================================================

void drop() {

int align_mode;

// check for byte-alignment

align_mode = bit_ptr % 8;

if (align_mode != 0) // if not byte-aligned

bit_ptr -= align_mode;

while ( !end_of_file &&

((nextbits(32) != PICTURE_START_CODE) &&

(nextbits(32) != GROUP_START_CODE)) )

getbits(8); // drop a byte till *_start_code is found

}

// =========================================================

// getbits --

// + reads n bits fr data stream and corrects the stream

// pointer, bit_ptr

// + flushes away bits already read

// + returns value of the first n bits read, -1 if EOF is reached

// =========================================================

int getbits(int n) {

unsigned int value;

int nread;

// if bits are in the buffer, no need to read fr stream if remaining bits

// > than n

if (bit_ptr >= n) {

value = curBits >> (bit_ptr-n);

// keep remaining bits, after reading value

curBits &= ~( 0xffffffff << (bit_ptr-n) );

bit_ptr -= n;

return value;

}

while (bit_ptr < n) {

// manipulate data stream into 'big-endian' order

// -- reading data into unsigned int's won't work on Intel x86s

nread = read(fd, (BYTE *)&byteword, sizeof(BYTE));

if (nread == 0) {

printf("EOF\n");

end_of_file = TRUE;

return -1;

}

else if (nread < 0) {

printf("read err: %d\n", errno);

exit(0);

}

bit_ptr += 8;

curBits = (curBits << 8) | byteword;

}

//extract value

value = curBits >> (bit_ptr-n);

// re-adjust pointer in curBits

curBits &= ~( 0xffffffff << (bit_ptr-n) );

bit_ptr -= n;

return value;

}

// =========================================================

// nextbits --

// + 'sniffs' bits at data stream

// + does not correct the bit_ptr

// + returns -1 if EOF is reached

// =========================================================

int nextbits(int n) {

int value, nread;

while (bit_ptr < n) {

nread = read(fd, (BYTE *)&byteword, sizeof(BYTE));

if (nread == 0) {

printf("EOF\n");

end_of_file = TRUE;

return -1;

}

else if (nread < 0) {

printf("read err: %d\n", errno);

exit(0);

}

bit_ptr += 8;

curBits = (curBits << 8) | byteword;

}

if (bit_ptr >= n) { // no need to read fr data stream

value = curBits >> bit_ptr-n;

return value;

}

}

// =========================================================

// next_start_code --

// + searches for the 24-bit start-code 0x000001

// + moves stream pointer (bit_ptr) to beginning of start-code

// + on return, it is required to call get_bits(32) to retrieve

// the start-code

//

// * modified to copy bytes into an output stream *

// =========================================================

void next_start_code(int outstream) {

int align_mode, state = -1;

BYTE output;

int nwrite;

// check for byte-alignment

align_mode = bit_ptr % 8;

if (align_mode != 0) // not byte-aligned

bit_ptr -= align_mode;

while (!end_of_file && (nextbits(24) != 0x000001)) {

output = getbits(8); // skip a byte till 0x000001 is found

// copy a byte into output

nwrite = write(outstream, (char *)&output, sizeof(BYTE));

if (nwrite < 0) {

printf("next_start_code: write errno [%d]\n", errno);

break;

}

}

return;

}