Merge branch 'libav9'

This commit is contained in:
ejurgensen
2014-01-10 21:54:03 +01:00
10 changed files with 421 additions and 390 deletions

View File

@@ -95,6 +95,56 @@ artwork_read(char *filename, struct evbuffer *evbuf)
return -1;
}
static int
rescale_needed(AVCodecContext *src, int max_w, int max_h, int *target_w, int *target_h)
{
int need_rescale;
DPRINTF(E_DBG, L_ART, "Original image dimensions: w %d h %d\n", src->width, src->height);
need_rescale = 1;
if ((max_w <= 0) || (max_h <= 0)) /* No valid dimensions, use original */
{
need_rescale = 0;
*target_w = src->width;
*target_h = src->height;
}
else if ((src->width <= max_w) && (src->height <= max_h)) /* Smaller than target */
{
need_rescale = 0;
*target_w = src->width;
*target_h = src->height;
}
else if (src->width * max_h > src->height * max_w) /* Wider aspect ratio than target */
{
*target_w = max_w;
*target_h = (double)max_w * ((double)src->height / (double)src->width);
}
else /* Taller or equal aspect ratio */
{
*target_w = (double)max_h * ((double)src->width / (double)src->height);
*target_h = max_h;
}
DPRINTF(E_DBG, L_ART, "Raw destination width %d height %d\n", *target_w, *target_h);
if ((*target_h > max_h) && (max_h > 0))
*target_h = max_h;
/* PNG prefers even row count */
*target_w += *target_w % 2;
if ((*target_w > max_w) && (max_w > 0))
*target_w = max_w - (max_w % 2);
DPRINTF(E_DBG, L_ART, "Destination width %d height %d\n", *target_w, *target_h);
return need_rescale;
}
static int
artwork_rescale(AVFormatContext *src_ctx, int s, int out_w, int out_h, int format, struct evbuffer *evbuf)
{
@@ -111,9 +161,6 @@ artwork_rescale(AVFormatContext *src_ctx, int s, int out_w, int out_h, int forma
AVCodec *img_decoder;
AVCodec *img_encoder;
int64_t pix_fmt_mask;
const enum PixelFormat *pix_fmts;
AVFrame *i_frame;
AVFrame *o_frame;
@@ -244,7 +291,12 @@ artwork_rescale(AVFormatContext *src_ctx, int s, int out_w, int out_h, int forma
dst->codec_type = CODEC_TYPE_VIDEO;
#endif
pix_fmt_mask = 0;
#if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35)
dst->pix_fmt = avcodec_find_best_pix_fmt2((enum AVPixelFormat *)img_encoder->pix_fmts, src->pix_fmt, 1, NULL);
#else
const enum PixelFormat *pix_fmts;
int64_t pix_fmt_mask = 0;
pix_fmts = img_encoder->pix_fmts;
while (pix_fmts && (*pix_fmts != -1))
{
@@ -253,6 +305,7 @@ artwork_rescale(AVFormatContext *src_ctx, int s, int out_w, int out_h, int forma
}
dst->pix_fmt = avcodec_find_best_pix_fmt(pix_fmt_mask, src->pix_fmt, 1, NULL);
#endif
if (dst->pix_fmt < 0)
{
@@ -520,15 +573,13 @@ static int
artwork_get(char *filename, int max_w, int max_h, int format, struct evbuffer *evbuf)
{
AVFormatContext *src_ctx;
AVCodecContext *src;
int s;
int target_w;
int target_h;
int need_rescale;
int format_ok;
int ret;
DPRINTF(E_DBG, L_ART, "Artwork request parameters: max w = %d, max h = %d\n", max_w, max_h);
DPRINTF(E_DBG, L_ART, "Getting artwork (max destination width %d height %d)\n", max_w, max_h);
src_ctx = NULL;
@@ -588,52 +639,10 @@ artwork_get(char *filename, int max_w, int max_h, int format, struct evbuffer *e
return -1;
}
src = src_ctx->streams[s]->codec;
DPRINTF(E_DBG, L_ART, "Original image '%s': w %d h %d\n", filename, src->width, src->height);
need_rescale = 1;
if ((max_w <= 0) || (max_h <= 0)) /* No valid dimensions, use original */
{
need_rescale = 0;
target_w = src->width;
target_h = src->height;
}
else if ((src->width <= max_w) && (src->height <= max_h)) /* Smaller than target */
{
need_rescale = 0;
target_w = src->width;
target_h = src->height;
}
else if (src->width * max_h > src->height * max_w) /* Wider aspect ratio than target */
{
target_w = max_w;
target_h = (double)max_w * ((double)src->height / (double)src->width);
}
else /* Taller or equal aspect ratio */
{
target_w = (double)max_h * ((double)src->width / (double)src->height);
target_h = max_h;
}
DPRINTF(E_DBG, L_ART, "Raw destination width %d height %d\n", target_w, target_h);
if ((target_h > max_h) && (max_h > 0))
target_h = max_h;
/* PNG prefers even row count */
target_w += target_w % 2;
if ((target_w > max_w) && (max_w > 0))
target_w = max_w - (max_w % 2);
DPRINTF(E_DBG, L_ART, "Destination width %d height %d\n", target_w, target_h);
ret = rescale_needed(src_ctx->streams[s]->codec, max_w, max_h, &target_w, &target_h);
/* Fastpath */
if (!need_rescale && format_ok)
if (!ret && format_ok)
{
ret = artwork_read(filename, evbuf);
if (ret == 0)
@@ -657,6 +666,115 @@ artwork_get(char *filename, int max_w, int max_h, int format, struct evbuffer *e
return ret;
}
#if LIBAVFORMAT_VERSION_MAJOR >= 55 || (LIBAVFORMAT_VERSION_MAJOR == 54 && LIBAVFORMAT_VERSION_MINOR >= 20)
static int
artwork_get_embedded_image(char *filename, int max_w, int max_h, int format, struct evbuffer *evbuf)
{
AVFormatContext *src_ctx;
AVStream *src_st;
int s;
int target_w;
int target_h;
int format_ok;
int ret;
/* If item is an internet stream don't look for artwork */
if (strncmp(filename, "http://", strlen("http://")) == 0)
return -1;
DPRINTF(E_SPAM, L_ART, "Trying embedded artwork in %s\n", filename);
src_ctx = NULL;
ret = avformat_open_input(&src_ctx, filename, NULL, NULL);
if (ret < 0)
{
DPRINTF(E_WARN, L_ART, "Cannot open media file '%s': %s\n", filename, strerror(AVUNERROR(ret)));
return -1;
}
ret = avformat_find_stream_info(src_ctx, NULL);
if (ret < 0)
{
DPRINTF(E_WARN, L_ART, "Cannot get stream info: %s\n", strerror(AVUNERROR(ret)));
avformat_close_input(&src_ctx);
return -1;
}
format_ok = 0;
for (s = 0; s < src_ctx->nb_streams; s++)
{
if (src_ctx->streams[s]->disposition & AV_DISPOSITION_ATTACHED_PIC)
{
if (src_ctx->streams[s]->codec->codec_id == CODEC_ID_PNG)
{
format_ok = (format & ART_CAN_PNG) ? ART_FMT_PNG : 0;
break;
}
else if (src_ctx->streams[s]->codec->codec_id == CODEC_ID_MJPEG)
{
format_ok = (format & ART_CAN_JPEG) ? ART_FMT_JPEG : 0;
break;
}
}
}
if (s == src_ctx->nb_streams)
{
DPRINTF(E_SPAM, L_ART, "Did not find embedded artwork in '%s'\n", filename);
avformat_close_input(&src_ctx);
return -1;
}
else
DPRINTF(E_DBG, L_ART, "Found embedded artwork in '%s'\n", filename);
src_st = src_ctx->streams[s];
ret = rescale_needed(src_st->codec, max_w, max_h, &target_w, &target_h);
/* Fastpath */
if (!ret && format_ok)
{
DPRINTF(E_DBG, L_ART, "Artwork not too large, using original image\n");
ret = evbuffer_expand(evbuf, src_st->attached_pic.size);
if (ret < 0)
{
DPRINTF(E_LOG, L_ART, "Out of memory for artwork\n");
avformat_close_input(&src_ctx);
return -1;
}
ret = evbuffer_add(evbuf, src_st->attached_pic.data, src_st->attached_pic.size);
if (ret < 0)
{
DPRINTF(E_LOG, L_ART, "Could not add embedded image to event buffer\n");
}
else
ret = format_ok;
}
else
{
DPRINTF(E_DBG, L_ART, "Artwork too large, rescaling image\n");
ret = artwork_rescale(src_ctx, s, target_w, target_h, format, evbuf);
}
avformat_close_input(&src_ctx);
if (ret < 0)
{
if (EVBUFFER_LENGTH(evbuf) > 0)
evbuffer_drain(evbuf, EVBUFFER_LENGTH(evbuf));
}
return ret;
}
#endif
static int
artwork_get_own_image(char *path, int max_w, int max_h, int format, struct evbuffer *evbuf)
@@ -667,6 +785,10 @@ artwork_get_own_image(char *path, int max_w, int max_h, int format, struct evbuf
int i;
int ret;
/* If item is an internet stream don't look for artwork */
if (strncmp(path, "http://", strlen("http://")) == 0)
return -1;
ret = snprintf(artwork, sizeof(artwork), "%s", path);
if ((ret < 0) || (ret >= sizeof(artwork)))
{
@@ -691,7 +813,7 @@ artwork_get_own_image(char *path, int max_w, int max_h, int format, struct evbuf
continue;
}
DPRINTF(E_DBG, L_ART, "Trying own artwork file %s\n", artwork);
DPRINTF(E_SPAM, L_ART, "Trying own artwork file %s\n", artwork);
ret = access(artwork, F_OK);
if (ret < 0)
@@ -703,6 +825,8 @@ artwork_get_own_image(char *path, int max_w, int max_h, int format, struct evbuf
if (i == (sizeof(cover_extension) / sizeof(cover_extension[0])))
return -1;
DPRINTF(E_DBG, L_ART, "Found own artwork file %s\n", artwork);
return artwork_get(artwork, max_w, max_h, format, evbuf);
}
@@ -718,6 +842,10 @@ artwork_get_dir_image(char *path, int isdir, int max_w, int max_h, int format, s
cfg_t *lib;
int nbasenames;
/* If item is an internet stream don't look for artwork */
if (strncmp(path, "http://", strlen("http://")) == 0)
return -1;
ret = snprintf(artwork, sizeof(artwork), "%s", path);
if ((ret < 0) || (ret >= sizeof(artwork)))
{
@@ -753,7 +881,7 @@ artwork_get_dir_image(char *path, int isdir, int max_w, int max_h, int format, s
continue;
}
DPRINTF(E_DBG, L_ART, "Trying directory artwork file %s\n", artwork);
DPRINTF(E_SPAM, L_ART, "Trying directory artwork file %s\n", artwork);
ret = access(artwork, F_OK);
if (ret < 0)
@@ -769,6 +897,8 @@ artwork_get_dir_image(char *path, int isdir, int max_w, int max_h, int format, s
if (i == nbasenames)
return -1;
DPRINTF(E_DBG, L_ART, "Found directory artwork file %s\n", artwork);
return artwork_get(artwork, max_w, max_h, format, evbuf);
}
@@ -782,6 +912,10 @@ artwork_get_parentdir_image(char *path, int isdir, int max_w, int max_h, int for
int i;
int ret;
/* If item is an internet stream don't look for artwork */
if (strncmp(path, "http://", strlen("http://")) == 0)
return -1;
ret = snprintf(artwork, sizeof(artwork), "%s", path);
if ((ret < 0) || (ret >= sizeof(artwork)))
{
@@ -814,7 +948,7 @@ artwork_get_parentdir_image(char *path, int isdir, int max_w, int max_h, int for
continue;
}
DPRINTF(E_DBG, L_ART, "Trying parent directory artwork file %s\n", artwork);
DPRINTF(E_SPAM, L_ART, "Trying parent directory artwork file %s\n", artwork);
ret = access(artwork, F_OK);
if (ret < 0)
@@ -826,6 +960,8 @@ artwork_get_parentdir_image(char *path, int isdir, int max_w, int max_h, int for
if (i == (sizeof(cover_extension) / sizeof(cover_extension[0])))
return -1;
DPRINTF(E_DBG, L_ART, "Found parent directory artwork file %s\n", artwork);
return artwork_get(artwork, max_w, max_h, format, evbuf);
}
@@ -836,7 +972,12 @@ artwork_get_item_filename(char *filename, int max_w, int max_h, int format, stru
{
int ret;
/* FUTURE: look at embedded artwork */
#if LIBAVFORMAT_VERSION_MAJOR >= 55 || (LIBAVFORMAT_VERSION_MAJOR == 54 && LIBAVFORMAT_VERSION_MINOR >= 20)
/* Look for embedded artwork */
ret = artwork_get_embedded_image(filename, max_w, max_h, format, evbuf);
if (ret > 0)
return ret;
#endif
/* Look for basename(filename).{png,jpg} */
ret = artwork_get_own_image(filename, max_w, max_h, format, evbuf);
@@ -903,12 +1044,11 @@ artwork_get_group(int id, int max_w, int max_h, int format, struct evbuffer *evb
goto files_art;
}
got_art = -1;
while ((got_art < 0) && ((ret = db_query_fetch_string(&qp, &dir)) == 0) && (dir))
got_art = 0;
while (!got_art && ((ret = db_query_fetch_string(&qp, &dir)) == 0) && (dir))
{
got_art = artwork_get_dir_image(dir, 1, max_w, max_h, format, evbuf);
if (got_art < 0)
got_art = artwork_get_parentdir_image(dir, 1, max_w, max_h, format, evbuf);
got_art = (artwork_get_dir_image(dir, 1, max_w, max_h, format, evbuf) > 0)
|| (artwork_get_parentdir_image(dir, 1, max_w, max_h, format, evbuf) > 0);
}
db_query_end(&qp);
@@ -934,10 +1074,15 @@ artwork_get_group(int id, int max_w, int max_h, int format, struct evbuffer *evb
return -1;
}
got_art = -1;
while ((got_art < 0) && ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id))
got_art = 0;
while (!got_art && ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id))
{
got_art = artwork_get_own_image(dbmfi.path, max_w, max_h, format, evbuf);
#if LIBAVFORMAT_VERSION_MAJOR >= 55 || (LIBAVFORMAT_VERSION_MAJOR == 54 && LIBAVFORMAT_VERSION_MINOR >= 20)
got_art = (artwork_get_embedded_image(dbmfi.path, max_w, max_h, format, evbuf) > 0)
|| (artwork_get_own_image(dbmfi.path, max_w, max_h, format, evbuf) > 0);
#else
got_art = (artwork_get_own_image(dbmfi.path, max_w, max_h, format, evbuf) > 0);
#endif
}
db_query_end(&qp);
@@ -947,5 +1092,7 @@ artwork_get_group(int id, int max_w, int max_h, int format, struct evbuffer *evb
else if (got_art > 0)
return got_art;
DPRINTF(E_DBG, L_ART, "No artwork found for group %d\n", id);
return -1;
}

View File

@@ -384,6 +384,14 @@ scan_metadata_ffmpeg(char *file, struct media_file_info *mfi)
case AVMEDIA_TYPE_VIDEO:
#else
case CODEC_TYPE_VIDEO:
#endif
#if LIBAVFORMAT_VERSION_MAJOR >= 55 || (LIBAVFORMAT_VERSION_MAJOR == 54 && LIBAVFORMAT_VERSION_MINOR >= 20)
if (ctx->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC)
{
DPRINTF(E_DBG, L_SCAN, "Found embedded artwork (stream %d)\n", i);
break;
}
#endif
if (!video_stream)
{

View File

@@ -851,7 +851,7 @@ raop_metadata_prepare(int id, uint64_t rtptime)
ret = artwork_get_item_filename(dbmfi.path, 600, 600, ART_CAN_PNG | ART_CAN_JPEG, rmd->artwork);
if (ret < 0)
{
DPRINTF(E_LOG, L_RAOP, "Failed to retrieve artwork for '%s' (%d); no artwork will be sent\n", dbmfi.title, id);
DPRINTF(E_INFO, L_RAOP, "Failed to retrieve artwork for '%s' (%d); no artwork will be sent\n", dbmfi.title, id);
evbuffer_free(rmd->artwork);
rmd->artwork = NULL;

View File

@@ -44,6 +44,10 @@
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/mathematics.h>
#if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35)
# include <libavutil/opt.h>
# include <libavresample/avresample.h>
#endif
#include "logger.h"
#include "conffile.h"
@@ -65,9 +69,13 @@ struct transcode_ctx {
int16_t *abuffer;
/* Resampling */
int need_resample;
int input_size;
#if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35)
AVAudioResampleContext *resample_ctx;
#else
ReSampleContext *resample_ctx;
int input_size;
#endif
int need_resample;
int16_t *re_abuffer;
off_t offset;
@@ -147,9 +155,15 @@ transcode(struct transcode_ctx *ctx, struct evbuffer *evbuf, int wanted)
#if BYTE_ORDER == BIG_ENDIAN
int i;
#endif
#if LIBAVCODEC_VERSION_MAJOR >= 54 || (LIBAVCODEC_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR >= 35)
AVFrame frame;
int got_frame = 0;
#if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35)
AVFrame *frame = NULL;
int got_frame;
int out_size;
int out_linesize;
int out_samples;
#elif LIBAVCODEC_VERSION_MAJOR >= 54 || (LIBAVCODEC_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR >= 35)
AVFrame *frame = NULL;
int got_frame;
#endif
processed = 0;
@@ -167,19 +181,29 @@ transcode(struct transcode_ctx *ctx, struct evbuffer *evbuf, int wanted)
/* Decode data */
while (ctx->apacket2.size > 0)
{
buflen = XCODE_BUFFER_SIZE;
#if LIBAVCODEC_VERSION_MAJOR >= 54 || (LIBAVCODEC_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR >= 35)
if (ctx->acodec->get_buffer != avcodec_default_get_buffer)
{
DPRINTF(E_WARN, L_XCODE, "Custom get_buffer, not allowed by ffmpeg/libav. Setting to default.\n");
got_frame = 0;
ctx->acodec->get_buffer = avcodec_default_get_buffer;
if (!frame)
{
frame = avcodec_alloc_frame();
if (!frame)
{
DPRINTF(E_LOG, L_XCODE, "Out of memory for decoded frame\n");
return -1;
}
}
else
avcodec_get_frame_defaults(frame);
used = avcodec_decode_audio4(ctx->acodec,
&frame, &got_frame,
frame, &got_frame,
&ctx->apacket2);
#else
buflen = XCODE_BUFFER_SIZE;
used = avcodec_decode_audio3(ctx->acodec,
ctx->abuffer, &buflen,
&ctx->apacket2);
@@ -195,14 +219,20 @@ transcode(struct transcode_ctx *ctx, struct evbuffer *evbuf, int wanted)
ctx->apacket2.data += used;
ctx->apacket2.size -= used;
#if LIBAVCODEC_VERSION_MAJOR >= 54 || (LIBAVCODEC_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR >= 35)
/* This part is from the libav wrapper for avcodec_decode_audio3 - it may be useless in this context */
if (got_frame != 0)
/* No frame decoded this time around */
#if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35)
if (!got_frame)
continue;
#elif LIBAVCODEC_VERSION_MAJOR >= 54 || (LIBAVCODEC_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR >= 35)
if (!got_frame)
continue;
else
{
/* This part is from the libav wrapper for avcodec_decode_audio3 */
int ch, plane_size;
int planar = av_sample_fmt_is_planar(ctx->acodec->sample_fmt);
int data_size = av_samples_get_buffer_size(&plane_size, ctx->acodec->channels,
frame.nb_samples, ctx->acodec->sample_fmt, 1);
frame->nb_samples, ctx->acodec->sample_fmt, 1);
if (XCODE_BUFFER_SIZE < data_size)
{
@@ -211,28 +241,54 @@ transcode(struct transcode_ctx *ctx, struct evbuffer *evbuf, int wanted)
continue;
}
memcpy(ctx->abuffer, frame.extended_data[0], plane_size);
memcpy(ctx->abuffer, frame->extended_data[0], plane_size);
if (planar && ctx->acodec->channels > 1)
{
uint8_t *out = ((uint8_t *)ctx->abuffer) + plane_size;
for (ch = 1; ch < ctx->acodec->channels; ch++)
{
memcpy(out, frame.extended_data[ch], plane_size);
memcpy(out, frame->extended_data[ch], plane_size);
out += plane_size;
}
}
buflen = data_size;
}
else
continue;
#else
/* No frame decoded this time around */
if (buflen == 0)
continue;
#endif
if (ctx->need_resample)
#if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35)
{
out_size = av_samples_get_buffer_size(&out_linesize, 2, frame->nb_samples, AV_SAMPLE_FMT_S16, 0);
buf = av_realloc(ctx->re_abuffer, out_size);
if (!buf)
{
DPRINTF(E_LOG, L_XCODE, "Out of memory for resample buffer!\n");
return -1;
}
out_samples = avresample_convert(ctx->resample_ctx, (uint8_t **)&buf, out_linesize, frame->nb_samples,
(uint8_t **)frame->data, frame->linesize[0], frame->nb_samples);
if (out_samples < 0)
{
DPRINTF(E_LOG, L_XCODE, "Resample returned no samples!\n");
return -1;
}
buflen = out_samples * 2 * 2; /* 16bit samples, 2 channels */
}
else
{
buf = (int16_t *)frame->data[0];
buflen = av_samples_get_buffer_size(NULL, ctx->acodec->channels, frame->nb_samples, ctx->acodec->sample_fmt, 1);
}
#else
{
buflen = audio_resample(ctx->resample_ctx, ctx->re_abuffer, ctx->abuffer, buflen / ctx->input_size);
@@ -247,6 +303,7 @@ transcode(struct transcode_ctx *ctx, struct evbuffer *evbuf, int wanted)
}
else
buf = ctx->abuffer;
#endif
#if BYTE_ORDER == BIG_ENDIAN
/* swap buffer, LE16 */
@@ -290,6 +347,14 @@ transcode(struct transcode_ctx *ctx, struct evbuffer *evbuf, int wanted)
ctx->offset += processed;
#if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35)
if (frame)
avcodec_free_frame(&frame);
#elif LIBAVCODEC_VERSION_MAJOR >= 54 || (LIBAVCODEC_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR >= 35)
if (frame)
av_free(frame);
#endif
return processed;
}
@@ -385,7 +450,6 @@ struct transcode_ctx *
transcode_setup(struct media_file_info *mfi, off_t *est_size, int wavhdr)
{
struct transcode_ctx *ctx;
int i;
int ret;
ctx = (struct transcode_ctx *)malloc(sizeof(struct transcode_ctx));
@@ -422,14 +486,21 @@ transcode_setup(struct media_file_info *mfi, off_t *est_size, int wavhdr)
goto setup_fail;
}
#if LIBAVCODEC_VERSION_MAJOR >= 53 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR >= 64)
ctx->astream = av_find_best_stream(ctx->fmtctx, AVMEDIA_TYPE_AUDIO, -1, -1, &ctx->adecoder, 0);
if (ctx->astream < 0)
{
DPRINTF(E_WARN, L_XCODE, "Did not find audio stream or suitable decoder for %s\n", mfi->fname);
goto setup_fail;
}
#else
int i;
ctx->astream = -1;
for (i = 0; i < ctx->fmtctx->nb_streams; i++)
{
#if LIBAVCODEC_VERSION_MAJOR >= 53 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR >= 64)
if (ctx->fmtctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
#else
if (ctx->fmtctx->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO)
#endif
{
ctx->astream = i;
@@ -444,20 +515,23 @@ transcode_setup(struct media_file_info *mfi, off_t *est_size, int wavhdr)
goto setup_fail;
}
ctx->acodec = ctx->fmtctx->streams[ctx->astream]->codec;
ctx->adecoder = avcodec_find_decoder(ctx->acodec->codec_id);
ctx->adecoder = avcodec_find_decoder(ctx->fmtctx->streams[ctx->astream]->codec->codec_id);
if (!ctx->adecoder)
{
DPRINTF(E_WARN, L_XCODE, "No suitable decoder found for codec\n");
goto setup_fail;
}
#endif
ctx->acodec = ctx->fmtctx->streams[ctx->astream]->codec;
if (ctx->adecoder->capabilities & CODEC_CAP_TRUNCATED)
ctx->acodec->flags |= CODEC_FLAG_TRUNCATED;
#if LIBAVCODEC_VERSION_MAJOR >= 54 || (LIBAVCODEC_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR >= 6)
ctx->acodec->request_sample_fmt = AV_SAMPLE_FMT_S16;
ctx->acodec->request_channel_layout = AV_CH_LAYOUT_STEREO;
ret = avcodec_open2(ctx->acodec, ctx->adecoder, NULL);
#else
ret = avcodec_open(ctx->acodec, ctx->adecoder);
@@ -477,10 +551,48 @@ transcode_setup(struct media_file_info *mfi, off_t *est_size, int wavhdr)
goto setup_fail_codec;
}
if ((ctx->acodec->sample_fmt != AV_SAMPLE_FMT_S16)
|| (ctx->acodec->channels != 2)
|| (ctx->acodec->sample_rate != 44100))
ctx->need_resample = (ctx->acodec->sample_fmt != AV_SAMPLE_FMT_S16)
|| (ctx->acodec->channels != 2)
|| (ctx->acodec->sample_rate != 44100);
if (ctx->need_resample)
{
#if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35)
if (!ctx->acodec->channel_layout)
{
DPRINTF(E_DBG, L_XCODE, "Resample requires channel_layout, but none from ffmpeg. Setting to default.\n");
ctx->acodec->channel_layout = av_get_default_channel_layout(ctx->acodec->channels);
}
DPRINTF(E_DBG, L_XCODE, "Will resample, decoded stream is: %s, %d channels (layout %" PRIu64 "), %d Hz\n",
av_get_sample_fmt_name(ctx->acodec->sample_fmt), ctx->acodec->channels,
ctx->acodec->channel_layout, ctx->acodec->sample_rate);
ctx->resample_ctx = avresample_alloc_context();
if (!ctx->resample_ctx)
{
DPRINTF(E_LOG, L_XCODE, "Out of memory for resample context\n");
goto setup_fail_codec;
}
av_opt_set_int(ctx->resample_ctx, "in_sample_fmt", ctx->acodec->sample_fmt, 0);
av_opt_set_int(ctx->resample_ctx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
av_opt_set_int(ctx->resample_ctx, "in_channel_layout", ctx->acodec->channel_layout, 0);
av_opt_set_int(ctx->resample_ctx, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);
av_opt_set_int(ctx->resample_ctx, "in_sample_rate", ctx->acodec->sample_rate, 0);
av_opt_set_int(ctx->resample_ctx, "out_sample_rate", 44100, 0);
ret = avresample_open(ctx->resample_ctx);
if (ret < 0)
{
DPRINTF(E_LOG, L_XCODE, "Could not open resample context\n");
avresample_free(&ctx->resample_ctx);
goto setup_fail_codec;
}
#else
DPRINTF(E_DBG, L_XCODE, "Setting up resampling (%d@%d)\n", ctx->acodec->channels, ctx->acodec->sample_rate);
ctx->resample_ctx = av_audio_resample_init(2, ctx->acodec->channels,
@@ -503,9 +615,11 @@ transcode_setup(struct media_file_info *mfi, off_t *est_size, int wavhdr)
audio_resample_close(ctx->resample_ctx);
goto setup_fail_codec;
}
#endif
ctx->need_resample = 1;
#if LIBAVUTIL_VERSION_MAJOR >= 52 || (LIBAVUTIL_VERSION_MAJOR == 51 && LIBAVUTIL_VERSION_MINOR >= 4)
#if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35)
#elif LIBAVUTIL_VERSION_MAJOR >= 52 || (LIBAVUTIL_VERSION_MAJOR == 51 && LIBAVUTIL_VERSION_MINOR >= 4)
ctx->input_size = ctx->acodec->channels * av_get_bytes_per_sample(ctx->acodec->sample_fmt);
#elif LIBAVCODEC_VERSION_MAJOR >= 53
ctx->input_size = ctx->acodec->channels * av_get_bits_per_sample_fmt(ctx->acodec->sample_fmt) / 8;
@@ -554,7 +668,11 @@ transcode_cleanup(struct transcode_ctx *ctx)
if (ctx->need_resample)
{
#if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35)
avresample_free(&ctx->resample_ctx);
#else
audio_resample_close(ctx->resample_ctx);
#endif
av_free(ctx->re_abuffer);
}