Moved some functionality from avi_reader into OpenDMLParser.
Added basic seeking support. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21401 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -51,21 +51,18 @@ struct avi_cookie
|
|||||||
char * buffer;
|
char * buffer;
|
||||||
unsigned buffer_size;
|
unsigned buffer_size;
|
||||||
|
|
||||||
int64 frame_count;
|
bool is_audio;
|
||||||
bigtime_t duration;
|
bool is_video;
|
||||||
|
|
||||||
media_format format;
|
media_format format;
|
||||||
|
|
||||||
bool audio;
|
bigtime_t duration;
|
||||||
|
int64 frame_count;
|
||||||
// audio only:
|
int64 frame_pos;
|
||||||
int64 byte_pos;
|
|
||||||
uint32 bytes_per_sec_rate;
|
|
||||||
uint32 bytes_per_sec_scale;
|
|
||||||
|
|
||||||
// video only:
|
|
||||||
uint32 frame_pos;
|
|
||||||
uint32 frames_per_sec_rate;
|
uint32 frames_per_sec_rate;
|
||||||
uint32 frames_per_sec_scale;
|
uint32 frames_per_sec_scale;
|
||||||
|
|
||||||
|
// video only:
|
||||||
uint32 line_count;
|
uint32 line_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -111,7 +108,7 @@ aviReader::Sniff(int32 *streamCount)
|
|||||||
TRACE("aviReader::Sniff: this stream seems to be supported\n");
|
TRACE("aviReader::Sniff: this stream seems to be supported\n");
|
||||||
|
|
||||||
fFile = new OpenDMLFile(pos_io_source);
|
fFile = new OpenDMLFile(pos_io_source);
|
||||||
if (B_OK != fFile->Init()) {
|
if (fFile->Init() < B_OK) {
|
||||||
ERROR("aviReader::Sniff: can't setup OpenDMLFile\n");
|
ERROR("aviReader::Sniff: can't setup OpenDMLFile\n");
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
@@ -144,6 +141,8 @@ aviReader::AllocateCookie(int32 streamNumber, void **_cookie)
|
|||||||
cookie->stream = streamNumber;
|
cookie->stream = streamNumber;
|
||||||
cookie->buffer = 0;
|
cookie->buffer = 0;
|
||||||
cookie->buffer_size = 0;
|
cookie->buffer_size = 0;
|
||||||
|
cookie->is_audio = false;
|
||||||
|
cookie->is_video = false;
|
||||||
|
|
||||||
BMediaFormats formats;
|
BMediaFormats formats;
|
||||||
media_format *format = &cookie->format;
|
media_format *format = &cookie->format;
|
||||||
@@ -167,54 +166,21 @@ aviReader::AllocateCookie(int32 streamNumber, void **_cookie)
|
|||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audio_format->format_tag == 0x0001) {// PCM
|
cookie->is_audio = true;
|
||||||
cookie->frame_count = stream_header->length / ((stream_header->sample_size + 7) / 8);
|
cookie->duration = fFile->StreamInfo(streamNumber)->duration;
|
||||||
TRACE("audio frame_count %Ld (is PCM)\n", cookie->frame_count);
|
cookie->frame_count = fFile->StreamInfo(streamNumber)->frame_count;
|
||||||
} else if (stream_header->rate) { // not PCM
|
cookie->frame_pos = 0;
|
||||||
cookie->frame_count = (stream_header->length * (int64)audio_format->frames_per_sec) / stream_header->rate;
|
cookie->frames_per_sec_rate = fFile->StreamInfo(streamNumber)->frames_per_sec_rate;
|
||||||
TRACE("audio frame_count %Ld (using rate)\n", cookie->frame_count);
|
cookie->frames_per_sec_scale = fFile->StreamInfo(streamNumber)->frames_per_sec_scale;
|
||||||
} else { // not PCM
|
|
||||||
cookie->frame_count = (stream_header->length * (int64)audio_format->frames_per_sec) / (stream_header->sample_size * audio_format->avg_bytes_per_sec);
|
|
||||||
TRACE("audio frame_count %Ld (using fallback)\n", cookie->frame_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stream_header->rate && stream_header->scale) {
|
TRACE("audio frame_count %Ld\n", cookie->frame_count);
|
||||||
cookie->duration = (1000000LL * (int64)stream_header->length * (int64)stream_header->scale) / stream_header->rate;
|
TRACE("audio duration %.6f (%Ld)\n", cookie->duration / 1E6, cookie->duration);
|
||||||
TRACE("audio duration %.6f (%Ld) (using scale & rate)\n", cookie->duration / 1E6, cookie->duration);
|
|
||||||
} else if (stream_header->rate) {
|
|
||||||
cookie->duration = (1000000LL * (int64)stream_header->length) / stream_header->rate;
|
|
||||||
TRACE("audio duration %.6f (%Ld) (using rate)\n", cookie->duration / 1E6, cookie->duration);
|
|
||||||
} else {
|
|
||||||
cookie->duration = fFile->Duration();
|
|
||||||
TRACE("audio duration %.6f (%Ld) (using fallback)\n", cookie->duration / 1E6, cookie->duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
cookie->audio = true;
|
|
||||||
cookie->byte_pos = 0;
|
|
||||||
|
|
||||||
if (stream_header->scale && stream_header->rate && stream_header->sample_size) {
|
|
||||||
cookie->bytes_per_sec_rate = stream_header->rate * stream_header->sample_size;
|
|
||||||
cookie->bytes_per_sec_scale = stream_header->scale;
|
|
||||||
TRACE("audio bytes_per_sec_rate %ld, bytes_per_sec_scale %ld (using both)\n", cookie->bytes_per_sec_rate, cookie->bytes_per_sec_scale);
|
|
||||||
} else if (audio_format->avg_bytes_per_sec) {
|
|
||||||
cookie->bytes_per_sec_rate = audio_format->avg_bytes_per_sec;
|
|
||||||
cookie->bytes_per_sec_scale = 1;
|
|
||||||
TRACE("audio bytes_per_sec_rate %ld, bytes_per_sec_scale %ld (using avg_bytes_per_sec)\n", cookie->bytes_per_sec_rate, cookie->bytes_per_sec_scale);
|
|
||||||
} else if (stream_header->rate) {
|
|
||||||
cookie->bytes_per_sec_rate = stream_header->rate;
|
|
||||||
cookie->bytes_per_sec_scale = 1;
|
|
||||||
TRACE("audio bytes_per_sec_rate %ld, bytes_per_sec_scale %ld (using rate)\n", cookie->bytes_per_sec_rate, cookie->bytes_per_sec_scale);
|
|
||||||
} else {
|
|
||||||
cookie->bytes_per_sec_rate = 128000;
|
|
||||||
cookie->bytes_per_sec_scale = 8;
|
|
||||||
TRACE("audio bytes_per_sec_rate %ld, bytes_per_sec_scale %ld (using fallback)\n", cookie->bytes_per_sec_rate, cookie->bytes_per_sec_scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (audio_format->format_tag == 0x0001) {
|
if (audio_format->format_tag == 0x0001) {
|
||||||
// a raw PCM format
|
// a raw PCM format
|
||||||
description.family = B_BEOS_FORMAT_FAMILY;
|
description.family = B_BEOS_FORMAT_FAMILY;
|
||||||
description.u.beos.format = B_BEOS_FORMAT_RAW_AUDIO;
|
description.u.beos.format = B_BEOS_FORMAT_RAW_AUDIO;
|
||||||
if (B_OK != formats.GetFormatFor(description, format))
|
if (formats.GetFormatFor(description, format) < B_OK)
|
||||||
format->type = B_MEDIA_RAW_AUDIO;
|
format->type = B_MEDIA_RAW_AUDIO;
|
||||||
format->u.raw_audio.frame_rate = audio_format->frames_per_sec;
|
format->u.raw_audio.frame_rate = audio_format->frames_per_sec;
|
||||||
format->u.raw_audio.channel_count = audio_format->channels;
|
format->u.raw_audio.channel_count = audio_format->channels;
|
||||||
@@ -237,14 +203,14 @@ aviReader::AllocateCookie(int32 streamNumber, void **_cookie)
|
|||||||
// some encoded format
|
// some encoded format
|
||||||
description.family = B_WAV_FORMAT_FAMILY;
|
description.family = B_WAV_FORMAT_FAMILY;
|
||||||
description.u.wav.codec = audio_format->format_tag;
|
description.u.wav.codec = audio_format->format_tag;
|
||||||
if (B_OK != formats.GetFormatFor(description, format))
|
if (formats.GetFormatFor(description, format) < B_OK)
|
||||||
format->type = B_MEDIA_ENCODED_AUDIO;
|
format->type = B_MEDIA_ENCODED_AUDIO;
|
||||||
format->u.encoded_audio.bit_rate = 8 * audio_format->avg_bytes_per_sec;
|
format->u.encoded_audio.bit_rate = 8 * audio_format->avg_bytes_per_sec;
|
||||||
TRACE("bit_rate %.3f\n", format->u.encoded_audio.bit_rate);
|
TRACE("bit_rate %.3f\n", format->u.encoded_audio.bit_rate);
|
||||||
format->u.encoded_audio.output.frame_rate = audio_format->frames_per_sec;
|
format->u.encoded_audio.output.frame_rate = audio_format->frames_per_sec;
|
||||||
format->u.encoded_audio.output.channel_count = audio_format->channels;
|
format->u.encoded_audio.output.channel_count = audio_format->channels;
|
||||||
}
|
}
|
||||||
// this doesn't seem to work (it's not even a fourcc)
|
// TODO: this doesn't seem to work (it's not even a fourcc)
|
||||||
format->user_data_type = B_CODEC_TYPE_INFO;
|
format->user_data_type = B_CODEC_TYPE_INFO;
|
||||||
*(uint32 *)format->user_data = audio_format->format_tag; format->user_data[4] = 0;
|
*(uint32 *)format->user_data = audio_format->format_tag; format->user_data[4] = 0;
|
||||||
|
|
||||||
@@ -270,27 +236,14 @@ aviReader::AllocateCookie(int32 streamNumber, void **_cookie)
|
|||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
cookie->audio = false;
|
cookie->is_video = true;
|
||||||
|
cookie->duration = fFile->StreamInfo(streamNumber)->duration;
|
||||||
|
cookie->frame_count = fFile->StreamInfo(streamNumber)->frame_count;
|
||||||
cookie->frame_pos = 0;
|
cookie->frame_pos = 0;
|
||||||
|
cookie->frames_per_sec_rate = fFile->StreamInfo(streamNumber)->frames_per_sec_rate;
|
||||||
|
cookie->frames_per_sec_scale = fFile->StreamInfo(streamNumber)->frames_per_sec_scale;
|
||||||
cookie->line_count = fFile->AviMainHeader()->height;
|
cookie->line_count = fFile->AviMainHeader()->height;
|
||||||
|
|
||||||
if (stream_header->scale && stream_header->rate) {
|
|
||||||
cookie->frames_per_sec_rate = stream_header->rate;
|
|
||||||
cookie->frames_per_sec_scale = stream_header->scale;
|
|
||||||
TRACE("frames_per_sec_rate %ld, frames_per_sec_scale %ld (using both)\n", cookie->frames_per_sec_rate, cookie->frames_per_sec_scale);
|
|
||||||
} else if (fFile->AviMainHeader()->micro_sec_per_frame) {
|
|
||||||
cookie->frames_per_sec_rate = 1000000;
|
|
||||||
cookie->frames_per_sec_scale = fFile->AviMainHeader()->micro_sec_per_frame;
|
|
||||||
TRACE("frames_per_sec_rate %ld, frames_per_sec_scale %ld (using micro_sec_per_frame)\n", cookie->frames_per_sec_rate, cookie->frames_per_sec_scale);
|
|
||||||
} else {
|
|
||||||
cookie->frames_per_sec_rate = 25;
|
|
||||||
cookie->frames_per_sec_scale = 1;
|
|
||||||
TRACE("frames_per_sec_rate %ld, frames_per_sec_scale %ld (using fallback)\n", cookie->frames_per_sec_rate, cookie->frames_per_sec_scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
cookie->frame_count = stream_header->length;
|
|
||||||
cookie->duration = (cookie->frame_count * (int64)cookie->frames_per_sec_scale * 1000000LL) / cookie->frames_per_sec_rate;
|
|
||||||
|
|
||||||
TRACE("video frame_count %Ld\n", cookie->frame_count);
|
TRACE("video frame_count %Ld\n", cookie->frame_count);
|
||||||
TRACE("video duration %.6f (%Ld)\n", cookie->duration / 1E6, cookie->duration);
|
TRACE("video duration %.6f (%Ld)\n", cookie->duration / 1E6, cookie->duration);
|
||||||
|
|
||||||
@@ -299,13 +252,13 @@ aviReader::AllocateCookie(int32 streamNumber, void **_cookie)
|
|||||||
description.u.avi.codec = video_format->compression;
|
description.u.avi.codec = video_format->compression;
|
||||||
else
|
else
|
||||||
description.u.avi.codec = stream_header->fourcc_handler;
|
description.u.avi.codec = stream_header->fourcc_handler;
|
||||||
if (B_OK != formats.GetFormatFor(description, format))
|
if (formats.GetFormatFor(description, format) < B_OK)
|
||||||
format->type = B_MEDIA_ENCODED_VIDEO;
|
format->type = B_MEDIA_ENCODED_VIDEO;
|
||||||
|
|
||||||
format->user_data_type = B_CODEC_TYPE_INFO;
|
format->user_data_type = B_CODEC_TYPE_INFO;
|
||||||
*(uint32 *)format->user_data = description.u.avi.codec; format->user_data[4] = 0;
|
*(uint32 *)format->user_data = description.u.avi.codec; format->user_data[4] = 0;
|
||||||
format->u.encoded_video.max_bit_rate = 8 * fFile->AviMainHeader()->max_bytes_per_sec;
|
format->u.encoded_video.max_bit_rate = 8 * fFile->AviMainHeader()->max_bytes_per_sec;
|
||||||
format->u.encoded_video.avg_bit_rate = format->u.encoded_video.max_bit_rate / 2; // XXX fix this
|
format->u.encoded_video.avg_bit_rate = (format->u.encoded_video.max_bit_rate * 3 / 4); // XXX fix this
|
||||||
format->u.encoded_video.output.field_rate = cookie->frames_per_sec_rate / (float)cookie->frames_per_sec_scale;
|
format->u.encoded_video.output.field_rate = cookie->frames_per_sec_rate / (float)cookie->frames_per_sec_scale;
|
||||||
format->u.encoded_video.output.interlace = 1; // 1: progressive
|
format->u.encoded_video.output.interlace = 1; // 1: progressive
|
||||||
format->u.encoded_video.output.first_active = 0;
|
format->u.encoded_video.output.first_active = 0;
|
||||||
@@ -360,18 +313,25 @@ aviReader::GetStreamInfo(void *_cookie, int64 *frameCount, bigtime_t *duration,
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
aviReader::Seek(void *cookie,
|
aviReader::Seek(void *_cookie, uint32 seekTo,
|
||||||
uint32 seekTo,
|
|
||||||
int64 *frame, bigtime_t *time)
|
int64 *frame, bigtime_t *time)
|
||||||
{
|
{
|
||||||
TRACE("aviReader::Seek: seekTo%s%s%s%s, time %Ld, frame %Ld\n",
|
avi_cookie *cookie = (avi_cookie *)_cookie;
|
||||||
|
|
||||||
|
TRACE("aviReader::Seek: stream %d, seekTo%s%s%s%s, time %Ld, frame %Ld\n",
|
||||||
|
cookie->stream,
|
||||||
(seekTo & B_MEDIA_SEEK_TO_TIME) ? " B_MEDIA_SEEK_TO_TIME" : "",
|
(seekTo & B_MEDIA_SEEK_TO_TIME) ? " B_MEDIA_SEEK_TO_TIME" : "",
|
||||||
(seekTo & B_MEDIA_SEEK_TO_FRAME) ? " B_MEDIA_SEEK_TO_FRAME" : "",
|
(seekTo & B_MEDIA_SEEK_TO_FRAME) ? " B_MEDIA_SEEK_TO_FRAME" : "",
|
||||||
(seekTo & B_MEDIA_SEEK_CLOSEST_FORWARD) ? " B_MEDIA_SEEK_CLOSEST_FORWARD" : "",
|
(seekTo & B_MEDIA_SEEK_CLOSEST_FORWARD) ? " B_MEDIA_SEEK_CLOSEST_FORWARD" : "",
|
||||||
(seekTo & B_MEDIA_SEEK_CLOSEST_BACKWARD) ? " B_MEDIA_SEEK_CLOSEST_BACKWARD" : "",
|
(seekTo & B_MEDIA_SEEK_CLOSEST_BACKWARD) ? " B_MEDIA_SEEK_CLOSEST_BACKWARD" : "",
|
||||||
*time, *frame);
|
*time, *frame);
|
||||||
|
|
||||||
return B_ERROR;
|
status_t rv = fFile->Seek(cookie->stream, seekTo, frame, time);
|
||||||
|
if (rv == B_OK) {
|
||||||
|
cookie->frame_pos = *frame;
|
||||||
|
TRACE("aviReader::Seek: stream %d, success, setting frame_pos to %lld\n", cookie->stream, cookie->frame_pos);
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -396,24 +356,26 @@ aviReader::GetNextChunk(void *_cookie,
|
|||||||
cookie->buffer_size = (size + 15) & ~15;
|
cookie->buffer_size = (size + 15) & ~15;
|
||||||
cookie->buffer = new char [cookie->buffer_size];
|
cookie->buffer = new char [cookie->buffer_size];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mediaHeader->start_time = (cookie->frame_pos * 1000000 * cookie->frames_per_sec_scale) / cookie->frames_per_sec_rate;
|
||||||
|
|
||||||
if (cookie->audio) {
|
if (cookie->is_audio) {
|
||||||
mediaHeader->start_time = (cookie->byte_pos * 1000000LL * (int64)cookie->bytes_per_sec_scale) / cookie->bytes_per_sec_rate;
|
|
||||||
mediaHeader->type = B_MEDIA_ENCODED_AUDIO;
|
mediaHeader->type = B_MEDIA_ENCODED_AUDIO;
|
||||||
mediaHeader->u.encoded_audio.buffer_flags = keyframe ? B_MEDIA_KEY_FRAME : 0;
|
mediaHeader->u.encoded_audio.buffer_flags = keyframe ? B_MEDIA_KEY_FRAME : 0;
|
||||||
|
cookie->frame_pos += size;
|
||||||
cookie->byte_pos += size;
|
} else if (cookie->is_video) {
|
||||||
} else {
|
|
||||||
mediaHeader->start_time = (cookie->frame_pos * 1000000LL * (int64)cookie->frames_per_sec_scale) / cookie->frames_per_sec_rate;
|
|
||||||
mediaHeader->type = B_MEDIA_ENCODED_VIDEO;
|
mediaHeader->type = B_MEDIA_ENCODED_VIDEO;
|
||||||
mediaHeader->u.encoded_video.field_flags = keyframe ? B_MEDIA_KEY_FRAME : 0;
|
mediaHeader->u.encoded_video.field_flags = keyframe ? 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;
|
||||||
|
|
||||||
cookie->frame_pos += 1;
|
cookie->frame_pos += 1;
|
||||||
|
} else {
|
||||||
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE("stream %d: start_time %.6f\n", cookie->stream, mediaHeader->start_time / 1000000.0);
|
TRACE("stream %d (%s): start_time %.6f, pos %.3f %%\n",
|
||||||
|
cookie->stream, cookie->is_audio ? "A" : cookie->is_video ? "V" : "?",
|
||||||
|
mediaHeader->start_time / 1000000.0, cookie->frame_pos * 100.0 / cookie->frame_count);
|
||||||
|
|
||||||
*chunkBuffer = cookie->buffer;
|
*chunkBuffer = cookie->buffer;
|
||||||
*chunkSize = size;
|
*chunkSize = size;
|
||||||
|
|||||||
@@ -96,18 +96,10 @@ OpenDMLFile::Init()
|
|||||||
{
|
{
|
||||||
fParser = new OpenDMLParser(fSource);
|
fParser = new OpenDMLParser(fSource);
|
||||||
|
|
||||||
if (fParser->Parse() < B_OK) {
|
if (fParser->Init() < B_OK) {
|
||||||
ERROR("OpenDMLFile::SetTo: warning, file parsing failed\n");
|
ERROR("OpenDMLFile::SetTo: parser init failed\n");
|
||||||
}
|
|
||||||
|
|
||||||
if (!fParser->AviMainHeader()) {
|
|
||||||
ERROR("OpenDMLFile::SetTo: avi main header not found\n");
|
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fParser->StreamCount() == 0) {
|
|
||||||
ERROR("OpenDMLFile::SetTo: no streams found\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fParser->StreamInfo(0)->odml_index_size != 0) {
|
if (fParser->StreamInfo(0)->odml_index_size != 0) {
|
||||||
fIndex = new OpenDMLIndex(fSource, fParser);
|
fIndex = new OpenDMLIndex(fSource, fParser);
|
||||||
@@ -391,18 +383,26 @@ OpenDMLFile::AviGetNextChunkInfo(int stream_index, int64 *start, uint32 *size, b
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
OpenDMLFile::GetNextChunkInfo(int stream_index, int64 *start, uint32 *size, bool *keyframe)
|
OpenDMLFile::GetNextChunkInfo(int stream_index, int64 *start, uint32 *size, bool *keyframe)
|
||||||
{
|
{
|
||||||
return fIndex->GetNextChunkInfo(stream_index, start, size, keyframe);
|
return fIndex->GetNextChunkInfo(stream_index, start, size, keyframe);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status_t
|
||||||
|
OpenDMLFile::Seek(int stream_index, uint32 seekTo, int64 *frame, bigtime_t *time)
|
||||||
|
{
|
||||||
|
return fIndex->Seek(stream_index, seekTo, frame, time);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
OpenDMLFile::StreamCount()
|
OpenDMLFile::StreamCount()
|
||||||
{
|
{
|
||||||
return fParser->StreamCount();
|
return fParser->StreamCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
bigtime_t
|
bigtime_t
|
||||||
OpenDMLFile::Duration()
|
OpenDMLFile::Duration()
|
||||||
{
|
{
|
||||||
@@ -422,7 +422,8 @@ OpenDMLFile::FrameCount()
|
|||||||
return fParser->AviMainHeader()->total_frames;
|
return fParser->AviMainHeader()->total_frames;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
bool
|
bool
|
||||||
OpenDMLFile::IsVideo(int stream_index)
|
OpenDMLFile::IsVideo(int stream_index)
|
||||||
{
|
{
|
||||||
@@ -466,3 +467,9 @@ OpenDMLFile::StreamFormat(int stream_index)
|
|||||||
return (fParser->StreamInfo(stream_index)->stream_header_valid) ?
|
return (fParser->StreamInfo(stream_index)->stream_header_valid) ?
|
||||||
&fParser->StreamInfo(stream_index)->stream_header : 0;
|
&fParser->StreamInfo(stream_index)->stream_header : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const stream_info *
|
||||||
|
OpenDMLFile::StreamInfo(int index)
|
||||||
|
{
|
||||||
|
return fParser->StreamInfo(index);
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,10 +40,14 @@ public:
|
|||||||
status_t Init();
|
status_t Init();
|
||||||
|
|
||||||
int StreamCount();
|
int StreamCount();
|
||||||
|
|
||||||
|
const stream_info * StreamInfo(int index);
|
||||||
|
|
||||||
|
/*
|
||||||
bigtime_t Duration();
|
bigtime_t Duration();
|
||||||
uint32 FrameCount();
|
uint32 FrameCount();
|
||||||
|
*/
|
||||||
|
|
||||||
bool IsVideo(int stream_index);
|
bool IsVideo(int stream_index);
|
||||||
bool IsAudio(int stream_index);
|
bool IsAudio(int stream_index);
|
||||||
|
|
||||||
@@ -54,6 +58,7 @@ public:
|
|||||||
const avi_stream_header * StreamFormat(int stream_index);
|
const avi_stream_header * StreamFormat(int stream_index);
|
||||||
|
|
||||||
status_t GetNextChunkInfo(int stream_index, int64 *start, uint32 *size, bool *keyframe);
|
status_t GetNextChunkInfo(int stream_index, int64 *start, uint32 *size, bool *keyframe);
|
||||||
|
status_t Seek(int stream_index, uint32 seekTo, int64 *frame, bigtime_t *time);
|
||||||
|
|
||||||
BPositionIO *Source() { return fSource; }
|
BPositionIO *Source() { return fSource; }
|
||||||
|
|
||||||
|
|||||||
@@ -41,12 +41,6 @@
|
|||||||
#define DO_SWAP_INT16(x) x = B_SWAP_INT16(x)
|
#define DO_SWAP_INT16(x) x = B_SWAP_INT16(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct movie_chunk
|
|
||||||
{
|
|
||||||
movie_chunk * next;
|
|
||||||
int64 start;
|
|
||||||
uint32 size;
|
|
||||||
};
|
|
||||||
|
|
||||||
OpenDMLParser::OpenDMLParser(BPositionIO *source)
|
OpenDMLParser::OpenDMLParser(BPositionIO *source)
|
||||||
: fSource(source),
|
: fSource(source),
|
||||||
@@ -128,6 +122,10 @@ OpenDMLParser::CreateNewStreamInfo()
|
|||||||
info->video_format_valid = false;
|
info->video_format_valid = false;
|
||||||
info->odml_index_start = 0;
|
info->odml_index_start = 0;
|
||||||
info->odml_index_size = 0;
|
info->odml_index_size = 0;
|
||||||
|
info->duration = 0;
|
||||||
|
info->frame_count = 0;
|
||||||
|
info->frames_per_sec_rate = 1;
|
||||||
|
info->frames_per_sec_scale = 1;
|
||||||
|
|
||||||
// append the new stream_info to the fStreams list and point fCurrentStream to it
|
// append the new stream_info to the fStreams list and point fCurrentStream to it
|
||||||
if (fStreams) {
|
if (fStreams) {
|
||||||
@@ -142,18 +140,128 @@ OpenDMLParser::CreateNewStreamInfo()
|
|||||||
}
|
}
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
OpenDMLParser::Parse()
|
OpenDMLParser::Init()
|
||||||
{
|
{
|
||||||
TRACE("OpenDMLParser::Parse\n");
|
TRACE("OpenDMLParser::Init\n");
|
||||||
|
|
||||||
if (!fSource) {
|
if (!fSource) {
|
||||||
ERROR("OpenDMLParser::Parse: no source\n");
|
ERROR("OpenDMLParser::Init: no source\n");
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
if (fSize < 32) {
|
if (fSize < 32) {
|
||||||
ERROR("OpenDMLParser::Parse: file too small\n");
|
ERROR("OpenDMLParser::Init: file too small\n");
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Parse() < B_OK) {
|
||||||
|
ERROR("OpenDMLParser::Init: warning: file parsing failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AviMainHeader() == NULL) {
|
||||||
|
ERROR("OpenDMLParser::Init: avi main header not found\n");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StreamCount() == 0) {
|
||||||
|
ERROR("OpenDMLParser::Init: no streams found\n");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 frame_count = OdmlExtendedHeader() ? OdmlExtendedHeader()->total_frames : AviMainHeader()->total_frames;
|
||||||
|
bigtime_t duration = frame_count * AviMainHeader()->micro_sec_per_frame;
|
||||||
|
printf("AVI Header frame count %lu, duration %.6f\n", frame_count, duration / 1E6);
|
||||||
|
|
||||||
|
for (int i = 0; i < fStreamCount; i++) {
|
||||||
|
SetupStreamLength(const_cast<stream_info *>(StreamInfo(i)));
|
||||||
|
}
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
OpenDMLParser::SetupStreamLength(stream_info *stream)
|
||||||
|
{
|
||||||
|
if (stream->is_audio)
|
||||||
|
SetupAudioStreamLength(stream);
|
||||||
|
if (stream->is_video)
|
||||||
|
SetupVideoStreamLength(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
// F:\avi-info\Information on AVI file.htm
|
||||||
|
|
||||||
|
void
|
||||||
|
OpenDMLParser::SetupAudioStreamLength(stream_info *stream)
|
||||||
|
{
|
||||||
|
stream->frame_count = stream->stream_header.length;
|
||||||
|
|
||||||
|
if (stream->audio_format->format_tag == 0x0001
|
||||||
|
&& stream->stream_header.sample_size != 0
|
||||||
|
&& stream->stream_header.sample_size != 1) { // PCM
|
||||||
|
stream->frame_count /= (stream->stream_header.sample_size + 7) / 8;
|
||||||
|
printf("audio: messing up PCM frame_count?\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->stream_header.rate && stream->stream_header.scale) {
|
||||||
|
stream->frames_per_sec_rate = stream->stream_header.rate;
|
||||||
|
stream->frames_per_sec_scale = stream->stream_header.scale;
|
||||||
|
stream->duration = (stream->frame_count * stream->frames_per_sec_scale * 1000000) / stream->frames_per_sec_rate;
|
||||||
|
printf("audio: using rate+scale\n");
|
||||||
|
} else if (stream->audio_format->avg_bytes_per_sec) {
|
||||||
|
stream->frames_per_sec_rate = stream->audio_format->avg_bytes_per_sec;
|
||||||
|
stream->frames_per_sec_scale = 1;
|
||||||
|
stream->duration = (stream->frame_count * stream->frames_per_sec_scale * 1000000) / stream->frames_per_sec_rate;
|
||||||
|
printf("audio: using avg_bytes_per_sec\n");
|
||||||
|
} else if (AviMainHeader()->micro_sec_per_frame) {
|
||||||
|
uint32 video_frame_count = OdmlExtendedHeader() ? OdmlExtendedHeader()->total_frames : AviMainHeader()->total_frames;
|
||||||
|
stream->duration = video_frame_count * AviMainHeader()->micro_sec_per_frame;
|
||||||
|
stream->frames_per_sec_rate = (stream->frame_count * 1000 * 1000000) / stream->duration;
|
||||||
|
stream->frames_per_sec_scale = 1000;
|
||||||
|
printf("audio: using micro_sec_per_frame\n");
|
||||||
|
} else {
|
||||||
|
printf("audio: no idea what to do\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->audio_format->avg_bytes_per_sec) {
|
||||||
|
int64 expected_frame_count = (stream->duration * stream->audio_format->avg_bytes_per_sec) / 1000000;
|
||||||
|
printf("audio: expected frame_count %lld, calculated stream frame_count %lld\n", expected_frame_count, stream->frame_count);
|
||||||
|
if (expected_frame_count * 9 > stream->frame_count * 10) {
|
||||||
|
printf("audio: something is wrong, ignoring calculated stream frame_count, rate and scale\n");
|
||||||
|
stream->frame_count = expected_frame_count;
|
||||||
|
stream->frames_per_sec_rate = stream->audio_format->avg_bytes_per_sec;
|
||||||
|
stream->frames_per_sec_scale = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("audio: frame_count %lld, duration %.6f, fps %.3f\n",
|
||||||
|
stream->frame_count, stream->duration / 1E6, stream->frames_per_sec_rate / (double)stream->frames_per_sec_scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
OpenDMLParser::SetupVideoStreamLength(stream_info *stream)
|
||||||
|
{
|
||||||
|
stream->frame_count = stream->stream_header.length;
|
||||||
|
if (stream->stream_header.rate && stream->stream_header.scale) {
|
||||||
|
stream->frames_per_sec_rate = stream->stream_header.rate;
|
||||||
|
stream->frames_per_sec_scale = stream->stream_header.scale;
|
||||||
|
printf("video: using rate+scale\n");
|
||||||
|
} else if (AviMainHeader()->micro_sec_per_frame) {
|
||||||
|
stream->frames_per_sec_rate = 1000000;
|
||||||
|
stream->frames_per_sec_scale = AviMainHeader()->micro_sec_per_frame;
|
||||||
|
printf("video: using micro_sec_per_frame\n");
|
||||||
|
} else {
|
||||||
|
stream->frames_per_sec_rate = 25;
|
||||||
|
stream->frames_per_sec_scale = 1;
|
||||||
|
printf("video: using fallback\n");
|
||||||
|
}
|
||||||
|
stream->duration = (stream->frame_count * stream->frames_per_sec_scale * 1000000) / stream->frames_per_sec_rate;
|
||||||
|
|
||||||
|
printf("video: frame_count %lld, duration %.6f, fps %.3f\n",
|
||||||
|
stream->frame_count, stream->duration / 1E6, stream->frames_per_sec_rate / (double)stream->frames_per_sec_scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t
|
||||||
|
OpenDMLParser::Parse()
|
||||||
|
{
|
||||||
|
TRACE("OpenDMLParser::Parse\n");
|
||||||
|
|
||||||
uint64 pos = 0;
|
uint64 pos = 0;
|
||||||
int riff_chunk_number = 0;
|
int riff_chunk_number = 0;
|
||||||
@@ -460,11 +568,6 @@ OpenDMLParser::ParseChunk_strh(uint64 start, uint32 size)
|
|||||||
DO_SWAP_INT16(fCurrentStream->stream_header.rect_bottom);
|
DO_SWAP_INT16(fCurrentStream->stream_header.rect_bottom);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (fCurrentStream->stream_header.scale == 0) {
|
|
||||||
printf("OpenDMLParser::ParseChunk_strh: scale is 0\n");
|
|
||||||
fCurrentStream->stream_header.scale = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fCurrentStream->stream_header_valid = true;
|
fCurrentStream->stream_header_valid = true;
|
||||||
fCurrentStream->is_audio = fCurrentStream->stream_header.fourcc_type == FOURCC('a','u','d','s');
|
fCurrentStream->is_audio = fCurrentStream->stream_header.fourcc_type == FOURCC('a','u','d','s');
|
||||||
fCurrentStream->is_video = fCurrentStream->stream_header.fourcc_type == FOURCC('v','i','d','s');
|
fCurrentStream->is_video = fCurrentStream->stream_header.fourcc_type == FOURCC('v','i','d','s');
|
||||||
@@ -478,7 +581,6 @@ OpenDMLParser::ParseChunk_strh(uint64 start, uint32 size)
|
|||||||
TRACE("initial_frames = %lu\n", fCurrentStream->stream_header.initial_frames);
|
TRACE("initial_frames = %lu\n", fCurrentStream->stream_header.initial_frames);
|
||||||
TRACE("scale = %lu\n", fCurrentStream->stream_header.scale);
|
TRACE("scale = %lu\n", fCurrentStream->stream_header.scale);
|
||||||
TRACE("rate = %lu\n", fCurrentStream->stream_header.rate);
|
TRACE("rate = %lu\n", fCurrentStream->stream_header.rate);
|
||||||
TRACE("frames/sec = %.3f\n", fCurrentStream->stream_header.rate / (float)fCurrentStream->stream_header.scale);
|
|
||||||
TRACE("start = %lu\n", fCurrentStream->stream_header.start);
|
TRACE("start = %lu\n", fCurrentStream->stream_header.start);
|
||||||
TRACE("length = %lu\n", fCurrentStream->stream_header.length);
|
TRACE("length = %lu\n", fCurrentStream->stream_header.length);
|
||||||
TRACE("suggested_buffer_size = %lu\n", fCurrentStream->stream_header.suggested_buffer_size);
|
TRACE("suggested_buffer_size = %lu\n", fCurrentStream->stream_header.suggested_buffer_size);
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
struct stream_info
|
struct stream_info
|
||||||
{
|
{
|
||||||
stream_info * next;
|
stream_info * next; // TODO: replace with a vector<>
|
||||||
bool is_audio;
|
bool is_audio;
|
||||||
bool is_video;
|
bool is_video;
|
||||||
bool stream_header_valid;
|
bool stream_header_valid;
|
||||||
@@ -41,6 +41,11 @@ struct stream_info
|
|||||||
bitmap_info_header video_format;
|
bitmap_info_header video_format;
|
||||||
int64 odml_index_start;
|
int64 odml_index_start;
|
||||||
uint32 odml_index_size;
|
uint32 odml_index_size;
|
||||||
|
|
||||||
|
bigtime_t duration;
|
||||||
|
int64 frame_count;
|
||||||
|
uint32 frames_per_sec_rate;
|
||||||
|
uint32 frames_per_sec_scale;
|
||||||
};
|
};
|
||||||
|
|
||||||
class OpenDMLParser
|
class OpenDMLParser
|
||||||
@@ -49,7 +54,7 @@ public:
|
|||||||
OpenDMLParser(BPositionIO *source);
|
OpenDMLParser(BPositionIO *source);
|
||||||
~OpenDMLParser();
|
~OpenDMLParser();
|
||||||
|
|
||||||
status_t Parse();
|
status_t Init();
|
||||||
|
|
||||||
int StreamCount();
|
int StreamCount();
|
||||||
|
|
||||||
@@ -64,6 +69,7 @@ public:
|
|||||||
const odml_extended_header * OdmlExtendedHeader();
|
const odml_extended_header * OdmlExtendedHeader();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
status_t Parse();
|
||||||
status_t ParseChunk_AVI(int number, uint64 start, uint32 size);
|
status_t ParseChunk_AVI(int number, uint64 start, uint32 size);
|
||||||
status_t ParseChunk_LIST(uint64 start, uint32 size);
|
status_t ParseChunk_LIST(uint64 start, uint32 size);
|
||||||
status_t ParseChunk_idx1(uint64 start, uint32 size);
|
status_t ParseChunk_idx1(uint64 start, uint32 size);
|
||||||
@@ -78,8 +84,12 @@ private:
|
|||||||
status_t ParseList_INFO(uint64 start, uint32 size);
|
status_t ParseList_INFO(uint64 start, uint32 size);
|
||||||
status_t ParseList_strl(uint64 start, uint32 size);
|
status_t ParseList_strl(uint64 start, uint32 size);
|
||||||
|
|
||||||
private:
|
|
||||||
void CreateNewStreamInfo();
|
void CreateNewStreamInfo();
|
||||||
|
void SetupStreamLength(stream_info *stream);
|
||||||
|
void SetupAudioStreamLength(stream_info *stream);
|
||||||
|
void SetupVideoStreamLength(stream_info *stream);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
BPositionIO * fSource;
|
BPositionIO * fSource;
|
||||||
int64 fSize;
|
int64 fSize;
|
||||||
|
|||||||
@@ -33,12 +33,6 @@
|
|||||||
#include <StopWatch.h>
|
#include <StopWatch.h>
|
||||||
|
|
||||||
|
|
||||||
struct StandardIndex::stream_data
|
|
||||||
{
|
|
||||||
uint32 chunk_id;
|
|
||||||
uint32 pos;
|
|
||||||
};
|
|
||||||
|
|
||||||
StandardIndex::StandardIndex(BPositionIO *source, OpenDMLParser *parser)
|
StandardIndex::StandardIndex(BPositionIO *source, OpenDMLParser *parser)
|
||||||
: Index(source, parser)
|
: Index(source, parser)
|
||||||
, fIndex(NULL)
|
, fIndex(NULL)
|
||||||
@@ -53,6 +47,10 @@ StandardIndex::StandardIndex(BPositionIO *source, OpenDMLParser *parser)
|
|||||||
StandardIndex::~StandardIndex()
|
StandardIndex::~StandardIndex()
|
||||||
{
|
{
|
||||||
delete [] fIndex;
|
delete [] fIndex;
|
||||||
|
if (fStreamData) {
|
||||||
|
for (int i = 0; i < fStreamCount; i++)
|
||||||
|
delete [] fStreamData[i].seek_hints;
|
||||||
|
}
|
||||||
delete [] fStreamData;
|
delete [] fStreamData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,6 +61,11 @@ StandardIndex::Init()
|
|||||||
uint32 indexBytes = fParser->StandardIndexSize();
|
uint32 indexBytes = fParser->StandardIndexSize();
|
||||||
fIndexSize = indexBytes / sizeof(avi_standard_index_entry);
|
fIndexSize = indexBytes / sizeof(avi_standard_index_entry);
|
||||||
indexBytes = fIndexSize * sizeof(avi_standard_index_entry);
|
indexBytes = fIndexSize * sizeof(avi_standard_index_entry);
|
||||||
|
uint32 seekHintsStride = 1800 * fStreamCount;
|
||||||
|
uint32 seekHintsMax = fIndexSize / seekHintsStride;
|
||||||
|
|
||||||
|
printf("StandardIndex::Init: seekHintsStride %lu\n", seekHintsStride);
|
||||||
|
printf("StandardIndex::Init: seekHintsMax %lu\n", seekHintsMax);
|
||||||
|
|
||||||
{ BStopWatch w("StandardIndex::Init: malloc");
|
{ BStopWatch w("StandardIndex::Init: malloc");
|
||||||
|
|
||||||
@@ -92,13 +95,61 @@ StandardIndex::Init()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//DumpIndex();
|
||||||
|
|
||||||
fStreamData = new stream_data[fStreamCount];
|
fStreamData = new stream_data[fStreamCount];
|
||||||
for (int i = 0; i < fStreamCount; i++) {
|
for (int i = 0; i < fStreamCount; i++) {
|
||||||
fStreamData[i].chunk_id = i / 10 + '0' + (i % 10 + '0') * 256;
|
fStreamData[i].chunk_id = i / 10 + '0' + (i % 10 + '0') * 256;
|
||||||
fStreamData[i].pos = 0;
|
fStreamData[i].chunk_count = 0;
|
||||||
|
fStreamData[i].keyframe_count = 0;
|
||||||
|
fStreamData[i].stream_pos = 0;
|
||||||
|
fStreamData[i].stream_size = 0;
|
||||||
|
fStreamData[i].seek_hints = new seek_hint[seekHintsMax];
|
||||||
|
fStreamData[i].seek_hints_count = 0;
|
||||||
|
fStreamData[i].seek_hints_next = seekHintsStride;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ BStopWatch w("StandardIndex::Init: scan index");
|
||||||
|
|
||||||
//DumpIndex();
|
for (int stream = 0; stream < fStreamCount; stream++) {
|
||||||
|
uint32 chunk_id = fStreamData[stream].chunk_id;
|
||||||
|
uint64 stream_size = 0;
|
||||||
|
uint32 chunk_count = 0;
|
||||||
|
uint32 keyframe_count = 0;
|
||||||
|
int seek_hints_next = seekHintsStride;
|
||||||
|
int seek_hints_count = 0;
|
||||||
|
for (int i = 0; i < fIndexSize; i++) {
|
||||||
|
if ((fIndex[i].chunk_id & 0xffff) == chunk_id) {
|
||||||
|
stream_size += fIndex[i].chunk_length;
|
||||||
|
chunk_count++;
|
||||||
|
keyframe_count += (fIndex[i].flags >> AVIIF_KEYFRAME_SHIFT) & 1;
|
||||||
|
|
||||||
|
if (i >= seek_hints_next) {
|
||||||
|
seek_hints_next = i + seekHintsStride;
|
||||||
|
seek_hint *hint = &fStreamData[stream].seek_hints[seek_hints_count++];
|
||||||
|
hint->stream_pos = fIndex[i].chunk_offset;
|
||||||
|
hint->index_pos = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fStreamData[stream].stream_size = stream_size;
|
||||||
|
fStreamData[stream].chunk_count = chunk_count;
|
||||||
|
fStreamData[stream].keyframe_count = keyframe_count;
|
||||||
|
fStreamData[stream].seek_hints_count = seek_hints_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < fStreamCount; i++) {
|
||||||
|
printf("stream %d, stream_size %llu\n", i, fStreamData[i].stream_size);
|
||||||
|
printf("stream %d, chunk_count %lu\n", i, fStreamData[i].chunk_count);
|
||||||
|
printf("stream %d, keyframe_count %lu\n", i, fStreamData[i].keyframe_count);
|
||||||
|
printf("stream %d, seek_hints_count %lu\n", i, fStreamData[i].seek_hints_count);
|
||||||
|
for (int j = 0; j < fStreamData[i].seek_hints_count; j++) {
|
||||||
|
printf(" seek_hint %3d, index_pos %6lu, stream_pos %lld\n", j,
|
||||||
|
fStreamData[i].seek_hints[j].index_pos,
|
||||||
|
fStreamData[i].seek_hints[j].stream_pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -132,15 +183,15 @@ status_t
|
|||||||
StandardIndex::GetNextChunkInfo(int stream_index, int64 *start, uint32 *size, bool *keyframe)
|
StandardIndex::GetNextChunkInfo(int stream_index, int64 *start, uint32 *size, bool *keyframe)
|
||||||
{
|
{
|
||||||
stream_data *data = &fStreamData[stream_index];
|
stream_data *data = &fStreamData[stream_index];
|
||||||
while (data->pos < fIndexSize) {
|
while (data->stream_pos < fIndexSize) {
|
||||||
if ((fIndex[data->pos].chunk_id & 0xffff) == data->chunk_id) {
|
if ((fIndex[data->stream_pos].chunk_id & 0xffff) == data->chunk_id) {
|
||||||
*keyframe = fIndex[data->pos].flags & AVIIF_KEYFRAME;
|
*keyframe = fIndex[data->stream_pos].flags & AVIIF_KEYFRAME;
|
||||||
*start = fDataOffset + fIndex[data->pos].chunk_offset + 8; // skip 8 bytes (chunk id + chunk size)
|
*start = fDataOffset + fIndex[data->stream_pos].chunk_offset + 8; // skip 8 bytes (chunk id + chunk size)
|
||||||
*size = fIndex[data->pos].chunk_length;
|
*size = fIndex[data->stream_pos].chunk_length;
|
||||||
data->pos++;
|
data->stream_pos++;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
data->pos++;
|
data->stream_pos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
@@ -150,13 +201,59 @@ StandardIndex::GetNextChunkInfo(int stream_index, int64 *start, uint32 *size, bo
|
|||||||
status_t
|
status_t
|
||||||
StandardIndex::Seek(int stream_index, uint32 seekTo, int64 *frame, bigtime_t *time)
|
StandardIndex::Seek(int stream_index, uint32 seekTo, int64 *frame, bigtime_t *time)
|
||||||
{
|
{
|
||||||
/*
|
printf("StandardIndex::Seek: stream %d, seekTo%s%s%s%s, time %Ld, frame %Ld\n",
|
||||||
printf("StandardIndex::Seek: seekTo%s%s%s%s, time %Ld, frame %Ld\n",
|
stream_index,
|
||||||
(seekTo & B_MEDIA_SEEK_TO_TIME) ? " B_MEDIA_SEEK_TO_TIME" : "",
|
(seekTo & B_MEDIA_SEEK_TO_TIME) ? " B_MEDIA_SEEK_TO_TIME" : "",
|
||||||
(seekTo & B_MEDIA_SEEK_TO_FRAME) ? " B_MEDIA_SEEK_TO_FRAME" : "",
|
(seekTo & B_MEDIA_SEEK_TO_FRAME) ? " B_MEDIA_SEEK_TO_FRAME" : "",
|
||||||
(seekTo & B_MEDIA_SEEK_CLOSEST_FORWARD) ? " B_MEDIA_SEEK_CLOSEST_FORWARD" : "",
|
(seekTo & B_MEDIA_SEEK_CLOSEST_FORWARD) ? " B_MEDIA_SEEK_CLOSEST_FORWARD" : "",
|
||||||
(seekTo & B_MEDIA_SEEK_CLOSEST_BACKWARD) ? " B_MEDIA_SEEK_CLOSEST_BACKWARD" : "");
|
(seekTo & B_MEDIA_SEEK_CLOSEST_BACKWARD) ? " B_MEDIA_SEEK_CLOSEST_BACKWARD" : "",
|
||||||
*/
|
*time, *frame);
|
||||||
|
|
||||||
|
const stream_info *stream = fParser->StreamInfo(stream_index);
|
||||||
|
stream_data *data = &fStreamData[stream_index];
|
||||||
|
|
||||||
|
int64 frame_pos;
|
||||||
|
if (seekTo & B_MEDIA_SEEK_TO_FRAME)
|
||||||
|
frame_pos = *frame;
|
||||||
|
else if (seekTo & B_MEDIA_SEEK_TO_TIME)
|
||||||
|
frame_pos = (*time * stream->frames_per_sec_rate) / (1000000 * stream->frames_per_sec_scale);
|
||||||
|
else
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
if (stream->is_audio) {
|
||||||
|
int64 bytes = 0;
|
||||||
|
for (int i = 0; i < fIndexSize; i++) {
|
||||||
|
if ((fIndex[i].chunk_id & 0xffff) == data->chunk_id) {
|
||||||
|
int64 bytesNext = bytes + fIndex[i].chunk_length;
|
||||||
|
if (bytes <= frame_pos && bytesNext > frame_pos) {
|
||||||
|
data->stream_pos = i;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
bytes = bytesNext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (stream->is_video) {
|
||||||
|
int pos = 0;
|
||||||
|
for (int i = 0; i < fIndexSize; i++) {
|
||||||
|
if ((fIndex[i].chunk_id & 0xffff) == data->chunk_id) {
|
||||||
|
if (pos == frame_pos) {
|
||||||
|
data->stream_pos = i;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("seek failed, position not found\n");
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
|
done:
|
||||||
|
printf("seek done: index: pos %d, size %d\n", data->stream_pos, fIndexSize);
|
||||||
|
*frame = frame_pos;
|
||||||
|
*time = (frame_pos * 1000000 * stream->frames_per_sec_scale) / stream->frames_per_sec_rate;
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,24 @@ private:
|
|||||||
void DumpIndex();
|
void DumpIndex();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct stream_data;
|
struct seek_hint
|
||||||
|
{
|
||||||
|
uint64 stream_pos;
|
||||||
|
uint32 index_pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct stream_data
|
||||||
|
{
|
||||||
|
uint32 chunk_id;
|
||||||
|
uint32 chunk_count;
|
||||||
|
uint32 keyframe_count;
|
||||||
|
uint32 stream_pos;
|
||||||
|
uint64 stream_size;
|
||||||
|
seek_hint * seek_hints;
|
||||||
|
int seek_hints_count;
|
||||||
|
uint32 seek_hints_next;
|
||||||
|
};
|
||||||
|
|
||||||
avi_standard_index_entry *fIndex;
|
avi_standard_index_entry *fIndex;
|
||||||
uint32 fIndexSize;
|
uint32 fIndexSize;
|
||||||
stream_data * fStreamData;
|
stream_data * fStreamData;
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ struct avi_standard_index_entry
|
|||||||
} _PACKED;
|
} _PACKED;
|
||||||
#define AVIIF_LIST 0x00000001
|
#define AVIIF_LIST 0x00000001
|
||||||
#define AVIIF_KEYFRAME 0x00000010
|
#define AVIIF_KEYFRAME 0x00000010
|
||||||
|
#define AVIIF_KEYFRAME_SHIFT 4
|
||||||
#define AVIIF_FIRSTPART 0x00000020
|
#define AVIIF_FIRSTPART 0x00000020
|
||||||
#define AVIIF_LASTPART 0x00000040
|
#define AVIIF_LASTPART 0x00000040
|
||||||
#define AVIIF_MIDPART (AVIIF_LASTPART | AVIFF_FIRSTPART)
|
#define AVIIF_MIDPART (AVIIF_LASTPART | AVIFF_FIRSTPART)
|
||||||
|
|||||||
Reference in New Issue
Block a user