commit bd5046d0fc9a7180998a74c07bf91a0cfe8e8ca9
Author: leigh123linux <leigh123linux(a)googlemail.com>
Date: Wed Jul 27 09:23:25 2016 +0100
patch for newer ffmpeg
cmus.spec | 8 +-
new_ffmpeg.patch | 728 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 735 insertions(+), 1 deletion(-)
---
diff --git a/cmus.spec b/cmus.spec
index a63edf0..a8b4cb0 100644
--- a/cmus.spec
+++ b/cmus.spec
@@ -1,11 +1,13 @@
Name: cmus
Version: 2.7.1
-Release: 1%{?dist}
+Release: 2%{?dist}
Summary: Ncurses-Based Music Player
Group: Applications/Multimedia
License: GPLv2+
URL:
https://cmus.github.io/
Source0:
https://github.com/cmus/%{name}/archive/v%{version}/%{name}-%{version}.ta...
+# patch from
https://github.com/mahkoh/cmus/commits/ffmpeg_legacy
+Patch0: new_ffmpeg.patch
BuildRequires: alsa-lib-devel
BuildRequires: faad2-devel
@@ -32,6 +34,7 @@ operating systems
%prep
%setup -q
+%patch0 -p1
%build
@@ -85,6 +88,9 @@ chmod -x examples/*
%changelog
+* Wed Jul 27 2016 Leigh Scott <leigh123linux(a)googlemail.com> - 2.7.1-2
+- patch for newer ffmpeg
+
* Fri Dec 04 2015 Sérgio Basto <sergio(a)serjux.com> - 2.7.1-1
- Update to 2.7.1
diff --git a/new_ffmpeg.patch b/new_ffmpeg.patch
new file mode 100644
index 0000000..4c461f6
--- /dev/null
+++ b/new_ffmpeg.patch
@@ -0,0 +1,728 @@
+--- a/ffmpeg.c
++++ b/ffmpeg.c
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright 2008-2013 Various Authors
++ * Copyright 2008-2016 Various Authors
+ * Copyright 2007 Kevin Ko <kevin.s.ko(a)gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+@@ -26,57 +26,67 @@
+ #endif
+
+ #include <stdio.h>
+-#ifdef HAVE_FFMPEG_AVCODEC_H
+-#include <ffmpeg/avcodec.h>
+-#include <ffmpeg/avformat.h>
+-#include <ffmpeg/avio.h>
+-#include <ffmpeg/swresample.h>
+-#include <ffmpeg/opt.h>
+-#include <ffmpeg/audioconvert.h>
+-#else
++#include <stdbool.h>
++
++/* Minimum API versions:
++ * avcodec: 54
++ * avformat: 54
++ * avutil: 51
++ * swresample: 0
++ */
++
+ #include <libavcodec/avcodec.h>
+ #include <libavformat/avformat.h>
+ #include <libavformat/avio.h>
+ #include <libswresample/swresample.h>
+ #include <libavutil/opt.h>
+-#include <libavutil/audioconvert.h>
++#if LIBAVUTIL_VERSION_MAJOR >= 53
++# include <libavutil/channel_layout.h>
++#else
++# include <libavutil/audioconvert.h>
++#endif
+ #ifndef AVUTIL_MATHEMATICS_H
+ #include <libavutil/mathematics.h>
+ #endif
+-#endif
+-
+-#if (LIBAVFORMAT_VERSION_INT < ((52<<16)+(31<<8)+0))
+-# define NUM_FFMPEG_KEYS 8
+-#endif
+-
+-#if (LIBAVCODEC_VERSION_INT < ((52<<16)+(64<<8)+0))
+-# define AVMEDIA_TYPE_AUDIO CODEC_TYPE_AUDIO
+-#endif
+-
+-#if (LIBAVCODEC_VERSION_INT < ((52<<16)+(94<<8)+1))
+-#define AV_SAMPLE_FMT_U8 SAMPLE_FMT_U8
+-#define AV_SAMPLE_FMT_S16 SAMPLE_FMT_S16
+-#define AV_SAMPLE_FMT_S32 SAMPLE_FMT_S32
+-#define AV_SAMPLE_FMT_FLT SAMPLE_FMT_FLT
+-#if (LIBAVCODEC_VERSION_INT > ((51<<16)+(64<<8)+0))
+-#define AV_SAMPLE_FMT_DBL SAMPLE_FMT_DBL
+-#endif
+-#endif
+-
+-#if (LIBAVUTIL_VERSION_INT < ((51<<16)+(5<<8)+0))
+-#define AV_DICT_IGNORE_SUFFIX AV_METADATA_IGNORE_SUFFIX
+-#define av_dict_get av_metadata_get
+-#define AVDictionaryEntry AVMetadataTag
+-#endif
+
+ #ifndef AVCODEC_MAX_AUDIO_FRAME_SIZE
+-#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000
++# define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000
++#endif
++
++#if LIBAVCODEC_VERSION_MAJOR >= 56
++# define ffmpeg_packet_unref(pkt) av_packet_unref(pkt)
++# define ffmpeg_frame_alloc() av_frame_alloc()
++# define ffmpeg_frame_free(frame) av_frame_free(frame)
++# define ffmpeg_free_context(cc) avcodec_free_context(cc)
++#else
++# define ffmpeg_packet_unref(pkt) av_free_packet(pkt)
++# define ffmpeg_frame_alloc() avcodec_alloc_frame()
++# define ffmpeg_frame_free(frame) avcodec_free_frame(frame)
++# define ffmpeg_free_context(cc) do { avcodec_close(*cc); av_freep(cc); } while (0)
++#endif
++
++#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 40, 100)
++# define ffmpeg_initialize_context(cc, stream) \
++ avcodec_copy_context(cc, stream->codec)
++#else
++# define ffmpeg_initialize_context(cc, stream) \
++ avcodec_parameters_to_context(cc, stream->codecpar)
++# define ffmpeg_receive_frame(...) avcodec_receive_frame(__VA_ARGS__)
++# define ffmpeg_send_packet(...) avcodec_send_packet(__VA_ARGS__)
++#endif
++
++#if LIBAVCODEC_VERSION_MAJOR >= 55
++# define FFMPEG_CODEC_ID_APE AV_CODEC_ID_APE
++#else
++# define FFMPEG_CODEC_ID_APE CODEC_ID_APE
+ #endif
+
+ struct ffmpeg_input {
+ AVPacket pkt;
+ int curr_pkt_size;
+ uint8_t *curr_pkt_buf;
++ int stream_index;
++ bool eof;
+
+ unsigned long curr_size;
+ unsigned long curr_duration;
+@@ -94,12 +104,55 @@
+ AVFormatContext *input_context;
+ AVCodec *codec;
+ SwrContext *swr;
+- int stream_index;
+
+ struct ffmpeg_input *input;
+ struct ffmpeg_output *output;
+ };
+
++#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 40, 100)
++static int ffmpeg_receive_frame(AVCodecContext *cc, AVFrame *frame)
++{
++ struct ffmpeg_private *private = cc->opaque;
++ struct ffmpeg_input *input = private->input;
++
++ int len = 0;
++ int got_frame = 0;
++
++ if (input->curr_pkt_size <= 0) {
++ return -1;
++ }
++
++ AVPacket avpkt;
++ av_new_packet(&avpkt, input->curr_pkt_size);
++ memcpy(avpkt.data, input->curr_pkt_buf, input->curr_pkt_size);
++ len = avcodec_decode_audio4(cc, frame, &got_frame, &avpkt);
++ ffmpeg_packet_unref(&avpkt);
++
++ if (len < 0) {
++ input->curr_pkt_size = 0;
++ return -1;
++ }
++
++ input->curr_pkt_size -= len;
++ input->curr_pkt_buf += len;
++
++ return !got_frame;
++}
++
++static int ffmpeg_send_packet(AVCodecContext *cc, AVPacket *pkt)
++{
++ struct ffmpeg_private *private = cc->opaque;
++ struct ffmpeg_input *input = private->input;
++
++ if (pkt) {
++ input->curr_pkt_size = pkt->size;
++ input->curr_pkt_buf = pkt->data;
++ }
++
++ return 0;
++}
++#endif
++
+ static struct ffmpeg_input *ffmpeg_input_create(void)
+ {
+ struct ffmpeg_input *input = xnew(struct ffmpeg_input, 1);
+@@ -110,12 +163,13 @@
+ }
+ input->curr_pkt_size = 0;
+ input->curr_pkt_buf = input->pkt.data;
++ input->eof = false;
+ return input;
+ }
+
+ static void ffmpeg_input_free(struct ffmpeg_input *input)
+ {
+- av_free_packet(&input->pkt);
++ ffmpeg_packet_unref(&input->pkt);
+ free(input);
+ }
+
+@@ -157,112 +211,79 @@
+
+ av_log_set_level(AV_LOG_QUIET);
+
+-#if (LIBAVFORMAT_VERSION_INT <= ((50<<16) + (4<<8) + 0))
+- avcodec_init();
+- register_avcodec(&wmav1_decoder);
+- register_avcodec(&wmav2_decoder);
+-
+- /* libavformat versions <= 50.4.0 have asf_init(). From SVN revision
+- * 5697->5707 of asf.c, this function was removed, preferring the use of
+- * explicit calls. Note that version 50.5.0 coincides with SVN revision
+- * 5729, so there is a window of incompatibility for revisions 5707 and 5720
+- * of asf.c.
+- */
+- asf_init();
+-
+- /* Uncomment this for shorten (.shn) support.
+- register_avcodec(&shorten_decoder);
+- raw_init();
+- */
+-
+- register_protocol(&file_protocol);
+-#else
+ /* We could register decoders explicitly to save memory, but we have to
+ * be careful about compatibility. */
+ av_register_all();
+-#endif
+ }
+
+ static int ffmpeg_open(struct input_plugin_data *ip_data)
+ {
+- struct ffmpeg_private *priv;
++ struct ffmpeg_private *priv = NULL;
+ int err = 0;
+- int i;
+ int stream_index = -1;
+ int64_t channel_layout = 0;
+- AVCodec *codec;
++ AVCodec *codec = NULL;
+ AVCodecContext *cc = NULL;
+ AVFormatContext *ic = NULL;
+ SwrContext *swr = NULL;
+
+ ffmpeg_init();
+
+-#if (LIBAVFORMAT_VERSION_INT <= ((53<<16)+(2<<8)+0))
+- err = av_open_input_file(&ic, ip_data->filename, NULL, 0, NULL);
+-#else
+ err = avformat_open_input(&ic, ip_data->filename, NULL, NULL);
+-#endif
+ if (err < 0) {
+ d_print("av_open failed: %d\n", err);
+ return -IP_ERROR_FILE_FORMAT;
+ }
+
+ do {
+-#if (LIBAVFORMAT_VERSION_INT <= ((53<<16)+(5<<8)+0))
+- err = av_find_stream_info(ic);
+-#else
+ err = avformat_find_stream_info(ic, NULL);
+-#endif
+ if (err < 0) {
+ d_print("unable to find stream info: %d\n", err);
+ err = -IP_ERROR_FILE_FORMAT;
+ break;
+ }
+
+- for (i = 0; i < ic->nb_streams; i++) {
+- cc = ic->streams[i]->codec;
+- if (cc->codec_type == AVMEDIA_TYPE_AUDIO) {
+- stream_index = i;
+- break;
++ err = av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0);
++ if (err < 0) {
++ if (err == AVERROR_STREAM_NOT_FOUND) {
++ d_print("could not find audio stream\n");
++ err = -IP_ERROR_FILE_FORMAT;
++ } else if (err == AVERROR_DECODER_NOT_FOUND) {
++ d_print("codec not found\n");
++ err = -IP_ERROR_UNSUPPORTED_FILE_TYPE;
++ } else {
++ err = -IP_ERROR_INTERNAL;
+ }
+- }
+-
+- if (stream_index == -1) {
+- d_print("could not find audio stream\n");
+- err = -IP_ERROR_FILE_FORMAT;
+- break;
+- }
+-
+- codec = avcodec_find_decoder(cc->codec_id);
+- if (!codec) {
+- d_print("codec not found: %d, %s\n", cc->codec_id, cc->codec_name);
+- err = -IP_ERROR_UNSUPPORTED_FILE_TYPE;
++ break;
++ }
++ stream_index = err;
++
++ cc = avcodec_alloc_context3(codec);
++ if (!cc) {
++ d_print("could not allocate decodec context\n");
++ err = -IP_ERROR_INTERNAL;
++ break;
++ }
++ if (ffmpeg_initialize_context(cc, ic->streams[stream_index]) < 0) {
++ d_print("could not initialize decodec context\n");
++ err = -IP_ERROR_INTERNAL;
+ break;
+ }
+
+ if (codec->capabilities & CODEC_CAP_TRUNCATED)
+ cc->flags |= CODEC_FLAG_TRUNCATED;
+
+-#if (LIBAVCODEC_VERSION_INT < ((53<<16)+(8<<8)+0))
+- if (avcodec_open(cc, codec) < 0) {
+-#else
+ if (avcodec_open2(cc, codec, NULL) < 0) {
+-#endif
+- d_print("could not open codec: %d, %s\n", cc->codec_id,
cc->codec_name);
++ d_print("could not open codec: %d, %s\n", cc->codec_id,
++ avcodec_get_name(cc->codec_id));
+ err = -IP_ERROR_UNSUPPORTED_FILE_TYPE;
+ break;
+ }
+-
+- /* We assume below that no more errors follow. */
+ } while (0);
+
+ if (err < 0) {
+- /* Clean up. cc is never opened at this point. (See above assumption.) */
+-#if (LIBAVCODEC_VERSION_INT < ((53<<16)+(25<<8)+0))
+- av_close_input_file(ic);
+-#else
++ ffmpeg_free_context(&cc);
+ avformat_close_input(&ic);
+-#endif
+ return err;
+ }
+
+@@ -270,19 +291,17 @@
+ priv->codec_context = cc;
+ priv->input_context = ic;
+ priv->codec = codec;
+- priv->stream_index = stream_index;
+ priv->input = ffmpeg_input_create();
+ if (priv->input == NULL) {
+- avcodec_close(cc);
+-#if (LIBAVCODEC_VERSION_INT < ((53<<16)+(25<<8)+0))
+- av_close_input_file(ic);
+-#else
++ ffmpeg_free_context(&cc);
+ avformat_close_input(&ic);
+-#endif
+ free(priv);
+ return -IP_ERROR_INTERNAL;
+ }
++ priv->input->stream_index = stream_index;
+ priv->output = ffmpeg_output_create();
++
++ cc->opaque = priv;
+
+ /* Prepare for resampling. */
+ swr = swr_alloc();
+@@ -314,9 +333,7 @@
+ #ifdef WORDS_BIGENDIAN
+ ip_data->sf |= sf_bigendian(1);
+ #endif
+-#if (LIBAVCODEC_VERSION_INT > ((52<<16)+(1<<8)+0))
+ channel_layout = cc->channel_layout;
+-#endif
+ channel_map_init_waveex(cc->channels, channel_layout, ip_data->channel_map);
+ return 0;
+ }
+@@ -325,12 +342,8 @@
+ {
+ struct ffmpeg_private *priv = ip_data->private;
+
+- avcodec_close(priv->codec_context);
+-#if (LIBAVCODEC_VERSION_INT < ((53<<16)+(25<<8)+0))
+- av_close_input_file(priv->input_context);
+-#else
++ ffmpeg_free_context(&priv->codec_context);
+ avformat_close_input(&priv->input_context);
+-#endif
+ swr_free(&priv->swr);
+ ffmpeg_input_free(priv->input);
+ ffmpeg_output_free(priv->output);
+@@ -339,117 +352,75 @@
+ return 0;
+ }
+
+-/*
+- * This returns the number of bytes added to the buffer.
+- * It returns < 0 on error. 0 on EOF.
+- */
+-static int ffmpeg_fill_buffer(AVFormatContext *ic, AVCodecContext *cc, struct
ffmpeg_input *input,
+- struct ffmpeg_output *output, SwrContext *swr)
+-{
+-#if (LIBAVCODEC_VERSION_INT >= ((53<<16) + (25<<8) + 0))
+- AVFrame *frame = avcodec_alloc_frame();
+- int got_frame;
+-#endif
++static int ffmpeg_fill_buffer(AVFormatContext *ic, AVCodecContext *cc,
++ struct ffmpeg_input *input, struct ffmpeg_output *output, SwrContext *swr)
++{
++ AVFrame *frame = ffmpeg_frame_alloc();
++ int res = -IP_ERROR_INTERNAL;
++
+ while (1) {
+-#if (LIBAVCODEC_VERSION_INT < ((53<<16) + (25<<8) + 0))
+- /* frame_size specifies the size of output->buffer for
+- * avcodec_decode_audio2. */
+- int frame_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
+-#endif
+- int len;
+-
+- if (input->curr_pkt_size <= 0) {
+- av_free_packet(&input->pkt);
+- if (av_read_frame(ic, &input->pkt) < 0) {
+- /* Force EOF once we can read no longer. */
+-#if (LIBAVCODEC_VERSION_INT >= ((53<<16) + (25<<8) + 0))
+- avcodec_free_frame(&frame);
+-#endif
+- return 0;
++ if (!ffmpeg_receive_frame(cc, frame)) {
++ res = swr_convert(swr,
++ &output->buffer,
++ frame->nb_samples,
++ (const uint8_t **)frame->extended_data,
++ frame->nb_samples);
++ if (res < 0) {
++ res = -IP_ERROR_INTERNAL;
++ break;
+ }
+- input->curr_pkt_size = input->pkt.size;
+- input->curr_pkt_buf = input->pkt.data;
++ output->buffer_pos = output->buffer;
++ output->buffer_used_len = res * cc->channels * sizeof(int16_t);
++ res = output->buffer_used_len;
++ break;
++ }
++
++ if (input->eof) {
++ res = 0;
++ break;
++ }
++
++ ffmpeg_packet_unref(&input->pkt);
++ res = av_read_frame(ic, &input->pkt);
++
++ if (res < 0) {
++ if (res == AVERROR_EOF) {
++ ffmpeg_send_packet(cc, NULL);
++ input->eof = true;
++ continue;
++ } else {
++ res = 0;
++ break;
++ }
++ }
++
++ if (input->pkt.stream_index == input->stream_index) {
+ input->curr_size += input->pkt.size;
+ input->curr_duration += input->pkt.duration;
+- continue;
+- }
+-
+- /* The change to avcodec_decode_audio2 occurred between
+- * 51.28.0 and 51.29.0 */
+-#if (LIBAVCODEC_VERSION_INT <= ((51<<16) + (28<<8) + 0))
+- len = avcodec_decode_audio(cc, (int16_t *)output->buffer, &frame_size,
+- input->curr_pkt_buf, input->curr_pkt_size);
+- /* The change to avcodec_decode_audio3 occurred between
+- * 52.25.0 and 52.26.0 */
+-#elif (LIBAVCODEC_VERSION_INT <= ((52<<16) + (25<<8) + 0))
+- len = avcodec_decode_audio2(cc, (int16_t *) output->buffer, &frame_size,
+- input->curr_pkt_buf, input->curr_pkt_size);
+-#elif (LIBAVCODEC_VERSION_INT < ((53<<16) + (25<<8) + 0))
+- {
+- AVPacket avpkt;
+- av_init_packet(&avpkt);
+- avpkt.data = input->curr_pkt_buf;
+- avpkt.size = input->curr_pkt_size;
+- len = avcodec_decode_audio3(cc, (int16_t *) output->buffer, &frame_size,
&avpkt);
+- av_free_packet(&avpkt);
+- }
+-#else
+- {
+- AVPacket avpkt;
+- av_new_packet(&avpkt, input->curr_pkt_size);
+- memcpy(avpkt.data, input->curr_pkt_buf, input->curr_pkt_size);
+- len = avcodec_decode_audio4(cc, frame, &got_frame, &avpkt);
+- av_free_packet(&avpkt);
+- }
+-#endif
+- if (len < 0) {
+- /* this is often reached when seeking, not sure why */
+- input->curr_pkt_size = 0;
+- continue;
+- }
+- input->curr_pkt_size -= len;
+- input->curr_pkt_buf += len;
+-#if (LIBAVCODEC_VERSION_INT < ((53<<16) + (25<<8) + 0))
+- if (frame_size > 0) {
+- output->buffer_pos = output->buffer;
+- output->buffer_used_len = frame_size;
+- return frame_size;
+- }
+-#else
+- if (got_frame) {
+- int res = swr_convert(swr,
+- &output->buffer,
+- frame->nb_samples,
+- (const uint8_t **)frame->extended_data,
+- frame->nb_samples);
+- if (res < 0)
+- res = 0;
+- output->buffer_pos = output->buffer;
+- output->buffer_used_len = res * cc->channels * sizeof(int16_t);
+- avcodec_free_frame(&frame);
+- return output->buffer_used_len;
+- }
+-#endif
+- }
+- /* This should never get here. */
+- return -IP_ERROR_INTERNAL;
++ if (ffmpeg_send_packet(cc, &input->pkt)) {
++ res = -IP_ERROR_INTERNAL;
++ break;
++ }
++ }
++ }
++
++ ffmpeg_frame_free(&frame);
++ return res;
+ }
+
+ static int ffmpeg_read(struct input_plugin_data *ip_data, char *buffer, int count)
+ {
+ struct ffmpeg_private *priv = ip_data->private;
+ struct ffmpeg_output *output = priv->output;
+- int rc;
+- int out_size;
+
+ if (output->buffer_used_len == 0) {
+- rc = ffmpeg_fill_buffer(priv->input_context, priv->codec_context,
++ int rc = ffmpeg_fill_buffer(priv->input_context, priv->codec_context,
+ priv->input, priv->output, priv->swr);
+ if (rc <= 0) {
+ return rc;
+ }
+ }
+- out_size = min(output->buffer_used_len, count);
++ int out_size = min(output->buffer_used_len, count);
+ memcpy(buffer, output->buffer_pos, out_size);
+ output->buffer_used_len -= out_size;
+ output->buffer_pos += out_size;
+@@ -459,30 +430,15 @@
+ static int ffmpeg_seek(struct input_plugin_data *ip_data, double offset)
+ {
+ struct ffmpeg_private *priv = ip_data->private;
+- AVStream *st = priv->input_context->streams[priv->stream_index];
+- int ret;
+-
+- /* There is a bug that was fixed in ffmpeg revision 5099 that affects seeking.
+- * Apparently, the stream's timebase was not used consistently in asf.c.
+- * Prior to 5099, ASF seeking assumed seconds as inputs. There is a
+- * window of incompatibility, since avformat's version was not updated at
+- * the same time. Instead, the transition to 50.3.0 occurred at
+- * revision 5028. */
+-#if (LIBAVFORMAT_VERSION_INT < ((50<<16)+(3<<8)+0))
+- int64_t pts = (int64_t) offset;
+-#else
++ AVStream *st = priv->input_context->streams[priv->input->stream_index];
++
+ int64_t pts = av_rescale_q(offset * AV_TIME_BASE, AV_TIME_BASE_Q, st->time_base);
+-#endif
+-
+-#if (LIBAVFORMAT_VERSION_INT >= ((53<<16) + (25<<8) + 0))
+- {
+- avcodec_flush_buffers(priv->codec_context);
+- /* Force reading a new packet in next ffmpeg_fill_buffer(). */
+- priv->input->curr_pkt_size = 0;
+- }
+-#endif
+-
+- ret = av_seek_frame(priv->input_context, priv->stream_index, pts, 0);
++
++ avcodec_flush_buffers(priv->codec_context);
++ /* Force reading a new packet in next ffmpeg_fill_buffer(). */
++ priv->input->curr_pkt_size = 0;
++
++ int ret = av_seek_frame(priv->input_context, priv->input->stream_index, pts,
0);
+
+ if (ret < 0) {
+ return -IP_ERROR_FUNCTION_NOT_SUPPORTED;
+@@ -492,56 +448,31 @@
+ }
+ }
+
+-#if (LIBAVFORMAT_VERSION_INT < ((52<<16)+(31<<8)+0))
+-/* Return new i. */
+-static int set_comment(struct keyval *comment, int i, const char *key, const char *val)
+-{
+- if (val[0] == 0) {
+- return i;
+- }
+- comment[i].key = xstrdup(key);
+- comment[i].val = xstrdup(val);
+- return i + 1;
+-}
+-#endif
+-
+-static int ffmpeg_read_comments(struct input_plugin_data *ip_data, struct keyval
**comments)
++static void ffmpeg_read_metadata(struct growing_keyvals *c, AVDictionary *metadata)
++{
++ AVDictionaryEntry *tag = NULL;
++
++ while ((tag = av_dict_get(metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
++ if (tag->value[0])
++ comments_add_const(c, tag->key, tag->value);
++ }
++}
++
++static int ffmpeg_read_comments(struct input_plugin_data *ip_data,
++ struct keyval **comments)
+ {
+ struct ffmpeg_private *priv = ip_data->private;
+ AVFormatContext *ic = priv->input_context;
+
+-#if (LIBAVFORMAT_VERSION_INT < ((52<<16)+(31<<8)+0))
+- char buff[16];
+- int i = 0;
+-
+- *comments = keyvals_new(NUM_FFMPEG_KEYS);
+-
+- i = set_comment(*comments, i, "artist", ic->author);
+- i = set_comment(*comments, i, "album", ic->album);
+- i = set_comment(*comments, i, "title", ic->title);
+- i = set_comment(*comments, i, "genre", ic->genre);
+-
+- if (ic->year != 0) {
+- snprintf(buff, sizeof(buff), "%d", ic->year);
+- i = set_comment(*comments, i, "date", buff);
+- }
+-
+- if (ic->track != 0) {
+- snprintf(buff, sizeof(buff), "%d", ic->track);
+- i = set_comment(*comments, i, "tracknumber", buff);
+- }
+-#else
+ GROWING_KEYVALS(c);
+- AVDictionaryEntry *tag = NULL;
+-
+- while ((tag = av_dict_get(ic->metadata, "", tag, AV_DICT_IGNORE_SUFFIX)))
{
+- if (tag && tag->value[0])
+- comments_add_const(&c, tag->key, tag->value);
++
++ ffmpeg_read_metadata(&c, ic->metadata);
++ for (unsigned i = 0; i < ic->nb_streams; i++) {
++ ffmpeg_read_metadata(&c, ic->streams[i]->metadata);
+ }
+
+ keyvals_terminate(&c);
+ *comments = c.keyvals;
+-#endif
+
+ return 0;
+ }
+@@ -562,13 +493,11 @@
+ static long ffmpeg_current_bitrate(struct input_plugin_data *ip_data)
+ {
+ struct ffmpeg_private *priv = ip_data->private;
+- AVStream *st = priv->input_context->streams[priv->stream_index];
++ AVStream *st = priv->input_context->streams[priv->input->stream_index];
+ long bitrate = -1;
+-#if (LIBAVFORMAT_VERSION_INT > ((51<<16)+(43<<8)+0))
+ /* ape codec returns silly numbers */
+- if (priv->codec->id == CODEC_ID_APE)
++ if (priv->codec->id == FFMPEG_CODEC_ID_APE)
+ return -1;
+-#endif
+ if (priv->input->curr_duration > 0) {
+ double seconds = priv->input->curr_duration * av_q2d(st->time_base);
+ bitrate = (8 * priv->input->curr_size) / seconds;
+@@ -584,31 +513,12 @@
+ return xstrdup(priv->codec->name);
+ }
+
+-#if (LIBAVCODEC_VERSION_INT < ((52<<16)+(104<<8)+0))
+-static const char *codec_profile_to_str(int profile)
+-{
+-#if (LIBAVCODEC_VERSION_INT >= ((51<<16)+(41<<8)+0))
+- switch (profile) {
+- case FF_PROFILE_AAC_MAIN: return "Main";
+- case FF_PROFILE_AAC_LOW: return "LC";
+- case FF_PROFILE_AAC_SSR: return "SSR";
+- case FF_PROFILE_AAC_LTP: return "LTP";
+- }
+-#endif
+- return NULL;
+-}
+-#endif
+-
+ static char *ffmpeg_codec_profile(struct input_plugin_data *ip_data)
+ {
+ struct ffmpeg_private *priv = ip_data->private;
+- const char *profile;
+-
+-#if (LIBAVCODEC_VERSION_INT < ((52<<16)+(104<<8)+0))
+- profile = codec_profile_to_str(priv->codec_context->profile);
+-#else
+- profile = av_get_profile_name(priv->codec, priv->codec_context->profile);
+-#endif
++
++ const char *profile = av_get_profile_name(priv->codec,
++ priv->codec_context->profile);
+
+ return profile ? xstrdup(profile) : NULL;
+ }
+@@ -626,16 +536,15 @@
+ .codec_profile = ffmpeg_codec_profile
+ };
+
+-const int ip_priority = 30;
++const int ip_priority = 300;
+ const char *const ip_extensions[] = {
+- "ac3", "aif", "aifc", "aiff", "ape",
"au", "mka", "shn", "tta", "wma",
+- /* also supported by other plugins */
+- "aac", "fla", "flac", "m4a", "m4b",
"mp+", "mp2", "mp3", "mp4", "mpc",
+- "mpp", "ogg", "wav", "wv",
++ "aa", "aac", "ac3", "aif", "aifc",
"aiff", "ape", "au", "fla", "flac",
++ "m4a", "m4b", "mka", "mkv", "mp+",
"mp2", "mp3", "mp4", "mpc", "mpp",
++ "ogg", "shn", "tak", "tta", "wav",
"webm", "wma", "wv",
+ #ifdef USE_FALLBACK_IP
+ "*",
+ #endif
+ NULL
+ };
+ const char *const ip_mime_types[] = { NULL };
+-const char * const ip_options[] = { NULL };
++const char *const ip_options[] = { NULL };