[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