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:
parent
b797c2778b
commit
dc51127a5d
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -30,6 +30,7 @@ private:
|
||||
vorbis_comment fComment;
|
||||
vorbis_dsp_state fDspState;
|
||||
vorbis_block fBlock;
|
||||
bigtime_t fStartTime;
|
||||
int fFrameSize;
|
||||
int fOutputBufferSize;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user