/*************************************************************************** * 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 #endif #include #include #include #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 [ ]\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; }