From ad77a42dbba74d706ec10c0df21db50395874944 Mon Sep 17 00:00:00 2001 From: ejurgensen Date: Fri, 8 Feb 2019 18:53:40 +0100 Subject: [PATCH] [xcode] Adapt to allow for new raw PCM input profiles, e.g. 48000/16 --- src/transcode.c | 77 ++++++++++++++++++++++++++++++++++++++++++------- src/transcode.h | 23 ++++++++++----- 2 files changed, 82 insertions(+), 18 deletions(-) diff --git a/src/transcode.c b/src/transcode.c index 4673b831..74146f70 100644 --- a/src/transcode.c +++ b/src/transcode.c @@ -187,9 +187,16 @@ init_settings(struct settings_ctx *settings, enum transcode_profile profile) switch (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_NOHEADER: + case XCODE_PCM16_44100: settings->encode_audio = 1; settings->format = "s16le"; settings->audio_codec = AV_CODEC_ID_PCM_S16LE; @@ -197,14 +204,36 @@ init_settings(struct settings_ctx *settings, enum transcode_profile profile) settings->channel_layout = AV_CH_LAYOUT_STEREO; settings->channels = 2; settings->sample_format = AV_SAMPLE_FMT_S16; - settings->icy = 1; break; - case XCODE_PCM_NATIVE: // Sample rate and bit depth determined by source + 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->icy = 1; + settings->sample_format = AV_SAMPLE_FMT_S16; + break; + + case XCODE_PCM24_44100: + 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_MP3: @@ -975,6 +1004,8 @@ open_filter(struct stream_ctx *out_stream, struct stream_ctx *in_stream) goto out_fail; } + DPRINTF(E_DBG, L_XCODE, "Created 'in' filter: %s\n", args); + snprintf(args, sizeof(args), "sample_fmts=%s:sample_rates=%d:channel_layouts=0x%"PRIx64, av_get_sample_fmt_name(out_stream->codec->sample_fmt), out_stream->codec->sample_rate, @@ -987,6 +1018,8 @@ open_filter(struct stream_ctx *out_stream, struct stream_ctx *in_stream) goto out_fail; } + DPRINTF(E_DBG, L_XCODE, "Created 'format' filter: %s\n", args); + ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", NULL, NULL, filter_graph); if (ret < 0) { @@ -1236,7 +1269,7 @@ transcode_setup(enum transcode_profile profile, enum data_kind data_kind, const } struct decode_ctx * -transcode_decode_setup_raw(void) +transcode_decode_setup_raw(enum transcode_profile profile) { const AVCodecDescriptor *codec_desc; struct decode_ctx *ctx; @@ -1245,7 +1278,7 @@ transcode_decode_setup_raw(void) CHECK_NULL(L_XCODE, ctx = calloc(1, sizeof(struct decode_ctx))); - if (init_settings(&ctx->settings, XCODE_PCM16_NOHEADER) < 0) + if (init_settings(&ctx->settings, profile) < 0) { goto out_free_ctx; } @@ -1408,6 +1441,9 @@ transcode_encode_cleanup(struct encode_ctx **ctx) void transcode_cleanup(struct transcode_ctx **ctx) { + if (!*ctx) + return; + transcode_encode_cleanup(&(*ctx)->encode_ctx); transcode_decode_cleanup(&(*ctx)->decode_ctx); free(*ctx); @@ -1525,7 +1561,7 @@ transcode(struct evbuffer *evbuf, int *icy_timer, struct transcode_ctx *ctx, int } transcode_frame * -transcode_frame_new(enum transcode_profile profile, void *data, size_t size) +transcode_frame_new(void *data, size_t size, int nsamples, int sample_rate, int bits_per_sample) { AVFrame *f; int ret; @@ -1537,21 +1573,35 @@ transcode_frame_new(enum transcode_profile profile, void *data, size_t size) return NULL; } - f->nb_samples = BTOS(size); - f->format = AV_SAMPLE_FMT_S16; + if (bits_per_sample == 16) + { + f->format = AV_SAMPLE_FMT_S16; + } + else if (bits_per_sample == 24) + { + f->format = AV_SAMPLE_FMT_S32; + } + else + { + DPRINTF(E_LOG, L_XCODE, "transcode_frame_new() called with unsupported bps (%d)\n", bits_per_sample); + av_frame_free(&f); + return NULL; + } + + f->sample_rate = sample_rate; + f->nb_samples = nsamples; f->channel_layout = AV_CH_LAYOUT_STEREO; #ifdef HAVE_FFMPEG f->channels = 2; #endif f->pts = AV_NOPTS_VALUE; - f->sample_rate = 44100; // We don't align because the frame won't be given directly to the encoder // anyway, it will first go through the filter (which might align it...?) 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: %s\n", err2str(ret)); + 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)); av_frame_free(&f); return NULL; } @@ -1695,6 +1745,11 @@ transcode_encode_query(struct encode_ctx *ctx, const char *query) if (ctx->audio_stream.stream) return av_get_bits_per_sample(ctx->audio_stream.stream->codecpar->codec_id); } + else if (strcmp(query, "channels") == 0) + { + if (ctx->audio_stream.stream) + return ctx->audio_stream.stream->codecpar->channels; + } return -1; } diff --git a/src/transcode.h b/src/transcode.h index 333d7df0..3ce05d26 100644 --- a/src/transcode.h +++ b/src/transcode.h @@ -8,12 +8,17 @@ enum transcode_profile { - // Decodes/resamples the best audio stream into 44100 PCM16 (does not add wav header) - XCODE_PCM16_NOHEADER, - // Decodes/resamples the best audio stream into 44100 PCM16 (with wav header) - XCODE_PCM16_HEADER, + // Used for errors + 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) + XCODE_PCM16_HEADER, + // Decodes/resamples the best audio stream (no wav headers) + XCODE_PCM16_44100, + XCODE_PCM16_48000, + XCODE_PCM24_44100, + XCODE_PCM24_48000, // Transcodes the best audio stream into MP3 XCODE_MP3, // Transcodes the best audio stream into OPUS @@ -44,7 +49,7 @@ 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); struct decode_ctx * -transcode_decode_setup_raw(void); +transcode_decode_setup_raw(enum transcode_profile profile); int transcode_needed(const char *user_agent, const char *client_codecs, char *file_codectype); @@ -100,13 +105,17 @@ transcode(struct evbuffer *evbuf, int *icy_timer, struct transcode_ctx *ctx, int * transcode_encode() function. It does not copy, so if you free the data the * frame will become invalid. * - * @in profile Tells the function what kind of frame to create * @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 * @return Opaque pointer to frame if OK, otherwise NULL */ transcode_frame * -transcode_frame_new(enum transcode_profile profile, void *data, size_t size); +transcode_frame_new(void *data, size_t size, int nsamples, int sample_rate, int bits_per_sample); void transcode_frame_free(transcode_frame *frame);