seek and sync, it doesn't get much better than this

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6632 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
shatty 2004-02-18 13:10:28 +00:00
parent b797c2778b
commit dc51127a5d
6 changed files with 69 additions and 27 deletions

View File

@ -51,6 +51,10 @@ OggSeekable::OggSeekable(long serialno)
ogg_stream_init(&fStreamState,serialno);
fPosition = 0;
fLastPagePosition = 0;
fCurrentFrame = 0;
fCurrentTime = 0;
fFirstGranulepos = 0;
fFrameRate = 0;
}
@ -267,6 +271,7 @@ OggSeekable::GetStreamInfo(int64 *frameCount, bigtime_t *duration,
status_t
OggSeekable::Seek(uint32 seekTo, int64 *frame, bigtime_t *time)
{
status_t status;
int64 granulepos;
if (seekTo & B_MEDIA_SEEK_TO_TIME) {
TRACE("OggSeekable::Seek: seek to time: %lld\n", *time);
@ -286,7 +291,12 @@ OggSeekable::Seek(uint32 seekTo, int64 *frame, bigtime_t *time)
// find the first packet with data in it
ogg_page page;
off_t left = 0;
Seek(0, SEEK_SET);
BAutolock autolock(fPositionLock);
off_t pos = Seek(0, SEEK_SET);
if (pos < 0) {
TRACE("OggSeekable::Seek: Seek = %s\n", strerror(status));
return status;
}
uint header_packets_left = GetHeaderPackets().size();
while (header_packets_left > 0) {
status_t status = ReadPage(&page, B_PAGE_SIZE);
@ -297,6 +307,17 @@ OggSeekable::Seek(uint32 seekTo, int64 *frame, bigtime_t *time)
header_packets_left -= ogg_page_packets(&page);
left += page.header_len + page.body_len;
}
TRACE("OggSeekable::Seek: header packets end after = %llu\n", left);
pos = Seek(left, SEEK_SET);
if (pos < 0) {
TRACE("OggSeekable::Seek: Seek2 = %s\n", strerror(status));
return status;
}
status = ReadPage(&page, B_PAGE_SIZE);
if (status != B_OK) {
TRACE("OggSeekable::Seek: ReadPage2 = %s\n", strerror(status));
return status;
}
if (ogg_page_continued(&page)) {
TRACE("OggSeekable::Seek: warning: data packet began in header page!\n");
// how to handle this?
@ -318,7 +339,7 @@ OggSeekable::Seek(uint32 seekTo, int64 *frame, bigtime_t *time)
done = true;
}
do {
status_t status = ReadPage(&page, B_PAGE_SIZE);
status = ReadPage(&page, B_PAGE_SIZE);
if (status != B_OK) {
TRACE("OggSeekable::Seek: ReadPage = %s\n", strerror(status));
return status;
@ -350,7 +371,7 @@ OggSeekable::Seek(uint32 seekTo, int64 *frame, bigtime_t *time)
if (*frame != 0) {
ogg_packet packet;
do {
status_t status = GetPacket(&packet);
status = GetPacket(&packet);
if (status != B_OK) {
TRACE("OggSeekable::Seek: GetPacket = %s\n", strerror(status));
return status;
@ -423,11 +444,11 @@ OggSeekable::Seek(uint32 seekTo, int64 *frame, bigtime_t *time)
}*/
// the default chunk is an ogg packet
status_t
OggSeekable::GetNextChunk(void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader)
media_header *mediaHeader)
{
BAutolock autolock(fPositionLock);
mediaHeader->start_time = fCurrentTime;
mediaHeader->file_pos = fPosition;
status_t result = GetPacket(&fChunkPacket);
@ -437,7 +458,11 @@ OggSeekable::GetNextChunk(void **chunkBuffer, int32 *chunkSize,
}
*chunkBuffer = &fChunkPacket;
*chunkSize = sizeof(fChunkPacket);
fCurrentFrame++;
if (fChunkPacket.granulepos > 0) {
fCurrentFrame = fChunkPacket.granulepos - fFirstGranulepos;
} else {
fCurrentFrame++;
}
fCurrentTime = (bigtime_t)((fCurrentFrame * 1000000LL) / fFrameRate);
return B_OK;
}

View File

@ -185,12 +185,12 @@ status_t
OggSpeexSeekable::GetNextChunk(void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader)
{
status_t result = GetPacket(&fChunkPacket);
status_t result = inherited::GetNextChunk(chunkBuffer, chunkSize, mediaHeader);
if (result != B_OK) {
TRACE("OggSpeexSeekable::GetNextChunk failed: GetPacket = %s\n", strerror(result));
TRACE("OggSpeexSeekable::GetNextChunk failed: GetNextChunk = %s\n", strerror(result));
return result;
}
*chunkBuffer = fChunkPacket.packet;
*chunkSize = fChunkPacket.bytes;
*chunkSize = ((ogg_packet*)*chunkBuffer)->bytes;
*chunkBuffer = ((ogg_packet*)*chunkBuffer)->packet;
return B_OK;
}

View File

@ -261,24 +261,21 @@ status_t
OggTobiasSeekable::GetNextChunk(void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader)
{
status_t result = GetPacket(&fChunkPacket);
status_t result = inherited::GetNextChunk(chunkBuffer, chunkSize, mediaHeader);
if (result != B_OK) {
TRACE("OggTobiasSeekable::GetNextChunk failed: GetPacket = %s\n", strerror(result));
TRACE("OggTobiasSeekable::GetNextChunk failed: GetNextChunk = %s\n", strerror(result));
return result;
}
*chunkBuffer = fChunkPacket.packet;
*chunkSize = fChunkPacket.bytes;
bool keyframe = fChunkPacket.packet[0] & (1 << 3); // ??
*chunkSize = ((ogg_packet*)*chunkBuffer)->bytes;
*chunkBuffer = ((ogg_packet*)*chunkBuffer)->packet;
bool keyframe = ((uint*)chunkBuffer)[0] & (1 << 3); // ??
if (fMediaFormat.type == B_MEDIA_ENCODED_VIDEO) {
mediaHeader->type = fMediaFormat.type;
mediaHeader->start_time = fCurrentTime;
mediaHeader->u.encoded_video.field_flags = (keyframe ? B_MEDIA_KEY_FRAME : 0);
mediaHeader->u.encoded_video.first_active_line
= fMediaFormat.u.encoded_video.output.first_active;
mediaHeader->u.encoded_video.line_count
= fMediaFormat.u.encoded_video.output.display.line_count;
}
fCurrentFrame++;
fCurrentTime = (bigtime_t)(fCurrentFrame * fMicrosecPerFrame);
return B_OK;
}

View File

@ -51,6 +51,7 @@ SpeexDecoder::SpeexDecoder()
fHeader = 0;
fStereoState = 0;
fSpeexOutputLength = 0;
fStartTime = 0;
fFrameSize = 0;
fOutputBufferSize = 0;
}
@ -249,8 +250,9 @@ SpeexDecoder::Decode(void *buffer, int64 *frameCount,
float * out_buffer = static_cast<float *>(buffer);
int32 out_bytes_needed = fOutputBufferSize;
bool start = false;
bool synced = false;
int total_samples = 0;
while (out_bytes_needed >= fSpeexOutputLength) {
// get a new packet
void *chunkBuffer;
@ -264,9 +266,11 @@ SpeexDecoder::Decode(void *buffer, int64 *frameCount,
TRACE("SpeexDecoder::Decode: GetNextChunk failed\n");
return status;
}
if (!start) {
mediaHeader->start_time = mh.start_time;
start = true;
if (!synced) {
if (mh.start_time > 0) {
mediaHeader->start_time = mh.start_time - total_samples / fHeader->rate;
synced = true;
}
}
speex_bits_read_from(&fBits, (char*)chunkBuffer, chunkSize);
for (int frame = 0 ; frame < fHeader->frames_per_packet ; frame++) {
@ -290,10 +294,16 @@ SpeexDecoder::Decode(void *buffer, int64 *frameCount,
}
out_buffer += fHeader->frame_size * fHeader->nb_channels;
out_bytes_needed -= fSpeexOutputLength;
total_samples += fHeader->frame_size;
}
}
done:
if (!synced) {
mediaHeader->start_time = fStartTime;
}
fStartTime = mediaHeader->start_time + total_samples / fHeader->rate;
*frameCount = (fOutputBufferSize - out_bytes_needed) / fFrameSize;
if (out_buffer != buffer) {

View File

@ -46,7 +46,7 @@ VorbisDecoder::VorbisDecoder()
TRACE("VorbisDecoder::VorbisDecoder\n");
vorbis_info_init(&fInfo);
vorbis_comment_init(&fComment);
fStartTime = 0;
fFrameSize = 0;
fOutputBufferSize = 0;
}
@ -170,8 +170,9 @@ VorbisDecoder::Decode(void *buffer, int64 *frameCount,
uint8 * out_buffer = static_cast<uint8 *>(buffer);
int32 out_bytes_needed = fOutputBufferSize;
bool start = false;
bool synced = false;
int total_samples = 0;
while (out_bytes_needed > 0) {
int samples;
float **pcm;
@ -192,9 +193,11 @@ VorbisDecoder::Decode(void *buffer, int64 *frameCount,
TRACE("VorbisDecoder::Decode: chunk not ogg_packet-sized\n");
return B_ERROR;
}
if (!start) {
mediaHeader->start_time = mh.start_time;
start = true;
if (!synced) {
if (mh.start_time > 0) {
mediaHeader->start_time = mh.start_time - total_samples / fInfo.rate;
synced = true;
}
}
ogg_packet * packet = static_cast<ogg_packet*>(chunkBuffer);
if (vorbis_synthesis(&fBlock,packet)==0) {
@ -203,6 +206,7 @@ VorbisDecoder::Decode(void *buffer, int64 *frameCount,
}
// reduce samples to the amount of samples we will actually consume
samples = min_c(samples,out_bytes_needed/fFrameSize);
total_samples += samples;
#if DECODE_AS_INT16
for (int sample = 0; sample < samples ; sample++) {
for (int channel = 0; channel < fInfo.channels; channel++) {
@ -231,6 +235,11 @@ VorbisDecoder::Decode(void *buffer, int64 *frameCount,
}
done:
if (!synced) {
mediaHeader->start_time = fStartTime;
}
fStartTime = mediaHeader->start_time + total_samples / fInfo.rate;
*frameCount = (fOutputBufferSize - out_bytes_needed) / fFrameSize;
if (out_buffer != buffer) {

View File

@ -30,6 +30,7 @@ private:
vorbis_comment fComment;
vorbis_dsp_state fDspState;
vorbis_block fBlock;
bigtime_t fStartTime;
int fFrameSize;
int fOutputBufferSize;
};