mirror of
https://github.com/OpenDriver2/REDRIVER2.git
synced 2024-11-25 20:02:33 +01:00
481856c02a
- disable ReadAVI verbosity
709 lines
20 KiB
C++
709 lines
20 KiB
C++
/*
|
|
* ReadAVI.cpp
|
|
*
|
|
*
|
|
* Copyright (c) 2004-2013, Michael Kohn <mike@mikekohn.net> http://www.mikekohn.net/
|
|
*
|
|
* Copyright (c) 2018, olegvedi@gmail.com (C++ implementation and adds)
|
|
*
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright notice, this
|
|
* list of conditions and the following disclaimer.
|
|
*
|
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* * Neither the name of the author nor the names of its contributors may be
|
|
* used to endorse or promote products derived from this software without
|
|
* specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
|
|
#include "ReadAVI.h"
|
|
|
|
#include <iostream>
|
|
#include <string.h>
|
|
|
|
#define ZEROIZE(x) {memset(&x, 0, sizeof(x));}
|
|
|
|
using namespace std;
|
|
|
|
// #define VERBOSE
|
|
#define DBG_LVL_DEF 0
|
|
|
|
#ifdef VERBOSE
|
|
#define MSG_DBG(dl, format, ...) {if(dl <= DBG_LVL_DEF ) fprintf(stdout, format ,##__VA_ARGS__);}
|
|
#else
|
|
#define MSG_DBG(dl, format, ...)
|
|
#endif
|
|
|
|
ReadAVI::chunk_type_int_t ReadAVI::chunk_types[ChunkTypesCnt] = {
|
|
{"db", ctype_uncompressed_video_frame },
|
|
{"dc", ctype_compressed_video_frame },
|
|
{"pc", ctype_palette_change },
|
|
{"wb", ctype_audio_data } };
|
|
|
|
ReadAVI::ReadAVI(const char* filename)
|
|
{
|
|
data_buf = NULL;
|
|
stream_format_vid.palette = NULL;
|
|
data_buf_size = 0;
|
|
//inFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
|
inFile.open(filename, ios_base::ate | ios_base::in | ios_base::binary);
|
|
|
|
fileSize = inFile.tellg();
|
|
inFile.close();
|
|
inFile.open(filename, ios_base::in | ios_base::binary);
|
|
|
|
|
|
try {
|
|
parse_riff();
|
|
}
|
|
catch (std::system_error& e) { //file corrupted?
|
|
std::cerr << e.code().message().c_str() << "\n";
|
|
if (index_entries.size() == 0) {
|
|
free();
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
|
|
ReadAVI::~ReadAVI()
|
|
{
|
|
free();
|
|
}
|
|
|
|
void ReadAVI::free()
|
|
{
|
|
if (inFile.is_open()) {
|
|
inFile.close();
|
|
}
|
|
|
|
delete[] stream_format_vid.palette;
|
|
delete[] data_buf;
|
|
}
|
|
|
|
void ReadAVI::check_data_buf(unsigned size)
|
|
{
|
|
if (data_buf_size < size) {
|
|
delete[] data_buf;
|
|
data_buf = new unsigned char[size + 1];
|
|
data_buf_size = size;
|
|
}
|
|
}
|
|
|
|
int ReadAVI::GetFrameFromIndex(frame_entry_t* frame_entry)
|
|
{
|
|
if (frame_entry->pointer >= index_entries.size()) {
|
|
MSG_DBG(2, "Pointer out of range\n");
|
|
return -5;
|
|
}
|
|
for (unsigned i = frame_entry->pointer; i < index_entries.size(); i++) {
|
|
if (index_entries[i].type & frame_entry->type) {
|
|
check_data_buf(index_entries[i].dwChunkLength);
|
|
try {
|
|
inFile.seekg(index_entries[i].dwChunkOffset, ios_base::beg);
|
|
read_chars_bin(data_buf, index_entries[i].dwChunkLength);
|
|
}
|
|
catch (...) {
|
|
return -1;
|
|
}
|
|
frame_entry->buf = data_buf;
|
|
frame_entry->pointer = i + 1;
|
|
frame_entry->stream_num = index_entries[i].stream_num;
|
|
frame_entry->type = index_entries[i].type;
|
|
return index_entries[i].dwChunkLength;
|
|
}
|
|
}
|
|
MSG_DBG(2, "No more frames\n");
|
|
return -1;
|
|
}
|
|
|
|
#ifdef VERBOSE
|
|
int ReadAVI::hex_dump_chunk(int chunk_len)
|
|
{
|
|
char chars[17];
|
|
unsigned char c;
|
|
int ch, n;
|
|
|
|
chars[16] = 0;
|
|
|
|
for (n = 0; n < chunk_len; n++) {
|
|
if ((n % 16) == 0) {
|
|
if (n != 0)
|
|
MSG_DBG(2, "%s\n", chars);
|
|
MSG_DBG(2, " ");
|
|
memset(chars, ' ', 16);
|
|
}
|
|
read_chars_bin(&c, 1);
|
|
ch = c;
|
|
if (ch == EOF)
|
|
break;
|
|
MSG_DBG(2, "%02x ", ch);
|
|
if (ch >= ' ' && ch <= 126) {
|
|
chars[n % 16] = ch;
|
|
}
|
|
else {
|
|
chars[n % 16] = '.';
|
|
}
|
|
}
|
|
|
|
if ((n % 16) != 0) {
|
|
for (ch = n % 16; ch < 16; ch++) {
|
|
MSG_DBG(2, " ");
|
|
}
|
|
}
|
|
MSG_DBG(2, "%s\n", chars);
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
int ReadAVI::decodeCkid(char* ckid, chunk_type_t* chunk_type)
|
|
{
|
|
int stream = (ckid[0] - '0') * 10 + (ckid[1] - '0');
|
|
for (int i = 0; i < ChunkTypesCnt; i++) {
|
|
if (chunk_types[i].type_id[0] == ckid[2] && chunk_types[i].type_id[1] == ckid[3]) {
|
|
*chunk_type = chunk_types[i].type;
|
|
return stream;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int ReadAVI::parse_idx1(int chunk_len)
|
|
{
|
|
index_entry_t index_entry;
|
|
index_entry.type = ctype_none;
|
|
int t;
|
|
|
|
MSG_DBG(2, " IDX1\n");
|
|
MSG_DBG(2, " -------------------------------\n");
|
|
MSG_DBG(2, " stream type dwFlags dwChunkOffset dwChunkLength\n");
|
|
|
|
for (t = 0; t < chunk_len / 16; t++) {
|
|
char buf[5];
|
|
read_chars(buf, 4);
|
|
index_entry.stream_num = decodeCkid(buf, &index_entry.type);
|
|
index_entry.dwFlags = read_int();
|
|
index_entry.dwChunkOffset = read_int() + movi_offset + 0x10;
|
|
index_entry.dwChunkLength = read_int();
|
|
|
|
MSG_DBG(2, " %d %d 0x%08x 0x%08x 0x%08x\n", index_entry.stream_num, index_entry.type,
|
|
index_entry.dwFlags, index_entry.dwChunkOffset, index_entry.dwChunkLength);
|
|
index_entries.push_back(index_entry);
|
|
}
|
|
|
|
MSG_DBG(2, "\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ReadAVI::read_avi_header()
|
|
{
|
|
#ifdef VERBOSE
|
|
long offset = inFile.tellg();
|
|
#endif
|
|
avi_header.TimeBetweenFrames = read_int();
|
|
avi_header.MaximumDataRate = read_int();
|
|
avi_header.PaddingGranularity = read_int();
|
|
avi_header.Flags = read_int();
|
|
avi_header.TotalNumberOfFrames = read_int();
|
|
avi_header.NumberOfInitialFrames = read_int();
|
|
avi_header.NumberOfStreams = read_int();
|
|
avi_header.SuggestedBufferSize = read_int();
|
|
avi_header.Width = read_int();
|
|
avi_header.Height = read_int();
|
|
avi_header.TimeScale = read_int();
|
|
avi_header.DataRate = read_int();
|
|
avi_header.StartTime = read_int();
|
|
avi_header.DataLength = read_int();
|
|
|
|
MSG_DBG(2, " offset=0x%lx\n", offset);
|
|
MSG_DBG(2, " TimeBetweenFrames: %d\n", avi_header.TimeBetweenFrames);
|
|
MSG_DBG(2, " MaximumDataRate: %d\n", avi_header.MaximumDataRate);
|
|
MSG_DBG(2, " PaddingGranularity: %d\n", avi_header.PaddingGranularity);
|
|
MSG_DBG(2, " Flags: %d\n", avi_header.Flags);
|
|
MSG_DBG(2, " TotalNumberOfFrames: %d\n", avi_header.TotalNumberOfFrames);
|
|
MSG_DBG(2, " NumberOfInitialFrames: %d\n", avi_header.NumberOfInitialFrames);
|
|
MSG_DBG(2, " NumberOfStreams: %d\n", avi_header.NumberOfStreams);
|
|
MSG_DBG(2, " SuggestedBufferSize: %d\n", avi_header.SuggestedBufferSize);
|
|
MSG_DBG(2, " Width: %d\n", avi_header.Width);
|
|
MSG_DBG(2, " Height: %d\n", avi_header.Height);
|
|
MSG_DBG(2, " TimeScale: %d\n", avi_header.TimeScale);
|
|
MSG_DBG(2, " DataRate: %d\n", avi_header.DataRate);
|
|
MSG_DBG(2, " StartTime: %d\n", avi_header.StartTime);
|
|
MSG_DBG(2, " DataLength: %d\n", avi_header.DataLength);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void print_data_handler(unsigned char* handler)
|
|
{
|
|
int t;
|
|
|
|
for (t = 0; t < 4; t++) {
|
|
if ((handler[t] >= 'a' && handler[t] <= 'z') || (handler[t] >= 'A' && handler[t] <= 'Z')
|
|
|| (handler[t] >= '0' && handler[t] <= '9'))
|
|
{
|
|
MSG_DBG(2, "%c", handler[t]);
|
|
}
|
|
else {
|
|
MSG_DBG(2, "[0x%02x]", handler[t]);
|
|
}
|
|
}
|
|
}
|
|
|
|
int ReadAVI::read_stream_header(stream_header_t* sheader)
|
|
{
|
|
#ifdef VERBOSE
|
|
long offset = inFile.tellg();
|
|
#endif
|
|
read_chars(sheader->DataType, 4);
|
|
read_chars(sheader->DataHandler, 4);
|
|
sheader->Flags = read_int();
|
|
sheader->Priority = read_int();
|
|
sheader->InitialFrames = read_int();
|
|
sheader->TimeScale = read_int();
|
|
sheader->DataRate = read_int();
|
|
sheader->StartTime = read_int();
|
|
sheader->DataLength = read_int();
|
|
sheader->SuggestedBufferSize = read_int();
|
|
sheader->Quality = read_int();
|
|
sheader->SampleSize = read_int();
|
|
|
|
MSG_DBG(2, " offset=0x%lx\n", offset);
|
|
MSG_DBG(2, " DataType: %s\n", sheader->DataType);
|
|
MSG_DBG(2, " DataHandler: ");
|
|
print_data_handler((unsigned char*)sheader->DataHandler);
|
|
MSG_DBG(2, "\n");
|
|
MSG_DBG(2, " Flags: %d\n", sheader->Flags);
|
|
MSG_DBG(2, " Priority: %d\n", sheader->Priority);
|
|
MSG_DBG(2, " InitialFrames: %d\n", sheader->InitialFrames);
|
|
MSG_DBG(2, " TimeScale: %d\n", sheader->TimeScale);
|
|
MSG_DBG(2, " DataRate: %d\n", sheader->DataRate);
|
|
MSG_DBG(2, " StartTime: %d\n", sheader->StartTime);
|
|
MSG_DBG(2, " DataLength: %d\n", sheader->DataLength);
|
|
MSG_DBG(2, " SuggestedBufferSize: %d\n", sheader->SuggestedBufferSize);
|
|
MSG_DBG(2, " Quality: %d\n", sheader->Quality);
|
|
MSG_DBG(2, " SampleSize: %d\n", sheader->SampleSize);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ReadAVI::read_stream_format()
|
|
{
|
|
int t, r, g, b;
|
|
#ifdef VERBOSE
|
|
long offset = inFile.tellg();
|
|
#endif
|
|
stream_format_vid.header_size = read_int();
|
|
stream_format_vid.image_width = read_int();
|
|
stream_format_vid.image_height = read_int();
|
|
stream_format_vid.number_of_planes = read_word();
|
|
stream_format_vid.bits_per_pixel = read_word();
|
|
read_chars(stream_format_vid.compression_type, 4);
|
|
//stream_format_vid.compression_type = read_int();
|
|
stream_format_vid.image_size_in_bytes = read_int();
|
|
stream_format_vid.x_pels_per_meter = read_int();
|
|
stream_format_vid.y_pels_per_meter = read_int();
|
|
stream_format_vid.colors_used = read_int();
|
|
stream_format_vid.colors_important = read_int();
|
|
stream_format_vid.palette = 0;
|
|
|
|
if (stream_format_vid.colors_important != 0) {
|
|
stream_format_vid.palette = new int[stream_format_vid.colors_important];
|
|
for (t = 0; t < stream_format_vid.colors_important; t++) {
|
|
unsigned char buf[3];
|
|
read_chars_bin(buf, 3);
|
|
b = buf[0];
|
|
g = buf[1];
|
|
r = buf[2];
|
|
stream_format_vid.palette[t] = (r << 16) + (g << 8) + b;
|
|
}
|
|
}
|
|
|
|
MSG_DBG(2, " offset=0x%lx\n", offset);
|
|
MSG_DBG(2, " header_size: %d\n", stream_format_vid.header_size);
|
|
MSG_DBG(2, " image_width: %d\n", stream_format_vid.image_width);
|
|
MSG_DBG(2, " image_height: %d\n", stream_format_vid.image_height);
|
|
MSG_DBG(2, " number_of_planes: %d\n", stream_format_vid.number_of_planes);
|
|
MSG_DBG(2, " bits_per_pixel: %d\n", stream_format_vid.bits_per_pixel);
|
|
MSG_DBG(2, " compression_type: %s\n", stream_format_vid.compression_type);
|
|
/* MSG_DBG(2, " compression_type: %04x (%c%c%c%c)\n", stream_format_vid.compression_type,
|
|
((stream_format_vid.compression_type) & 255), ((stream_format_vid.compression_type >> 8) & 255),
|
|
((stream_format_vid.compression_type >> 16) & 255), ((stream_format_vid.compression_type >> 24) & 255));
|
|
*/
|
|
MSG_DBG(2, " image_size_in_bytes: %d\n", stream_format_vid.image_size_in_bytes);
|
|
MSG_DBG(2, " x_pels_per_meter: %d\n", stream_format_vid.x_pels_per_meter);
|
|
MSG_DBG(2, " y_pels_per_meter: %d\n", stream_format_vid.y_pels_per_meter);
|
|
MSG_DBG(2, " colors_used: %d\n", stream_format_vid.colors_used);
|
|
MSG_DBG(2, " colors_important: %d\n", stream_format_vid.colors_important);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ReadAVI::read_stream_format_auds()
|
|
{
|
|
#ifdef VERBOSE
|
|
long offset = inFile.tellg();
|
|
#endif
|
|
stream_format_auds.format = read_word();
|
|
stream_format_auds.channels = read_word();
|
|
stream_format_auds.samples_per_second = read_int();
|
|
stream_format_auds.bytes_per_second = read_int();
|
|
int block_align = read_word();
|
|
stream_format_auds.block_size_of_data = read_word();
|
|
stream_format_auds.bits_per_sample = read_word();
|
|
//stream_format_auds.extended_size=read_word();
|
|
|
|
MSG_DBG(2, " offset=0x%lx\n", offset);
|
|
MSG_DBG(2, " format: %d\n", stream_format_auds.format);
|
|
MSG_DBG(2, " channels: %d\n", stream_format_auds.channels);
|
|
MSG_DBG(2, " samples_per_second: %d\n", stream_format_auds.samples_per_second);
|
|
MSG_DBG(2, " bytes_per_second: %d\n", stream_format_auds.bytes_per_second);
|
|
MSG_DBG(2, " block_align: %d\n", block_align);
|
|
MSG_DBG(2, " block_size_of_data: %d\n", stream_format_auds.block_size_of_data);
|
|
MSG_DBG(2, " bits_per_sample: %d\n", stream_format_auds.bits_per_sample);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ReadAVI::parse_hdrl_list()
|
|
{
|
|
char chunk_id[5];
|
|
int chunk_size;
|
|
char chunk_type[5];
|
|
int end_of_chunk;
|
|
int next_chunk;
|
|
#ifdef VERBOSE
|
|
long offset = inFile.tellg();
|
|
#endif
|
|
int stream_type = 0; // 0=video 1=sound
|
|
|
|
read_chars(chunk_id, 4);
|
|
chunk_size = read_int();
|
|
read_chars(chunk_type, 4);
|
|
|
|
MSG_DBG(2, " AVI Header LIST (id=%s size=%d type=%s offset=0x%lx)\n", chunk_id, chunk_size, chunk_type, offset);
|
|
MSG_DBG(2, " {\n");
|
|
|
|
end_of_chunk = chunk_size - 4 + inFile.tellg();
|
|
if ((end_of_chunk % 4) != 0) {
|
|
//MSG_DBG(2, "Adjusting end of chunk %d\n", end_of_chunk);
|
|
//end_of_chunk=end_of_chunk+(4-(end_of_chunk%4));
|
|
//MSG_DBG(2, "Adjusting end of chunk %d\n", end_of_chunk);
|
|
}
|
|
|
|
if (strcmp(chunk_id, "JUNK") == 0) {
|
|
inFile.seekg(end_of_chunk, ios_base::beg);
|
|
MSG_DBG(2, " }\n");
|
|
return 0;
|
|
}
|
|
|
|
while (inFile.tellg() < end_of_chunk) {
|
|
#ifdef VERBOSE
|
|
long offset = inFile.tellg();
|
|
#endif
|
|
read_chars(chunk_type, 4);
|
|
chunk_size = read_int();
|
|
next_chunk = chunk_size + inFile.tellg();
|
|
if ((chunk_size % 4) != 0) {
|
|
//MSG_DBG(2, "Chunk size not a multiple of 4?\n");
|
|
//chunk_size=chunk_size+(4-(chunk_size%4));
|
|
}
|
|
|
|
MSG_DBG(2, " %.4s (size=%d offset=0x%lx)\n", chunk_type, chunk_size, offset);
|
|
MSG_DBG(2, " {\n");
|
|
|
|
if (strcmp("strh", chunk_type) == 0)
|
|
{
|
|
long marker = inFile.tellg();
|
|
char buffer[5];
|
|
read_chars(buffer, 4);
|
|
inFile.seekg(marker, ios_base::beg);
|
|
|
|
if (strcmp(buffer, "vids") == 0)
|
|
{
|
|
stream_type = 0;
|
|
read_stream_header(&stream_header_vid);
|
|
}
|
|
else if (strcmp(buffer, "auds") == 0)
|
|
{
|
|
stream_type = 1;
|
|
read_stream_header(&stream_header_auds);
|
|
}
|
|
else
|
|
{
|
|
MSG_DBG(2, "Unknown stream type %s\n", buffer);
|
|
return -1;
|
|
}
|
|
}
|
|
else if (strcmp("strf", chunk_type) == 0)
|
|
{
|
|
if (stream_type == 0) {
|
|
read_stream_format();
|
|
}
|
|
else {
|
|
read_stream_format_auds();
|
|
}
|
|
}
|
|
else if (strcmp("strd", chunk_type) == 0)
|
|
{
|
|
|
|
}
|
|
else
|
|
{
|
|
MSG_DBG(2, " Unknown chunk type: %s\n", chunk_type);
|
|
// skip_chunk();
|
|
}
|
|
|
|
MSG_DBG(2, " }\n");
|
|
|
|
inFile.seekg(next_chunk, ios_base::beg);
|
|
}
|
|
|
|
MSG_DBG(2, " }\n");
|
|
inFile.seekg(end_of_chunk, ios_base::beg);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ReadAVI::parse_movi(int size)
|
|
{
|
|
char chunk_id[5];
|
|
long end_of_chunk;
|
|
index_entry_t index_entry;
|
|
int blk_size;
|
|
|
|
do {
|
|
long offset = inFile.tellg();
|
|
/*
|
|
if (fileSize - offset < 8)
|
|
break;
|
|
*/
|
|
read_chars(chunk_id, 4);
|
|
index_entry.stream_num = decodeCkid(chunk_id, &index_entry.type);
|
|
|
|
if (index_entry.stream_num < 0) {
|
|
inFile.seekg(offset - 4, ios_base::beg);
|
|
break;
|
|
}
|
|
|
|
index_entry.dwChunkLength = read_int();
|
|
|
|
if (!(avi_header.Flags & AVIF_HASINDEX)) {
|
|
index_entry.dwChunkOffset = offset + 8;
|
|
index_entries.push_back(index_entry);
|
|
}
|
|
|
|
MSG_DBG(3, " AVI Movi Chunk ( id=%s(%d-%d) chunk_size=%d offset=0x%lx)\n", chunk_id, index_entry.type,
|
|
index_entry.stream_num, index_entry.dwChunkLength, offset);
|
|
MSG_DBG(3, " {\n");
|
|
|
|
end_of_chunk = index_entry.dwChunkLength + inFile.tellg();
|
|
end_of_chunk = (end_of_chunk + 1) & ~1;
|
|
/* if ((end_of_chunk % 4) != 0) {
|
|
end_of_chunk = end_of_chunk + (4 - (end_of_chunk % 4));
|
|
}
|
|
*/
|
|
// MSG_DBG(2, "end_of_chunk:%d %X\n", end_of_chunk, end_of_chunk);
|
|
inFile.seekg(end_of_chunk, ios_base::beg);
|
|
MSG_DBG(3, " }\n");
|
|
|
|
blk_size = end_of_chunk - offset;
|
|
size -= blk_size;
|
|
MSG_DBG(3, "size:%d \n", size);
|
|
|
|
} while (size > 7);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ReadAVI::parse_hdrl(unsigned int size)
|
|
{
|
|
char chunk_id[5];
|
|
int chunk_size;
|
|
int end_of_chunk;
|
|
long offset = inFile.tellg();
|
|
|
|
read_chars(chunk_id, 4);
|
|
chunk_size = read_int();
|
|
|
|
MSG_DBG(2, " AVI Header Chunk (id=%s size=%d offset=0x%lx)\n", chunk_id, chunk_size, offset);
|
|
MSG_DBG(2, " {\n");
|
|
|
|
end_of_chunk = chunk_size + inFile.tellg();
|
|
if ((end_of_chunk % 4) != 0) {
|
|
end_of_chunk = end_of_chunk + (4 - (end_of_chunk % 4));
|
|
}
|
|
|
|
read_avi_header();
|
|
MSG_DBG(2, " }\n");
|
|
|
|
while (inFile.tellg() < offset + size - 4) {
|
|
//MSG_DBG(2, "Should end at 0x%lx 0x%lx\n",offset+size,inFile.tellg());
|
|
parse_hdrl_list();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ReadAVI::parse_riff()
|
|
{
|
|
char chunk_id[5];
|
|
int chunk_size;
|
|
char chunk_type[5];
|
|
int end_of_chunk, end_of_subchunk;
|
|
|
|
ZEROIZE(avi_header);
|
|
ZEROIZE(stream_header_vid);
|
|
ZEROIZE(stream_format_vid);
|
|
ZEROIZE(stream_header_auds);
|
|
ZEROIZE(stream_format_auds);
|
|
#ifdef VERBOSE
|
|
long offset = inFile.tellg();
|
|
#endif
|
|
read_chars(chunk_id, 4);
|
|
chunk_size = read_int();
|
|
read_chars(chunk_type, 4);
|
|
|
|
MSG_DBG(2, "RIFF Chunk (id=%s size=%d type=%s offset=0x%lx)\n", chunk_id, chunk_size, chunk_type, offset);
|
|
MSG_DBG(2, "{\n");
|
|
|
|
if (strcmp("RIFF", chunk_id) != 0)
|
|
{
|
|
MSG_DBG(2, "Not a RIFF file.\n");
|
|
return 1;
|
|
}
|
|
else if (strcmp("AVI ", chunk_type) != 0)
|
|
{
|
|
MSG_DBG(2, "Not an AVI file.\n");
|
|
return 1;
|
|
}
|
|
|
|
end_of_chunk = chunk_size - 4 + inFile.tellg();
|
|
|
|
while (inFile.tellg() < end_of_chunk) {
|
|
long offset = inFile.tellg();
|
|
read_chars(chunk_id, 4);
|
|
chunk_size = read_int();
|
|
end_of_subchunk = chunk_size + inFile.tellg();
|
|
|
|
if (strcmp("JUNK", chunk_id) == 0 || strcmp("PAD ", chunk_id) == 0) {
|
|
chunk_type[0] = 0;
|
|
}
|
|
else {
|
|
read_chars(chunk_type, 4);
|
|
}
|
|
|
|
MSG_DBG(2, " New Chunk (id=%s size=%d type=%s offset=0x%lx)\n", chunk_id, chunk_size, chunk_type, offset);
|
|
MSG_DBG(2, " {\n");
|
|
|
|
fflush(stdout);
|
|
|
|
if (strcmp("JUNK", chunk_id) == 0 || strcmp("PAD ", chunk_id) == 0) {
|
|
if ((chunk_size % 4) != 0) {
|
|
chunk_size = chunk_size + (4 - (chunk_size % 4));
|
|
}
|
|
#ifdef VERBOSE
|
|
hex_dump_chunk(chunk_size);
|
|
#endif
|
|
}
|
|
else if (strcmp("INFO", chunk_type) == 0) {
|
|
if ((chunk_size % 4) != 0) {
|
|
chunk_size = chunk_size + (4 - (chunk_size % 4));
|
|
}
|
|
#ifdef VERBOSE
|
|
hex_dump_chunk(chunk_size);
|
|
#endif
|
|
}
|
|
else if (strcmp("hdrl", chunk_type) == 0) {
|
|
parse_hdrl(chunk_size);
|
|
/* skip_chunk(); */
|
|
}
|
|
else if (strcmp("movi", chunk_type) == 0) {
|
|
movi_offset = offset;
|
|
parse_movi(chunk_size);
|
|
}
|
|
else if (strcmp("idx1", chunk_id) == 0) {
|
|
inFile.seekg(inFile.tellg() - std::streamoff(4), ios_base::beg);
|
|
parse_idx1(chunk_size);
|
|
}/* else if (strcmp("indx", chunk_id) == 0) {
|
|
inFile.seekg(inFile.tellg() - 4L, ios_base::beg);
|
|
parse_indx(chunk_size);
|
|
}*/else {
|
|
MSG_DBG(2, " Unknown chunk at %d (%4s)\n", (int)inFile.tellg() - 8, chunk_type);
|
|
if (chunk_size == 0)
|
|
break;
|
|
}
|
|
|
|
inFile.seekg(end_of_subchunk, ios_base::beg);
|
|
MSG_DBG(2, " }\n");
|
|
|
|
}
|
|
|
|
if (stream_format_vid.palette) {
|
|
delete[] stream_format_vid.palette;
|
|
stream_format_vid.palette = NULL;
|
|
}
|
|
|
|
MSG_DBG(2, "}\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ReadAVI::read_int()
|
|
{
|
|
int c;
|
|
unsigned char buf[4];
|
|
|
|
inFile.read((char*)buf, 4);
|
|
c = buf[0];
|
|
c = c + (buf[1] << 8);
|
|
c = c + (buf[2] << 16);
|
|
c = c + (buf[3] << 24);
|
|
|
|
return c;
|
|
}
|
|
|
|
int ReadAVI::read_word()
|
|
{
|
|
int c;
|
|
unsigned char buf[2];
|
|
|
|
inFile.read((char*)buf, 2);
|
|
c = buf[0];
|
|
c = c + (buf[1] << 8);
|
|
|
|
return c;
|
|
}
|
|
|
|
void ReadAVI::read_chars(char* s, int count)
|
|
{
|
|
inFile.read(s, count);
|
|
s[count] = 0;
|
|
}
|
|
|
|
void ReadAVI::read_chars_bin(unsigned char* s, int count)
|
|
{
|
|
inFile.read((char*)s, count);
|
|
}
|