请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

windows下重采样问题

我从麦克风读取到的数据大小是88200(老师的视频里面是4096),我用av_dump_format函数查看格式如下,
Input #0, dshow, from ‘audio=@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{0D541114-F0DB-4B7E-BADF-7F045E1881F0}’:
Duration: N/A, bitrate: N/A
Stream #0:0: Audio: pcm_s16le, 44100 Hz, 2 channels, s16, 1411 kb

那我的样本数量=88200/2/2=22050? 当我用22050时,avcodec_send_frame函数会失败,返回-22(编码器已经打开),有如下输出信息nb_samples(22050)>frame_size(1024)。如果我使用1024而不用22050,那么会在memcpy时引发异常,原因是src_data太小放不大这88200字节的数据,然后修改src_data大小,让其分配多一些的内存,使其放得下88200字节,在swr_convert函数重采样转换时也会引发异常。

以下是我的源代码(用的是ffmpeg5.1版本的库)
#include <stdio.h>
#include <string.h>

#ifdef __cplusplus
extern “C”
{
#endif
#include “libavformat/avformat.h”
#include “libavutil/avutil.h”
#include “libavdevice/avdevice.h”
#include “libswresample/swresample.h”
#include “libavcodec/avcodec.h”
#include “libavutil/samplefmt.h”
#include “libavutil/channel_layout.h”
#include “libavutil/time.h”

#ifdef __cplusplus
}
#endif

int main()
{
// av_log_set_level(AV_LOG_DEBUG);

avdevice_register_all();

FILE *outFile = fopen("output.aac", "wb+");
if (outFile == NULL)
{
    av_log(NULL, AV_LOG_ERROR, "Could not open output file.\n");
    return -1;
}

const AVInputFormat *infmt = av_find_input_format("dshow");

char devName[1024] = "audio=";
AVDeviceInfoList *devs = NULL;
avdevice_list_input_sources(infmt, NULL, NULL, &devs);
if (devs == NULL)
{
    av_log(NULL, AV_LOG_ERROR, "Could not find audio capture device.\n");
    return -1;
}

for (int i = 0; i < devs->nb_devices; i++)
{
    AVDeviceInfo *devInfo = devs->devices[i];
    if (*(devInfo->media_types) == AVMEDIA_TYPE_AUDIO)
        strcat(devName, devInfo->device_name);
}

AVFormatContext *fmtCtx = NULL;
int ret = avformat_open_input(&fmtCtx, devName, infmt, NULL);
if (ret != 0)
{
    char err[1024];
    av_strerror(ret, err, sizeof(err));
    av_log(NULL, AV_LOG_ERROR, "Could not open input file: %s\n", err);
    return -1;
}

const AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
AVCodecContext *codecCtx = avcodec_alloc_context3(codec);
if (codecCtx == NULL)
{
    av_log(NULL, AV_LOG_ERROR, "Could not allocate audio codec context.\n");
    return -1;
}

codecCtx->bit_rate = 0;
codecCtx->profile = FF_PROFILE_AAC_HE_V2;
codecCtx->sample_fmt = AV_SAMPLE_FMT_FLTP;//avcodec_open2调用后会自动设置成FLTP格式,
codecCtx->sample_rate = 44100;
AVChannelLayout cl = AV_CHANNEL_LAYOUT_STEREO;

av_channel_layout_copy(&codecCtx->ch_layout, &cl);

if (avcodec_open2(codecCtx, codec, NULL) < 0)
{
    char err[1024];
    av_strerror(ret, err, sizeof(err));
    av_log(NULL, AV_LOG_ERROR, "Could not open audio codec: %s\n", err);
    return -1;
}

SwrContext *swrCtx = NULL;
swr_alloc_set_opts2(&swrCtx, &cl, AV_SAMPLE_FMT_S16, 44100,
                    &codecCtx->ch_layout, codecCtx->sample_fmt, codecCtx->sample_rate, 0, NULL);
if (swrCtx == NULL)
{
    av_log(NULL, AV_LOG_ERROR, "Could not allocate SwrContext.\n");
    return -1;
}
//该函数被标记为过时,不建议使用
// swrCtx = swr_alloc_set_opts(NULL, AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16, 44100,
//                             codecCtx->ch_layout.u.mask, codecCtx->sample_fmt, codecCtx->sample_rate, 0, NULL);
// if (swrCtx == NULL)
// {
//     av_log(NULL, AV_LOG_ERROR, "Could not allocate SwrContext.\n");
//     return -1;
// }

if (swr_init(swrCtx) < 0)
{
    av_log(NULL, AV_LOG_ERROR, "Could not initialize SwrContext.\n");
    return -1;
}

AVFrame *frame = av_frame_alloc();
if (frame == NULL)
{
    av_log(NULL, AV_LOG_ERROR, "Could not allocate audio frame.\n");
    return -1;
}

frame->nb_samples = 22050;
frame->format = AV_SAMPLE_FMT_S16;
av_channel_layout_copy(&frame->ch_layout, &cl);

ret = av_frame_get_buffer(frame, 0);
if (ret != 0)
{
    av_log(NULL, AV_LOG_ERROR, "Could not allocate audio buffer.\n");
    return -1;
}

AVPacket *pkt = av_packet_alloc();
if (pkt == NULL)
{
    av_log(NULL, AV_LOG_ERROR, "Could not allocate packet.\n");
    return -1;
}

uint8_t **srcData = nullptr, **dstData = nullptr;
int srcLineSize = 0, dstLineSize = 0;

av_samples_alloc_array_and_samples(&srcData, &srcLineSize, 2, 22050, AV_SAMPLE_FMT_FLTP, 0);
av_samples_alloc_array_and_samples(&dstData, &dstLineSize, 2, av_rescale_rnd(22050, 44100, 44100, AV_ROUND_UP),
                                   AV_SAMPLE_FMT_S16, 0);

int ct = 0;
while (ct++ < 10)
{
    int ret = av_read_frame(fmtCtx, pkt);
    if (ret < 0)
    {
        if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
        {
            av_usleep(10000);
            continue;
        }
        break;
    }
    memcpy((void *)srcData[0], (const void *)pkt->data, pkt->size);

    swr_convert(swrCtx, dstData, 22050, (const uint8_t **)srcData, 22050);

    memcpy((void *)frame->data[0], (const void *)dstData[0], dstLineSize);

    ret = avcodec_send_frame(codecCtx, frame);
    while (ret >= 0)
    {
        ret = avcodec_receive_packet(codecCtx, pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
            break;
        else if (ret < 0)
        {
            av_log(NULL, AV_LOG_ERROR,
                   "Error while sending a packet to the decoder.\n");
            return -1;
        }

        fwrite(pkt->data, 1, pkt->size, outFile);
    }

    av_packet_unref(pkt);
}

// 清空编码器数据
ret = avcodec_send_frame(codecCtx, NULL);
while (ret >= 0)
{
    ret = avcodec_receive_packet(codecCtx, pkt);
    if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
        break;
    else if (ret < 0)
    {
        av_log(NULL, AV_LOG_ERROR,
               "Error while sending a packet to the decoder.\n");
        return -1;
    }

    fwrite(pkt->data, 1, pkt->size, outFile);
}

av_packet_unref(pkt);

fclose(outFile);

return 0;

}

正在回答 回答被采纳积分+3

1回答

李超 2024-02-01 20:06:38

把重采样与编码分开来做,先确保重采样成功后,再进行编码。你现在重采样没有做好,再加上编码就会把问题搞复杂。

0 回复 有任何疑惑可以回复我~
  • 提问者 weixin_慕用1394226 #1
    现在重采样问题解决了,但是录制出来的音频很快,和开了十几倍速一样的,swr_convert(swrCtx, frame->data, 1024, (const uint8_t **)&pkt->data, 1024);现在我没有拷贝内存,pkt数据是有88200字节的,格式是2通道,44100,s16,重采样输出的格式是fltp格式,采样率和声道数没有改变。 for (int i = 0; i < frame->nb_samples; i++)
                {
    
                    for (int j = 0; j < frame->ch_layout.nb_channels; j++)
                        fwrite(frame->data[j] + 4 * i, 1, 4, outFile);
                }数据是这样写入到文件的
    回复 有任何疑惑可以回复我~ 2024-02-02 15:18:47
  • 提问者 weixin_慕用1394226 #2
    ffmpeg命令行录制的音频是正常的,除了有些滋滋滋的声音
    回复 有任何疑惑可以回复我~ 2024-02-02 15:20:20
  • 李超 回复 提问者 weixin_慕用1394226 #3
    你用ffplay 播放时没有指定播放参数吧?或者制定的播放参数是错误的
    回复 有任何疑惑可以回复我~ 2024-02-04 20:41:34
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信