From dc51127a5db31f16a87d751f5e81a86e4dcfe7f3 Mon Sep 17 00:00:00 2001 From: shatty Date: Wed, 18 Feb 2004 13:10:28 +0000 Subject: [PATCH] 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 --- src/add-ons/media/plugins/ogg/OggSeekable.cpp | 37 ++++++++++++++++--- .../media/plugins/ogg/OggSpeexSeekable.cpp | 8 ++-- .../media/plugins/ogg/OggTobiasSeekable.cpp | 13 +++---- .../media/plugins/speex/speexCodecPlugin.cpp | 18 +++++++-- .../plugins/vorbis/vorbisCodecPlugin.cpp | 19 +++++++--- .../media/plugins/vorbis/vorbisCodecPlugin.h | 1 + 6 files changed, 69 insertions(+), 27 deletions(-) diff --git a/src/add-ons/media/plugins/ogg/OggSeekable.cpp b/src/add-ons/media/plugins/ogg/OggSeekable.cpp index 2fda467bb1..073912b850 100644 --- a/src/add-ons/media/plugins/ogg/OggSeekable.cpp +++ b/src/add-ons/media/plugins/ogg/OggSeekable.cpp @@ -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; } diff --git a/src/add-ons/media/plugins/ogg/OggSpeexSeekable.cpp b/src/add-ons/media/plugins/ogg/OggSpeexSeekable.cpp index 5afa0f03db..c17c61bb1a 100644 --- a/src/add-ons/media/plugins/ogg/OggSpeexSeekable.cpp +++ b/src/add-ons/media/plugins/ogg/OggSpeexSeekable.cpp @@ -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; } diff --git a/src/add-ons/media/plugins/ogg/OggTobiasSeekable.cpp b/src/add-ons/media/plugins/ogg/OggTobiasSeekable.cpp index 0463ee2232..c66fb986c1 100644 --- a/src/add-ons/media/plugins/ogg/OggTobiasSeekable.cpp +++ b/src/add-ons/media/plugins/ogg/OggTobiasSeekable.cpp @@ -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; } diff --git a/src/add-ons/media/plugins/speex/speexCodecPlugin.cpp b/src/add-ons/media/plugins/speex/speexCodecPlugin.cpp index 45d4600264..bdc89389a8 100644 --- a/src/add-ons/media/plugins/speex/speexCodecPlugin.cpp +++ b/src/add-ons/media/plugins/speex/speexCodecPlugin.cpp @@ -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(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) { diff --git a/src/add-ons/media/plugins/vorbis/vorbisCodecPlugin.cpp b/src/add-ons/media/plugins/vorbis/vorbisCodecPlugin.cpp index f5e13abe33..101c88851b 100644 --- a/src/add-ons/media/plugins/vorbis/vorbisCodecPlugin.cpp +++ b/src/add-ons/media/plugins/vorbis/vorbisCodecPlugin.cpp @@ -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(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(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) { diff --git a/src/add-ons/media/plugins/vorbis/vorbisCodecPlugin.h b/src/add-ons/media/plugins/vorbis/vorbisCodecPlugin.h index f948ba24aa..40e61d7da7 100644 --- a/src/add-ons/media/plugins/vorbis/vorbisCodecPlugin.h +++ b/src/add-ons/media/plugins/vorbis/vorbisCodecPlugin.h @@ -30,6 +30,7 @@ private: vorbis_comment fComment; vorbis_dsp_state fDspState; vorbis_block fBlock; + bigtime_t fStartTime; int fFrameSize; int fOutputBufferSize; };