I am using libavcodec to mp3 encoding the pcm recording file collected
by alsa. Please refer to the attachment for the code. Although the code
can run successfully, the following error will occur:
[libmp3lame @ 0x5653c7e9b880] 5 frames left in the queue on closing.
I want to ask you a few questions:
1. What is the reason for this error?
2. How does this error affect the mp3 audio?
3. How can I solve it?
Here is a detailed information:
computer system: Manjaro x86_64
linux kernel version: Linux 5.12.2-1
ALSA version: Advanced Linux Sound Architecture Driver Version
k5.12.2-1-MANJARO.
ffmpeg version: ffmpeg version n4.4 Copyright (c) 2000-2021 the FFmpeg
developers
Thank you for reading my mail.
//
// Created by aszswaz on 2021/6/6.
//
#include "stdio.h"
#include "config.h"
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>
#include <libavutil/opt.h>
#include <libswresample/swresample.h>
int pcm_to_mp3(const char *pcm_file_path, const char *mp3_file_path) {
fprintf(stdout, "pcm_file: %s, mp3_file: %s\n", pcm_file_path, mp3_file_path);
FILE *pcm_file = NULL;
FILE *mp3_file = NULL;
int result;
// 获得mp3编码器
fprintf(stdout, "Initialize the mp3 encoder...\n");
const AVCodec *avCodec = avcodec_find_encoder(AV_CODEC_ID_MP3);
if (!avCodec) {
fprintf(stderr, "Failed to initialize mp3 encoder!\n");
return -1;
}
// 创建编码器上下文
AVCodecContext *avCodecContext = avcodec_alloc_context3(avCodec);
if (!avCodecContext) {
fprintf(stderr, "Failed to create encoder context!\n");
return -1;
}
avCodecContext->bit_rate = 64000;
avCodecContext->channels = CHANNEL;
avCodecContext->channel_layout = AV_CH_LAYOUT_STEREO;
avCodecContext->sample_rate = OSR;
avCodecContext->sample_fmt = AV_SAMPLE_FMT_S16P;
avCodecContext->time_base = av_get_time_base_q();
// 打开编码器
result = avcodec_open2(avCodecContext, avCodec, NULL);
if (result < 0) {
fprintf(stderr, "avcodec_open2:%s\n", av_err2str(result));
return result;
}
fprintf(stdout, "mp3 encoder initialized successfully!\n");
fprintf(stdout, "Opening file:%s\n", mp3_file_path);
// 打开输出文件
mp3_file = fopen(mp3_file_path, "wb");
if (!mp3_file) {
fprintf(stderr, "fail to open the file:%s!\n", mp3_file_path);
return -1;
}
// AVFrame 接受重采样的每一帧的音频数据 每帧的样本大小为1152
AVFrame *avFrame = av_frame_alloc();
if (!avFrame) {
fprintf(stderr, "Failed to get mp3 data frame!\n");
return -1;
}
// mp3一帧的样本数为1152
avFrame->nb_samples = 1152;
avFrame->channels = CHANNEL;
avFrame->channel_layout = AV_CH_LAYOUT_STEREO;
avFrame->format = AV_SAMPLE_FMT_S16P;
// 给帧分配内存空间
result = av_frame_get_buffer(avFrame, 0);
if (result < 0) {
fprintf(stderr, "Failed to get memory! Exception information:%s\n", av_err2str(result));
return result;
}
// 重采样 创建音频重采样上下文
fprintf(stdout, "Initialize mp3 resampling parameters...\n");
SwrContext *swrContext = swr_alloc();
if (!swrContext) {
fprintf(stderr, "Failed to create audio resampling context!\n");
return -1;
}
// 设置重采样输入pcm参数:通道布局:立体声 采样率:44100 样本格式 s16交错存储
av_opt_set_int(swrContext, "in_channel_layout", AV_CH_LAYOUT_STEREO, 0);
av_opt_set_int(swrContext, "in_sample_rate", OSR, 0);
av_opt_set_sample_fmt(swrContext, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
// 设置重采样输出mp3参数:通道布局:立体声 采样率:44100 样本格式 s16平面存储
av_opt_set_int(swrContext, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);
av_opt_set_int(swrContext, "out_sample_rate", OSR, 0);
av_opt_set_sample_fmt(swrContext, "out_sample_fmt", AV_SAMPLE_FMT_S16P, 0);
// 重采样初始化
result = swr_init(swrContext);
if (result < 0) {
fprintf(stderr, "Resampling initialization failed, error message:%s\n", av_err2str(result));
return result;
}
fprintf(stdout, "Resampling initialized successfully\n");
uint8_t **input_data = NULL;
uint8_t **output_data = NULL;
int input_linesize, output_linesize;
// 打开pcm文件
fprintf(stdout, "Open pcm file:%s\n", pcm_file_path);
pcm_file = fopen(pcm_file_path, "rb");
if (!pcm_file) {
fprintf(stderr, "File %s failed to open!", pcm_file_path);
return -1;
}
fprintf(stdout, "Start encoding conversion...\n");
// 给pcm文件数据分配空间
result = av_samples_alloc_array_and_samples(&input_data, &input_linesize, 2, 1152, AV_SAMPLE_FMT_S16, 0);
if (result < 0) {
fprintf(stderr, "Failed to allocate space for pcm file! The error message is:%s\n", av_err2str(result));
return result;
}
// 缓存重采样数据的空间分配
result = av_samples_alloc_array_and_samples(&output_data, &output_linesize, 2, 1152, AV_SAMPLE_FMT_S16P, 0);
if (result < 0) {
fprintf(stderr, "Error getting mp3 resampling data, error message:%s\n", av_err2str(result));
return result;
}
// 存放编码后的数据
AVPacket *avPacket = av_packet_alloc();
if (!avPacket) {
fprintf(stderr, "Failed to get the memory of the encoded data packet storage!\n");
return -1;
}
long total_size = 0;
while (!feof(pcm_file)) {
long read_size = (long) fread(input_data[0], 1, 1152 * 4, pcm_file);
total_size += read_size;
fprintf(stdout, "It has been read:%zu\n", total_size);
if (read_size <= 0) {
break;
}
// 重采样
result = swr_convert(swrContext, output_data, 1152, (const uint8_t **) input_data, 1152);
if (result < 0) {
fprintf(stderr, "Audio encoding failed, error message:%s\n", av_err2str(result));
return result;
}
// 将重采样后的数据存入frame,MP3是s16p 先存放左声道的数据 后存放右声道的数据, data[0]是左声道,1是右声道
avFrame->data[0] = output_data[0];
avFrame->data[1] = output_data[1];
// 编码,写入mp3文件,实际上是对frame这个结构体里面的数据进行编码操作,发送到编码线程:使用编码器 和 存储数据的frame
result = avcodec_send_frame(avCodecContext, avFrame);
if (result < 0) {
fprintf(stderr, "mp3 encoding failed! The error message is:%s\n", av_err2str(result));
return result;
}
while (result >= 0) {
// 接收编码后的数据,使用编码器 和 存储编码数据的pkt, 有可能需要多次才能接收完成
result = avcodec_receive_packet(avCodecContext, avPacket);
// AVERROR_EOF表示没有数据了 这两个错误不影响继续接收数据
if (result == AVERROR_EOF || result == AVERROR(EAGAIN)) {
continue;
} else if (result < 0) {
break;
}
fwrite(avPacket->data, 1, avPacket->size, mp3_file);
av_packet_unref(avPacket);
}
}
// 关闭缓存
if (input_data) {
av_free(input_data);
}
if (output_data) {
av_free(output_data);
}
fclose(pcm_file);
fclose(mp3_file);
//s释放 frame pkt
av_frame_free(&avFrame);
av_packet_free(&avPacket);
// 释放重采样上下文
swr_free(&swrContext);
// 释放编码器上下文
avcodec_free_context(&avCodecContext);
fprintf(stdout, "Coding complete!\n");
return 0;
}//
// Created by aszswaz on 2021/6/6.
//
#ifndef MEMORIZE_ENGLISH_EVERY_DAY_MP3FORMAT_H
#define MEMORIZE_ENGLISH_EVERY_DAY_MP3FORMAT_H
/**
* pcm文件转换为mp3文件
*/
int pcm_to_mp3(const char *pcm_file, const char *mp3_file);
#endif //MEMORIZE_ENGLISH_EVERY_DAY_MP3FORMAT_H
_______________________________________________
Libav-user mailing list
[email protected]
https://ffmpeg.org/mailman/listinfo/libav-user
To unsubscribe, visit link above, or email
[email protected] with subject "unsubscribe".