2013-07-14 20:38:55 +00:00
|
|
|
/* ***** BEGIN GPL LICENSE BLOCK *****
|
|
|
|
*
|
|
|
|
* Copyright 2008 Peter Schlaile
|
|
|
|
*
|
|
|
|
* This file is part of libredcode.
|
|
|
|
*
|
|
|
|
* Libredcode 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.
|
|
|
|
*
|
|
|
|
* Libredcode 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 Libredcode; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****/
|
|
|
|
|
2008-06-02 21:35:57 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "format.h"
|
|
|
|
|
|
|
|
struct red_reob {
|
2009-02-08 19:13:29 +00:00
|
|
|
unsigned int len;
|
|
|
|
unsigned int head;
|
2008-06-02 21:35:57 +00:00
|
|
|
|
2009-02-08 19:13:29 +00:00
|
|
|
unsigned int rdvo;
|
|
|
|
unsigned int rdvs;
|
|
|
|
unsigned int rdao;
|
|
|
|
unsigned int rdas;
|
2008-06-02 21:35:57 +00:00
|
|
|
|
2009-02-08 19:13:29 +00:00
|
|
|
unsigned int unknown1;
|
|
|
|
unsigned int unknown2;
|
|
|
|
unsigned int totlen;
|
2008-06-02 21:35:57 +00:00
|
|
|
|
2009-02-08 19:13:29 +00:00
|
|
|
unsigned int avgv;
|
|
|
|
unsigned int avgs;
|
2008-06-02 21:35:57 +00:00
|
|
|
|
2009-02-08 19:13:29 +00:00
|
|
|
unsigned int unknown3;
|
|
|
|
unsigned int unknown4;
|
|
|
|
unsigned int unknown5;
|
2008-06-02 21:35:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct redcode_handle {
|
|
|
|
FILE * fp;
|
|
|
|
struct red_reob * reob;
|
2009-02-08 19:13:29 +00:00
|
|
|
unsigned int * rdvo;
|
|
|
|
unsigned int * rdvs;
|
|
|
|
unsigned int * rdao;
|
|
|
|
unsigned int * rdas;
|
2008-06-02 21:35:57 +00:00
|
|
|
long cfra;
|
2009-02-08 09:07:36 +00:00
|
|
|
long length;
|
2008-06-02 21:35:57 +00:00
|
|
|
};
|
|
|
|
|
2009-02-08 19:13:29 +00:00
|
|
|
unsigned int read_be32(unsigned int val)
|
2009-02-08 09:07:36 +00:00
|
|
|
{
|
|
|
|
unsigned char * v = (unsigned char*) & val;
|
|
|
|
|
|
|
|
return (v[0] << 24) | (v[1] << 16) | (v[2] << 8) | v[3];
|
|
|
|
}
|
2008-06-02 21:35:57 +00:00
|
|
|
|
|
|
|
static unsigned char* read_packet(FILE * fp, char * expect)
|
|
|
|
{
|
2009-02-08 19:13:29 +00:00
|
|
|
unsigned int len;
|
2008-06-02 21:35:57 +00:00
|
|
|
char head[5];
|
|
|
|
unsigned char * rv;
|
|
|
|
|
|
|
|
fread(&len, 4, 1, fp);
|
|
|
|
fread(&head, 4, 1, fp);
|
|
|
|
|
|
|
|
head[4] = 0;
|
|
|
|
|
2009-02-08 09:07:36 +00:00
|
|
|
len = read_be32(len);
|
2008-06-02 21:35:57 +00:00
|
|
|
|
|
|
|
if (strcmp(expect, head) != 0) {
|
|
|
|
fprintf(stderr, "Read: %s, expect: %s\n", head, expect);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = (unsigned char*) malloc(len + 8);
|
|
|
|
|
|
|
|
memcpy(rv, &len, 4);
|
|
|
|
memcpy(rv + 4, &head, 4);
|
|
|
|
|
|
|
|
fread(rv + 8, len, 1, fp);
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2009-02-08 19:13:29 +00:00
|
|
|
static unsigned int * read_index_packet(FILE * fp, char * expect)
|
2008-06-02 21:35:57 +00:00
|
|
|
{
|
2009-02-08 19:13:29 +00:00
|
|
|
unsigned int * rv = (unsigned int*) read_packet(fp, expect);
|
2008-06-02 21:35:57 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!rv) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 2; i < rv[0]/4; i++) {
|
2009-02-08 09:07:36 +00:00
|
|
|
rv[i] = read_be32(rv[i]);
|
2008-06-02 21:35:57 +00:00
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct red_reob * read_reob(FILE * fp)
|
|
|
|
{
|
|
|
|
fseek(fp, -0x38, SEEK_END);
|
|
|
|
|
|
|
|
return (struct red_reob *) read_index_packet(fp, "REOB");
|
|
|
|
}
|
|
|
|
|
2009-02-08 19:13:29 +00:00
|
|
|
static unsigned int * read_index(FILE * fp, unsigned int i, char * expect)
|
2008-06-02 21:35:57 +00:00
|
|
|
{
|
|
|
|
fseek(fp, i, SEEK_SET);
|
|
|
|
|
2009-02-08 19:13:29 +00:00
|
|
|
return (unsigned int*) read_index_packet(fp, expect);
|
2008-06-02 21:35:57 +00:00
|
|
|
}
|
|
|
|
|
2009-02-08 19:13:29 +00:00
|
|
|
static unsigned char * read_data(FILE * fp, unsigned int i, char * expect)
|
2008-06-02 21:35:57 +00:00
|
|
|
{
|
|
|
|
fseek(fp, i, SEEK_SET);
|
|
|
|
|
|
|
|
return read_packet(fp, expect);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct redcode_handle * redcode_open(const char * fname)
|
|
|
|
{
|
|
|
|
struct redcode_handle * rv = NULL;
|
|
|
|
struct red_reob * reob = NULL;
|
2009-02-08 09:07:36 +00:00
|
|
|
int i;
|
2008-06-02 21:35:57 +00:00
|
|
|
|
|
|
|
FILE * fp = fopen(fname, "rb");
|
|
|
|
|
|
|
|
if (!fp) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
reob = read_reob(fp);
|
|
|
|
if (!reob) {
|
|
|
|
fclose(fp);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = (struct redcode_handle*) calloc(1, sizeof(struct redcode_handle));
|
|
|
|
|
|
|
|
rv->fp = fp;
|
|
|
|
rv->reob = reob;
|
|
|
|
rv->rdvo = read_index(fp, reob->rdvo, "RDVO");
|
|
|
|
rv->rdvs = read_index(fp, reob->rdvs, "RDVS");
|
|
|
|
rv->rdao = read_index(fp, reob->rdao, "RDAO");
|
|
|
|
rv->rdas = read_index(fp, reob->rdas, "RDAS");
|
|
|
|
|
|
|
|
if (!rv->rdvo || !rv->rdvs || !rv->rdao || !rv->rdas) {
|
|
|
|
redcode_close(rv);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-02-08 09:07:36 +00:00
|
|
|
for (i = 0; i < (rv->rdvo[0] - 8)/4; i++) {
|
|
|
|
if (rv->rdvo[i + 2]) {
|
|
|
|
rv->length = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-02 21:35:57 +00:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
void redcode_close(struct redcode_handle * handle)
|
|
|
|
{
|
|
|
|
if (handle->reob) {
|
|
|
|
free(handle->reob);
|
|
|
|
}
|
|
|
|
if (handle->rdvo) {
|
|
|
|
free(handle->rdvo);
|
|
|
|
}
|
|
|
|
if (handle->rdvs) {
|
|
|
|
free(handle->rdvs);
|
|
|
|
}
|
|
|
|
if (handle->rdao) {
|
|
|
|
free(handle->rdao);
|
|
|
|
}
|
|
|
|
if (handle->rdas) {
|
|
|
|
free(handle->rdas);
|
|
|
|
}
|
|
|
|
fclose(handle->fp);
|
|
|
|
free(handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
long redcode_get_length(struct redcode_handle * handle)
|
|
|
|
{
|
2009-02-08 09:07:36 +00:00
|
|
|
return handle->length;
|
2008-06-02 21:35:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct redcode_frame * redcode_read_video_frame(
|
|
|
|
struct redcode_handle * handle, long frame)
|
|
|
|
{
|
|
|
|
struct redcode_frame * rv;
|
|
|
|
unsigned char * data;
|
|
|
|
|
|
|
|
if (frame > handle->rdvo[0]/4 || handle->rdvo[frame + 2] == 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
data = read_data(handle->fp, handle->rdvo[frame + 2], "REDV");
|
|
|
|
if (!data) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = (struct redcode_frame*) calloc(1, sizeof(struct redcode_frame));
|
|
|
|
|
|
|
|
rv->offset = 12+8;
|
2009-02-08 19:13:29 +00:00
|
|
|
rv->length = *(unsigned int*)data - rv->offset;
|
2008-06-02 21:35:57 +00:00
|
|
|
rv->data = data;
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct redcode_frame * redcode_read_audio_frame(
|
|
|
|
struct redcode_handle * handle, long frame)
|
|
|
|
{
|
|
|
|
struct redcode_frame * rv;
|
|
|
|
unsigned char * data;
|
|
|
|
|
|
|
|
if (frame > handle->rdao[0]/4 || handle->rdao[frame + 2] == 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
data = read_data(handle->fp, handle->rdao[frame+2], "REDA");
|
|
|
|
if (!data) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = (struct redcode_frame*) calloc(1, sizeof(struct redcode_frame));
|
|
|
|
|
|
|
|
rv->offset = 24+8;
|
2009-02-08 19:13:29 +00:00
|
|
|
rv->length = *(unsigned int*)data - rv->offset;
|
2008-06-02 21:35:57 +00:00
|
|
|
rv->data = data;
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
void redcode_free_frame(struct redcode_frame * frame)
|
|
|
|
{
|
|
|
|
free(frame->data);
|
|
|
|
free(frame);
|
|
|
|
}
|