/** * gst_audio_format_build_integer: * @sign: signed or unsigned format * @endianness: G_LITTLE_ENDIAN or G_BIG_ENDIAN * @width: amount of bits used per sample * @depth: amount of used bits in @width * * Construct a #GstAudioFormat with given parameters. * * Returns: a #GstAudioFormat or GST_AUDIO_FORMAT_UNKNOWN when no audio format * exists with the given parameters. */ GstAudioFormat gst_audio_format_build_integer (gboolean sign, gint endianness, gint width, gint depth) { gint i, e; for (i = 0; i < G_N_ELEMENTS (formats); i++) { GstAudioFormatInfo *finfo = &formats[i]; /* must be int */ if (!GST_AUDIO_FORMAT_INFO_IS_INTEGER (finfo)) continue; /* width and depth must match */ if (width != GST_AUDIO_FORMAT_INFO_WIDTH (finfo)) continue; if (depth != GST_AUDIO_FORMAT_INFO_DEPTH (finfo)) continue; /* if there is endianness, it must match */ e = GST_AUDIO_FORMAT_INFO_ENDIANNESS (finfo); if (e && e != endianness) continue; /* check sign */ if ((sign && !GST_AUDIO_FORMAT_INFO_IS_SIGNED (finfo)) || (!sign && GST_AUDIO_FORMAT_INFO_IS_SIGNED (finfo))) continue; return GST_AUDIO_FORMAT_INFO_FORMAT (finfo); } return GST_AUDIO_FORMAT_UNKNOWN; }
static gint audio_convert_get_func_index (AudioConvertCtx * ctx, const GstAudioFormatInfo * fmt) { gint index = 0; if (GST_AUDIO_FORMAT_INFO_IS_INTEGER (fmt)) { index += (GST_AUDIO_FORMAT_INFO_WIDTH (fmt) / 8 - 1) * 4; index += GST_AUDIO_FORMAT_INFO_IS_LITTLE_ENDIAN (fmt) ? 0 : 2; index += GST_AUDIO_FORMAT_INFO_IS_SIGNED (fmt) ? 1 : 0; index += (ctx->ns == NOISE_SHAPING_NONE) ? 0 : 24; } else { /* this is float/double */ index = 16; index += (GST_AUDIO_FORMAT_INFO_WIDTH (fmt) == 32) ? 0 : 2; index += GST_AUDIO_FORMAT_INFO_IS_LITTLE_ENDIAN (fmt) ? 0 : 1; index += (DOUBLE_INTERMEDIATE_FORMAT (ctx)) ? 4 : 0; } return index; }
gboolean audio_convert_convert (AudioConvertCtx * ctx, gpointer src, gpointer dst, gint samples, gboolean src_writable) { guint insize, outsize, size; gpointer outbuf, tmpbuf; guint intemp = 0, outtemp = 0, biggest; gint in_width, out_width; g_return_val_if_fail (ctx != NULL, FALSE); g_return_val_if_fail (src != NULL, FALSE); g_return_val_if_fail (dst != NULL, FALSE); g_return_val_if_fail (samples >= 0, FALSE); if (samples == 0) return TRUE; insize = ctx->in.bpf * samples; outsize = ctx->out.bpf * samples; in_width = GST_AUDIO_FORMAT_INFO_WIDTH (ctx->in.finfo); out_width = GST_AUDIO_FORMAT_INFO_WIDTH (ctx->out.finfo); /* find biggest temp buffer size */ size = (DOUBLE_INTERMEDIATE_FORMAT (ctx)) ? sizeof (gdouble) : sizeof (gint32); if (!ctx->in_default) intemp = gst_util_uint64_scale (insize, size * 8, in_width); if (!ctx->mix_passthrough || !ctx->out_default) outtemp = gst_util_uint64_scale (outsize, size * 8, out_width); biggest = MAX (intemp, outtemp); /* see if one of the buffers can be used as temp */ if ((outsize >= biggest) && (ctx->out.bpf <= size)) tmpbuf = dst; else if ((insize >= biggest) && src_writable && (ctx->in.bpf >= size)) tmpbuf = src; else { if (biggest > ctx->tmpbufsize) { ctx->tmpbuf = g_realloc (ctx->tmpbuf, biggest); ctx->tmpbufsize = biggest; } tmpbuf = ctx->tmpbuf; } /* start conversion */ if (!ctx->in_default) { /* check if final conversion */ if (!(ctx->out_default && ctx->mix_passthrough)) outbuf = tmpbuf; else outbuf = dst; /* unpack to default format */ ctx->unpack (src, outbuf, ctx->in_scale, samples * ctx->in.channels); src = outbuf; } if (!ctx->mix_passthrough) { /* check if final conversion */ if (!ctx->out_default) outbuf = tmpbuf; else outbuf = dst; /* convert channels */ ctx->channel_mix (ctx, src, outbuf, samples); src = outbuf; } /* we only need to quantize if output format is int */ if (GST_AUDIO_FORMAT_INFO_IS_INTEGER (ctx->out.finfo)) { if (ctx->out_default) outbuf = dst; else outbuf = tmpbuf; ctx->quantize (ctx, src, outbuf, samples); } if (!ctx->out_default) { /* pack default format into dst */ ctx->pack (src, dst, ctx->out_scale, samples * ctx->out.channels); } return TRUE; }
gboolean audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in, GstAudioInfo * out, GstAudioConvertDithering dither, GstAudioConvertNoiseShaping ns) { gint idx_in, idx_out; gint in_depth, out_depth; g_return_val_if_fail (ctx != NULL, FALSE); g_return_val_if_fail (in != NULL, FALSE); g_return_val_if_fail (out != NULL, FALSE); /* first clean the existing context */ audio_convert_clean_context (ctx); if ((GST_AUDIO_INFO_CHANNELS (in) != GST_AUDIO_INFO_CHANNELS (out)) && (GST_AUDIO_INFO_IS_UNPOSITIONED (in) || GST_AUDIO_INFO_IS_UNPOSITIONED (out))) goto unpositioned; ctx->in = *in; ctx->out = *out; in_depth = GST_AUDIO_FORMAT_INFO_DEPTH (in->finfo); out_depth = GST_AUDIO_FORMAT_INFO_DEPTH (out->finfo); GST_INFO ("depth in %d, out %d", in_depth, out_depth); /* Don't dither or apply noise shaping if target depth is bigger than 20 bits * as DA converters only can do a SNR up to 20 bits in reality. * Also don't dither or apply noise shaping if target depth is larger than * source depth. */ if (out_depth <= 20 && (!GST_AUDIO_FORMAT_INFO_IS_INTEGER (in->finfo) || in_depth >= out_depth)) { ctx->dither = dither; ctx->ns = ns; GST_INFO ("using dither %d and noise shaping %d", dither, ns); } else { ctx->dither = DITHER_NONE; ctx->ns = NOISE_SHAPING_NONE; GST_INFO ("using no dither and noise shaping"); } /* Use simple error feedback when output sample rate is smaller than * 32000 as the other methods might move the noise to audible ranges */ if (ctx->ns > NOISE_SHAPING_ERROR_FEEDBACK && out->rate < 32000) ctx->ns = NOISE_SHAPING_ERROR_FEEDBACK; gst_channel_mix_setup_matrix (ctx); idx_in = audio_convert_get_func_index (ctx, in->finfo); ctx->unpack = unpack_funcs[idx_in]; idx_out = audio_convert_get_func_index (ctx, out->finfo); ctx->pack = pack_funcs[idx_out]; GST_INFO ("func index in %d, out %d", idx_in, idx_out); /* if both formats are float/double or we use noise shaping use double as * intermediate format and switch mixing */ if (!DOUBLE_INTERMEDIATE_FORMAT (ctx)) { GST_INFO ("use int mixing"); ctx->channel_mix = (AudioConvertMix) gst_channel_mix_mix_int; } else { GST_INFO ("use float mixing"); ctx->channel_mix = (AudioConvertMix) gst_channel_mix_mix_float; } GST_INFO ("unitsizes: %d -> %d", in->bpf, out->bpf); /* check if input is in default format */ ctx->in_default = check_default (ctx, in->finfo); /* check if channel mixer is passthrough */ ctx->mix_passthrough = gst_channel_mix_passthrough (ctx); /* check if output is in default format */ ctx->out_default = check_default (ctx, out->finfo); GST_INFO ("in default %d, mix passthrough %d, out default %d", ctx->in_default, ctx->mix_passthrough, ctx->out_default); ctx->in_scale = GST_AUDIO_FORMAT_INFO_IS_INTEGER (in->finfo) ? (32 - in_depth) : 0; ctx->out_scale = GST_AUDIO_FORMAT_INFO_IS_INTEGER (out->finfo) ? (32 - out_depth) : 0; GST_INFO ("scale in %d, out %d", ctx->in_scale, ctx->out_scale); gst_audio_quantize_setup (ctx); return TRUE; /* ERRORS */ unpositioned: { GST_WARNING ("unpositioned channels"); return FALSE; } }