From 53780a7ef34122528ce3e1fd2ecdc154971eb23e Mon Sep 17 00:00:00 2001 From: ejurgensen Date: Tue, 2 Apr 2019 22:47:11 +0200 Subject: [PATCH] [xcode] Make sample rate + channels variable This change is preparation to use ffmpeg's resampling capabilities to keep local audio in sync (by up/downsampling slightly). This requires that sample rates are not fixed for a transcode profile. Added benefit of this is that we don't need quite as many xcode profiles. --- src/artwork.c | 6 +- src/httpd.c | 8 +- src/httpd_streaming.c | 24 +++--- src/inputs/file_http.c | 2 +- src/misc.h | 4 +- src/outputs.c | 30 +++---- src/outputs/cast.c | 6 +- src/transcode.c | 175 +++++++++++++++-------------------------- src/transcode.h | 32 +++----- 9 files changed, 114 insertions(+), 173 deletions(-) diff --git a/src/artwork.c b/src/artwork.c index e0858d30..fe1267e5 100644 --- a/src/artwork.c +++ b/src/artwork.c @@ -408,7 +408,7 @@ artwork_get(struct evbuffer *evbuf, char *path, struct evbuffer *inbuf, int max_ DPRINTF(E_SPAM, L_ART, "Getting artwork (max destination width %d height %d)\n", max_w, max_h); - xcode_decode = transcode_decode_setup(XCODE_JPEG, DATA_KIND_FILE, path, inbuf, 0); // Covers XCODE_PNG too + xcode_decode = transcode_decode_setup(XCODE_JPEG, NULL, DATA_KIND_FILE, path, inbuf, 0); // Covers XCODE_PNG too if (!xcode_decode) { if (path) @@ -462,9 +462,9 @@ artwork_get(struct evbuffer *evbuf, char *path, struct evbuffer *inbuf, int max_ } if (format_ok == ART_FMT_JPEG) - xcode_encode = transcode_encode_setup(XCODE_JPEG, xcode_decode, NULL, target_w, target_h); + xcode_encode = transcode_encode_setup(XCODE_JPEG, NULL, xcode_decode, NULL, target_w, target_h); else - xcode_encode = transcode_encode_setup(XCODE_PNG, xcode_decode, NULL, target_w, target_h); + xcode_encode = transcode_encode_setup(XCODE_PNG, NULL, xcode_decode, NULL, target_w, target_h); if (!xcode_encode) { diff --git a/src/httpd.c b/src/httpd.c index 5a9fe26d..fbc73443 100644 --- a/src/httpd.c +++ b/src/httpd.c @@ -80,6 +80,11 @@ "

%s

\n" \ "\n\n" +#define HTTPD_STREAM_SAMPLE_RATE 44100 +#define HTTPD_STREAM_BPS 16 +#define HTTPD_STREAM_CHANNELS 2 + + struct content_type_map { char *ext; char *ctype; @@ -1029,6 +1034,7 @@ httpd_request_parse(struct evhttp_request *req, struct httpd_uri_parsed *uri_par void httpd_stream_file(struct evhttp_request *req, int id) { + struct media_quality quality = { HTTPD_STREAM_SAMPLE_RATE, HTTPD_STREAM_BPS, HTTPD_STREAM_CHANNELS }; struct media_file_info *mfi; struct stream_ctx *st; void (*stream_cb)(int fd, short event, void *arg); @@ -1128,7 +1134,7 @@ httpd_stream_file(struct evhttp_request *req, int id) stream_cb = stream_chunk_xcode_cb; - st->xcode = transcode_setup(XCODE_PCM16_HEADER, mfi->data_kind, mfi->path, mfi->song_length, &st->size); + st->xcode = transcode_setup(XCODE_PCM16_HEADER, &quality, mfi->data_kind, mfi->path, mfi->song_length, &st->size); if (!st->xcode) { DPRINTF(E_WARN, L_HTTPD, "Transcoding setup failed, aborting streaming\n"); diff --git a/src/httpd_streaming.c b/src/httpd_streaming.c index c26b6dde..0e7980e8 100644 --- a/src/httpd_streaming.c +++ b/src/httpd_streaming.c @@ -47,6 +47,11 @@ extern struct event_base *evbase_httpd; // How many bytes we try to read at a time from the httpd pipe #define STREAMING_READ_SIZE STOB(352, 16, 2) +#define STREAMING_MP3_SAMPLE_RATE 44100 +#define STREAMING_MP3_BPS 16 +#define STREAMING_MP3_CHANNELS 2 + + // Linked list of mp3 streaming requests struct streaming_session { struct evhttp_request *req; @@ -140,6 +145,7 @@ streaming_end(void) static void streaming_meta_cb(evutil_socket_t fd, short event, void *arg) { + struct media_quality mp3_quality = { STREAMING_MP3_SAMPLE_RATE, STREAMING_MP3_BPS, STREAMING_MP3_CHANNELS }; struct media_quality quality; struct decode_ctx *decode_ctx; int ret; @@ -151,19 +157,17 @@ streaming_meta_cb(evutil_socket_t fd, short event, void *arg) goto error; decode_ctx = NULL; - if (quality.sample_rate == 44100 && quality.bits_per_sample == 16) - decode_ctx = transcode_decode_setup_raw(XCODE_PCM16_44100); - else if (quality.sample_rate == 44100 && quality.bits_per_sample == 24) - decode_ctx = transcode_decode_setup_raw(XCODE_PCM24_44100); - else if (quality.sample_rate == 48000 && quality.bits_per_sample == 16) - decode_ctx = transcode_decode_setup_raw(XCODE_PCM16_48000); - else if (quality.sample_rate == 48000 && quality.bits_per_sample == 24) - decode_ctx = transcode_decode_setup_raw(XCODE_PCM24_48000); + if (quality.bits_per_sample == 16) + decode_ctx = transcode_decode_setup_raw(XCODE_PCM16, &quality); + else if (quality.bits_per_sample == 24) + decode_ctx = transcode_decode_setup_raw(XCODE_PCM24, &quality); + else if (quality.bits_per_sample == 32) + decode_ctx = transcode_decode_setup_raw(XCODE_PCM32, &quality); if (!decode_ctx) goto error; - streaming_encode_ctx = transcode_encode_setup(XCODE_MP3, decode_ctx, NULL, 0, 0); + streaming_encode_ctx = transcode_encode_setup(XCODE_MP3, &mp3_quality, decode_ctx, NULL, 0, 0); transcode_decode_cleanup(&decode_ctx); if (!streaming_encode_ctx) { @@ -198,7 +202,7 @@ encode_buffer(uint8_t *buffer, size_t size) samples = BTOS(size, streaming_quality.bits_per_sample, streaming_quality.channels); - frame = transcode_frame_new(buffer, size, samples, streaming_quality.sample_rate, streaming_quality.bits_per_sample); + frame = transcode_frame_new(buffer, size, samples, &streaming_quality); if (!frame) { DPRINTF(E_LOG, L_STREAMING, "Could not convert raw PCM to frame\n"); diff --git a/src/inputs/file_http.c b/src/inputs/file_http.c index 3d8a35c3..6864e103 100644 --- a/src/inputs/file_http.c +++ b/src/inputs/file_http.c @@ -34,7 +34,7 @@ setup(struct input_source *source) { struct transcode_ctx *ctx; - ctx = transcode_setup(XCODE_PCM_NATIVE, source->data_kind, source->path, source->len_ms, NULL); + ctx = transcode_setup(XCODE_PCM_NATIVE, NULL, source->data_kind, source->path, source->len_ms, NULL); if (!ctx) return -1; diff --git a/src/misc.h b/src/misc.h index 8d95b17c..220d6906 100644 --- a/src/misc.h +++ b/src/misc.h @@ -18,11 +18,11 @@ #define ARRAY_SIZE(x) ((unsigned int)(sizeof(x) / sizeof((x)[0]))) #ifndef MIN -# define MIN(a, b) ((a < b) ? a : b) +# define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif #ifndef MAX -#define MAX(a, b) ((a > b) ? a : b) +# define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif diff --git a/src/outputs.c b/src/outputs.c index fcfcac4c..1fa99109 100644 --- a/src/outputs.c +++ b/src/outputs.c @@ -250,24 +250,12 @@ device_stop_cb(struct output_device *device, enum output_device_state status) static enum transcode_profile quality_to_xcode(struct media_quality *quality) { - if (quality->sample_rate == 44100 && quality->bits_per_sample == 16) - return XCODE_PCM16_44100; - if (quality->sample_rate == 44100 && quality->bits_per_sample == 24) - return XCODE_PCM24_44100; - if (quality->sample_rate == 44100 && quality->bits_per_sample == 32) - return XCODE_PCM32_44100; - if (quality->sample_rate == 48000 && quality->bits_per_sample == 16) - return XCODE_PCM16_48000; - if (quality->sample_rate == 48000 && quality->bits_per_sample == 24) - return XCODE_PCM24_48000; - if (quality->sample_rate == 48000 && quality->bits_per_sample == 32) - return XCODE_PCM32_48000; - if (quality->sample_rate == 96000 && quality->bits_per_sample == 16) - return XCODE_PCM16_96000; - if (quality->sample_rate == 96000 && quality->bits_per_sample == 24) - return XCODE_PCM24_96000; - if (quality->sample_rate == 96000 && quality->bits_per_sample == 32) - return XCODE_PCM32_96000; + if (quality->bits_per_sample == 16) + return XCODE_PCM16; + if (quality->bits_per_sample == 24) + return XCODE_PCM24; + if (quality->bits_per_sample == 32) + return XCODE_PCM32; return XCODE_UNKNOWN; } @@ -288,7 +276,7 @@ encoding_reset(struct media_quality *quality) return -1; } - decode_ctx = transcode_decode_setup_raw(profile); + decode_ctx = transcode_decode_setup_raw(profile, quality); if (!decode_ctx) { DPRINTF(E_LOG, L_PLAYER, "Could not create subscription decoding context (profile %d)\n", profile); @@ -306,7 +294,7 @@ encoding_reset(struct media_quality *quality) profile = quality_to_xcode(&subscription->quality); if (profile != XCODE_UNKNOWN) - subscription->encode_ctx = transcode_encode_setup(profile, decode_ctx, NULL, 0, 0); + subscription->encode_ctx = transcode_encode_setup(profile, &subscription->quality, decode_ctx, NULL, 0, 0); else DPRINTF(E_LOG, L_PLAYER, "Could not setup resampling to %d/%d/%d for output\n", subscription->quality.sample_rate, subscription->quality.bits_per_sample, subscription->quality.channels); @@ -354,7 +342,7 @@ buffer_fill(struct output_buffer *obuf, void *buf, size_t bufsize, struct media_ if (!output_quality_subscriptions[i].encode_ctx) continue; - frame = transcode_frame_new(buf, bufsize, nsamples, quality->sample_rate, quality->bits_per_sample); + frame = transcode_frame_new(buf, bufsize, nsamples, quality); if (!frame) continue; diff --git a/src/outputs/cast.c b/src/outputs/cast.c index 48def1ea..e9355bcf 100644 --- a/src/outputs/cast.c +++ b/src/outputs/cast.c @@ -1842,7 +1842,7 @@ payload_encode(struct evbuffer *evbuf, uint8_t *rawbuf, size_t rawbuf_size, int transcode_frame *frame; int len; - frame = transcode_frame_new(rawbuf, rawbuf_size, nsamples, quality->sample_rate, quality->bits_per_sample); + frame = transcode_frame_new(rawbuf, rawbuf_size, nsamples, quality); if (!frame) { DPRINTF(E_LOG, L_CAST, "Could not convert raw PCM to frame (bufsize=%zu)\n", rawbuf_size); @@ -2204,14 +2204,14 @@ cast_init(void) return -1; } - decode_ctx = transcode_decode_setup_raw(XCODE_PCM16_48000); + decode_ctx = transcode_decode_setup_raw(XCODE_PCM16, &cast_quality_default); if (!decode_ctx) { DPRINTF(E_LOG, L_CAST, "Could not create decoding context\n"); goto out_tls_deinit; } - cast_encode_ctx = transcode_encode_setup(XCODE_OPUS, decode_ctx, NULL, 0, 0); + cast_encode_ctx = transcode_encode_setup(XCODE_OPUS, &cast_quality_default, decode_ctx, NULL, 0, 0); transcode_decode_cleanup(&decode_ctx); if (!cast_encode_ctx) { diff --git a/src/transcode.c b/src/transcode.c index 80bf619e..e4170e0e 100644 --- a/src/transcode.c +++ b/src/transcode.c @@ -181,7 +181,7 @@ struct encode_ctx /* -------------------------- PROFILE CONFIGURATION ------------------------ */ static int -init_settings(struct settings_ctx *settings, enum transcode_profile profile) +init_settings(struct settings_ctx *settings, enum transcode_profile profile, struct media_quality *quality) { memset(settings, 0, sizeof(struct settings_ctx)); @@ -189,100 +189,29 @@ init_settings(struct settings_ctx *settings, enum transcode_profile profile) { case XCODE_PCM_NATIVE: // Sample rate and bit depth determined by source settings->encode_audio = 1; - settings->channel_layout = AV_CH_LAYOUT_STEREO; - settings->channels = 2; settings->icy = 1; break; case XCODE_PCM16_HEADER: settings->wavheader = 1; - case XCODE_PCM16_44100: + case XCODE_PCM16: settings->encode_audio = 1; settings->format = "s16le"; settings->audio_codec = AV_CODEC_ID_PCM_S16LE; - settings->sample_rate = 44100; - settings->channel_layout = AV_CH_LAYOUT_STEREO; - settings->channels = 2; settings->sample_format = AV_SAMPLE_FMT_S16; break; - case XCODE_PCM16_48000: - settings->encode_audio = 1; - settings->format = "s16le"; - settings->audio_codec = AV_CODEC_ID_PCM_S16LE; - settings->sample_rate = 48000; - settings->channel_layout = AV_CH_LAYOUT_STEREO; - settings->channels = 2; - settings->sample_format = AV_SAMPLE_FMT_S16; - break; - - case XCODE_PCM16_96000: - settings->encode_audio = 1; - settings->format = "s16le"; - settings->audio_codec = AV_CODEC_ID_PCM_S16LE; - settings->sample_rate = 96000; - settings->channel_layout = AV_CH_LAYOUT_STEREO; - settings->channels = 2; - settings->sample_format = AV_SAMPLE_FMT_S16; - break; - - case XCODE_PCM24_44100: + case XCODE_PCM24: settings->encode_audio = 1; settings->format = "s24le"; settings->audio_codec = AV_CODEC_ID_PCM_S24LE; - settings->sample_rate = 44100; - settings->channel_layout = AV_CH_LAYOUT_STEREO; - settings->channels = 2; settings->sample_format = AV_SAMPLE_FMT_S32; break; - case XCODE_PCM24_48000: - settings->encode_audio = 1; - settings->format = "s24le"; - settings->audio_codec = AV_CODEC_ID_PCM_S24LE; - settings->sample_rate = 48000; - settings->channel_layout = AV_CH_LAYOUT_STEREO; - settings->channels = 2; - settings->sample_format = AV_SAMPLE_FMT_S32; - break; - - case XCODE_PCM24_96000: - settings->encode_audio = 1; - settings->format = "s24le"; - settings->audio_codec = AV_CODEC_ID_PCM_S24LE; - settings->sample_rate = 96000; - settings->channel_layout = AV_CH_LAYOUT_STEREO; - settings->channels = 2; - settings->sample_format = AV_SAMPLE_FMT_S32; - break; - - case XCODE_PCM32_44100: + case XCODE_PCM32: settings->encode_audio = 1; settings->format = "s32le"; settings->audio_codec = AV_CODEC_ID_PCM_S32LE; - settings->sample_rate = 44100; - settings->channel_layout = AV_CH_LAYOUT_STEREO; - settings->channels = 2; - settings->sample_format = AV_SAMPLE_FMT_S32; - break; - - case XCODE_PCM32_48000: - settings->encode_audio = 1; - settings->format = "s32le"; - settings->audio_codec = AV_CODEC_ID_PCM_S32LE; - settings->sample_rate = 48000; - settings->channel_layout = AV_CH_LAYOUT_STEREO; - settings->channels = 2; - settings->sample_format = AV_SAMPLE_FMT_S32; - break; - - case XCODE_PCM32_96000: - settings->encode_audio = 1; - settings->format = "s32le"; - settings->audio_codec = AV_CODEC_ID_PCM_S32LE; - settings->sample_rate = 96000; - settings->channel_layout = AV_CH_LAYOUT_STEREO; - settings->channels = 2; settings->sample_format = AV_SAMPLE_FMT_S32; break; @@ -290,9 +219,6 @@ init_settings(struct settings_ctx *settings, enum transcode_profile profile) settings->encode_audio = 1; settings->format = "mp3"; settings->audio_codec = AV_CODEC_ID_MP3; - settings->sample_rate = 44100; - settings->channel_layout = AV_CH_LAYOUT_STEREO; - settings->channels = 2; settings->sample_format = AV_SAMPLE_FMT_S16P; break; @@ -300,9 +226,6 @@ init_settings(struct settings_ctx *settings, enum transcode_profile profile) settings->encode_audio = 1; settings->format = "data"; // Means we get the raw packet from the encoder, no muxing settings->audio_codec = AV_CODEC_ID_OPUS; - settings->sample_rate = 48000; - settings->channel_layout = AV_CH_LAYOUT_STEREO; - settings->channels = 2; settings->sample_format = AV_SAMPLE_FMT_S16; // Only libopus support break; @@ -326,6 +249,23 @@ init_settings(struct settings_ctx *settings, enum transcode_profile profile) return -1; } + if (quality && quality->sample_rate) + { + settings->sample_rate = quality->sample_rate; + } + + if (quality && quality->channels) + { + settings->channels = quality->channels; + settings->channel_layout = av_get_default_channel_layout(quality->channels); + } + + if (quality && quality->bits_per_sample && (quality->bits_per_sample != 8 * av_get_bytes_per_sample(settings->sample_format))) + { + DPRINTF(E_LOG, L_XCODE, "Bug! Mismatch between profile and media quality\n"); + return -1; + } + return 0; } @@ -352,6 +292,19 @@ stream_settings_set(struct stream_ctx *s, struct settings_ctx *settings, enum AV /* -------------------------------- HELPERS -------------------------------- */ +static enum AVSampleFormat +bitdepth2format(int bits_per_sample) +{ + if (bits_per_sample == 16) + return AV_SAMPLE_FMT_S16; + else if (bits_per_sample == 24) + return AV_SAMPLE_FMT_S32; + else if (bits_per_sample == 32) + return AV_SAMPLE_FMT_S32; + else + return AV_SAMPLE_FMT_NONE; +} + static inline char * err2str(int errnum) { @@ -1209,7 +1162,7 @@ close_filters(struct encode_ctx *ctx) /* Setup */ struct decode_ctx * -transcode_decode_setup(enum transcode_profile profile, enum data_kind data_kind, const char *path, struct evbuffer *evbuf, uint32_t song_length) +transcode_decode_setup(enum transcode_profile profile, struct media_quality *quality, enum data_kind data_kind, const char *path, struct evbuffer *evbuf, uint32_t song_length) { struct decode_ctx *ctx; @@ -1220,7 +1173,7 @@ transcode_decode_setup(enum transcode_profile profile, enum data_kind data_kind, ctx->duration = song_length; ctx->data_kind = data_kind; - if ((init_settings(&ctx->settings, profile) < 0) || (open_input(ctx, path, evbuf) < 0)) + if ((init_settings(&ctx->settings, profile, quality) < 0) || (open_input(ctx, path, evbuf) < 0)) goto fail_free; return ctx; @@ -1233,7 +1186,7 @@ transcode_decode_setup(enum transcode_profile profile, enum data_kind data_kind, } struct encode_ctx * -transcode_encode_setup(enum transcode_profile profile, struct decode_ctx *src_ctx, off_t *est_size, int width, int height) +transcode_encode_setup(enum transcode_profile profile, struct media_quality *quality, struct decode_ctx *src_ctx, off_t *est_size, int width, int height) { struct encode_ctx *ctx; int bps; @@ -1242,17 +1195,19 @@ transcode_encode_setup(enum transcode_profile profile, struct decode_ctx *src_ct CHECK_NULL(L_XCODE, ctx->filt_frame = av_frame_alloc()); CHECK_NULL(L_XCODE, ctx->encoded_pkt = av_packet_alloc()); - if (init_settings(&ctx->settings, profile) < 0) + if (init_settings(&ctx->settings, profile, quality) < 0) goto fail_free; ctx->settings.width = width; ctx->settings.height = height; - // Profile does not specify a sample rate -> use same as source + // Caller did not specify a sample rate -> use same as source if (!ctx->settings.sample_rate && ctx->settings.encode_audio) - ctx->settings.sample_rate = src_ctx->audio_stream.codec->sample_rate; + { + ctx->settings.sample_rate = src_ctx->audio_stream.codec->sample_rate; + } - // Profile does not specify a sample format -> use same as source + // Caller did not specify a sample format -> use same as source if (!ctx->settings.sample_format && ctx->settings.encode_audio) { bps = av_get_bytes_per_sample(src_ctx->audio_stream.codec->sample_fmt); @@ -1270,6 +1225,13 @@ transcode_encode_setup(enum transcode_profile profile, struct decode_ctx *src_ct } } + // Caller did not specify channels -> use same as source + if (!ctx->settings.channels && ctx->settings.encode_audio) + { + ctx->settings.channels = src_ctx->audio_stream.codec->channels; + ctx->settings.channel_layout = src_ctx->audio_stream.codec->channel_layout; + } + if (ctx->settings.wavheader) make_wav_header(ctx, src_ctx, est_size); @@ -1297,20 +1259,20 @@ transcode_encode_setup(enum transcode_profile profile, struct decode_ctx *src_ct } struct transcode_ctx * -transcode_setup(enum transcode_profile profile, enum data_kind data_kind, const char *path, uint32_t song_length, off_t *est_size) +transcode_setup(enum transcode_profile profile, struct media_quality *quality, enum data_kind data_kind, const char *path, uint32_t song_length, off_t *est_size) { struct transcode_ctx *ctx; CHECK_NULL(L_XCODE, ctx = calloc(1, sizeof(struct transcode_ctx))); - ctx->decode_ctx = transcode_decode_setup(profile, data_kind, path, NULL, song_length); + ctx->decode_ctx = transcode_decode_setup(profile, quality, data_kind, path, NULL, song_length); if (!ctx->decode_ctx) { free(ctx); return NULL; } - ctx->encode_ctx = transcode_encode_setup(profile, ctx->decode_ctx, est_size, 0, 0); + ctx->encode_ctx = transcode_encode_setup(profile, quality, ctx->decode_ctx, est_size, 0, 0); if (!ctx->encode_ctx) { transcode_decode_cleanup(&ctx->decode_ctx); @@ -1322,7 +1284,7 @@ transcode_setup(enum transcode_profile profile, enum data_kind data_kind, const } struct decode_ctx * -transcode_decode_setup_raw(enum transcode_profile profile) +transcode_decode_setup_raw(enum transcode_profile profile, struct media_quality *quality) { const AVCodecDescriptor *codec_desc; struct decode_ctx *ctx; @@ -1331,7 +1293,7 @@ transcode_decode_setup_raw(enum transcode_profile profile) CHECK_NULL(L_XCODE, ctx = calloc(1, sizeof(struct decode_ctx))); - if (init_settings(&ctx->settings, profile) < 0) + if (init_settings(&ctx->settings, profile, quality) < 0) { goto out_free_ctx; } @@ -1614,7 +1576,7 @@ transcode(struct evbuffer *evbuf, int *icy_timer, struct transcode_ctx *ctx, int } transcode_frame * -transcode_frame_new(void *data, size_t size, int nsamples, int sample_rate, int bits_per_sample) +transcode_frame_new(void *data, size_t size, int nsamples, struct media_quality *quality) { AVFrame *f; int ret; @@ -1626,30 +1588,19 @@ transcode_frame_new(void *data, size_t size, int nsamples, int sample_rate, int return NULL; } - if (bits_per_sample == 16) + f->format = bitdepth2format(quality->bits_per_sample); + if (f->format == AV_SAMPLE_FMT_NONE) { - f->format = AV_SAMPLE_FMT_S16; - } - else if (bits_per_sample == 24) - { - f->format = AV_SAMPLE_FMT_S32; - } - else if (bits_per_sample == 32) - { - f->format = AV_SAMPLE_FMT_S32; - } - else - { - DPRINTF(E_LOG, L_XCODE, "transcode_frame_new() called with unsupported bps (%d)\n", bits_per_sample); + DPRINTF(E_LOG, L_XCODE, "transcode_frame_new() called with unsupported bps (%d)\n", quality->bits_per_sample); av_frame_free(&f); return NULL; } - f->sample_rate = sample_rate; + f->sample_rate = quality->sample_rate; f->nb_samples = nsamples; - f->channel_layout = AV_CH_LAYOUT_STEREO; + f->channel_layout = av_get_default_channel_layout(quality->channels); #ifdef HAVE_FFMPEG - f->channels = 2; + f->channels = quality->channels; #endif f->pts = AV_NOPTS_VALUE; @@ -1658,7 +1609,7 @@ transcode_frame_new(void *data, size_t size, int nsamples, int sample_rate, int ret = avcodec_fill_audio_frame(f, 2, f->format, data, size, 1); if (ret < 0) { - DPRINTF(E_LOG, L_XCODE, "Error filling frame with rawbuf, size %zu, samples %d (%d/%d/2): %s\n", size, nsamples, sample_rate, bits_per_sample, err2str(ret)); + DPRINTF(E_LOG, L_XCODE, "Error filling frame with rawbuf, size %zu, samples %d (%d/%d/2): %s\n", size, nsamples, quality->sample_rate, quality->bits_per_sample, err2str(ret)); av_frame_free(&f); return NULL; } diff --git a/src/transcode.h b/src/transcode.h index 3db09ae2..6b1f753c 100644 --- a/src/transcode.h +++ b/src/transcode.h @@ -5,6 +5,7 @@ #include #include "db.h" #include "http.h" +#include "misc.h" enum transcode_profile { @@ -12,18 +13,12 @@ enum transcode_profile XCODE_UNKNOWN = 0, // Decodes the best audio stream into PCM16 or PCM24, no resampling (does not add wav header) XCODE_PCM_NATIVE, - // Decodes/resamples the best audio stream into 44100 PCM16 (with wav header) + // Decodes/resamples the best audio stream into PCM16 (with wav header) XCODE_PCM16_HEADER, - // Decodes/resamples the best audio stream (no wav headers) - XCODE_PCM16_44100, - XCODE_PCM16_48000, - XCODE_PCM16_96000, - XCODE_PCM24_44100, - XCODE_PCM24_48000, - XCODE_PCM24_96000, - XCODE_PCM32_44100, - XCODE_PCM32_48000, - XCODE_PCM32_96000, + // Decodes/resamples the best audio stream into PCM16/24/32 (no wav headers) + XCODE_PCM16, + XCODE_PCM24, + XCODE_PCM32, // Transcodes the best audio stream into MP3 XCODE_MP3, // Transcodes the best audio stream into OPUS @@ -45,16 +40,16 @@ typedef void transcode_frame; // Setting up struct decode_ctx * -transcode_decode_setup(enum transcode_profile profile, enum data_kind data_kind, const char *path, struct evbuffer *evbuf, uint32_t song_length); +transcode_decode_setup(enum transcode_profile profile, struct media_quality *quality, enum data_kind data_kind, const char *path, struct evbuffer *evbuf, uint32_t song_length); struct encode_ctx * -transcode_encode_setup(enum transcode_profile profile, struct decode_ctx *src_ctx, off_t *est_size, int width, int height); +transcode_encode_setup(enum transcode_profile profile, struct media_quality *quality, struct decode_ctx *src_ctx, off_t *est_size, int width, int height); struct transcode_ctx * -transcode_setup(enum transcode_profile profile, enum data_kind data_kind, const char *path, uint32_t song_length, off_t *est_size); +transcode_setup(enum transcode_profile profile, struct media_quality *quality, enum data_kind data_kind, const char *path, uint32_t song_length, off_t *est_size); struct decode_ctx * -transcode_decode_setup_raw(enum transcode_profile profile); +transcode_decode_setup_raw(enum transcode_profile profile, struct media_quality *quality); int transcode_needed(const char *user_agent, const char *client_codecs, char *file_codectype); @@ -113,14 +108,11 @@ transcode(struct evbuffer *evbuf, int *icy_timer, struct transcode_ctx *ctx, int * @in data Buffer with raw data * @in size Size of buffer * @in nsamples Number of samples in the buffer - * @in sample_rate - * Sample rate - * @in bits_per_sample - * BPS must be either 16 or 24 + * @in quality Sample rate, bits per sample and channels * @return Opaque pointer to frame if OK, otherwise NULL */ transcode_frame * -transcode_frame_new(void *data, size_t size, int nsamples, int sample_rate, int bits_per_sample); +transcode_frame_new(void *data, size_t size, int nsamples, struct media_quality *quality); void transcode_frame_free(transcode_frame *frame);