Added ODML Index support, still needs work though too much duplicated code. Feedback welcome

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34354 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
David McPaul
2009-11-29 21:07:35 +00:00
parent 3acb81a693
commit 51b0c01316
8 changed files with 187 additions and 17 deletions
@@ -445,33 +445,36 @@ aviReader::GetNextChunk(void *_cookie, const void **chunkBuffer,
mediaHeader->start_time = (cookie->frame_pos * 1000000LL mediaHeader->start_time = (cookie->frame_pos * 1000000LL
* cookie->frames_per_sec_scale) / cookie->frames_per_sec_rate; * 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" : "?", cookie->stream, cookie->is_audio ? "A" : cookie->is_video ? "V" : "?",
mediaHeader->start_time / 1000000.0, cookie->frame_pos * 100.0 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) { if (cookie->is_audio) {
mediaHeader->type = B_MEDIA_ENCODED_AUDIO; mediaHeader->type = B_MEDIA_ENCODED_AUDIO;
mediaHeader->u.encoded_audio.buffer_flags = keyframe ? mediaHeader->u.encoded_audio.buffer_flags = keyframe ?
B_MEDIA_KEY_FRAME : 0; 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; cookie->byte_pos += size;
// frame_pos is sample no for vbr encoded audio and byte position for everything else // 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 // 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; // 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 // advance by bytes in chunk and calculate frame_pos
// time = cookie->byte_pos * 1000000LL / cookie->bytes_per_second; // time = cookie->byte_pos * 1000000LL / cookie->bytes_per_second;
// cookie->frame_pos = time * cookie->frames_per_sec_rate / cookie->frames_per_sec_scale / 1000000LL; // cookie->frame_pos = time * cookie->frames_per_sec_rate / cookie->frames_per_sec_scale / 1000000LL;
// } }
} else if (cookie->is_video) { } else if (cookie->is_video) {
mediaHeader->type = B_MEDIA_ENCODED_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; B_MEDIA_KEY_FRAME : 0;
mediaHeader->u.encoded_video.first_active_line = 0; mediaHeader->u.encoded_video.first_active_line = 0;
mediaHeader->u.encoded_video.line_count = cookie->line_count; 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; cookie->frame_pos += cookie->frame_size;
} else { } else {
return B_BAD_VALUE; return B_BAD_VALUE;
@@ -26,7 +26,6 @@
#include <math.h> #include <math.h>
#include <stdio.h> #include <stdio.h>
#include "FallbackIndex.h" #include "FallbackIndex.h"
#include "OpenDMLParser.h"
//#define TRACE_START_INDEX //#define TRACE_START_INDEX
#ifdef TRACE_START_INDEX #ifdef TRACE_START_INDEX
@@ -26,7 +26,6 @@
#include <stdio.h> #include <stdio.h>
#include "ReaderPlugin.h" // B_MEDIA_* #include "ReaderPlugin.h" // B_MEDIA_*
#include "Index.h" #include "Index.h"
#include "OpenDMLParser.h"
//#define TRACE_INDEX //#define TRACE_INDEX
#ifdef TRACE_INDEX #ifdef TRACE_INDEX
@@ -129,7 +128,7 @@ Index::Seek(int stream_index, uint32 seekTo, int64 *frame,
if (data->seek_index[i].keyframe) { if (data->seek_index[i].keyframe) {
lastKeyframePos = pos; lastKeyframePos = pos;
lastKeyframeIndex = i; 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); pos, frame_pos);
} }
@@ -169,7 +168,7 @@ Index::Seek(int stream_index, uint32 seekTo, int64 *frame,
return B_ERROR; return B_ERROR;
done: 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 // recalculate frame and time after seek
*frame = frame_pos; *frame = frame_pos;
*time = (frame_pos * 1000000LL * stream->frames_per_sec_scale) *time = (frame_pos * 1000000LL * stream->frames_per_sec_scale)
@@ -199,7 +198,7 @@ Index::DumpIndex(int stream_index)
IndexEntry _index; IndexEntry _index;
for (uint32 i = 0; i < fStreamData[stream_index].seek_index_next; i++) { for (uint32 i = 0; i < fStreamData[stream_index].seek_index_next; i++) {
_index = fStreamData[stream_index].seek_index[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);
} }
} }
@@ -28,6 +28,8 @@
#include <SupportDefs.h> #include <SupportDefs.h>
#include <vector> #include <vector>
#include "OpenDMLParser.h"
/* /*
This class handles all indexing of an AVI file This class handles all indexing of an AVI file
Subclasses should override Init and create index entries based on the Subclasses should override Init and create index entries based on the
@@ -23,9 +23,20 @@
* OF THE POSSIBILITY OF SUCH DAMAGE. * OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <SupportDefs.h> #include <SupportDefs.h>
#include <math.h>
#include <stdio.h> #include <stdio.h>
#include "OpenDMLIndex.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) OpenDMLIndex::OpenDMLIndex(BPositionIO *source, OpenDMLParser *parser)
: Index(source, parser) : Index(source, parser)
@@ -41,5 +52,149 @@ OpenDMLIndex::~OpenDMLIndex()
status_t status_t
OpenDMLIndex::Init() 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;
}
@@ -34,6 +34,9 @@ public:
~OpenDMLIndex(); ~OpenDMLIndex();
status_t Init(); 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 #endif
@@ -28,8 +28,8 @@
#include <math.h> #include <math.h>
#include <stdio.h> #include <stdio.h>
#include <new> #include <new>
#include "StandardIndex.h" #include "StandardIndex.h"
#include "OpenDMLParser.h"
//#define TRACE_START_INDEX //#define TRACE_START_INDEX
@@ -95,7 +95,7 @@ StandardIndex::Init()
} }
int stream_index; int stream_index;
off_t position; int64 position;
uint32 size; uint32 size;
uint64 frame[fStreamCount]; uint64 frame[fStreamCount];
uint64 frame_no; uint64 frame_no;
@@ -111,11 +111,21 @@ StandardIndex::Init()
for (uint32 i = 0; i < fIndexSize; i++) { 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 & 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); 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; keyframe = (fIndex[i].flags >> AVIIF_KEYFRAME_SHIFT) & 1;
size = fIndex[i].chunk_length; size = fIndex[i].chunk_length;
@@ -26,7 +26,6 @@
#define _STANDARD_INDEX_H #define _STANDARD_INDEX_H
#include "Index.h" #include "Index.h"
#include "avi.h"
class StandardIndex : public Index class StandardIndex : public Index
{ {