diff --git a/src/add-ons/media/plugins/avi_reader/libOpenDML/OpenDMLFile.cpp b/src/add-ons/media/plugins/avi_reader/libOpenDML/OpenDMLFile.cpp index 493ff93175..2dd7f5cf36 100644 --- a/src/add-ons/media/plugins/avi_reader/libOpenDML/OpenDMLFile.cpp +++ b/src/add-ons/media/plugins/avi_reader/libOpenDML/OpenDMLFile.cpp @@ -10,15 +10,18 @@ struct OpenDMLFile::stream_data const stream_info *info; uint32 chunk_id; + + bool has_odml_index; + bool has_standard_index; - char * superindex; - int superindex_entry_size; - int superindex_entry_count; - int superindex_entry_pos; + char * odml_superindex; + int odml_superindex_entry_size; + int odml_superindex_entry_count; + int odml_superindex_entry_pos; - // index info (superindex entry) - int64 index_entry_start; + // index info (odml_superindex entry, or standard avi index) int64 index_base_offset; + int64 index_entry_start; int index_entry_size; int index_entry_count; int index_entry_pos; @@ -96,10 +99,28 @@ OpenDMLFile::InitData() fStreamCount = fParser->StreamCount(); fStreamData = new stream_data[fStreamCount]; + // If this file has a standard avi index, determine + // start, size and count of entries, so it can be + // assigned to each stream when the stream has no + // individual OpenDML index + int64 standard_index_start; + int standard_index_entry_size; + int standard_index_entry_count; + if (fParser->StandardIndexSize()) { + standard_index_start = fParser->StandardIndexStart(); + standard_index_entry_size = 16; + standard_index_entry_count = fParser->StandardIndexSize() / 16; + } else { + standard_index_entry_count = 0; + } + for (int stream = 0; stream < fStreamCount; stream++) { TRACE("OpenDMLFile::InitData: stream %d\n", stream); fStreamData[stream].info = fParser->StreamInfo(stream); + fStreamData[stream].has_odml_index = false; + fStreamData[stream].has_standard_index = false; + if (fStreamData[stream].info->odml_index_size) { TRACE("OpenDMLFile::InitData: index header, start %Ld, size %lu\n", fStreamData[stream].info->odml_index_start, fStreamData[stream].info->odml_index_size); @@ -117,82 +138,80 @@ OpenDMLFile::InitData() if (h.index_type == AVI_INDEX_OF_INDEXES) { int size = h.entries_used * h.longs_per_entry * 4; - TRACE("OpenDMLFile::InitData: reading superindex of %d bytes\n", size); - fStreamData[stream].superindex_entry_size = h.longs_per_entry * 4; - fStreamData[stream].superindex_entry_count = h.entries_used; - fStreamData[stream].superindex_entry_pos = 0; - fStreamData[stream].superindex = new char [size]; - fSource->ReadAt(fStreamData[stream].info->odml_index_start + sizeof(h), fStreamData[stream].superindex, size); + TRACE("OpenDMLFile::InitData: reading odml_superindex of %d bytes\n", size); + fStreamData[stream].odml_superindex_entry_size = h.longs_per_entry * 4; + fStreamData[stream].odml_superindex_entry_count = h.entries_used; + fStreamData[stream].odml_superindex_entry_pos = 0; + fStreamData[stream].odml_superindex = new char [size]; + fSource->ReadAt(fStreamData[stream].info->odml_index_start + sizeof(h), fStreamData[stream].odml_superindex, size); + fStreamData[stream].has_odml_index = true; } else if (h.index_type == AVI_INDEX_OF_CHUNKS){ - TRACE("OpenDMLFile::InitData: creating fake superindex\n"); - fStreamData[stream].superindex_entry_size = 16; - fStreamData[stream].superindex_entry_count = 1; - fStreamData[stream].superindex_entry_pos = 0; - fStreamData[stream].superindex = new char [16]; - ((odml_superindex_entry *)fStreamData[stream].superindex)->start = fStreamData[stream].info->odml_index_start; - ((odml_superindex_entry *)fStreamData[stream].superindex)->size = fStreamData[stream].info->odml_index_size; - ((odml_superindex_entry *)fStreamData[stream].superindex)->duration = 0; + TRACE("OpenDMLFile::InitData: creating fake odml_superindex\n"); + fStreamData[stream].odml_superindex_entry_size = 16; + fStreamData[stream].odml_superindex_entry_count = 1; + fStreamData[stream].odml_superindex_entry_pos = 0; + fStreamData[stream].odml_superindex = new char [16]; + ((odml_superindex_entry *)fStreamData[stream].odml_superindex)->start = fStreamData[stream].info->odml_index_start; + ((odml_superindex_entry *)fStreamData[stream].odml_superindex)->size = fStreamData[stream].info->odml_index_size; + ((odml_superindex_entry *)fStreamData[stream].odml_superindex)->duration = 0; + fStreamData[stream].has_odml_index = true; } else if (h.index_type == AVI_INDEX_IS_DATA){ TRACE("OpenDMLFile::InitData: AVI_INDEX_IS_DATA not supported\n"); - fStreamData[stream].superindex = 0; - fStreamData[stream].superindex_entry_count = 0; - fStreamData[stream].superindex_entry_pos = 0; + fStreamData[stream].odml_superindex = 0; + fStreamData[stream].odml_superindex_entry_count = 0; + fStreamData[stream].odml_superindex_entry_pos = 0; } else { TRACE("OpenDMLFile::InitData: index type not recongnized\n"); - fStreamData[stream].superindex = 0; - fStreamData[stream].superindex_entry_count = 0; - fStreamData[stream].superindex_entry_pos = 0; + fStreamData[stream].odml_superindex = 0; + fStreamData[stream].odml_superindex_entry_count = 0; + fStreamData[stream].odml_superindex_entry_pos = 0; } - - for (int i = 0; i < fStreamData[stream].superindex_entry_count; i++) { - odml_superindex_entry *entry = (odml_superindex_entry *) (fStreamData[stream].superindex + i * fStreamData[stream].superindex_entry_size); - TRACE("superindex entry %d: start %10Ld, size %8ld, duration %lu\n", i, entry->start, entry->size, entry->duration); + for (int i = 0; i < fStreamData[stream].odml_superindex_entry_count; i++) { + odml_superindex_entry *entry = (odml_superindex_entry *) (fStreamData[stream].odml_superindex + i * fStreamData[stream].odml_superindex_entry_size); + TRACE("odml_superindex entry %d: start %10Ld, size %8ld, duration %lu\n", i, entry->start, entry->size, entry->duration); } - - fStreamData[stream].index_entry_start = 0; - fStreamData[stream].index_base_offset = 0; - fStreamData[stream].index_entry_size = 0; - fStreamData[stream].index_entry_count = 0; - fStreamData[stream].index_entry_pos = 0; - fStreamData[stream].index_chunk = new char [INDEX_CHUNK_SIZE]; - fStreamData[stream].index_chunk_entry_count = 0; - fStreamData[stream].index_chunk_entry_pos = 0; } else { - fStreamData[stream].superindex = 0; - - - - - fStreamData[stream].index_entry_start = 0; - fStreamData[stream].index_base_offset = 0; - fStreamData[stream].index_entry_size = 0; - fStreamData[stream].index_entry_count = 0; - fStreamData[stream].index_entry_pos = 0; - fStreamData[stream].index_chunk = new char [INDEX_CHUNK_SIZE]; - fStreamData[stream].index_chunk_entry_count = 0; - fStreamData[stream].index_chunk_entry_pos = 0; - - - + // this stream has no superindex, as it doesn't have an opendml index :=) + fStreamData[stream].odml_superindex = 0; + fStreamData[stream].odml_superindex_entry_count = 0; + fStreamData[stream].odml_superindex_entry_pos = 0; } + + fStreamData[stream].index_base_offset = 0; + fStreamData[stream].index_entry_start = 0; + fStreamData[stream].index_entry_size = 0; + fStreamData[stream].index_entry_count = 0; + fStreamData[stream].index_entry_pos = 0; + fStreamData[stream].index_chunk = new char [INDEX_CHUNK_SIZE]; + fStreamData[stream].index_chunk_entry_count = 0; + fStreamData[stream].index_chunk_entry_pos = 0; + // if this stream doesn't have an OpenDML index, + // but the file has a standard avi index, we can use it :) + if (!fStreamData[stream].has_odml_index && standard_index_entry_count != 0) { + fStreamData[stream].has_standard_index = true; + fStreamData[stream].index_base_offset = fParser->MovieListStart() - 4; // offset includes the 4 byte 'movi' id + fStreamData[stream].index_entry_start = standard_index_start; + fStreamData[stream].index_entry_size = standard_index_entry_size; + fStreamData[stream].index_entry_count = standard_index_entry_count; + } } } bool -OpenDMLFile::ReadIndexInfo(int stream_index) +OpenDMLFile::OdmlReadIndexInfo(int stream_index) { stream_data *data = &fStreamData[stream_index]; - if (data->superindex_entry_pos >= data->superindex_entry_count) { - TRACE("reached end of superindex\n"); + if (data->odml_superindex_entry_pos >= data->odml_superindex_entry_count) { + TRACE("reached end of odml_superindex\n"); return false; } - odml_superindex_entry *entry = (odml_superindex_entry *) (data->superindex + data->superindex_entry_pos * data->superindex_entry_size); + odml_superindex_entry *entry = (odml_superindex_entry *) (data->odml_superindex + data->odml_superindex_entry_pos * data->odml_superindex_entry_size); - TRACE("OpenDMLFile::ReadIndexInfo: stream %d, pos %d, start %Ld, size %lu, duration %u\n", - stream_index, data->superindex_entry_pos, entry->start, entry->size, entry->duration); + TRACE("OpenDMLFile::OdmlReadIndexInfo: stream %d, pos %d, start %Ld, size %lu, duration %u\n", + stream_index, data->odml_superindex_entry_pos, entry->start, entry->size, entry->duration); odml_chunk_index_header chunk_index_header; @@ -214,17 +233,17 @@ OpenDMLFile::ReadIndexInfo(int stream_index) data->index_entry_count = chunk_index_header.entries_used; data->index_entry_pos = 0; - data->superindex_entry_pos++; + data->odml_superindex_entry_pos++; return true; } bool -OpenDMLFile::ReadIndexChunk(int stream_index) +OpenDMLFile::OdmlReadIndexChunk(int stream_index) { stream_data *data = &fStreamData[stream_index]; while (data->index_entry_pos >= data->index_entry_count) { - if (!ReadIndexInfo(stream_index)) + if (!OdmlReadIndexInfo(stream_index)) return false; } @@ -233,7 +252,7 @@ OpenDMLFile::ReadIndexChunk(int stream_index) int size = data->index_chunk_entry_count * data->index_entry_size; int64 start = data->index_entry_start + data->index_entry_pos * data->index_entry_size; - TRACE("OpenDMLFile::ReadIndexChunk: stream %d, index_chunk_entry_count %d, size %d, start %Ld\n", + TRACE("OpenDMLFile::OdmlReadIndexChunk: stream %d, index_chunk_entry_count %d, size %d, start %Ld\n", stream_index, data->index_chunk_entry_count, size, start); if (size != fSource->ReadAt(start, data->index_chunk, size)) { @@ -246,12 +265,14 @@ OpenDMLFile::ReadIndexChunk(int stream_index) } bool -OpenDMLFile::GetNextChunkInfo(int stream_index, int64 *start, uint32 *size, bool *keyframe) +OpenDMLFile::OdmlGetNextChunkInfo(int stream_index, int64 *start, uint32 *size, bool *keyframe) { + // this function uses the OpenDML index (an OpenDML AVI contains one index per stream) + stream_data *data = &fStreamData[stream_index]; while (data->index_chunk_entry_pos >= data->index_chunk_entry_count) { - if (!ReadIndexChunk(stream_index)) + if (!OdmlReadIndexChunk(stream_index)) return false; } @@ -267,7 +288,63 @@ OpenDMLFile::GetNextChunkInfo(int stream_index, int64 *start, uint32 *size, bool stream_index, *start, *size, *keyframe ? ", keyframe" : ""); return true; } + +bool +OpenDMLFile::AviGetNextChunkInfo(int stream_index, int64 *start, uint32 *size, bool *keyframe) +{ + // this function uses the AVI standard index (a standard AVI contains one index per file, that covers all streams) + stream_data *data = &fStreamData[stream_index]; + + while (data->index_entry_pos < data->index_entry_count) { + if (data->index_chunk_entry_pos == data->index_chunk_entry_count) { + data->index_chunk_entry_count = min_c(data->index_entry_count - data->index_entry_pos, INDEX_CHUNK_SIZE / data->index_entry_size); + data->index_chunk_entry_pos = 0; + uint32 start = data->index_entry_start + data->index_entry_pos * data->index_entry_size; + int size = data->index_chunk_entry_count * data->index_entry_size; + TRACE("OpenDMLFile::AviGetNextChunkInfo: stream %d, index_chunk_entry_count %d, size %d, start %lu\n", + stream_index, data->index_chunk_entry_count, size, start); + if (size != fSource->ReadAt(start, data->index_chunk, size)) { + TRACE("OpenDMLFile::AviGetNextChunkInfo: read error\n"); + return false; + } + } + + avi_standard_index_entry *entry = (avi_standard_index_entry *)(data->index_chunk + data->index_chunk_entry_pos * data->index_entry_size); + + TRACE("OpenDMLFile::AviGetNextChunkInfo: stream %d, chunk_id "FOURCC_FORMAT" (0x%08x), flags 0x%x, offset %lu, length %lu\n", + stream_index, FOURCC_PARAM(entry->chunk_id), entry->chunk_id, entry->flags, entry->chunk_offset, entry->chunk_length); + + data->index_chunk_entry_pos++; + data->index_entry_pos++; + + int real_stream_index = ((entry->chunk_id & 0xff) - '0') * 10 + ((entry->chunk_id >> 8) & 0xff) - '0'; + + TRACE("OpenDMLFile::AviGetNextChunkInfo: real_stream_index %d %d %d\n", real_stream_index, ((entry->chunk_id & 0xff) - '0'), ((entry->chunk_id >> 8) & 0xff) - '0'); + + if (real_stream_index == stream_index) { + *keyframe = entry->flags & AVIIF_KEYFRAME; + *start = data->index_base_offset + entry->chunk_offset + 8; + *size = entry->chunk_length; + return true; + } + + } + TRACE("OpenDMLFile::AviGetNextChunkInfo: index end reached\n"); + return false; +} + +bool +OpenDMLFile::GetNextChunkInfo(int stream_index, int64 *start, uint32 *size, bool *keyframe) +{ + stream_data *data = &fStreamData[stream_index]; + if (data->has_standard_index) + return AviGetNextChunkInfo(stream_index, start, size, keyframe); + if (data->has_odml_index) + return OdmlGetNextChunkInfo(stream_index, start, size, keyframe); + return false; +} + int OpenDMLFile::StreamCount() { diff --git a/src/add-ons/media/plugins/avi_reader/libOpenDML/OpenDMLFile.h b/src/add-ons/media/plugins/avi_reader/libOpenDML/OpenDMLFile.h index eb84f5de30..d36d49cea0 100644 --- a/src/add-ons/media/plugins/avi_reader/libOpenDML/OpenDMLFile.h +++ b/src/add-ons/media/plugins/avi_reader/libOpenDML/OpenDMLFile.h @@ -29,9 +29,13 @@ public: private: void InitData(); - bool ReadIndexChunk(int stream_index); - bool ReadIndexInfo(int stream_index); - + + bool OdmlReadIndexChunk(int stream_index); + bool OdmlReadIndexInfo(int stream_index); + bool OdmlGetNextChunkInfo(int stream_index, int64 *start, uint32 *size, bool *keyframe); + + bool AviGetNextChunkInfo(int stream_index, int64 *start, uint32 *size, bool *keyframe); + private: BPositionIO * fSource; OpenDMLParser * fParser; diff --git a/src/add-ons/media/plugins/avi_reader/libOpenDML/OpenDMLParser.cpp b/src/add-ons/media/plugins/avi_reader/libOpenDML/OpenDMLParser.cpp index 9789f9351a..aafe67de10 100644 --- a/src/add-ons/media/plugins/avi_reader/libOpenDML/OpenDMLParser.cpp +++ b/src/add-ons/media/plugins/avi_reader/libOpenDML/OpenDMLParser.cpp @@ -20,6 +20,7 @@ struct movie_chunk OpenDMLParser::OpenDMLParser() : fSource(0), fSize(0), + fMovieListStart(0), fStandardIndexStart(0), fStandardIndexSize(0), fStreamCount(0), @@ -65,6 +66,12 @@ OpenDMLParser::StandardIndexSize() return fStandardIndexSize; } +int64 +OpenDMLParser::MovieListStart() +{ + return fMovieListStart; +} + const avi_main_header * OpenDMLParser::AviMainHeader() { @@ -602,6 +609,9 @@ void OpenDMLParser::ParseList_movi(uint64 start, uint32 size) { TRACE("OpenDMLParser::ParseList_movi\n"); + + if (fMovieListStart == 0) + fMovieListStart = start; fMovieChunkCount++; return; diff --git a/src/add-ons/media/plugins/avi_reader/libOpenDML/OpenDMLParser.h b/src/add-ons/media/plugins/avi_reader/libOpenDML/OpenDMLParser.h index 9dc4938910..86558e7a00 100644 --- a/src/add-ons/media/plugins/avi_reader/libOpenDML/OpenDMLParser.h +++ b/src/add-ons/media/plugins/avi_reader/libOpenDML/OpenDMLParser.h @@ -32,6 +32,8 @@ public: int64 StandardIndexStart(); uint32 StandardIndexSize(); + + int64 MovieListStart(); const avi_main_header * AviMainHeader(); const odml_extended_header * OdmlExtendedHeader(); @@ -55,6 +57,8 @@ private: BPositionIO * fSource; int64 fSize; + int64 fMovieListStart; + int64 fStandardIndexStart; uint32 fStandardIndexSize; diff --git a/src/add-ons/media/plugins/avi_reader/libOpenDML/avi.h b/src/add-ons/media/plugins/avi_reader/libOpenDML/avi.h index 57c1ffee99..2e5d86df61 100644 --- a/src/add-ons/media/plugins/avi_reader/libOpenDML/avi.h +++ b/src/add-ons/media/plugins/avi_reader/libOpenDML/avi.h @@ -31,6 +31,14 @@ struct avi_standard_index_entry uint32 chunk_offset; uint32 chunk_length; } _PACKED; +#define AVIIF_LIST 0x00000001 +#define AVIIF_KEYFRAME 0x00000010 +#define AVIIF_FIRSTPART 0x00000020 +#define AVIIF_LASTPART 0x00000040 +#define AVIIF_MIDPART (AVIIF_LASTPART | AVIFF_FIRSTPART) +#define AVIIF_NOTIME 0x00000100 +#define AVIIF_COMPUSE 0x0fff0000 + struct odml_extended_header {