diff options
Diffstat (limited to 'src/decoder_api.c')
-rw-r--r-- | src/decoder_api.c | 48 |
1 files changed, 30 insertions, 18 deletions
diff --git a/src/decoder_api.c b/src/decoder_api.c index b8edb8aa..bcab6010 100644 --- a/src/decoder_api.c +++ b/src/decoder_api.c @@ -30,6 +30,10 @@ #include <glib.h> +#include <libavutil/channel_layout.h> +#include <libavutil/frame.h> +#include <libavutil/samplefmt.h> + #include <assert.h> #include <stdlib.h> @@ -347,25 +351,24 @@ static bool update_stream_tag(struct decoder *decoder, struct input_stream *is) enum decoder_command decoder_data(struct decoder *decoder, struct input_stream *is, - const void *_data, size_t length, + AVFrame *frame, uint16_t kbit_rate) { struct decoder_control *dc = decoder->dc; - const char *data = _data; - GError *error = NULL; - enum decoder_command cmd; + enum decoder_command cmd = DECODE_COMMAND_NONE; + uint8_t *data; + int length; assert(dc->state == DECODE_STATE_DECODE); assert(dc->pipe != NULL); - assert(length % audio_format_frame_size(&dc->in_audio_format) == 0); decoder_lock(dc); cmd = decoder_get_virtual_command(decoder); decoder_unlock(dc); if (cmd == DECODE_COMMAND_STOP || cmd == DECODE_COMMAND_SEEK || - length == 0) - return cmd; + !frame->nb_samples) + goto finish; /* send stream tags */ @@ -383,23 +386,27 @@ enum decoder_command decoder_data(struct decoder *decoder, cmd = do_send_tag(decoder, decoder->stream_tag); if (cmd != DECODE_COMMAND_NONE) - return cmd; + goto finish; } if (!audio_format_equals(&dc->in_audio_format, &dc->out_audio_format)) { - data = pcm_convert(&decoder->conv_state, - &dc->in_audio_format, data, length, - &dc->out_audio_format, &length, - &error); - if (data == NULL) { + AVFrame *tmp = pcm_convert(&decoder->conv_state, + &dc->in_audio_format, &dc->out_audio_format, frame); + if (!tmp) { /* the PCM conversion has failed - stop playback, since we have no better way to bail out */ - g_warning("%s", error->message); - return DECODE_COMMAND_STOP; + g_warning("Error converting to output format.\n"); + cmd = DECODE_COMMAND_STOP; + goto finish; } + av_frame_free(&frame); + frame = tmp; } + length = frame->nb_samples * av_get_bytes_per_sample(frame->format) * + dc->out_audio_format.channels; + data = frame->data[0]; while (length > 0) { struct music_chunk *chunk; char *dest; @@ -409,7 +416,8 @@ enum decoder_command decoder_data(struct decoder *decoder, chunk = decoder_get_chunk(decoder); if (chunk == NULL) { assert(dc->command != DECODE_COMMAND_NONE); - return dc->command; + cmd = dc->command; + goto finish; } dest = music_chunk_write(chunk, &dc->out_audio_format, @@ -448,12 +456,16 @@ enum decoder_command decoder_data(struct decoder *decoder, audio_format_time_to_size(&dc->out_audio_format); if (dc->end_ms > 0 && - decoder->timestamp >= dc->end_ms / 1000.0) + decoder->timestamp >= dc->end_ms / 1000.0) { /* the end of this range has been reached: stop decoding */ - return DECODE_COMMAND_STOP; + cmd = DECODE_COMMAND_STOP; + break; + } } +finish: + av_frame_free(&frame); return DECODE_COMMAND_NONE; } |