Hi,
here is a patch that allows for seeking in aac files.
bye
eichhofener
diff --git a/src/decoder/DecoderBuffer.cxx b/src/decoder/DecoderBuffer.cxx
index 4767151..2667a7b 100644
--- a/src/decoder/DecoderBuffer.cxx
+++ b/src/decoder/DecoderBuffer.cxx
@@ -20,148 +20,94 @@
#include "config.h"
#include "DecoderBuffer.hxx"
#include "DecoderAPI.hxx"
-#include "util/ConstBuffer.hxx"
#include "util/VarSize.hxx"
+#include "util/Error.hxx"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
-struct DecoderBuffer {
- Decoder *decoder;
- InputStream *is;
- /** the allocated size of the buffer */
- size_t size;
-
- /** the current length of the buffer */
- size_t length;
-
- /** number of bytes already consumed at the beginning of the
- buffer */
- size_t consumed;
-
- /** the actual buffer (dynamic size) */
- unsigned char data[sizeof(size_t)];
-
- DecoderBuffer(Decoder *_decoder, InputStream &_is,
- size_t _size)
- :decoder(_decoder), is(&_is),
- size(_size), length(0), consumed(0) {}
-};
-
-DecoderBuffer *
-decoder_buffer_new(Decoder *decoder, InputStream &is,
- size_t size)
-{
- assert(size > 0);
-
- return NewVarSize<DecoderBuffer>(sizeof(DecoderBuffer::data),
- size,
- decoder, is, size);
-}
-
-void
-decoder_buffer_free(DecoderBuffer *buffer)
+void DecoderBuffer::shift()
{
- assert(buffer != nullptr);
+ assert(consumed > 0);
- DeleteVarSize(buffer);
+ length -= consumed;
+ memmove(bufdata, bufdata + consumed, length);
+ consumed = 0;
}
-bool
-decoder_buffer_is_empty(const DecoderBuffer *buffer)
-{
- return buffer->consumed == buffer->length;
-}
-
-bool
-decoder_buffer_is_full(const DecoderBuffer *buffer)
-{
- return buffer->consumed == 0 && buffer->length == buffer->size;
-}
-
-void
-decoder_buffer_clear(DecoderBuffer *buffer)
-{
- buffer->length = buffer->consumed = 0;
-}
-
-static void
-decoder_buffer_shift(DecoderBuffer *buffer)
-{
- assert(buffer->consumed > 0);
-
- buffer->length -= buffer->consumed;
- memmove(buffer->data, buffer->data + buffer->consumed, buffer->length);
- buffer->consumed = 0;
-}
-
-bool
-decoder_buffer_fill(DecoderBuffer *buffer)
+bool DecoderBuffer::fill()
{
size_t nbytes;
- if (buffer->consumed > 0)
- decoder_buffer_shift(buffer);
+ if (consumed > 0) shift();
- if (buffer->length >= buffer->size)
+ if (length >= bufsize)
/* buffer is full */
return false;
- nbytes = decoder_read(buffer->decoder, *buffer->is,
- buffer->data + buffer->length,
- buffer->size - buffer->length);
+ nbytes = decoder_read(decoder, is,
+ bufdata + length,
+ bufsize - length);
if (nbytes == 0)
/* end of file, I/O error or decoder command
received */
return false;
- buffer->length += nbytes;
- assert(buffer->length <= buffer->size);
+ length += nbytes;
+ assert(length <= bufsize);
return true;
}
-ConstBuffer<void>
-decoder_buffer_read(const DecoderBuffer *buffer)
+ConstBuffer<void> DecoderBuffer::read() const
{
return {
- buffer->data + buffer->consumed,
- buffer->length - buffer->consumed
+ bufdata + consumed,
+ length - consumed
};
}
-void
-decoder_buffer_consume(DecoderBuffer *buffer, size_t nbytes)
+void DecoderBuffer::consume(size_t nbytes)
{
/* just move the "consumed" pointer - decoder_buffer_shift()
will do the real work later (called by
decoder_buffer_fill()) */
- buffer->consumed += nbytes;
+ consumed += nbytes;
+ offset += nbytes;
+
+ assert(consumed <= length);
+}
- assert(buffer->consumed <= buffer->length);
+bool DecoderBuffer::seek(InputStream::offset_type o)
+{
+ Error e;
+ if(!is.Seek(o, SEEK_SET, e)) return false;
+
+ offset=o;
+ clear();
+ return true;
}
-bool
-decoder_buffer_skip(DecoderBuffer *buffer, size_t nbytes)
+bool DecoderBuffer::skip(size_t nbytes)
{
bool success;
/* this could probably be optimized by seeking */
while (true) {
- auto data = decoder_buffer_read(buffer);
+ auto data = read();
if (!data.IsEmpty()) {
if (data.size > nbytes)
data.size = nbytes;
- decoder_buffer_consume(buffer, data.size);
+ consume(data.size);
nbytes -= data.size;
if (nbytes == 0)
return true;
}
- success = decoder_buffer_fill(buffer);
+ success = fill();
if (!success)
return false;
}
diff --git a/src/decoder/DecoderBuffer.hxx b/src/decoder/DecoderBuffer.hxx
index 4cadd77..9b7eaf9 100644
--- a/src/decoder/DecoderBuffer.hxx
+++ b/src/decoder/DecoderBuffer.hxx
@@ -21,6 +21,8 @@
#define MPD_DECODER_BUFFER_HXX
#include "Compiler.h"
+#include "input/InputStream.hxx"
+#include "util/ConstBuffer.hxx"
#include <stddef.h>
@@ -29,83 +31,116 @@
* create a buffer object, and use its high-level methods to fill and
* read it. It will automatically handle shifting the buffer.
*/
-struct DecoderBuffer;
-
struct Decoder;
struct InputStream;
template<typename T> struct ConstBuffer;
-/**
- * Creates a new buffer.
- *
- * @param decoder the decoder object, used for decoder_read(), may be nullptr
- * @param is the input stream object where we should read from
- * @param size the maximum size of the buffer
- * @return the new decoder_buffer object
- */
-DecoderBuffer *
-decoder_buffer_new(Decoder *decoder, InputStream &is,
- size_t size);
-
-/**
- * Frees resources used by the decoder_buffer object.
- */
-void
-decoder_buffer_free(DecoderBuffer *buffer);
-
-gcc_pure
-bool
-decoder_buffer_is_empty(const DecoderBuffer *buffer);
-
-gcc_pure
-bool
-decoder_buffer_is_full(const DecoderBuffer *buffer);
+class DecoderBuffer
+{
+public:
+ /**
+ * Creates a new buffer.
+ *
+ * @param decoder the decoder object, used for decoder_read(), may be nullptr
+ * @param is the input stream object where we should read from
+ * @param size the maximum size of the buffer
+ */
+ DecoderBuffer(Decoder* _decoder, InputStream& _is, size_t _size)
+ :decoder(_decoder), is(_is), offset(0), bufsize(_size), length(0), consumed(0)
+ {
+ bufdata=new unsigned char[bufsize];
+ }
+
+ /**
+ * Frees resources used by the decoder_buffer object.
+ */
+ ~DecoderBuffer() { delete[] bufdata; }
+
+ /**
+ * Read data from the input_stream and append it to the buffer.
+ *
+ * @return true if data was appended; false if there is no data
+ * available (yet), end of file, I/O error or a decoder command was
+ * received
+ */
+ bool fill();
+
+ /**
+ * Skips the specified number of bytes, discarding its data.
+ *
+ * @param buffer the decoder_buffer object
+ * @param nbytes the number of bytes to skip
+ * @return true on success, false on error
+ */
+ bool skip(size_t nbytes);
+
+ /**
+ * Reads data from the buffer. This data is not yet consumed, you
+ * have to call decoder_buffer_consume() to do that. The returned
+ * buffer becomes invalid after a decoder_buffer_fill() or a
+ * decoder_buffer_consume() call.
+ *
+ * @param buffer the decoder_buffer object
+ */
+ ConstBuffer<void> read() const;
+
+ /**
+ * Consume (delete, invalidate) a part of the buffer. The "nbytes"
+ * parameter must not be larger than the length returned by
+ * decoder_buffer_read().
+ *
+ * @param buffer the decoder_buffer object
+ * @param nbytes the number of bytes to consume
+ */
+ void consume(size_t nbytes);
+
+ bool seek(InputStream::offset_type offset);
+
+ void clear()
+ {
+ length = consumed = 0;
+ }
+
+ bool full() const
+ {
+ return consumed == 0 && length == bufsize;
+ }
+
+ InputStream::offset_type getOffset() const { return offset; }
+
+private:
+ bool empty() const
+ {
+ return consumed == length;
+ }
+
+ void shift();
+
+private:
+ Decoder* decoder;
+
+protected:
+ InputStream& is;
+
+private:
+ InputStream::offset_type offset;
+
+ /** the allocated size of the buffer */
+ size_t bufsize;
+
+ /** the current length of the buffer */
+ size_t length;
+
+ /** number of bytes already consumed at the beginning of the
+ buffer */
+ size_t consumed;
+
+ /** the actual buffer (dynamic size) */
+ unsigned char* bufdata;
+};
-void
-decoder_buffer_clear(DecoderBuffer *buffer);
-/**
- * Read data from the input_stream and append it to the buffer.
- *
- * @return true if data was appended; false if there is no data
- * available (yet), end of file, I/O error or a decoder command was
- * received
- */
-bool
-decoder_buffer_fill(DecoderBuffer *buffer);
-/**
- * Reads data from the buffer. This data is not yet consumed, you
- * have to call decoder_buffer_consume() to do that. The returned
- * buffer becomes invalid after a decoder_buffer_fill() or a
- * decoder_buffer_consume() call.
- *
- * @param buffer the decoder_buffer object
- */
-gcc_pure
-ConstBuffer<void>
-decoder_buffer_read(const DecoderBuffer *buffer);
-
-/**
- * Consume (delete, invalidate) a part of the buffer. The "nbytes"
- * parameter must not be larger than the length returned by
- * decoder_buffer_read().
- *
- * @param buffer the decoder_buffer object
- * @param nbytes the number of bytes to consume
- */
-void
-decoder_buffer_consume(DecoderBuffer *buffer, size_t nbytes);
-
-/**
- * Skips the specified number of bytes, discarding its data.
- *
- * @param buffer the decoder_buffer object
- * @param nbytes the number of bytes to skip
- * @return true on success, false on error
- */
-bool
-decoder_buffer_skip(DecoderBuffer *buffer, size_t nbytes);
#endif
diff --git a/src/decoder/plugins/FaadDecoderPlugin.cxx b/src/decoder/plugins/FaadDecoderPlugin.cxx
index e80665d..03d493b 100644
--- a/src/decoder/plugins/FaadDecoderPlugin.cxx
+++ b/src/decoder/plugins/FaadDecoderPlugin.cxx
@@ -35,21 +35,64 @@
#include <string.h>
#include <unistd.h>
+#include <vector>
+#include <iostream>
+
#define AAC_MAX_CHANNELS 6
-static const unsigned adts_sample_rates[] =
- { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
- 16000, 12000, 11025, 8000, 7350, 0, 0, 0
+static constexpr Domain faad_decoder_domain("faad_decoder");
+
+
+class DecoderBufferFaad : public DecoderBuffer
+{
+public:
+ DecoderBufferFaad(Decoder* _decoder, InputStream& _is, size_t _size)
+ : DecoderBuffer(_decoder, _is, _size)
+ {
+ duration=faad_song_duration();
+ }
+
+ double getDuration() const { return duration; }
+ size_t adts_find_frame();
+
+ float seekSample(float seekTime);
+
+ enum { samplesPerFrame=1024 };
+private:
+ /**
+ * Check whether the buffer head is an AAC frame, and return the frame
+ * length. Returns 0 if it is not a frame.
+ */
+ static size_t adts_check_frame(const unsigned char *bufdata);
+
+ /**
+ * Find the next AAC frame in the buffer. Returns 0 if no frame is
+ * found or if not enough data is available.
+ */
+ float adts_song_duration();
+
+ float faad_song_duration();
+
+private:
+ static const unsigned adts_sample_rates[];
+
+ unsigned sampleRate;
+ float duration;
+
+ short offset0;
+ std::vector<short> offsets;
};
-static constexpr Domain faad_decoder_domain("faad_decoder");
+const unsigned DecoderBufferFaad::adts_sample_rates[] =
+ { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+ 16000, 12000, 11025, 8000, 7350, 0, 0, 0
+};
/**
* Check whether the buffer head is an AAC frame, and return the frame
* length. Returns 0 if it is not a frame.
*/
-static size_t
-adts_check_frame(const unsigned char *data)
+size_t DecoderBufferFaad::adts_check_frame(const unsigned char *data)
{
/* check syncword */
if (!((data[0] == 0xFF) && ((data[1] & 0xF6) == 0xF0)))
@@ -64,14 +107,13 @@ adts_check_frame(const unsigned char *data)
* Find the next AAC frame in the buffer. Returns 0 if no frame is
* found or if not enough data is available.
*/
-static size_t
-adts_find_frame(DecoderBuffer *buffer)
+size_t DecoderBufferFaad::adts_find_frame()
{
while (true) {
- auto data = ConstBuffer<uint8_t>::FromVoid(decoder_buffer_read(buffer));
+ auto data = ConstBuffer<uint8_t>::FromVoid(read());
if (data.size < 8) {
/* not enough data yet */
- if (!decoder_buffer_fill(buffer))
+ if (!fill())
/* failed */
return 0;
@@ -83,13 +125,13 @@ adts_find_frame(DecoderBuffer *buffer)
memchr(data.data, 0xff, data.size);
if (p == nullptr) {
/* no marker - discard the buffer */
- decoder_buffer_clear(buffer);
+ clear();
continue;
}
if (p > data.data) {
/* discard data before 0xff */
- decoder_buffer_consume(buffer, p - data.data);
+ consume(p - data.data);
continue;
}
@@ -98,7 +140,7 @@ adts_find_frame(DecoderBuffer *buffer)
if (frame_length == 0) {
/* it's just some random 0xff byte; discard it
and continue searching */
- decoder_buffer_consume(buffer, 1);
+ consume(1);
continue;
}
@@ -106,11 +148,11 @@ adts_find_frame(DecoderBuffer *buffer)
/* available buffer size is smaller than the
frame will be - attempt to read more
data */
- if (!decoder_buffer_fill(buffer)) {
+ if (!fill()) {
/* not enough data; discard this frame
to prevent a possible buffer
overflow */
- decoder_buffer_clear(buffer);
+ clear();
}
continue;
@@ -121,44 +163,52 @@ adts_find_frame(DecoderBuffer *buffer)
}
}
-static float
-adts_song_duration(DecoderBuffer *buffer)
+float DecoderBufferFaad::adts_song_duration()
{
- unsigned sample_rate = 0;
+ sampleRate = 0;
+ short lastOffset=0;
+ offset0=0;
+ offsets.clear();
/* Read all frames to ensure correct time and bitrate */
unsigned frames = 0;
for (;; frames++) {
- unsigned frame_length = adts_find_frame(buffer);
+ unsigned frame_length = adts_find_frame();
if (frame_length == 0)
break;
if (frames == 0) {
- auto data = ConstBuffer<uint8_t>::FromVoid(decoder_buffer_read(buffer));
+ auto data = ConstBuffer<uint8_t>::FromVoid(read());
assert(!data.IsEmpty());
assert(frame_length <= data.size);
- sample_rate = adts_sample_rates[(data.data[2] & 0x3c) >> 2];
+ sampleRate = adts_sample_rates[(data.data[2] & 0x3c) >> 2];
+ offset0=getOffset();
+ lastOffset=offset0;
+ }
+ else
+ {
+ offsets.push_back(getOffset()-lastOffset);
+ lastOffset=getOffset();
}
- decoder_buffer_consume(buffer, frame_length);
+ consume(frame_length);
}
- float frames_per_second = (float)sample_rate / 1024.0;
+ float frames_per_second = ((float)sampleRate) / samplesPerFrame;
if (frames_per_second <= 0)
return -1;
return (float)frames / frames_per_second;
}
-static float
-faad_song_duration(DecoderBuffer *buffer, InputStream &is)
+float DecoderBufferFaad::faad_song_duration()
{
const auto size = is.GetSize();
const size_t fileread = size >= 0 ? size : 0;
- decoder_buffer_fill(buffer);
- auto data = ConstBuffer<uint8_t>::FromVoid(decoder_buffer_read(buffer));
+ fill();
+ auto data = ConstBuffer<uint8_t>::FromVoid(read());
if (data.IsEmpty())
return -1;
@@ -167,29 +217,28 @@ faad_song_duration(DecoderBuffer *buffer, InputStream &is)
/* skip the ID3 tag */
tagsize = (data.data[6] << 21) | (data.data[7] << 14) |
- (data.data[8] << 7) | (data.data[9] << 0);
+ (data.data[8] << 7) | (data.data[9] << 0);
tagsize += 10;
- bool success = decoder_buffer_skip(buffer, tagsize) &&
- decoder_buffer_fill(buffer);
+ bool success = skip(tagsize) && fill();
if (!success)
return -1;
- data = ConstBuffer<uint8_t>::FromVoid(decoder_buffer_read(buffer));
+ data = ConstBuffer<uint8_t>::FromVoid(read());
if (data.IsEmpty())
return -1;
}
if (is.IsSeekable() && data.size >= 2 &&
- data.data[0] == 0xFF && ((data.data[1] & 0xF6) == 0xF0)) {
+ data.data[0] == 0xFF && ((data.data[1] & 0xF6) == 0xF0)) {
/* obtain the duration from the ADTS header */
- float song_length = adts_song_duration(buffer);
+ float song_length = adts_song_duration();
is.LockSeek(tagsize, SEEK_SET, IgnoreError());
- decoder_buffer_clear(buffer);
- decoder_buffer_fill(buffer);
+ clear();
+ fill();
return song_length;
} else if (data.size >= 5 && memcmp(data.data, "ADIF", 4) == 0) {
@@ -215,12 +264,25 @@ faad_song_duration(DecoderBuffer *buffer, InputStream &is)
return -1;
}
+float DecoderBufferFaad::seekSample(float seekTime)
+{
+ int frame=seekTime*sampleRate/samplesPerFrame;
+
+ InputStream::offset_type seekOffset=offset0;
+ for(int i=0; i<frame; ++i)
+ seekOffset+=offsets[i];
+
+ std::cout << "seek offset "<< seekOffset << std::endl;
+ seek(seekOffset);
+ return ((float)frame)*samplesPerFrame/sampleRate;
+}
+
/**
* Wrapper for NeAACDecInit() which works around some API
* inconsistencies in libfaad.
*/
static bool
-faad_decoder_init(NeAACDecHandle decoder, DecoderBuffer *buffer,
+faad_decoder_init(NeAACDecHandle decoder, DecoderBuffer& buffer,
AudioFormat &audio_format, Error &error)
{
uint32_t sample_rate;
@@ -233,7 +295,7 @@ faad_decoder_init(NeAACDecHandle decoder, DecoderBuffer *buffer,
uint32_t *sample_rate_p = &sample_rate;
#endif
- auto data = ConstBuffer<uint8_t>::FromVoid(decoder_buffer_read(buffer));
+ auto data = ConstBuffer<uint8_t>::FromVoid(buffer.read());
if (data.IsEmpty()) {
error.Set(faad_decoder_domain, "Empty file");
return false;
@@ -241,16 +303,16 @@ faad_decoder_init(NeAACDecHandle decoder, DecoderBuffer *buffer,
uint8_t channels;
int32_t nbytes = NeAACDecInit(decoder,
- /* deconst hack, libfaad requires this */
- const_cast<uint8_t *>(data.data),
- data.size,
- sample_rate_p, &channels);
+ /* deconst hack, libfaad requires this */
+ const_cast<uint8_t *>(data.data),
+ data.size,
+ sample_rate_p, &channels);
if (nbytes < 0) {
error.Set(faad_decoder_domain, "Not an AAC stream");
return false;
}
- decoder_buffer_consume(buffer, nbytes);
+ buffer.consume(nbytes);
return audio_format_init_checked(audio_format, sample_rate,
SampleFormat::S16, channels, error);
@@ -261,17 +323,17 @@ faad_decoder_init(NeAACDecHandle decoder, DecoderBuffer *buffer,
* inconsistencies in libfaad.
*/
static const void *
-faad_decoder_decode(NeAACDecHandle decoder, DecoderBuffer *buffer,
- NeAACDecFrameInfo *frame_info)
+faad_decoder_decode(NeAACDecHandle decoder, DecoderBuffer& buffer,
+ NeAACDecFrameInfo *frame_info)
{
- auto data = ConstBuffer<uint8_t>::FromVoid(decoder_buffer_read(buffer));
+ auto data = ConstBuffer<uint8_t>::FromVoid(buffer.read());
if (data.IsEmpty())
return nullptr;
return NeAACDecDecode(decoder, frame_info,
- /* deconst hack, libfaad requires this */
- const_cast<uint8_t *>(data.data),
- data.size);
+ /* deconst hack, libfaad requires this */
+ const_cast<uint8_t *>(data.data),
+ data.size);
}
/**
@@ -282,10 +344,8 @@ faad_decoder_decode(NeAACDecHandle decoder, DecoderBuffer *buffer,
static float
faad_get_file_time_float(InputStream &is)
{
- DecoderBuffer *buffer =
- decoder_buffer_new(nullptr, is,
- FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS);
- float length = faad_song_duration(buffer, is);
+ DecoderBufferFaad buffer(nullptr, is, FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS);
+ float length = buffer.getDuration();
if (length < 0) {
NeAACDecHandle decoder = NeAACDecOpen();
@@ -295,18 +355,16 @@ faad_get_file_time_float(InputStream &is)
config->outputFormat = FAAD_FMT_16BIT;
NeAACDecSetConfiguration(decoder, config);
- decoder_buffer_fill(buffer);
+ buffer.fill();
AudioFormat audio_format;
if (faad_decoder_init(decoder, buffer, audio_format,
- IgnoreError()))
+ IgnoreError()))
length = 0;
NeAACDecClose(decoder);
}
- decoder_buffer_free(buffer);
-
return length;
}
@@ -319,9 +377,9 @@ static int
faad_get_file_time(InputStream &is)
{
int file_time = -1;
- float length;
+ float length=faad_get_file_time_float(is);
- if ((length = faad_get_file_time_float(is)) >= 0)
+ if (length >= 0)
file_time = length + 0.5;
return file_time;
@@ -330,10 +388,8 @@ faad_get_file_time(InputStream &is)
static void
faad_stream_decode(Decoder &mpd_decoder, InputStream &is)
{
- DecoderBuffer *buffer =
- decoder_buffer_new(&mpd_decoder, is,
- FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS);
- const float total_time = faad_song_duration(buffer, is);
+ DecoderBufferFaad buffer(&mpd_decoder, is, FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS);
+ const float total_time = buffer.getDuration();
/* create the libfaad decoder */
@@ -346,10 +402,10 @@ faad_stream_decode(Decoder &mpd_decoder, InputStream &is)
config->dontUpSampleImplicitSBR = 0;
NeAACDecSetConfiguration(decoder, config);
- while (!decoder_buffer_is_full(buffer) && !is.LockIsEOF() &&
- decoder_get_command(mpd_decoder) == DecoderCommand::NONE) {
- adts_find_frame(buffer);
- decoder_buffer_fill(buffer);
+ while (!buffer.full() && !is.LockIsEOF() &&
+ decoder_get_command(mpd_decoder) == DecoderCommand::NONE) {
+ buffer.adts_find_frame();
+ buffer.fill();
}
/* initialize it */
@@ -359,13 +415,12 @@ faad_stream_decode(Decoder &mpd_decoder, InputStream &is)
if (!faad_decoder_init(decoder, buffer, audio_format, error)) {
LogError(error);
NeAACDecClose(decoder);
- decoder_buffer_free(buffer);
return;
}
/* initialize the MPD core */
- decoder_initialized(mpd_decoder, audio_format, false, total_time);
+ decoder_initialized(mpd_decoder, audio_format, true, total_time);
/* the decoder loop */
@@ -378,7 +433,7 @@ faad_stream_decode(Decoder &mpd_decoder, InputStream &is)
/* find the next frame */
- frame_size = adts_find_frame(buffer);
+ frame_size = buffer.adts_find_frame();
if (frame_size == 0)
/* end of file */
break;
@@ -389,34 +444,34 @@ faad_stream_decode(Decoder &mpd_decoder, InputStream &is)
if (frame_info.error > 0) {
FormatWarning(faad_decoder_domain,
- "error decoding AAC stream: %s",
- NeAACDecGetErrorMessage(frame_info.error));
+ "error decoding AAC stream: %s",
+ NeAACDecGetErrorMessage(frame_info.error));
break;
}
if (frame_info.channels != audio_format.channels) {
FormatDefault(faad_decoder_domain,
- "channel count changed from %u to %u",
- audio_format.channels, frame_info.channels);
+ "channel count changed from %u to %u",
+ audio_format.channels, frame_info.channels);
break;
}
if (frame_info.samplerate != audio_format.sample_rate) {
FormatDefault(faad_decoder_domain,
- "sample rate changed from %u to %lu",
- audio_format.sample_rate,
- (unsigned long)frame_info.samplerate);
+ "sample rate changed from %u to %lu",
+ audio_format.sample_rate,
+ (unsigned long)frame_info.samplerate);
break;
}
- decoder_buffer_consume(buffer, frame_info.bytesconsumed);
+ buffer.consume(frame_info.bytesconsumed);
/* update bit rate and position */
if (frame_info.samples > 0) {
bit_rate = frame_info.bytesconsumed * 8.0 *
- frame_info.channels * audio_format.sample_rate /
- frame_info.samples / 1000 + 0.5;
+ frame_info.channels * audio_format.sample_rate /
+ frame_info.samples / 1000 + 0.5;
}
/* send PCM samples to MPD */
@@ -424,12 +479,22 @@ faad_stream_decode(Decoder &mpd_decoder, InputStream &is)
cmd = decoder_data(mpd_decoder, is, decoded,
(size_t)frame_info.samples * 2,
bit_rate);
+
+ if (cmd == DecoderCommand::SEEK)
+ {
+ float seekTime = decoder_seek_where(mpd_decoder);
+ float foundTime=buffer.seekSample(seekTime);
+ decoder_command_finished(mpd_decoder);
+ decoder_timestamp(mpd_decoder, foundTime);
+
+ cmd = DecoderCommand::NONE;
+ }
+
} while (cmd != DecoderCommand::STOP);
/* cleanup */
NeAACDecClose(decoder);
- decoder_buffer_free(buffer);
}
static bool
_______________________________________________
mpd-devel mailing list
[email protected]
http://mailman.blarg.de/listinfo/mpd-devel