Author: dlmcpaul Date: 2009-11-29 22:07:35 +0100 (Sun, 29 Nov 2009) New Revision: 34354 Changeset: http://dev.haiku-os.org/changeset/34354/haiku Modified: haiku/trunk/src/add-ons/media/plugins/avi_reader/avi_reader.cpp haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/FallbackIndex.cpp haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/Index.cpp haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/Index.h haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/OpenDMLIndex.cpp haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/OpenDMLIndex.h haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/StandardIndex.cpp haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/StandardIndex.h Log: Added ODML Index support, still needs work though too much duplicated code. Feedback welcome Modified: haiku/trunk/src/add-ons/media/plugins/avi_reader/avi_reader.cpp =================================================================== --- haiku/trunk/src/add-ons/media/plugins/avi_reader/avi_reader.cpp 2009-11-29 20:51:12 UTC (rev 34353) +++ haiku/trunk/src/add-ons/media/plugins/avi_reader/avi_reader.cpp 2009-11-29 21:07:35 UTC (rev 34354) @@ -445,33 +445,36 @@ mediaHeader->start_time = (cookie->frame_pos * 1000000LL * cookie->frames_per_sec_scale) / cookie->frames_per_sec_rate; - TRACE("stream %d (%s): start_time %.6f, pos %.3f %%, frame %Ld chunk size %ld\n", + TRACE("stream %d (%s): start_time %.6f, pos %.3f %%, frame %Ld chunk size %ld offset %Ld\n", cookie->stream, cookie->is_audio ? "A" : cookie->is_video ? "V" : "?", mediaHeader->start_time / 1000000.0, cookie->frame_pos * 100.0 - / cookie->frame_count, cookie->frame_pos, size); + / cookie->frame_count, cookie->frame_pos, size, start); if (cookie->is_audio) { mediaHeader->type = B_MEDIA_ENCODED_AUDIO; mediaHeader->u.encoded_audio.buffer_flags = keyframe ? B_MEDIA_KEY_FRAME : 0; - cookie->frame_pos += (uint64)(ceil((double)size / (double)cookie->frame_size)) * cookie->frames_per_sec_scale; cookie->byte_pos += size; // frame_pos is sample no for vbr encoded audio and byte position for everything else -// if (cookie->is_vbr) { + if (cookie->is_vbr) { // advance by frame_size -// } else { + cookie->frame_pos += cookie->frame_size; + } else { + cookie->frame_pos += (uint64)(ceil((double)size / (double)cookie->frame_size)) * cookie->frames_per_sec_scale; // cookie->frame_pos += (uint64)(ceil((double)size / (double)cookie->frame_size)) * cookie->frames_per_sec / cookie->avg_bytes_per_sec; // advance by bytes in chunk and calculate frame_pos // time = cookie->byte_pos * 1000000LL / cookie->bytes_per_second; // cookie->frame_pos = time * cookie->frames_per_sec_rate / cookie->frames_per_sec_scale / 1000000LL; -// } + } } else if (cookie->is_video) { mediaHeader->type = B_MEDIA_ENCODED_VIDEO; - mediaHeader->u.encoded_video.field_flags = keyframe ? + mediaHeader->u.encoded_video.field_flags = keyframe ? B_MEDIA_KEY_FRAME : 0; mediaHeader->u.encoded_video.first_active_line = 0; mediaHeader->u.encoded_video.line_count = cookie->line_count; + mediaHeader->u.encoded_video.field_number = 0; + mediaHeader->u.encoded_video.field_sequence = cookie->frame_pos; cookie->frame_pos += cookie->frame_size; } else { return B_BAD_VALUE; Modified: haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/FallbackIndex.cpp =================================================================== --- haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/FallbackIndex.cpp 2009-11-29 20:51:12 UTC (rev 34353) +++ haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/FallbackIndex.cpp 2009-11-29 21:07:35 UTC (rev 34354) @@ -26,7 +26,6 @@ #include <math.h> #include <stdio.h> #include "FallbackIndex.h" -#include "OpenDMLParser.h" //#define TRACE_START_INDEX #ifdef TRACE_START_INDEX Modified: haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/Index.cpp =================================================================== --- haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/Index.cpp 2009-11-29 20:51:12 UTC (rev 34353) +++ haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/Index.cpp 2009-11-29 21:07:35 UTC (rev 34354) @@ -26,7 +26,6 @@ #include <stdio.h> #include "ReaderPlugin.h" // B_MEDIA_* #include "Index.h" -#include "OpenDMLParser.h" //#define TRACE_INDEX #ifdef TRACE_INDEX @@ -129,7 +128,7 @@ if (data->seek_index[i].keyframe) { lastKeyframePos = pos; lastKeyframeIndex = i; - TRACE("keyframe at index %ld, frame %ld (seek: %ld)\n", i, + TRACE("keyframe at index %ld, frame %Ld (seek: %Ld)\n", i, pos, frame_pos); } @@ -169,7 +168,7 @@ return B_ERROR; done: - TRACE("seek done: index: pos %d\n", data->current_chunk); + TRACE("seek done: index: pos %Ld\n", data->current_chunk); // recalculate frame and time after seek *frame = frame_pos; *time = (frame_pos * 1000000LL * stream->frames_per_sec_scale) @@ -199,7 +198,7 @@ IndexEntry _index; for (uint32 i = 0; i < fStreamData[stream_index].seek_index_next; i++) { _index = fStreamData[stream_index].seek_index[i]; - printf("Frame %Ld, pos %Ld, size %ld, pts %Ld\n",_index.frame_no, _index.position, _index.size, _index.pts); + printf("index %ld Frame %Ld, pos %Ld, size %ld, pts %Ld\n",i,_index.frame_no, _index.position, _index.size, _index.pts); } } Modified: haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/Index.h =================================================================== --- haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/Index.h 2009-11-29 20:51:12 UTC (rev 34353) +++ haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/Index.h 2009-11-29 21:07:35 UTC (rev 34354) @@ -28,6 +28,8 @@ #include <SupportDefs.h> #include <vector> +#include "OpenDMLParser.h" + /* This class handles all indexing of an AVI file Subclasses should override Init and create index entries based on the Modified: haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/OpenDMLIndex.cpp =================================================================== --- haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/OpenDMLIndex.cpp 2009-11-29 20:51:12 UTC (rev 34353) +++ haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/OpenDMLIndex.cpp 2009-11-29 21:07:35 UTC (rev 34354) @@ -23,10 +23,21 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <SupportDefs.h> +#include <math.h> #include <stdio.h> + #include "OpenDMLIndex.h" +//#define TRACE_START_INDEX +#ifdef TRACE_START_INDEX + #define TRACE printf +#else + #define TRACE(a...) +#endif +#define ERROR(a...) fprintf(stderr, a) + + OpenDMLIndex::OpenDMLIndex(BPositionIO *source, OpenDMLParser *parser) : Index(source, parser) { @@ -41,5 +52,149 @@ status_t OpenDMLIndex::Init() { - return B_ERROR; + TRACE("Constructing a OpenDML Index\n"); + + uint32 lastFrame; + bigtime_t pts; + odml_index_header superIndex; + const OpenDMLStream *stream; + + int64 pos = 0; + uint32 bytesRead; + + for (uint32 i=0; i < fStreamCount; i++) { + stream = fParser->StreamInfo(i); + + pos = stream->odml_index_start; + bytesRead = sizeof(odml_index_header); + + if ((int32)bytesRead != fSource->ReadAt(pos, &superIndex, bytesRead)) { + ERROR("libOpenDML: OpenDMLIndex::Init file reading failed to read superindex\n"); + return B_IO_ERROR; + } + + pos += bytesRead; + + pts = 0; + lastFrame = 0; + + ReadIndex(i, pos, &lastFrame, &pts, &superIndex); + } + + return B_OK; } + +status_t +OpenDMLIndex::ReadIndex(uint32 stream_index, int64 pos, uint32 *lastFrame, bigtime_t *pts, odml_index_header *superIndex) { + +odml_superindex_entry superIndexEntry; +//odml_field_index_entry fieldIndexEntry; +uint32 bytesRead; + +const OpenDMLStream *stream = fParser->StreamInfo(stream_index); + + for (uint32 i=0; i < superIndex->entries_used; i++) { + + if (superIndex->index_type == AVI_INDEX_OF_INDEXES) { + + bytesRead = sizeof(odml_superindex_entry); + + if ((int32)bytesRead != fSource->ReadAt(pos, &superIndexEntry, bytesRead)) { + ERROR("libOpenDML: OpenDMLIndex::Init file reading failed to read superindex entry\n"); + return B_IO_ERROR; + } + + pos += bytesRead; + + if (superIndexEntry.start == 0) { + continue; + } + + if (superIndex->index_sub_type == AVI_INDEX_2FIELD) { + } else { + ReadChunkIndex(stream_index, superIndexEntry.start + 8, lastFrame, pts, stream); + } + } + } + + return B_OK; +} + +status_t +OpenDMLIndex::ReadChunkIndex(uint32 stream_index, int64 pos, uint32 *lastFrame, bigtime_t *pts, const OpenDMLStream *stream) { + +odml_index_entry chunkIndexEntry; +odml_chunk_index_header chunkIndex; +uint32 bytesRead; +uint32 frameNo; +bool keyframe; +uint32 sample_size; +int64 position; +uint32 size; + + bytesRead = sizeof(odml_chunk_index_header); + + if ((int32)bytesRead != fSource->ReadAt(pos, &chunkIndex, bytesRead)) { + ERROR("libOpenDML: OpenDMLIndex::Init file reading failed to read Chunk Index\n"); + return B_IO_ERROR; + } + + pos += bytesRead; + + for (uint32 i=0; i<chunkIndex.entries_used; i++) { + bytesRead = sizeof(odml_index_entry); + + if ((int32)bytesRead != fSource->ReadAt(pos, &chunkIndexEntry, bytesRead)) { + ERROR("libOpenDML: OpenDMLIndex::Init file reading failed to read Chunk Index Entry\n"); + return B_IO_ERROR; + } + + pos += bytesRead; + + keyframe = (chunkIndexEntry.size & 0x80000000) ? false : true; + position = chunkIndex.base_offset + chunkIndexEntry.start - 8; + size = chunkIndexEntry.size & 0x7fffffff; + frameNo = *lastFrame; + + if (stream->is_video) { + // Video is easy enough, it is always 1 frame = 1 index + *pts = *lastFrame * 1000000LL * stream->frames_per_sec_scale / stream->frames_per_sec_rate; + (*lastFrame)++; + } else if (stream->is_audio) { + + *pts = *lastFrame * 1000000LL / stream->audio_format->frames_per_sec; + + // Audio varies based on many different hacks over the years + // The simplest is chunk size / sample size = no of samples in the chunk for uncompressed audio + // ABR Compressed audio is more difficult and VBR Compressed audio is even harder + // What follows is what I have worked out from various sources across the internet. + if (stream->audio_format->format_tag != 0x0001) { + // VBR audio is detected as having a block_align >= 960 + if (stream->audio_format->block_align >= 960) { + // VBR Audio so block_align is the largest no of samples in a chunk + // scale is the no of samples in a frame + // rate is the sample rate + // but we must round up when calculating no of frames in a chunk + *lastFrame += (uint64)(ceil((double)size / (double)stream->audio_format->block_align)) * stream->frames_per_sec_scale; + } else { + // ABR Audio so use Chunk Size and average bytes per second to determine how many samples there are in the chunk + *lastFrame += (uint64)(ceil((double)size / (double)stream->audio_format->block_align)) * stream->audio_format->frames_per_sec / stream->audio_format->avg_bytes_per_sec; + } + } else { + // sample size can be corrupt + if (stream->stream_header.sample_size > 0) { + sample_size = stream->stream_header.sample_size; + } else { + // compute sample size + sample_size = stream->audio_format->bits_per_sample * stream->audio_format->channels / 8; + } + *lastFrame += size / stream->stream_header.sample_size; + } + } + + AddIndex(stream_index, position, size, frameNo, *pts, keyframe); + } + + return B_OK; +} + Modified: haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/OpenDMLIndex.h =================================================================== --- haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/OpenDMLIndex.h 2009-11-29 20:51:12 UTC (rev 34353) +++ haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/OpenDMLIndex.h 2009-11-29 21:07:35 UTC (rev 34354) @@ -34,6 +34,9 @@ ~OpenDMLIndex(); status_t Init(); +private: + status_t ReadIndex(uint32 stream_index, int64 pos, uint32 *lastFrame, bigtime_t *pts, odml_index_header *superIndex); + status_t ReadChunkIndex(uint32 stream_index, int64 pos, uint32 *lastFrame, bigtime_t *pts, const OpenDMLStream *stream); }; #endif Modified: haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/StandardIndex.cpp =================================================================== --- haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/StandardIndex.cpp 2009-11-29 20:51:12 UTC (rev 34353) +++ haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/StandardIndex.cpp 2009-11-29 21:07:35 UTC (rev 34354) @@ -28,8 +28,8 @@ #include <math.h> #include <stdio.h> #include <new> + #include "StandardIndex.h" -#include "OpenDMLParser.h" //#define TRACE_START_INDEX @@ -95,7 +95,7 @@ } int stream_index; - off_t position; + int64 position; uint32 size; uint64 frame[fStreamCount]; uint64 frame_no; @@ -111,11 +111,21 @@ for (uint32 i = 0; i < fIndexSize; i++) { + if (fIndex[i].chunk_id == 0) { + printf("Corrupt Index entry at %ld/%ld\n",i,fIndexSize); + continue; + } + stream_index = ((fIndex[i].chunk_id & 0xff) - '0') * 10; - stream_index += ((fIndex[i].chunk_id >> 8) & 0xff) - '0'; + stream_index += ((fIndex[i].chunk_id >> 8) & 0xff) - '0'; stream = fParser->StreamInfo(stream_index); + if (stream == NULL) { + printf("No Stream Info for stream %d\n",stream_index); + continue; + } + keyframe = (fIndex[i].flags >> AVIIF_KEYFRAME_SHIFT) & 1; size = fIndex[i].chunk_length; Modified: haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/StandardIndex.h =================================================================== --- haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/StandardIndex.h 2009-11-29 20:51:12 UTC (rev 34353) +++ haiku/trunk/src/add-ons/media/plugins/avi_reader/libOpenDML/StandardIndex.h 2009-11-29 21:07:35 UTC (rev 34354) @@ -26,7 +26,6 @@ #define _STANDARD_INDEX_H #include "Index.h" -#include "avi.h" class StandardIndex : public Index {