rework seeking calculations
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28025 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
fe0570240c
commit
aef9c5249e
@ -46,16 +46,16 @@
|
||||
|
||||
struct wavdata
|
||||
{
|
||||
uint64 position;
|
||||
uint64 datasize;
|
||||
int64 position;
|
||||
int64 datasize;
|
||||
|
||||
int32 bitsperframe;
|
||||
int32 fps;
|
||||
uint32 bitrate;
|
||||
uint32 fps;
|
||||
|
||||
void *buffer;
|
||||
int32 buffersize;
|
||||
uint32 buffersize;
|
||||
|
||||
int64 framecount;
|
||||
uint64 framecount;
|
||||
bigtime_t duration;
|
||||
|
||||
bool raw;
|
||||
@ -63,6 +63,30 @@ struct wavdata
|
||||
media_format format;
|
||||
};
|
||||
|
||||
static bigtime_t FrameToTime(uint64 frame, uint32 fps) {
|
||||
return frame * 1000000LL / fps;
|
||||
}
|
||||
|
||||
static uint64 TimeToFrame(bigtime_t time, uint32 fps) {
|
||||
return (time * fps) / 1000000LL;
|
||||
}
|
||||
|
||||
static int64 TimeToPosition(bigtime_t time, uint32 bitrate) {
|
||||
return (time * bitrate) / 8000000LL;
|
||||
}
|
||||
|
||||
static bigtime_t PositionToTime(int64 position, uint32 bitrate) {
|
||||
return (position * 8000000LL) / bitrate;
|
||||
}
|
||||
|
||||
static int64 FrameToPosition(uint64 frame, uint32 bitrate, uint32 fps) {
|
||||
return TimeToPosition(FrameToTime(frame,fps),bitrate);
|
||||
}
|
||||
|
||||
static uint64 PositionToFrame(int64 position, uint32 bitrate, uint32 fps) {
|
||||
return TimeToFrame(PositionToTime(position,bitrate),fps);
|
||||
}
|
||||
|
||||
WavReader::WavReader()
|
||||
{
|
||||
TRACE("WavReader::WavReader\n");
|
||||
@ -204,19 +228,23 @@ WavReader::Sniff(int32 *streamCount)
|
||||
}
|
||||
|
||||
fChannelCount = UINT16(format.channels);
|
||||
fFrameRate = UINT32(format.samples_per_sec);
|
||||
fSampleRate = UINT32(format.samples_per_sec);
|
||||
fBlockAlign = UINT16(format.block_align);
|
||||
fBitsPerSample = UINT16(format.bits_per_sample);
|
||||
if (fBitsPerSample == 0) {
|
||||
printf("WavReader::Sniff: Error, bits_per_sample = 0 assuming 8\n");
|
||||
fBitsPerSample = 8;
|
||||
printf("WavReader::Sniff: Error, bits_per_sample = 0 calculating\n");
|
||||
fBitsPerSample = fBlockAlign * 8 / fChannelCount;
|
||||
}
|
||||
fFrameRate = fSampleRate * fChannelCount;
|
||||
|
||||
fAvgBytesPerSec = format.avg_bytes_per_sec;
|
||||
fFrameCount = foundFact ? UINT32(fact.sample_length) : 0;
|
||||
|
||||
// fact.sample_length is really no of samples for all channels
|
||||
fFrameCount = foundFact ? UINT32(fact.sample_length) / fChannelCount : 0;
|
||||
fFormatCode = UINT16(format.format_tag);
|
||||
if (fFormatCode == 0xfffe && foundFmtExt)
|
||||
fFormatCode = (format_ext.guid[1] << 8) | format_ext.guid[0];
|
||||
|
||||
fBlockAlign = UINT16(format.block_align);
|
||||
int min_align = (fFormatCode == 0x0001) ? (fBitsPerSample * fChannelCount + 7) / 8 : 1;
|
||||
if (fBlockAlign < min_align)
|
||||
fBlockAlign = min_align;
|
||||
@ -224,6 +252,7 @@ WavReader::Sniff(int32 *streamCount)
|
||||
TRACE(" fDataStart %Ld\n", fDataStart);
|
||||
TRACE(" fDataSize %Ld\n", fDataSize);
|
||||
TRACE(" fChannelCount %ld\n", fChannelCount);
|
||||
TRACE(" fSampleRate %ld\n", fSampleRate);
|
||||
TRACE(" fFrameRate %ld\n", fFrameRate);
|
||||
TRACE(" fFrameCount %Ld\n", fFrameCount);
|
||||
TRACE(" fBitsPerSample %d\n", fBitsPerSample);
|
||||
@ -231,7 +260,7 @@ WavReader::Sniff(int32 *streamCount)
|
||||
TRACE(" min_align %d\n", min_align);
|
||||
TRACE(" fFormatCode 0x%04x\n", fFormatCode);
|
||||
|
||||
// XXX fact.sample_length contains duration of encodec files?
|
||||
// XXX fact.sample_length contains duration of encoded files?
|
||||
|
||||
*streamCount = 1;
|
||||
return B_OK;
|
||||
@ -262,29 +291,25 @@ WavReader::AllocateCookie(int32 streamNumber, void **cookie)
|
||||
|
||||
data->position = 0;
|
||||
data->datasize = fDataSize;
|
||||
data->bitsperframe = fChannelCount * fBitsPerSample;
|
||||
data->fps = fFrameRate;
|
||||
data->fps = fSampleRate;
|
||||
data->buffersize = (BUFFER_SIZE / fBlockAlign) * fBlockAlign;
|
||||
data->buffer = malloc(data->buffersize);
|
||||
data->framecount = fFrameCount ? fFrameCount : (8 * fDataSize) / data->bitsperframe;
|
||||
if (fFormatCode == 0x0055) {
|
||||
// mp3 in wav file
|
||||
if (fAvgBytesPerSec) {
|
||||
data->duration = (data->datasize * 1000000LL) / fAvgBytesPerSec;
|
||||
} else {
|
||||
data->duration = (data->framecount * 1000000LL) / data->fps / fBitsPerSample * fChannelCount;
|
||||
}
|
||||
} else {
|
||||
data->duration = (data->framecount * 1000000LL) / data->fps;
|
||||
}
|
||||
data->framecount = fFrameCount ? fFrameCount : (8 * fDataSize) / (fChannelCount * fBitsPerSample);
|
||||
data->raw = fFormatCode == 0x0001;
|
||||
|
||||
TRACE(" bitsperframe %ld\n", data->bitsperframe);
|
||||
TRACE(" fps %ld\n", data->fps);
|
||||
TRACE(" buffersize %ld\n", data->buffersize);
|
||||
if (!fAvgBytesPerSec) {
|
||||
fAvgBytesPerSec = fSampleRate * fBlockAlign;
|
||||
}
|
||||
|
||||
data->duration = (data->datasize * 1000000LL) / fAvgBytesPerSec;
|
||||
data->bitrate = fAvgBytesPerSec * 8;
|
||||
|
||||
TRACE(" raw %s\n", data->raw ? "true" : "false");
|
||||
TRACE(" framecount %Ld\n", data->framecount);
|
||||
TRACE(" duration %Ld\n", data->duration);
|
||||
TRACE(" raw %d\n", data->raw);
|
||||
TRACE(" duration %Ld\n", data->duration);
|
||||
TRACE(" bitrate %ld\n", data->bitrate);
|
||||
TRACE(" fps %ld\n", data->fps);
|
||||
TRACE(" buffersize %ld\n", data->buffersize);
|
||||
|
||||
BMediaFormats formats;
|
||||
if (fFormatCode == 0x0001) {
|
||||
@ -293,7 +318,8 @@ WavReader::AllocateCookie(int32 streamNumber, void **cookie)
|
||||
description.family = B_BEOS_FORMAT_FAMILY;
|
||||
description.u.beos.format = B_BEOS_FORMAT_RAW_AUDIO;
|
||||
formats.GetFormatFor(description, &data->format);
|
||||
data->format.u.raw_audio.frame_rate = fFrameRate;
|
||||
// Really SampleRate
|
||||
data->format.u.raw_audio.frame_rate = fSampleRate;
|
||||
data->format.u.raw_audio.channel_count = fChannelCount;
|
||||
switch (fBitsPerSample) {
|
||||
case 8:
|
||||
@ -321,7 +347,8 @@ WavReader::AllocateCookie(int32 streamNumber, void **cookie)
|
||||
description.family = B_WAV_FORMAT_FAMILY;
|
||||
description.u.wav.codec = fFormatCode;
|
||||
formats.GetFormatFor(description, &data->format);
|
||||
data->format.u.encoded_audio.output.frame_rate = fFrameRate;
|
||||
// Really SampleRate
|
||||
data->format.u.encoded_audio.output.frame_rate = fSampleRate;
|
||||
data->format.u.encoded_audio.output.channel_count = fChannelCount;
|
||||
}
|
||||
|
||||
@ -358,6 +385,42 @@ WavReader::GetStreamInfo(void *cookie, int64 *frameCount, bigtime_t *duration,
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t
|
||||
WavReader::CalculateNewPosition(void *cookie,
|
||||
uint32 flags,
|
||||
int64 *frame, bigtime_t *time, int64 *position)
|
||||
{
|
||||
wavdata *data = reinterpret_cast<wavdata *>(cookie);
|
||||
|
||||
if (flags & B_MEDIA_SEEK_TO_FRAME) {
|
||||
TRACE(" to frame %Ld",*frame);
|
||||
*position = FrameToPosition(*frame, data->bitrate, data->fps);
|
||||
|
||||
} else if (flags & B_MEDIA_SEEK_TO_TIME) {
|
||||
TRACE(" to time %Ld", *time);
|
||||
*position = TimeToPosition(*time, data->bitrate);
|
||||
} else {
|
||||
printf("WavReader::CalculateNewPosition invalid flag passed %ld\n", flags);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
*position = (*position / fBlockAlign) * fBlockAlign; // round down to a block start
|
||||
|
||||
TRACE(", position %Ld ", *position);
|
||||
|
||||
*frame = PositionToFrame(*position, data->bitrate, data->fps);
|
||||
*time = FrameToTime(*frame,data->fps);
|
||||
|
||||
TRACE("newtime %Ld ", *time);
|
||||
TRACE("newframe %Ld\n", *frame);
|
||||
|
||||
if (*position < 0 || *position > data->datasize) {
|
||||
printf("WavReader::CalculateNewPosition invalid position %Ld\n", *position);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t
|
||||
WavReader::Seek(void *cookie,
|
||||
@ -366,42 +429,18 @@ WavReader::Seek(void *cookie,
|
||||
{
|
||||
// Seek to the given position
|
||||
wavdata *data = reinterpret_cast<wavdata *>(cookie);
|
||||
uint64 pos;
|
||||
|
||||
if (flags & B_MEDIA_SEEK_TO_FRAME) {
|
||||
if (data->raw)
|
||||
pos = (*frame * data->bitsperframe) / 8;
|
||||
else
|
||||
pos = (*frame * fDataSize) / data->framecount;
|
||||
pos = (pos / fBlockAlign) * fBlockAlign; // round down to a block start
|
||||
TRACE("WavReader::Seek to frame %Ld, pos %Ld\n", *frame, pos);
|
||||
} else if (flags & B_MEDIA_SEEK_TO_TIME) {
|
||||
if (data->raw)
|
||||
pos = (*time * data->fps * data->bitsperframe) / (1000000LL * 8);
|
||||
else
|
||||
pos = (*time * fDataSize) / data->duration;
|
||||
pos = (pos / fBlockAlign) * fBlockAlign; // round down to a block start
|
||||
TRACE("WavReader::Seek to time %Ld, pos %Ld\n", *time, pos);
|
||||
} else {
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (data->raw)
|
||||
*frame = (8 * pos) / data->bitsperframe;
|
||||
else
|
||||
*frame = (pos * data->framecount) / fDataSize;
|
||||
*time = (*frame * 1000000LL) / data->fps;
|
||||
|
||||
TRACE("WavReader::Seek newtime %Ld\n", *time);
|
||||
TRACE("WavReader::Seek newframe %Ld\n", *frame);
|
||||
status_t status;
|
||||
int64 pos;
|
||||
|
||||
if (pos < 0 || pos > data->datasize) {
|
||||
TRACE("WavReader::Seek invalid position %Ld\n", pos);
|
||||
return B_ERROR;
|
||||
TRACE("WavReader::Seek");
|
||||
status = CalculateNewPosition(cookie, flags, frame, time, &pos);
|
||||
|
||||
if (status == B_OK) {
|
||||
// set the new position so next GetNextChunk will read from new seek pos
|
||||
data->position = pos;
|
||||
}
|
||||
|
||||
data->position = pos;
|
||||
return B_OK;
|
||||
return status;
|
||||
}
|
||||
|
||||
status_t
|
||||
@ -409,42 +448,10 @@ WavReader::FindKeyFrame(void* cookie, uint32 flags,
|
||||
int64* frame, bigtime_t* time)
|
||||
{
|
||||
// Find a seek position without actually seeking
|
||||
wavdata *data = reinterpret_cast<wavdata *>(cookie);
|
||||
uint64 pos;
|
||||
|
||||
if (flags & B_MEDIA_SEEK_TO_FRAME) {
|
||||
if (data->raw)
|
||||
pos = (*frame * data->bitsperframe) / 8;
|
||||
else
|
||||
pos = (*frame * fDataSize) / data->framecount;
|
||||
pos = (pos / fBlockAlign) * fBlockAlign; // round down to a block start
|
||||
TRACE("WavReader::Seek to frame %Ld, pos %Ld\n", *frame, pos);
|
||||
} else if (flags & B_MEDIA_SEEK_TO_TIME) {
|
||||
if (data->raw)
|
||||
pos = (*time * data->fps * data->bitsperframe) / (1000000LL * 8);
|
||||
else
|
||||
pos = (*time * fDataSize) / data->duration;
|
||||
pos = (pos / fBlockAlign) * fBlockAlign; // round down to a block start
|
||||
TRACE("WavReader::Seek to time %Ld, pos %Ld\n", *time, pos);
|
||||
} else {
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (data->raw)
|
||||
*frame = (8 * pos) / data->bitsperframe;
|
||||
else
|
||||
*frame = (pos * data->framecount) / fDataSize;
|
||||
*time = (*frame * 1000000LL) / data->fps;
|
||||
|
||||
TRACE("WavReader::Seek newtime %Ld\n", *time);
|
||||
TRACE("WavReader::Seek newframe %Ld\n", *frame);
|
||||
int64 pos;
|
||||
TRACE("WavReader::FindKeyFrame");
|
||||
|
||||
if (pos < 0 || pos > data->datasize) {
|
||||
TRACE("WavReader::Seek invalid position %Ld\n", pos);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
return CalculateNewPosition(cookie, flags, frame, time, &pos);
|
||||
}
|
||||
|
||||
status_t
|
||||
@ -456,28 +463,25 @@ WavReader::GetNextChunk(void *cookie,
|
||||
|
||||
// XXX it might be much better to not return any start_time information for encoded formats here,
|
||||
// XXX and instead use the last time returned from seek and count forward after decoding.
|
||||
if (data->raw)
|
||||
mediaHeader->start_time = (((8 * data->position) / data->bitsperframe) * 1000000LL) / data->fps;
|
||||
else
|
||||
mediaHeader->start_time = (data->position * data->duration) / fDataSize;
|
||||
mediaHeader->start_time = PositionToTime(data->position,data->bitrate);
|
||||
mediaHeader->file_pos = fDataStart + data->position;
|
||||
|
||||
/*
|
||||
printf("position = %9Ld\n", data->position);
|
||||
printf("fDataSize = %9Ld\n", fDataSize);
|
||||
printf("duration = %9Ld\n", data->duration);
|
||||
printf("start_time = %9Ld\n", mediaHeader->start_time);
|
||||
*/
|
||||
TRACE("(%s) position = %9Ld ", data->raw ? "raw" : "encoded", data->position);
|
||||
TRACE("frame = %9Ld ", PositionToFrame(data->position,data->bitrate,data->fps));
|
||||
TRACE("fDataSize = %9Ld ", fDataSize);
|
||||
TRACE("start_time = %9Ld\n", mediaHeader->start_time);
|
||||
|
||||
int64 maxreadsize = data->datasize - data->position;
|
||||
int32 readsize = data->buffersize;
|
||||
if (maxreadsize < readsize)
|
||||
readsize = maxreadsize;
|
||||
if (readsize == 0)
|
||||
if (readsize == 0) {
|
||||
printf("WavReader::GetNextChunk: LAST BUFFER ERROR at time %9Ld\n",mediaHeader->start_time);
|
||||
return B_LAST_BUFFER_ERROR;
|
||||
|
||||
}
|
||||
|
||||
if (readsize != Source()->ReadAt(fDataStart + data->position, data->buffer, readsize)) {
|
||||
TRACE("WavReader::GetNextChunk: unexpected read error\n");
|
||||
printf("WavReader::GetNextChunk: unexpected read error at position %9Ld\n",fDataStart + data->position);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,10 @@ public:
|
||||
status_t GetNextChunk(void *cookie,
|
||||
const void **chunkBuffer, size_t *chunkSize,
|
||||
media_header *mediaHeader);
|
||||
|
||||
|
||||
status_t CalculateNewPosition(void* cookie, uint32 flags,
|
||||
int64 *frame, bigtime_t *time, int64 *position);
|
||||
|
||||
BPositionIO *Source() { return fSource; }
|
||||
|
||||
private:
|
||||
@ -67,10 +70,11 @@ private:
|
||||
int64 fFrameCount;
|
||||
int32 fChannelCount;
|
||||
int32 fFrameRate;
|
||||
int fBitsPerSample;
|
||||
int32 fSampleRate;
|
||||
uint16 fBitsPerSample;
|
||||
uint16 fFormatCode;
|
||||
uint16 fBlockAlign;
|
||||
uint16 fAvgBytesPerSec;
|
||||
uint32 fAvgBytesPerSec;
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user