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:
@@ -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
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user