[Libav-user] Enconding and Resampling issue

Kevin Kouketsu kevink at stepsoftware.com.br
Tue Jan 7 14:37:29 EET 2020


Hello,

I need to reencode and resample raw PCM 44.1KHz to AAC 48 KHz.

I’m really lost because have no much information about swr_convert.

What I’m doing until now is:
- Allocate AVCodecContext with encoder specifications:

void start_encoder(const AVFormatContext* formatContext, AVCodec*& encoderCodec, AVCodecContext*& encoderContext)
{
	encoderCodec = avcodec_find_encoder(AV_CODEC_ID_AAC);
	if (encoderCodec == nullptr)
		throw std::runtime_error("Could not find encoder for AAC");

	//stream->id = mpegtsFormatContext->nb_streams - 1;
	encoderContext = avcodec_alloc_context3(encoderCodec);
	if (!encoderCodec)
		throw std::runtime_error("Could not allocate an encoding context.");

	auto codec = encoderCodec;
	auto c = encoderContext;

	// Configura o encoder.
	switch (codec->type)
	{
	case AVMEDIA_TYPE_AUDIO:
		c->sample_fmt = codec->sample_fmts ? codec->sample_fmts[0] : AV_SAMPLE_FMT_FLTP;
		c->bit_rate = 128000;
		c->sample_rate = 48000;

		// Garante que o samplerate de saída requisitado é aceito pelo encoder.
		{
			bool supported{ false };
			if (codec->supported_samplerates)
			{
				for (auto i = 0; codec->supported_samplerates[i]; i++)
				{
					if (codec->supported_samplerates[i] == c->sample_rate)
					{
						supported = true;
						break;
					}
				}
			}

			if (!supported)
				throw std::invalid_argument("Sample rate not supported by encoder.");
		}

		c->channel_layout = AV_CH_LAYOUT_STEREO;
		c->channels = av_get_channel_layout_nb_channels(c->channel_layout);

		if (codec->channel_layouts)
		{
			c->channel_layout = codec->channel_layouts[0];
			for (auto i = 0; codec->channel_layouts[i]; i++)
			{
				if (codec->channel_layouts[i] == AV_CH_LAYOUT_STEREO)
					c->channel_layout = AV_CH_LAYOUT_STEREO;
			}
		}

		c->channels = av_get_channel_layout_nb_channels(c->channel_layout);
		break;

	default:
		break;
	}

	// Some formats want stream headers to be separate. 
	if (formatContext->oformat->flags & AVFMT_GLOBALHEADER)
		c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

	// open it
	AVDictionary* opt{ nullptr };
	check(avcodec_open2(c, codec, &opt));
}
 
- Allocating resampler contexto

void initialize_resampler(SwrContext*& resamplerCtx, AVCodecContext* encoder, AVFrame*& rawResampledAudioFrame, AVStream* audioFormatStream)
{
	int nb_samples = (encoder->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE) ? encoder->sample_rate : encoder->frame_size;

	int encoderFrameSize = encoder->channels * av_get_bytes_per_sample(encoder->sample_fmt) * encoder->frame_size;
	rawResampledAudioFrame = allocate_audioframe(encoder->sample_fmt, encoder->channel_layout, encoder->sample_rate, nb_samples);

	// Copy the stream parameters to the muxer
	check(avcodec_parameters_from_context(audioFormatStream->codecpar, encoder));

	// Create resampler context
	resamplerCtx = swr_alloc();
	if (resamplerCtx == nullptr)
		throw std::runtime_error("Could not allocate resampler context");

	// Set options
	check(av_opt_set_int(resamplerCtx, "in_channel_count", 2, 0));
	check(av_opt_set_int(resamplerCtx, "in_sample_rate", 44100, 0));
	check(av_opt_set_sample_fmt(resamplerCtx, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0));
	check(av_opt_set_int(resamplerCtx, "out_channel_count", encoder->channels, 0));
	check(av_opt_set_int(resamplerCtx, "out_sample_rate", encoder->sample_rate, 0));
	check(av_opt_set_sample_fmt(resamplerCtx, "out_sample_fmt", encoder->sample_fmt, 0));

	// initialize the resampling context
	check(swr_init(resamplerCtx));
}

- Allocating AVFrame to decodedFrame:

To get AVFrame, I’m sending to a decoder 

			AVPacket input_packet;
			av_init_packet(&input_packet);

			while (av_read_frame(inputContext, &input_packet) >= 0)
			{
				// Allocate data
				uint8_t** convertedData = NULL;
				if (av_samples_alloc_array_and_samples(&convertedData, NULL, STREAM_AUDIO_CHANNELS, RAW_AUDIO_FRAME_SIZE, STREAM_AUDIO_SAMPLE_FORMAT_GM, 0) < 0)
					throw - 20;

				check(avcodec_send_packet(decoderContext, &input_packet));
				check(avcodec_receive_frame(decoderContext, decodedFrame));
                                   }

As you can see, I’m Reading a frame from input (microfone), sending the packet to decoder to get AVFrame and what I have to do after?

I need to convert AV_SAMPLE_FMT_FLTP to AV_SAMPLE_FMT_S16 but I don’t know how. 

My entire loop (doesn’t work):

			AVPacket input_packet;
			av_init_packet(&input_packet);

			while (av_read_frame(inputContext, &input_packet) >= 0)
			{
				// Allocate data
				uint8_t** convertedData = NULL;
				if (av_samples_alloc_array_and_samples(&convertedData, NULL, STREAM_AUDIO_CHANNELS, RAW_AUDIO_FRAME_SIZE, STREAM_AUDIO_SAMPLE_FORMAT_GM, 0) < 0)
					throw - 20;

				check(avcodec_send_packet(decoderContext, &input_packet));
				check(avcodec_receive_frame(decoderContext, decodedFrame));

				int outSamples = swr_convert(resamplerContext, convertedData, RAW_AUDIO_FRAME_SIZE, const_cast<const uint8_t**>(decodedFrame->data), decodedFrame->nb_samples);
				check(outSamples);

				av_init_packet(&pkt);

				memcpy(&decodedFrame->data[0][0], convertedData, outSamples * sizeof STREAM_AUDIO_SAMPLE_TYPE * STREAM_AUDIO_CHANNELS);
				auto in_stream = inputContext->streams[pkt.stream_index];
				auto out_stream = outputContext->streams[pkt.stream_index];

				//Convert PTS/DTS
				pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
				pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
				pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
				pkt.pos = -1;

				check(av_frame_make_writable(decodedFrame));

				check(avcodec_send_frame(encoderContext, decodedFrame));
				check(avcodec_receive_packet(encoderContext, &pkt));

				check(av_interleaved_write_frame(outputContext, &pkt));
				av_packet_unref(&pkt);
			}

Enviado do Email para Windows 10

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://ffmpeg.org/pipermail/libav-user/attachments/20200107/ab46517f/attachment.html>


More information about the Libav-user mailing list