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*x)%4 == 0)
{
temp = ((-(0.148 * data[y*x*4 + 0]) - // R
(0.291 * data[y*x*4 + 1]) + // G
(0.439 * data[y*x*4 + 2]) + 128) + // B
(-(0.148 * data[y*(x+1)*4 + 0]) - // R
(0.291 * data[y*(x+1)*4 + 1]) + // G
(0.439 * data[y*(x+1)*4 + 2]) + 128) + // B
(-(0.148 * data[(y+1)*x*4 + 0]) - // R
(0.291 * data[(y+1)*x*4 + 1]) + // G
(0.439 * data[(y+1)*x*4 + 2]) + 128) + // B
(-(0.148 * data[(y+1)*(x+1)*4 + 0]) - // R
(0.291 * data[(y+1)*(x+1)*4 + 1]) + // G
(0.439 * data[(y+1)*(x+1)*4 + 2]) + 128)) / 4; // B
if (temp < 0) temp = 0; if (temp > 255) temp = 255; Us[(y*x)/4] = temp;
temp = (((0.439 * data[y*x*4 + 0]) - // R
(0.368 * data[y*x*4 + 1]) - // G
(0.071 * data[y*x*4 + 2]) + 128) + // B
((0.439 * data[y*(x+1)*4 + 0]) - // R
(0.368 * data[y*(x+1)*4 + 1]) - // G
(0.071 * data[y*(x+1)*4 + 2]) + 128) + // B
((0.439 * data[(y+1)*x*4 + 0]) - // R
(0.368 * data[(y+1)*x*4 + 1]) - // G
(0.071 * data[(y+1)*x*4 + 2]) + 128) + // B
((0.439 * data[(y+1)*(x+1)*4 + 0]) - // R
(0.368 * data[(y+1)*(x+1)*4 + 1]) - // G
(0.071 * data[(y+1)*(x+1)*4 + 2]) + 128)) / 4; // B
if (temp < 0) temp = 0; if (temp > 255) temp = 255; Vs[(y*x)/4] = temp;
}
}
*/
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;
}