diff options
| -rw-r--r-- | INSTALL | 2 | ||||
| -rw-r--r-- | src/config.h | 13 | ||||
| -rw-r--r-- | src/player.c | 134 | ||||
| -rw-r--r-- | src/player.h | 1 | 
4 files changed, 74 insertions, 76 deletions
@@ -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;  | 
