All pastes #486277 Raw Edit

Miscellany

public text v1 · immutable
·published 2007-05-13 20:47 UTC
rendered paste body
/***************************************************************************
 *   Copyright (C) 2007 by Nicholas Thomas                                 *
 *   nick@lupine.me.uk                                                     *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
 
 
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#define OUTPUT_FPS		25	// We output at 25fps, non-interlaced. TODO: make this CLI configurable (implies switch to getopts)
#define OUTPUT_MS_PER_FRAME	1000 / OUTPUT_FPS
 
#define ERR_NONE		0
#define ERR_CMD_ARGS		1
#define ERR_IO			2
 
typedef struct 
{
	u_int32_t x;
	u_int32_t y;
	u_int32_t width;
	u_int32_t height;
	u_int8_t ***data;
} InputRect;
 
typedef struct 
{
	u_int32_t delta_t;
	u_int32_t num_rects;
	InputRect *rects;
} InputFrame;
 
 
void bail(const char *error_message, int retval)
{
	fprintf(stderr, error_message);
	fcloseall();
	exit(retval);
}
 
inline int read8(FILE *data, u_int8_t *buf)
{
	if (fread(buf, sizeof(u_int8_t), 1, data) != 1) 
		return ERR_IO;
	else return ERR_NONE;
}
 
inline int read32(FILE *data, u_int32_t *buf)
{
	if (fread(buf, sizeof(u_int32_t), 1, data) != 1) 
		return ERR_IO;
	else return ERR_NONE;
}
 
// Reads header information from the file.
int getHeader(FILE *data, u_int32_t *height, u_int32_t *width)
{
	read32(data, width);
	read32(data, height);
}
 
// This function writes the frame to output as YUV data.
int writeOutputFrame(FILE *output, u_int8_t ***data, u_int32_t width, u_int32_t height)
{
	// TODO: Error checking
	// 	YUV values apparently need clamping to the 0-255 range
	// In this function, we need to convert from RGBA, upside-down left to right pixel data to
	// YUV format
	u_int8_t *Ys;
	u_int8_t *Us;
	u_int8_t *Vs;
	unsigned long x, y;
	long temp;
 
	Ys = malloc(sizeof(u_int8_t) * width * height);
 
//	Us = malloc((sizeof(u_int8_t) * width * height) / 4);
//	Vs = malloc((sizeof(u_int8_t) * width * height) / 4);
	for (x = 0; x < width; x++)	// Don't forget, our data are bottom-to-top
		for(y = 0; y < height; y++) // Magic conversion factors
		{
			Ys[(y*width)+x] = (0.257 * data[x][y][0]) +     		// R
				  (0.504 * data[x][y][1]) +     		// G
				  (0.098 * data[x][y][2]) + 16;  		// B
/*
			Ys[(y*width)+x] = (0.257 * data[(y*width*4) + (x*4) + 0]) +     		// R
				  (0.504 * data[(y*width*4) + (x*4) + 1]) +     		// G
				  (0.098 * data[(y*width*4) + (x*4) + 2]) + 16;  		// B
*/
/*
			// Only execute the below  code for 1/4 of the pixels. Even only.
			if (y% 2 ==0 && x % 2 == 0 && y +1 != height)
			{
				Us[((y/2)*(width/2))+(x/2)] = ((-(0.148 * data[(y*width*4) + (x*4) + 0]) - 		// R
	                                             (0.291 * data[(y*width*4) + (x*4) + 1]) + 			// G
	                                             (0.439 * data[(y*width*4) + (x*4) + 2]) + 128) +		// B 
 
						   (-(0.148 * data[(y*width*4) + ((x+1)*4) + 0]) - 		// R
						     (0.291 * data[(y*width*4) + ((x+1)*4) + 1]) + 		// G
						     (0.439 * data[(y*width*4) + ((x+1)*4) + 2]) + 128) +	// B 
 
						   (-(0.148 * data[((y+1)*width*4) + (x*4) + 0]) - 	// R
						     (0.291 * data[((y+1)*width*4) + (x*4) + 1]) + 	// G
						     (0.439 * data[((y+1)*width*4) + (x*4) + 2]) + 128) +	// B 
 
						   (-(0.148 * data[((y+1)*width*4) + ((x+1)*4) + 0]) - 	// R
						     (0.291 * data[((y+1)*width*4) + ((x+1)*4) + 1]) + 	// G
						     (0.439 * data[((y+1)*width*4) + ((x+1)*4) + 2]))) / 4;	// B 
 
				Vs[((y/2)*(width/2))+(x/2)] =  (((0.439 * data[(y*width*4) + (x*4) + 0]) - 			// R
						     (0.368 * data[(y*width*4) + (x*4) + 1]) - 			// G 
						     (0.071 * data[(y*width*4) + (x*4) + 2]) + 128) +		// B
 
						    ((0.439 * data[(y*width*4) + ((x+1)*4) + 0]) - 		// R
						     (0.368 * data[(y*width*4) + ((x+1)*4) + 1]) - 		// G 
						     (0.071 * data[(y*width*4) + ((x+1)*4) + 2]) + 128) +	// B
 
						    ((0.439 * data[((y+1)*width*4) + (x*4) + 0]) - 		// R
						     (0.368 * data[((y+1)*width*4) + (x*4) + 1]) - 		// G 
						     (0.071 * data[((y+1)*width*4) + (x*4) + 2]) + 128) +	// B
 
						    ((0.439 * data[((y+1)*width*4) + ((x+1)*4) + 0]) - 		// R
						     (0.368 * data[((y+1)*width*4) + ((x+1)*4) + 1]) - 		// G 
						     (0.071 * data[((y+1)*width*4) + ((x+1)*4) + 2]) + 128))/4; // B 
			}*/
		} 
 
	fwrite(Ys, sizeof(u_int8_t), height * width, output);
//	fwrite(Us, sizeof(u_int8_t), (height * width)/4, output);
//	fwrite(Vs, sizeof(u_int8_t), (height * width)/4, output);
 
	free(Ys);
//	free(Us);
//	free(Vs);
	return ERR_NONE;
}
 
int readInputRect(FILE *input, InputRect *rect)
{
	unsigned long n, x, y;
	// TODO: Error checking
	// These read correctly
	read32(input, &rect->x);
	read32(input, &rect->y);
	read32(input, &rect->width);
	read32(input, &rect->height);
	fprintf(stderr, "New rect. delta x: %i; y: %i; width: %i; height: %i\n", rect->x, rect->y, rect->width, rect->height);
 
	rect->data = malloc(rect->width * sizeof(u_int8_t **)); // NOTE: 4 due to RGBA
 
	for (x = 0; x < rect->width; x++) 
	{
		rect->data[x] = malloc(rect->height * sizeof(u_int8_t *));
		for (y = 0; y < rect->height; y++) 
			rect->data[x][y] = malloc(4 * sizeof(u_int8_t));
	}
 
	for (x = 0; y < rect->width; x++)
		for (y = 0; y < rect->height; y++)
		{
			fread(&rect->data[x][y][0], sizeof(u_int8_t), 1, input);
			fread(&rect->data[x][y][1], sizeof(u_int8_t), 1, input);
			fread(&rect->data[x][y][2], sizeof(u_int8_t), 1, input);
			fread(&rect->data[x][y][3], sizeof(u_int8_t), 1, input);
		}
	return ERR_NONE;
}
 
int readInputFrame(FILE *input, InputFrame *buf)
{
	unsigned long n;
	// TODO: Error checking
	read32(input, &buf->delta_t);
	read32(input, &buf->num_rects);
	fprintf(stderr, "New frame. delta t: %i; number of rects: %i\n", buf->delta_t, buf->num_rects);
	buf->rects = (InputRect *) malloc(sizeof(InputRect) * buf->num_rects);
 
	for (n = 0; n < buf->num_rects; n++)
		readInputRect(input, &buf->rects[n]);
 
	return ERR_NONE;
}
 
int applyInputFrame(u_int8_t ***raw_frame, InputFrame *data, u_int32_t frame_height, u_int32_t frame_width)
{
	// TODO: Error-checking
	unsigned long i, j, x, y;
 
	for (i = 0; i < data->num_rects; i++)
	{
		InputRect *rect = &data->rects[i];
 
		for (x = 0; y < rect->width; x++)
			for (y = 0; y < rect->height; y++)
			{
				raw_frame[x+rect->x][y+rect->y][0] = rect->data[x][y][0];
				raw_frame[x+rect->x][y+rect->y][1] = rect->data[x][y][1];
				raw_frame[x+rect->x][y+rect->y][2] = rect->data[x][y][2];
				raw_frame[x+rect->x][y+rect->y][3] = rect->data[x][y][3];
			}
/*
		for (y = 0; y < rect->height; y++)
			memcpy(&raw_frame[((rect->y + y) * frame_width * 4) + (rect->x * 4)], &rect->data[y * rect->width * 4], sizeof(u_int8_t) * rect->width * 4);
*/
// 		memcpy(raw_frame, rect->data, sizeof(u_int8_t) * rect->height * rect->width * 4);
/*
		for (j = 0; j < rect->height; j++)
		{
			int rect_line = rect->y + j;
			int frame_line = (frame_height -1) - rect_line;
 
			u_int8_t *raw_frame_line = raw_frame + 4 * frame_width * frame_line;	// go to the correct line of the frame.
			u_int8_t *rect_data_line = rect->data + 4 * rect->width * j;		// go to the correct line of the rect data.
 
			memcpy(raw_frame_line + 4 * rect->x, rect_data_line, sizeof(u_int8_t) * rect->width * 4);
		}*/
	}
}
 
int freeInputFrame(InputFrame *frame)
{
	//TODO: Error-checking
	unsigned long n, x, y;
	for (n = 0; n < frame->num_rects; n++)
		for (x = 0; x < frame->rects[n].width; x++) 
		{
			for (y = 0; y < frame->rects[n].height; y++) 
				free(frame->rects[n].data[x][y]);
			free(frame->rects[n].data[x]);
		}
//		free(frame->rects[n].data);
 
	free(frame->rects);
}
 
int main(int argc, char *argv[])
{
	FILE *input;
	FILE *output;
	int err, x, y;
	unsigned long n;
	char *s;
 
	unsigned long current_input_video_time = 0;
	unsigned long outputted_frames = 0;
 
	InputFrame input_buf;
 
	u_int8_t ***raw_frame;  // The full frame at current_input_video_time
	u_int32_t video_height = 0;
	u_int32_t video_width = 0;
 
 
 
	switch (argc)
	{
		case 1: // Where no command-line arguments are given, assume input from stdin and output from stdout
		{
			input = stdin; 
			output = stdout;
		} 
		break;
		case 3: // If input is specified, output must also be specified as rsc2raw input_file output_file
		{
			input = fopen(argv[1], "r");
			output = fopen(argv[2], "w");
		}
		break;
		default: // Bail out with an error.
		{
			fprintf(stderr, "Failure parsing command-line arguments.\n");
			fprintf(stderr, "Format: rsc2raw [<inputfile> <outputfile>]\n");
			fprintf(stderr, "Running \"rsc2raw\" with no arguments results in processing from stdin to stdout\n");
			fcloseall();
			exit(ERR_CMD_ARGS);
		};
		break;
	}
 
	// Check assignment worked properly 
	if (input == NULL || output == NULL) 
		exit(ERR_IO);
 
	err = getHeader(input, &video_width, &video_height);
	if (err != ERR_NONE) 
		bail("Failure reading header - probably an invalid input file.\n", err);
 
	raw_frame = malloc(video_width * sizeof(u_int8_t **));
	for (x = 0; x < video_width; x++) 
	{
		raw_frame[x] = malloc(video_height * sizeof(u_int8_t *));
		for (y = 0; y < video_height; y++) 
			raw_frame[x][y] = malloc(4 * sizeof(u_int8_t)); // NOTE: 4 due to RGBA
	}
 
	// Now keep going until we either run out of input or hit an error.
	while(feof(input) == 0)
	{
		int i_err = ferror(input);
		int o_err = ferror(output);
		if (i_err != 0 || o_err != 0)
			fprintf(stderr, "Error occured reading/writing last frame! i: %i; o: %i\n", i_err, o_err);
 
		// We want to output a new frame every (1000/OUTPUT_FPS) 40 ms. Our input frames have variable delta time
		while (current_input_video_time < outputted_frames * OUTPUT_MS_PER_FRAME)
		{
			// TODO: Error-checking
			readInputFrame(input, &input_buf);
			applyInputFrame(raw_frame, &input_buf, video_height, video_width);
			current_input_video_time += input_buf.delta_t;
			freeInputFrame(&input_buf);
		}
		writeOutputFrame(output, raw_frame, video_width, video_height);
		outputted_frames++;
	}
 
	// TODO: Full memory deallocation
	for (x = 0; x < video_width; x++) 
	{
		for (y = 0; y < video_height; y++) 
			free(raw_frame[x][y]);
		free(raw_frame[x]);
	}
	free(raw_frame);
 
	fcloseall();
	return ERR_NONE;
}