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;
}