diff options
Diffstat (limited to 'src/player.c')
-rw-r--r-- | src/player.c | 690 |
1 files changed, 232 insertions, 458 deletions
diff --git a/src/player.c b/src/player.c index 55b9e90..e16f690 100644 --- a/src/player.c +++ b/src/player.c @@ -1,5 +1,5 @@ /* -Copyright (c) 2008-2013 +Copyright (c) 2008-2014 Lars-Dominik Braun <lars@6xq.net> Permission is hereby granted, free of charge, to any person obtaining a copy @@ -31,519 +31,293 @@ THE SOFTWARE. #include <assert.h> #include <arpa/inet.h> +#include <ao/ao.h> +#include <libavcodec/avcodec.h> +#include <libavformat/avformat.h> +#include <libavutil/avutil.h> +#include <libavfilter/avfilter.h> +#include <libavfilter/avfiltergraph.h> +#include <libavfilter/buffersink.h> +#include <libavfilter/buffersrc.h> +#include <libavutil/channel_layout.h> +#include <libavutil/opt.h> + #include "player.h" #include "config.h" #include "ui.h" #include "ui_types.h" -#define bigToHostEndian32(x) ntohl(x) - -/* pandora uses float values with 2 digits precision. Scale them by 100 to get - * a "nice" integer */ -#define RG_SCALE_FACTOR 100 - -/* wait until the pause flag is cleared - * @param player structure - * @return true if the player should quit - */ -static bool BarPlayerCheckPauseQuit (struct audioPlayer *player) { - bool quit = false; - - pthread_mutex_lock (&player->pauseMutex); - while (true) { - if (player->doQuit) { - quit = true; - break; - } - if (!player->doPause) { - break; - } - pthread_cond_wait(&player->pauseCond, - &player->pauseMutex); - } - pthread_mutex_unlock (&player->pauseMutex); - - return quit; +static void printError (const BarSettings_t * const settings, + const char * const msg, int ret) { + char avmsg[128]; + av_strerror (ret, avmsg, sizeof (avmsg)); + BarUiMsg (settings, MSG_ERR, "%s (%s)\n", msg, avmsg); } -/* compute replaygain scale factor - * algo taken from here: http://www.dsprelated.com/showmessage/29246/1.php - * mpd does the same - * @param apply this gain - * @return this * yourvalue = newgain value +/* global initialization + * + * XXX: in theory we can select the filters/formats we want to support, but + * this does not work in practise. */ -unsigned int BarPlayerCalcScale (const float applyGain) { - return pow (10.0, applyGain / 20.0) * RG_SCALE_FACTOR; +void BarPlayerInit () { + ao_initialize (); + av_register_all (); + avfilter_register_all (); + avformat_network_init (); } -/* apply replaygain to signed short value - * @param value - * @param replaygain scale (calculated by computeReplayGainScale) - * @return scaled value - */ -static inline signed short int applyReplayGain (const signed short int value, - const unsigned int scale) { - int tmpReplayBuf = value * (signed int) scale; - /* clipping */ - if (tmpReplayBuf > SHRT_MAX*RG_SCALE_FACTOR) { - return SHRT_MAX; - } else if (tmpReplayBuf < SHRT_MIN*RG_SCALE_FACTOR) { - return SHRT_MIN; - } else { - return tmpReplayBuf / RG_SCALE_FACTOR; - } +void BarPlayerDestroy () { + avformat_network_deinit (); + avfilter_uninit (); + ao_shutdown (); } -/* Refill player's buffer with dataSize of data - * @param player structure - * @param new data - * @param data size - * @return 1 on success, 0 when buffer overflow occured +/* Update volume filter + * + * XXX: I’m not sure whether this is thread-safe or not */ -static inline int BarPlayerBufferFill (struct audioPlayer *player, - const char *data, const size_t dataSize) { - /* fill buffer */ - if (player->bufferFilled + dataSize > BAR_PLAYER_BUFSIZE) { - BarUiMsg (player->settings, MSG_ERR, "Buffer overflow!\n"); - return 0; +void BarPlayerSetVolume (struct audioPlayer * const player) { + assert (player != NULL); + assert (player->fvolume != NULL); + + int ret; + /* convert from decibel */ + const double volume = pow (10, (player->settings->volume + player->gain) / 20); + /* XXX: can we avoid accessing ->priv here? */ + if ((ret = av_opt_set_double (player->fvolume->priv, "volume", volume, + 0)) != 0) { + printError (player->settings, "Cannot set volume", ret); } - memcpy (player->buffer+player->bufferFilled, data, dataSize); - player->bufferFilled += dataSize; - player->bufferRead = 0; - player->bytesReceived += dataSize; - return 1; } -/* move data beginning from read pointer to buffer beginning and - * overwrite data already read from buffer - * @param player structure - * @return nothing at all +#define softfail(msg) \ + printError (player->settings, msg, ret); \ + pret = PLAYER_RET_SOFTFAIL; \ + goto finish; + +/* player thread; for every song a new thread is started + * @param audioPlayer structure + * @return PLAYER_RET_* */ -static inline void BarPlayerBufferMove (struct audioPlayer *player) { - /* move remaining bytes to buffer beginning */ - memmove (player->buffer, player->buffer + player->bufferRead, - (player->bufferFilled - player->bufferRead)); - player->bufferFilled -= player->bufferRead; -} +void *BarPlayerThread (void *data) { + assert (data != NULL); -#ifdef ENABLE_FAAD + struct audioPlayer * const player = data; + int ret; + intptr_t pret = PLAYER_RET_OK; + const enum AVSampleFormat avformat = AV_SAMPLE_FMT_S16; -/* play aac stream - * @param streamed data - * @param received bytes - * @param extra data (player data) - * @return received bytes or less on error - */ -static WaitressCbReturn_t BarPlayerAACCb (void *ptr, size_t size, - void *stream) { - const char *data = ptr; - struct audioPlayer *player = stream; - - if (BarPlayerCheckPauseQuit (player) || - !BarPlayerBufferFill (player, data, size)) { - return WAITRESS_CB_RET_ERR; + ao_device *aoDev = NULL; + ao_sample_format aoFmt; + + AVFilterGraph *fgraph = NULL; + AVFrame *frame = NULL, *filteredFrame = NULL; + AVFormatContext *fctx = NULL; + AVCodecContext *cctx = NULL; + + /* stream setup */ + if ((ret = avformat_open_input (&fctx, player->url, NULL, NULL)) < 0) { + softfail ("Unable to open audio file"); } - if (player->mode == PLAYER_RECV_DATA) { - short int *aacDecoded; - NeAACDecFrameInfo frameInfo; - size_t i; - - while (player->sampleSizeCurr < player->sampleSizeN && - (player->bufferFilled - player->bufferRead) >= - player->sampleSize[player->sampleSizeCurr]) { - /* going through this loop can take up to a few seconds => - * allow earlier thread abort */ - if (BarPlayerCheckPauseQuit (player)) { - return WAITRESS_CB_RET_ERR; - } + if ((ret = avformat_find_stream_info (fctx, NULL)) < 0) { + softfail ("find_stream_info"); + } - /* decode frame */ - aacDecoded = NeAACDecDecode(player->aacHandle, &frameInfo, - &player->buffer[player->bufferRead], - player->sampleSize[player->sampleSizeCurr]); - player->bufferRead += player->sampleSize[player->sampleSizeCurr]; - ++player->sampleSizeCurr; - - if (frameInfo.error != 0) { - /* skip this frame, songPlayed will be slightly off if this - * happens */ - BarUiMsg (player->settings, MSG_ERR, "Decoding error: %s\n", - NeAACDecGetErrorMessage (frameInfo.error)); - continue; - } - /* assuming data in stsz atom is correct */ - assert (frameInfo.bytesconsumed == - player->sampleSize[player->sampleSizeCurr-1]); + const int streamIdx = av_find_best_stream (fctx, AVMEDIA_TYPE_AUDIO, -1, + -1, NULL, 0); + if (streamIdx < 0) { + softfail ("find_best_stream"); + } - for (i = 0; i < frameInfo.samples; i++) { - aacDecoded[i] = applyReplayGain (aacDecoded[i], player->scale); - } - /* ao_play needs bytes: 1 sample = 16 bits = 2 bytes */ - ao_play (player->audioOutDevice, (char *) aacDecoded, - frameInfo.samples * 2); - /* add played frame length to played time, explained below */ - player->songPlayed += (unsigned long long int) frameInfo.samples * - (unsigned long long int) BAR_PLAYER_MS_TO_S_FACTOR / - (unsigned long long int) player->samplerate / - (unsigned long long int) player->channels; - } - if (player->sampleSizeCurr >= player->sampleSizeN) { - /* no more frames, drop data */ - player->bufferRead = player->bufferFilled; - } - } else { - if (player->mode == PLAYER_INITIALIZED) { - while (player->bufferRead+4 < player->bufferFilled) { - if (memcmp (player->buffer + player->bufferRead, "esds", - 4) == 0) { - player->mode = PLAYER_FOUND_ESDS; - player->bufferRead += 4; - break; - } - player->bufferRead++; - } - } - if (player->mode == PLAYER_FOUND_ESDS) { - /* FIXME: is this the correct way? */ - /* we're gonna read 10 bytes */ - while (player->bufferRead+1+4+5 < player->bufferFilled) { - if (memcmp (player->buffer + player->bufferRead, - "\x05\x80\x80\x80", 4) == 0) { - ao_sample_format format; - int audioOutDriver; - - /* +1+4 needs to be replaced by <something>! */ - player->bufferRead += 1+4; - char err = NeAACDecInit2 (player->aacHandle, player->buffer + - player->bufferRead, 5, &player->samplerate, - &player->channels); - player->bufferRead += 5; - if (err != 0) { - BarUiMsg (player->settings, MSG_ERR, - "Error while initializing audio decoder " - "(%i)\n", err); - return WAITRESS_CB_RET_ERR; - } - audioOutDriver = ao_default_driver_id(); - memset (&format, 0, sizeof (format)); - format.bits = 16; - format.channels = player->channels; - format.rate = player->samplerate; - format.byte_format = AO_FMT_NATIVE; - if ((player->audioOutDevice = ao_open_live (audioOutDriver, - &format, NULL)) == NULL) { - /* we're not interested in the errno */ - player->aoError = 1; - BarUiMsg (player->settings, MSG_ERR, - "Cannot open audio device\n"); - return WAITRESS_CB_RET_ERR; - } - player->mode = PLAYER_AUDIO_INITIALIZED; - break; - } - player->bufferRead++; - } - } - if (player->mode == PLAYER_AUDIO_INITIALIZED) { - while (player->bufferRead+4+8 < player->bufferFilled) { - if (memcmp (player->buffer + player->bufferRead, "stsz", - 4) == 0) { - player->mode = PLAYER_FOUND_STSZ; - player->bufferRead += 4; - /* skip version and unknown */ - player->bufferRead += 8; - break; - } - player->bufferRead++; - } - } - /* get frame sizes */ - if (player->mode == PLAYER_FOUND_STSZ) { - while (player->bufferRead+4 < player->bufferFilled) { - /* how many frames do we have? */ - if (player->sampleSizeN == 0) { - /* mp4 uses big endian, convert */ - memcpy (&player->sampleSizeN, player->buffer + - player->bufferRead, sizeof (uint32_t)); - player->sampleSizeN = - bigToHostEndian32 (player->sampleSizeN); - - player->sampleSize = malloc (player->sampleSizeN * - sizeof (*player->sampleSize)); - assert (player->sampleSize != NULL); - player->bufferRead += sizeof (uint32_t); - player->sampleSizeCurr = 0; - /* set up song duration (assuming one frame always contains - * the same number of samples) - * calculation: channels * number of frames * samples per - * frame / samplerate */ - /* FIXME: Hard-coded number of samples per frame */ - player->songDuration = (unsigned long long int) player->sampleSizeN * - 4096LL * (unsigned long long int) BAR_PLAYER_MS_TO_S_FACTOR / - (unsigned long long int) player->samplerate / - (unsigned long long int) player->channels; - break; - } else { - memcpy (&player->sampleSize[player->sampleSizeCurr], - player->buffer + player->bufferRead, - sizeof (uint32_t)); - player->sampleSize[player->sampleSizeCurr] = - bigToHostEndian32 ( - player->sampleSize[player->sampleSizeCurr]); - - player->sampleSizeCurr++; - player->bufferRead += sizeof (uint32_t); - } - /* all sizes read, nearly ready for data mode */ - if (player->sampleSizeCurr >= player->sampleSizeN) { - player->mode = PLAYER_SAMPLESIZE_INITIALIZED; - break; - } - } - } - /* search for data atom and let the show begin... */ - if (player->mode == PLAYER_SAMPLESIZE_INITIALIZED) { - while (player->bufferRead+4 < player->bufferFilled) { - if (memcmp (player->buffer + player->bufferRead, "mdat", - 4) == 0) { - player->mode = PLAYER_RECV_DATA; - player->sampleSizeCurr = 0; - player->bufferRead += 4; - break; - } - player->bufferRead++; - } - } + AVStream * const st = fctx->streams[streamIdx]; + cctx = st->codec; + + /* decoder setup */ + AVCodec * const decoder = avcodec_find_decoder (cctx->codec_id); + if (decoder == NULL) { + softfail ("find_decoder"); } - BarPlayerBufferMove (player); + if ((ret = avcodec_open2 (cctx, decoder, NULL)) < 0) { + softfail ("codec_open2"); + } - return WAITRESS_CB_RET_OK; -} + frame = avcodec_alloc_frame (); + assert (frame != NULL); + filteredFrame = avcodec_alloc_frame (); + assert (filteredFrame != NULL); -#endif /* ENABLE_FAAD */ + AVPacket pkt; + av_init_packet (&pkt); + pkt.data = NULL; + pkt.size = 0; -#ifdef ENABLE_MAD + /* filter setup */ + char strbuf[256]; -/* convert mad's internal fixed point format to short int - * @param mad fixed - * @return short int - */ -static inline signed short int BarPlayerMadToShort (const mad_fixed_t fixed) { - /* Clipping */ - if (fixed >= MAD_F_ONE) { - return SHRT_MAX; - } else if (fixed <= -MAD_F_ONE) { - return -SHRT_MAX; + if ((fgraph = avfilter_graph_alloc ()) == NULL) { + softfail ("graph_alloc"); } - /* Conversion */ - return (signed short int) (fixed >> (MAD_F_FRACBITS - 15)); -} + /* abuffer */ + AVFilterContext *fabuf = NULL; + AVRational time_base = st->time_base; + snprintf (strbuf, sizeof (strbuf), + "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64, + time_base.num, time_base.den, cctx->sample_rate, + av_get_sample_fmt_name (cctx->sample_fmt), + cctx->channel_layout); + if ((ret = avfilter_graph_create_filter (&fabuf, + avfilter_get_by_name ("abuffer"), NULL, strbuf, NULL, fgraph)) < 0) { + softfail ("create_filter abuffer"); + } -/* mp3 playback callback - */ -static WaitressCbReturn_t BarPlayerMp3Cb (void *ptr, size_t size, - void *stream) { - const char *data = ptr; - struct audioPlayer *player = stream; - size_t i; - - if (BarPlayerCheckPauseQuit (player) || - !BarPlayerBufferFill (player, data, size)) { - return WAITRESS_CB_RET_ERR; + /* volume */ + if ((ret = avfilter_graph_create_filter (&player->fvolume, + avfilter_get_by_name ("volume"), NULL, NULL, NULL, fgraph)) < 0) { + softfail ("create_filter volume"); + } + BarPlayerSetVolume (player); + + /* aformat: convert float samples into something more usable */ + AVFilterContext *fafmt = NULL; + snprintf (strbuf, sizeof (strbuf), "sample_fmts=%s", + av_get_sample_fmt_name (avformat)); + if ((ret = avfilter_graph_create_filter (&fafmt, + avfilter_get_by_name ("aformat"), NULL, strbuf, NULL, + fgraph)) < 0) { + softfail ("create_filter aformat"); } - /* some "prebuffering" */ - if (player->mode < PLAYER_RECV_DATA && - player->bufferFilled < BAR_PLAYER_BUFSIZE / 2) { - return WAITRESS_CB_RET_OK; + /* abuffersink */ + AVFilterContext *fbufsink = NULL; + if ((ret = avfilter_graph_create_filter (&fbufsink, + avfilter_get_by_name ("abuffersink"), NULL, NULL, NULL, fgraph)) < 0) { + softfail ("create_filter abuffersink"); } - mad_stream_buffer (&player->mp3Stream, player->buffer, - player->bufferFilled); - player->mp3Stream.error = 0; - do { - /* channels * max samples, found in mad.h */ - signed short int madDecoded[2*1152], *madPtr = madDecoded; - - if (mad_frame_decode (&player->mp3Frame, &player->mp3Stream) != 0) { - if (player->mp3Stream.error != MAD_ERROR_BUFLEN) { - BarUiMsg (player->settings, MSG_ERR, - "mp3 decoding error: %s\n", - mad_stream_errorstr (&player->mp3Stream)); - return WAITRESS_CB_RET_ERR; - } else { - /* rebuffering required => exit loop */ + /* connect filter: abuffer -> volume -> aformat -> abuffersink */ + if (avfilter_link (fabuf, 0, player->fvolume, 0) != 0 || + avfilter_link (player->fvolume, 0, fafmt, 0) != 0 || + avfilter_link (fafmt, 0, fbufsink, 0) != 0) { + softfail ("filter_link"); + } + + if ((ret = avfilter_graph_config (fgraph, NULL)) < 0) { + softfail ("graph_config"); + } + + /* setup libao */ + memset (&aoFmt, 0, sizeof (aoFmt)); + aoFmt.bits = av_get_bytes_per_sample (avformat) * 8; + assert (aoFmt.bits > 0); + aoFmt.channels = cctx->channels; + aoFmt.rate = cctx->sample_rate; + aoFmt.byte_format = AO_FMT_NATIVE; + + int driver = ao_default_driver_id (); + if ((aoDev = ao_open_live (driver, &aoFmt, NULL)) == NULL) { + BarUiMsg (player->settings, MSG_ERR, "Cannot open audio device.\n"); + pret = PLAYER_RET_HARDFAIL; + goto finish; + } + + player->songPlayed = 0; + player->songDuration = av_q2d (st->time_base) * (double) st->duration; + + while (av_read_frame (fctx, &pkt) >= 0) { + AVPacket pkt_orig = pkt; + + /* pausing */ + pthread_mutex_lock (&player->pauseMutex); + while (true) { + if (!player->doPause) { + av_read_play (fctx); break; + } else { + av_read_pause (fctx); } + pthread_cond_wait (&player->pauseCond, &player->pauseMutex); } - mad_synth_frame (&player->mp3Synth, &player->mp3Frame); - for (i = 0; i < player->mp3Synth.pcm.length; i++) { - /* left channel */ - *(madPtr++) = applyReplayGain (BarPlayerMadToShort ( - player->mp3Synth.pcm.samples[0][i]), player->scale); - - /* right channel */ - *(madPtr++) = applyReplayGain (BarPlayerMadToShort ( - player->mp3Synth.pcm.samples[1][i]), player->scale); - } - if (player->mode < PLAYER_AUDIO_INITIALIZED) { - ao_sample_format format; - int audioOutDriver; - - player->channels = player->mp3Synth.pcm.channels; - player->samplerate = player->mp3Synth.pcm.samplerate; - audioOutDriver = ao_default_driver_id(); - memset (&format, 0, sizeof (format)); - format.bits = 16; - format.channels = player->channels; - format.rate = player->samplerate; - format.byte_format = AO_FMT_NATIVE; - if ((player->audioOutDevice = ao_open_live (audioOutDriver, - &format, NULL)) == NULL) { - player->aoError = 1; - BarUiMsg (player->settings, MSG_ERR, - "Cannot open audio device\n"); - return WAITRESS_CB_RET_ERR; - } - - /* calc song length using the framerate of the first decoded frame */ - player->songDuration = (unsigned long long int) player->waith.request.contentLength / - ((unsigned long long int) player->mp3Frame.header.bitrate / - (unsigned long long int) BAR_PLAYER_MS_TO_S_FACTOR / 8LL); + pthread_mutex_unlock (&player->pauseMutex); - /* must be > PLAYER_SAMPLESIZE_INITIALIZED, otherwise time won't - * be visible to user (ugly, but mp3 decoding != aac decoding) */ - player->mode = PLAYER_RECV_DATA; - } - /* samples * length * channels */ - ao_play (player->audioOutDevice, (char *) madDecoded, - player->mp3Synth.pcm.length * 2 * 2); - - /* avoid division by 0 */ - if (player->mode == PLAYER_RECV_DATA) { - /* same calculation as in aac player; don't need to divide by - * channels, length is number of samples for _one_ channel */ - player->songPlayed += (unsigned long long int) player->mp3Synth.pcm.length * - (unsigned long long int) BAR_PLAYER_MS_TO_S_FACTOR / - (unsigned long long int) player->samplerate; + if (player->doQuit) { + av_free_packet (&pkt_orig); + break; } - if (BarPlayerCheckPauseQuit (player)) { - return WAITRESS_CB_RET_ERR; + if (pkt.stream_index != streamIdx) { + av_free_packet (&pkt_orig); + continue; } - } while (player->mp3Stream.error != MAD_ERROR_BUFLEN); - player->bufferRead += player->mp3Stream.next_frame - player->buffer; + do { + int got_frame = 0; - BarPlayerBufferMove (player); + const int decoded = avcodec_decode_audio4 (cctx, frame, &got_frame, + &pkt); + if (decoded < 0) { + softfail ("decode_audio4"); + } - return WAITRESS_CB_RET_OK; -} -#endif /* ENABLE_MAD */ + if (got_frame != 0) { + /* XXX: suppresses warning from resample filter */ + if (frame->pts == (int64_t) AV_NOPTS_VALUE) { + frame->pts = 0; + } + ret = av_buffersrc_write_frame (fabuf, frame); + assert (ret >= 0); + + while (true) { + AVFilterBufferRef *audioref = NULL; + if (av_buffersink_read (fbufsink, &audioref) < 0) { + /* try again next frame */ + break; + } -/* player thread; for every song a new thread is started - * @param audioPlayer structure - * @return PLAYER_RET_* - */ -void *BarPlayerThread (void *data) { - struct audioPlayer *player = data; - char extraHeaders[32]; - void *ret = PLAYER_RET_OK; - #ifdef ENABLE_FAAD - NeAACDecConfigurationPtr conf; - #endif - WaitressReturn_t wRet = WAITRESS_RET_ERR; - - /* init handles */ - player->waith.data = (void *) player; - /* extraHeaders will be initialized later */ - player->waith.extraHeaders = extraHeaders; - player->buffer = malloc (BAR_PLAYER_BUFSIZE); - - switch (player->audioFormat) { - #ifdef ENABLE_FAAD - case PIANO_AF_AACPLUS: - player->aacHandle = NeAACDecOpen(); - /* set aac conf */ - conf = NeAACDecGetCurrentConfiguration(player->aacHandle); - conf->outputFormat = FAAD_FMT_16BIT; - conf->downMatrix = 1; - NeAACDecSetConfiguration(player->aacHandle, conf); - - player->waith.callback = BarPlayerAACCb; - break; - #endif /* ENABLE_FAAD */ + ret = avfilter_copy_buf_props (filteredFrame, audioref); + assert (ret >= 0); - #ifdef ENABLE_MAD - case PIANO_AF_MP3: - mad_stream_init (&player->mp3Stream); - mad_frame_init (&player->mp3Frame); - mad_synth_init (&player->mp3Synth); + const int numChannels = av_get_channel_layout_nb_channels ( + filteredFrame->channel_layout); + const int bps = av_get_bytes_per_sample(filteredFrame->format); + ao_play (aoDev, (char *) filteredFrame->data[0], + filteredFrame->nb_samples * numChannels * bps); - player->waith.callback = BarPlayerMp3Cb; - break; - #endif /* ENABLE_MAD */ + avfilter_unref_bufferp (&audioref); + } + } - default: - BarUiMsg (player->settings, MSG_ERR, "Unsupported audio format!\n"); - ret = (void *) PLAYER_RET_HARDFAIL; - goto cleanup; - break; - } - - player->mode = PLAYER_INITIALIZED; - - /* This loop should work around song abortions by requesting the - * missing part of the song */ - do { - snprintf (extraHeaders, sizeof (extraHeaders), "Range: bytes=%zu-\r\n", - player->bytesReceived); - wRet = WaitressFetchCall (&player->waith); - } while (wRet == WAITRESS_RET_PARTIAL_FILE || wRet == WAITRESS_RET_TIMEOUT - || wRet == WAITRESS_RET_READ_ERR); - - switch (player->audioFormat) { - #ifdef ENABLE_FAAD - case PIANO_AF_AACPLUS: - NeAACDecClose(player->aacHandle); - free (player->sampleSize); - break; - #endif /* ENABLE_FAAD */ + pkt.data += decoded; + pkt.size -= decoded; + } while (pkt.size > 0); - #ifdef ENABLE_MAD - case PIANO_AF_MP3: - mad_synth_finish (&player->mp3Synth); - mad_frame_finish (&player->mp3Frame); - mad_stream_finish (&player->mp3Stream); - break; - #endif /* ENABLE_MAD */ + av_free_packet (&pkt_orig); - default: - /* this should never happen */ - assert (0); - break; + player->songPlayed = av_q2d (st->time_base) * (double) pkt.pts; } - if (player->aoError) { - ret = (void *) PLAYER_RET_HARDFAIL; +finish: + ao_close (aoDev); + if (fgraph != NULL) { + avfilter_graph_free (&fgraph); } - - /* Pandora sends broken audio url’s sometimes (“bad request”). ignore them. */ - if (wRet != WAITRESS_RET_OK && wRet != WAITRESS_RET_CB_ABORT) { - BarUiMsg (player->settings, MSG_ERR, "Cannot access audio file: %s\n", - WaitressErrorToStr (wRet)); - ret = (void *) PLAYER_RET_SOFTFAIL; + if (cctx != NULL) { + avcodec_close (cctx); + } + if (fctx != NULL) { + avformat_close_input (&fctx); + } + if (frame != NULL) { + avcodec_free_frame (&frame); + } + if (filteredFrame != NULL) { + avcodec_free_frame (&filteredFrame); } -cleanup: - ao_close (player->audioOutDevice); - WaitressFree (&player->waith); - free (player->buffer); - - player->mode = PLAYER_FINISHED_PLAYBACK; + player->mode = PLAYER_FINISHED; - return ret; + return (void *) pret; } + |