From f3dff6792232d1e3f2deb8baf21dc1fa81581090 Mon Sep 17 00:00:00 2001 From: Lars-Dominik Braun Date: Fri, 24 Mar 2017 11:02:27 +0100 Subject: Replace deprecated avcodec_decode_audio4 Use new send_packet/receive_frame API. Bumps libav and ffmpeg version requirements. Revert this commit if you need an older version. --- INSTALL | 2 +- src/config.h | 13 +----- src/player.c | 134 +++++++++++++++++++++++++++++++---------------------------- src/player.h | 1 + 4 files changed, 74 insertions(+), 76 deletions(-) diff --git a/INSTALL b/INSTALL index b0db803..637791f 100644 --- a/INSTALL +++ b/INSTALL @@ -10,7 +10,7 @@ Dependencies - libcurl - gcrypt[1] - json-c -- libav/ffmpeg[2] +- libav>=12/ffmpeg>=3.1 [2] - UTF-8 console/locale [1] with blowfish cipher enabled diff --git a/src/config.h b/src/config.h index e88f41b..2cc010f 100644 --- a/src/config.h +++ b/src/config.h @@ -1,5 +1,4 @@ -#ifndef SRC_CONFIG_H_S6A1C09K -#define SRC_CONFIG_H_S6A1C09K +#pragma once /* package name */ #define PACKAGE "pianobar" @@ -20,13 +19,3 @@ #define HAVE_AVFILTER_GRAPH_SEND_COMMAND #endif -/* need avcodec.h (ffmpeg 1.2) */ -#if LIBAVFILTER_VERSION_MAJOR == 3 && \ - LIBAVFILTER_VERSION_MINOR <= 42 && \ - LIBAVFILTER_VERSION_MINOR > 32 && \ - LIBAVFILTER_VERSION_MICRO >= 100 -#define HAVE_AV_BUFFERSINK_GET_BUFFER_REF -#define HAVE_LIBAVFILTER_AVCODEC_H -#endif - -#endif /* SRC_CONFIG_H_S6A1C09K */ diff --git a/src/player.c b/src/player.c index f3c57f8..9cbee69 100644 --- a/src/player.c +++ b/src/player.c @@ -166,16 +166,23 @@ static bool openStream (player_t * const player) { } player->st = player->fctx->streams[player->streamIdx]; - AVCodecContext * const cctx = player->st->codec; player->st->discard = AVDISCARD_DEFAULT; /* decoder setup */ - AVCodec * const decoder = avcodec_find_decoder (cctx->codec_id); + if ((player->cctx = avcodec_alloc_context3 (NULL)) == NULL) { + softfail ("avcodec_alloc_context3"); + } + const AVCodecParameters * const cp = player->st->codecpar; + if ((ret = avcodec_parameters_to_context (player->cctx, cp)) < 0) { + softfail ("avcodec_parameters_to_context"); + } + + AVCodec * const decoder = avcodec_find_decoder (cp->codec_id); if (decoder == NULL) { softfail ("find_decoder"); } - if ((ret = avcodec_open2 (cctx, decoder, NULL)) < 0) { + if ((ret = avcodec_open2 (player->cctx, decoder, NULL)) < 0) { softfail ("codec_open2"); } @@ -196,7 +203,7 @@ static bool openFilter (player_t * const player) { /* filter setup */ char strbuf[256]; int ret = 0; - AVCodecContext * const cctx = player->st->codec; + AVCodecParameters * const cp = player->st->codecpar; if ((player->fgraph = avfilter_graph_alloc ()) == NULL) { softfail ("graph_alloc"); @@ -205,17 +212,11 @@ static bool openFilter (player_t * const player) { /* abuffer */ AVRational time_base = player->st->time_base; - /* Workaround for a bug in libav-11, which reports an invalid channel - * layout mp3 files */ - if (cctx->channel_layout == 0) { - cctx->channel_layout = av_get_default_channel_layout (cctx->channels); - } - 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); + time_base.num, time_base.den, cp->sample_rate, + av_get_sample_fmt_name (player->cctx->sample_fmt), + cp->channel_layout); if ((ret = avfilter_graph_create_filter (&player->fabuf, avfilter_get_by_name ("abuffer"), NULL, strbuf, NULL, player->fgraph)) < 0) { @@ -263,14 +264,14 @@ static bool openFilter (player_t * const player) { /* setup libao */ static bool openDevice (player_t * const player) { - AVCodecContext * const cctx = player->st->codec; + const AVCodecParameters * const cp = player->st->codecpar; ao_sample_format aoFmt; 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.channels = cp->channels; + aoFmt.rate = cp->sample_rate; aoFmt.byte_format = AO_FMT_NATIVE; int driver = ao_default_driver_id (); @@ -288,6 +289,7 @@ static int play (player_t * const player) { assert (player != NULL); AVPacket pkt; + AVCodecContext * const cctx = player->cctx; av_init_packet (&pkt); pkt.data = NULL; pkt.size = 0; @@ -298,18 +300,28 @@ static int play (player_t * const player) { filteredFrame = av_frame_alloc (); assert (filteredFrame != NULL); - while (!player->doQuit) { - int ret = av_read_frame (player->fctx, &pkt); - if (ret < 0) { - av_free_packet (&pkt); - return ret; - } else if (pkt.stream_index != player->streamIdx) { - av_free_packet (&pkt); - continue; + enum { FILL, DRAIN, DONE } drainMode = FILL; + int ret = 0; + while (!player->doQuit && drainMode != DONE) { + if (drainMode == FILL) { + ret = av_read_frame (player->fctx, &pkt); + if (ret == AVERROR_EOF) { + /* enter drain mode */ + drainMode = DRAIN; + avcodec_send_packet (cctx, NULL); + } else if (pkt.stream_index != player->streamIdx) { + /* unused packet */ + av_packet_unref (&pkt); + continue; + } else if (ret < 0) { + /* error, abort */ + break; + } else { + /* fill buffer */ + avcodec_send_packet (cctx, &pkt); + } } - AVPacket pkt_orig = pkt; - /* pausing */ pthread_mutex_lock (&player->pauseMutex); if (player->doPause) { @@ -321,54 +333,50 @@ static int play (player_t * const player) { } pthread_mutex_unlock (&player->pauseMutex); - while (pkt.size > 0 && !player->doQuit) { - int got_frame = 0; - - const int decoded = avcodec_decode_audio4 (player->st->codec, - frame, &got_frame, &pkt); - if (decoded < 0) { - /* skip this one */ + while (!player->doQuit) { + ret = avcodec_receive_frame (cctx, frame); + if (ret == AVERROR_EOF) { + /* done draining */ + drainMode = DONE; + break; + } else if (ret != 0) { + /* no more output */ break; } - 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 (player->fabuf, frame); - assert (ret >= 0); - - while (true) { - if (av_buffersink_get_frame (player->fbufsink, filteredFrame) < 0) { - /* try again next frame */ - break; - } - - const int numChannels = av_get_channel_layout_nb_channels ( - filteredFrame->channel_layout); - const int bps = av_get_bytes_per_sample(filteredFrame->format); - ao_play (player->aoDev, (char *) filteredFrame->data[0], - filteredFrame->nb_samples * numChannels * bps); - - av_frame_unref (filteredFrame); - } + /* XXX: suppresses warning from resample filter */ + if (frame->pts == (int64_t) AV_NOPTS_VALUE) { + frame->pts = 0; } + ret = av_buffersrc_write_frame (player->fabuf, frame); + assert (ret >= 0); - pkt.data += decoded; - pkt.size -= decoded; - }; + while (true) { + if (av_buffersink_get_frame (player->fbufsink, filteredFrame) < 0) { + /* try again next frame */ + break; + } - av_free_packet (&pkt_orig); + const int numChannels = av_get_channel_layout_nb_channels ( + filteredFrame->channel_layout); + const int bps = av_get_bytes_per_sample(filteredFrame->format); + ao_play (player->aoDev, (char *) filteredFrame->data[0], + filteredFrame->nb_samples * numChannels * bps); + + av_frame_unref (filteredFrame); + } + } player->songPlayed = av_q2d (player->st->time_base) * (double) pkt.pts; player->lastTimestamp = pkt.pts; + + av_packet_unref (&pkt); } av_frame_free (&filteredFrame); av_frame_free (&frame); - return 0; + return ret; } static void finish (player_t * const player) { @@ -378,9 +386,9 @@ static void finish (player_t * const player) { avfilter_graph_free (&player->fgraph); player->fgraph = NULL; } - if (player->st != NULL && player->st->codec != NULL) { - avcodec_close (player->st->codec); - player->st = NULL; + if (player->cctx != NULL) { + avcodec_close (player->cctx); + player->cctx = NULL; } if (player->fctx != NULL) { avformat_close_input (&player->fctx); diff --git a/src/player.h b/src/player.h index 4f0c963..97e5e95 100644 --- a/src/player.h +++ b/src/player.h @@ -63,6 +63,7 @@ typedef struct { AVFilterGraph *fgraph; AVFormatContext *fctx; AVStream *st; + AVCodecContext *cctx; AVFilterContext *fbufsink, *fabuf; int streamIdx; int64_t lastTimestamp; -- cgit v1.2.3