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
* 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;
@@ -26,7 +26,6 @@
#include <math.h>
#include <stdio.h>
#include "FallbackIndex.h"
#include "OpenDMLParser.h"
//#define TRACE_START_INDEX
#ifdef TRACE_START_INDEX
@@ -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 @@ Index::Seek(int stream_index, uint32 seekTo, int64 *frame,
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 @@ Index::Seek(int stream_index, uint32 seekTo, int64 *frame,
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 @@ Index::DumpIndex(int stream_index)
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);
}
}
@@ -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
@@ -23,9 +23,20 @@
* 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 @@ OpenDMLIndex::~OpenDMLIndex()
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;
}
@@ -34,6 +34,9 @@ public:
~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
@@ -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 @@ StandardIndex::Init()
}
int stream_index;
off_t position;
int64 position;
uint32 size;
uint64 frame[fStreamCount];
uint64 frame_no;
@@ -111,11 +111,21 @@ StandardIndex::Init()
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;
@@ -26,7 +26,6 @@
#define _STANDARD_INDEX_H
#include "Index.h"
#include "avi.h"
class StandardIndex : public Index
{