All pastes #486484 Raw Edit

Miscellany

public text v1 · immutable
·published 2007-05-13 22:21 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 *width, u_int32_t *height)
{
	read32(data, width);
	read32(data, height);
}
 
int init(int argc, char *argv[], FILE *input, FILE *output)
{
 
}
 
// 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 (y = 0; y < height; y++)	// Don't forget, our data are bottom-to-top
		for(x = 0; x < width; x++) // Magic conversion factors
			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
 
 

			if ((y % 2 == 0 && x % 2 == 0)
			{
				Us[((y*width)+x)/4]=((-(0.148 * data[(y*width*4) + (x*4) + 0]) - 			// R
	                                               (0.291 * data[(y*width*4) + (x*4) + 1]) + 			// G
	                                               (0.439 * (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]) + 128)) / 4;	// B 
				
 
				Vs[((y*width) + x)/4]=(((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 *buf)
{
	unsigned long n;
	// TODO: Error checking
	// These read correctly
	read32(input, &buf->x);
	read32(input, &buf->y);
	read32(input, &buf->width);
	read32(input, &buf->height);
	fprintf(stderr, "New rect. delta x: %i; y: %i; width: %i; height: %i\n", buf->x, buf->y, buf->width, buf->height);
	buf->data = malloc(sizeof(u_int8_t) * buf->height * buf->width * 4); // NOTE: *4 because data is RGBA.
	fread(buf->data, sizeof(u_int8_t), buf->height * buf->width * 4, 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_width, u_int32_t frame_height)
{
	// TODO: Error-checking
	unsigned long i, j, k;
	
	for (i = 0; i < data->num_rects; i++)
	{
		InputRect *rect = &data->rects[i];
		
		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;
	for (n = 0; n < frame->num_rects; n++)
		free(frame->rects[n].data);
 
	free(frame->rects);
}
 
int main(int argc, char *argv[])
{
	FILE *input;
	FILE *output;
	int err;
	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(sizeof(u_int8_t) * video_height * video_width * 4); // 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_width, video_height);
			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
	free(raw_frame);
	fcloseall();
	return ERR_NONE;
}