[xcode] Adapt to allow for new raw PCM input profiles, e.g. 48000/16

This commit is contained in:
ejurgensen 2019-02-08 18:53:40 +01:00
parent 1696fc3384
commit ad77a42dbb
2 changed files with 82 additions and 18 deletions

View File

@ -187,9 +187,16 @@ init_settings(struct settings_ctx *settings, enum transcode_profile profile)
switch (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: case XCODE_PCM16_HEADER:
settings->wavheader = 1; settings->wavheader = 1;
case XCODE_PCM16_NOHEADER: case XCODE_PCM16_44100:
settings->encode_audio = 1; settings->encode_audio = 1;
settings->format = "s16le"; settings->format = "s16le";
settings->audio_codec = AV_CODEC_ID_PCM_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->channel_layout = AV_CH_LAYOUT_STEREO;
settings->channels = 2; settings->channels = 2;
settings->sample_format = AV_SAMPLE_FMT_S16; settings->sample_format = AV_SAMPLE_FMT_S16;
settings->icy = 1;
break; break;
case XCODE_PCM_NATIVE: // Sample rate and bit depth determined by source case XCODE_PCM16_48000:
settings->encode_audio = 1; 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->channel_layout = AV_CH_LAYOUT_STEREO;
settings->channels = 2; 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; break;
case XCODE_MP3: case XCODE_MP3:
@ -975,6 +1004,8 @@ open_filter(struct stream_ctx *out_stream, struct stream_ctx *in_stream)
goto out_fail; goto out_fail;
} }
DPRINTF(E_DBG, L_XCODE, "Created 'in' filter: %s\n", args);
snprintf(args, sizeof(args), snprintf(args, sizeof(args),
"sample_fmts=%s:sample_rates=%d:channel_layouts=0x%"PRIx64, "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, 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; 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); ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", NULL, NULL, filter_graph);
if (ret < 0) if (ret < 0)
{ {
@ -1236,7 +1269,7 @@ transcode_setup(enum transcode_profile profile, enum data_kind data_kind, const
} }
struct decode_ctx * struct decode_ctx *
transcode_decode_setup_raw(void) transcode_decode_setup_raw(enum transcode_profile profile)
{ {
const AVCodecDescriptor *codec_desc; const AVCodecDescriptor *codec_desc;
struct decode_ctx *ctx; struct decode_ctx *ctx;
@ -1245,7 +1278,7 @@ transcode_decode_setup_raw(void)
CHECK_NULL(L_XCODE, ctx = calloc(1, sizeof(struct decode_ctx))); 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; goto out_free_ctx;
} }
@ -1408,6 +1441,9 @@ transcode_encode_cleanup(struct encode_ctx **ctx)
void void
transcode_cleanup(struct transcode_ctx **ctx) transcode_cleanup(struct transcode_ctx **ctx)
{ {
if (!*ctx)
return;
transcode_encode_cleanup(&(*ctx)->encode_ctx); transcode_encode_cleanup(&(*ctx)->encode_ctx);
transcode_decode_cleanup(&(*ctx)->decode_ctx); transcode_decode_cleanup(&(*ctx)->decode_ctx);
free(*ctx); free(*ctx);
@ -1525,7 +1561,7 @@ transcode(struct evbuffer *evbuf, int *icy_timer, struct transcode_ctx *ctx, int
} }
transcode_frame * 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; AVFrame *f;
int ret; int ret;
@ -1537,21 +1573,35 @@ transcode_frame_new(enum transcode_profile profile, void *data, size_t size)
return NULL; return NULL;
} }
f->nb_samples = BTOS(size); if (bits_per_sample == 16)
{
f->format = AV_SAMPLE_FMT_S16; 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; f->channel_layout = AV_CH_LAYOUT_STEREO;
#ifdef HAVE_FFMPEG #ifdef HAVE_FFMPEG
f->channels = 2; f->channels = 2;
#endif #endif
f->pts = AV_NOPTS_VALUE; f->pts = AV_NOPTS_VALUE;
f->sample_rate = 44100;
// We don't align because the frame won't be given directly to the encoder // 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...?) // anyway, it will first go through the filter (which might align it...?)
ret = avcodec_fill_audio_frame(f, 2, f->format, data, size, 1); ret = avcodec_fill_audio_frame(f, 2, f->format, data, size, 1);
if (ret < 0) 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); av_frame_free(&f);
return NULL; return NULL;
} }
@ -1695,6 +1745,11 @@ transcode_encode_query(struct encode_ctx *ctx, const char *query)
if (ctx->audio_stream.stream) if (ctx->audio_stream.stream)
return av_get_bits_per_sample(ctx->audio_stream.stream->codecpar->codec_id); 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; return -1;
} }

View File

@ -8,12 +8,17 @@
enum transcode_profile enum transcode_profile
{ {
// Decodes/resamples the best audio stream into 44100 PCM16 (does not add wav header) // Used for errors
XCODE_PCM16_NOHEADER, XCODE_UNKNOWN = 0,
// Decodes/resamples the best audio stream into 44100 PCM16 (with wav header)
XCODE_PCM16_HEADER,
// Decodes the best audio stream into PCM16 or PCM24, no resampling (does not add wav header) // Decodes the best audio stream into PCM16 or PCM24, no resampling (does not add wav header)
XCODE_PCM_NATIVE, 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 // Transcodes the best audio stream into MP3
XCODE_MP3, XCODE_MP3,
// Transcodes the best audio stream into OPUS // 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); 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 * struct decode_ctx *
transcode_decode_setup_raw(void); transcode_decode_setup_raw(enum transcode_profile profile);
int int
transcode_needed(const char *user_agent, const char *client_codecs, char *file_codectype); 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 * transcode_encode() function. It does not copy, so if you free the data the
* frame will become invalid. * frame will become invalid.
* *
* @in profile Tells the function what kind of frame to create
* @in data Buffer with raw data * @in data Buffer with raw data
* @in size Size of buffer * @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 * @return Opaque pointer to frame if OK, otherwise NULL
*/ */
transcode_frame * 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 void
transcode_frame_free(transcode_frame *frame); transcode_frame_free(transcode_frame *frame);