使用ffmpeg API将pcm_alaw类型的音频数据包装到MKA音频文件中

如何解决使用ffmpeg API将pcm_alaw类型的音频数据包装到MKA音频文件中

想象一下,在我的项目中,我收到了RTP个数据包,其中包含有效载荷type-8,以便稍后将此负载保存为音轨的第N部分。我从RTP数据包中提取了此负载,并将其保存到临时缓冲区:

...

while ((rtp = receiveRtpPackets()).withoutErrors()) {
   payloadData.push(rtp.getPayloadData());
}

audioGenerator.setPayloadData(payloadData);
audioGenerator.recordToFile();

...

用此有效负载填充一定大小的临时缓冲区后,我将处理此缓冲区,即提取整个有效负载并使用ffmpeg对其进行编码,以进一步保存为Matroska格式的音频文件。但是我有一个问题。由于RTP数据包的有效载荷为type 8,因此我必须将pcm_alaw格式的原始音频数据保存为mka音频格式。但是,当将原始数据pcm_alaw保存到音频文件时,我会从库中获得以下消息:

...

[libopus @ 0x18eff60] Queue input is backward in time
[libopus @ 0x18eff60] Queue input is backward in time
[libopus @ 0x18eff60] Queue input is backward in time
[libopus @ 0x18eff60] Queue input is backward in time

...

当您在vlc中打开音频文件时,没有任何播放(音频轨道时间戳丢失)。

我的项目的任务是简单地提取 pcm_alaw 数据并将其以mka格式包装在容器中。确定编解码器的最佳方法是使用av_guess_codec()函数,该函数依次自动选择所需的编解码器ID。但是,我不知道如何将原始数据正确打包到容器中。

请注意,我可以获取由RTP数据包类型( All类型的RTP数据包有效负载)。我所知道的是,在任何情况下,我都必须将音频数据打包在mka容器中

我还附加了我使用的代码(从this资源中借来):

audiogenerater.h

extern "C"
{
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswresample/swresample.h"
}

class AudioGenerater
{
public:

    AudioGenerater();
   ~AudioGenerater() = default;

    void generateAudioFileWithOptions(
            QString        fileName,QByteArray     pcmData,int            channel,int            bitRate,int            sampleRate,AVSampleFormat format);
            
private:

    // init Format
    bool initFormat(QString audioFileName);

private:

    AVCodec         *m_AudioCodec        = nullptr;
    AVCodecContext  *m_AudioCodecContext = nullptr;
    AVFormatContext *m_FormatContext     = nullptr;
    AVOutputFormat  *m_OutputFormat      = nullptr;
};

audiogenerater.cpp

AudioGenerater::AudioGenerater()
{
    av_register_all();
    avcodec_register_all();
}

AudioGenerater::~AudioGenerater()
{
    // ... 
}

bool AudioGenerater::initFormat(QString audioFileName)
{
    // Create an output Format context
    int result = avformat_alloc_output_context2(&m_FormatContext,nullptr,audioFileName.toLocal8Bit().data());
    if (result < 0) {
        return false;
    }

    m_OutputFormat = m_FormatContext->oformat;

    // Create an audio stream
    AVStream* audioStream = avformat_new_stream(m_FormatContext,m_AudioCodec);
    if (audioStream == nullptr) {
        avformat_free_context(m_FormatContext);
        return false;
    }

    // Set the parameters in the stream
    audioStream->id = m_FormatContext->nb_streams - 1;
    audioStream->time_base = { 1,8000 };
    result = avcodec_parameters_from_context(audioStream->codecpar,m_AudioCodecContext);
    if (result < 0) {
        avformat_free_context(m_FormatContext);
        return false;
    }

    // Print FormatContext information
    av_dump_format(m_FormatContext,audioFileName.toLocal8Bit().data(),1);

    // Open file IO
    if (!(m_OutputFormat->flags & AVFMT_NOFILE)) {
        result = avio_open(&m_FormatContext->pb,AVIO_FLAG_WRITE);
        if (result < 0) {
            avformat_free_context(m_FormatContext);
            return false;
        }
    }

    return true;
}

void AudioGenerater::generateAudioFileWithOptions(
    QString _fileName,QByteArray _pcmData,int _channel,int _bitRate,int _sampleRate,AVSampleFormat _format)
{
    AVFormatContext* oc;
    if (avformat_alloc_output_context2(
            &oc,_fileName.toStdString().c_str())
        < 0) {
        qDebug() << "Error in line: " << __LINE__;
        return;
    }
    if (!oc) {
        printf("Could not deduce output format from file extension: using mka.\n");
        avformat_alloc_output_context2(
            &oc,"mka",_fileName.toStdString().c_str());
    }
    if (!oc) {
        qDebug() << "Error in line: " << __LINE__;
        return;
    }
    AVOutputFormat* fmt = oc->oformat;
    if (fmt->audio_codec == AV_CODEC_ID_NONE) {
        qDebug() << "Error in line: " << __LINE__;
        return;
    }

    AVCodecID codecID = av_guess_codec(
        fmt,_fileName.toStdString().c_str(),AVMEDIA_TYPE_AUDIO);
    // Find Codec
    m_AudioCodec = avcodec_find_encoder(codecID);
    if (m_AudioCodec == nullptr) {
        qDebug() << "Error in line: " << __LINE__;
        return;
    }
    // Create an encoder context
    m_AudioCodecContext = avcodec_alloc_context3(m_AudioCodec);
    if (m_AudioCodecContext == nullptr) {
        qDebug() << "Error in line: " << __LINE__;
        return;
    }

    // Setting parameters
    m_AudioCodecContext->bit_rate = _bitRate;
    m_AudioCodecContext->sample_rate = _sampleRate;
    m_AudioCodecContext->sample_fmt = _format;
    m_AudioCodecContext->channels = _channel;

    m_AudioCodecContext->channel_layout = av_get_default_channel_layout(_channel);
    m_AudioCodecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

    // Turn on the encoder
    int result = avcodec_open2(m_AudioCodecContext,m_AudioCodec,nullptr);
    if (result < 0) {
        avcodec_free_context(&m_AudioCodecContext);
        if (m_FormatContext != nullptr)
            avformat_free_context(m_FormatContext);
        return;
    }

    // Create a package
    if (!initFormat(_fileName)) {
        avcodec_free_context(&m_AudioCodecContext);
        if (m_FormatContext != nullptr)
            avformat_free_context(m_FormatContext);
        return;
    }

    // write to the file header
    result = avformat_write_header(m_FormatContext,nullptr);
    if (result < 0) {
        avcodec_free_context(&m_AudioCodecContext);
        if (m_FormatContext != nullptr)
            avformat_free_context(m_FormatContext);
        return;
    }

    // Create Frame
    AVFrame* frame = av_frame_alloc();
    if (frame == nullptr) {
        avcodec_free_context(&m_AudioCodecContext);
        if (m_FormatContext != nullptr)
            avformat_free_context(m_FormatContext);
        return;
    }

    int nb_samples = 0;
    if (m_AudioCodecContext->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE) {
        nb_samples = 10000;
    }
    else {
        nb_samples = m_AudioCodecContext->frame_size;
    }

    // Set the parameters of the Frame
    frame->nb_samples = nb_samples;
    frame->format = m_AudioCodecContext->sample_fmt;
    frame->channel_layout = m_AudioCodecContext->channel_layout;

    // Apply for data memory
    result = av_frame_get_buffer(frame,0);
    if (result < 0) {
        av_frame_free(&frame);
        {
            avcodec_free_context(&m_AudioCodecContext);
            if (m_FormatContext != nullptr)
                avformat_free_context(m_FormatContext);
            return;
        }
    }

    // Set the Frame to be writable
    result = av_frame_make_writable(frame);
    if (result < 0) {
        av_frame_free(&frame);
        {
            avcodec_free_context(&m_AudioCodecContext);
            if (m_FormatContext != nullptr)
                avformat_free_context(m_FormatContext);
            return;
        }
    }

    int perFrameDataSize = frame->linesize[0];
    int count = _pcmData.size() / perFrameDataSize;
    bool needAddOne = false;
    if (_pcmData.size() % perFrameDataSize != 0) {
        count++;
        needAddOne = true;
    }

    int frameCount = 0;
    for (int i = 0; i < count; ++i) {
        // Create a Packet
        AVPacket* pkt = av_packet_alloc();
        if (pkt == nullptr) {
            avcodec_free_context(&m_AudioCodecContext);
            if (m_FormatContext != nullptr)
                avformat_free_context(m_FormatContext);
            return;
        }
        av_init_packet(pkt);

        if (i == count - 1)
            perFrameDataSize = _pcmData.size() % perFrameDataSize;

        // Synthesize WAV files
        memset(frame->data[0],perFrameDataSize);
        memcpy(frame->data[0],&(_pcmData.data()[perFrameDataSize * i]),perFrameDataSize);

        frame->pts = frameCount++;
        // send Frame
        result = avcodec_send_frame(m_AudioCodecContext,frame);
        if (result < 0)
            continue;

        // Receive the encoded Packet
        result = avcodec_receive_packet(m_AudioCodecContext,pkt);
        if (result < 0) {
            av_packet_free(&pkt);
            continue;
        }

        // write to file
        av_packet_rescale_ts(pkt,m_AudioCodecContext->time_base,m_FormatContext->streams[0]->time_base);
        pkt->stream_index = 0;
        result = av_interleaved_write_frame(m_FormatContext,pkt);
        if (result < 0)
            continue;

        av_packet_free(&pkt);
    }

    // write to the end of the file
    av_write_trailer(m_FormatContext);
    // Close file IO
    avio_closep(&m_FormatContext->pb);
    // Release Frame memory
    av_frame_free(&frame);

    avcodec_free_context(&m_AudioCodecContext);
    if (m_FormatContext != nullptr)
        avformat_free_context(m_FormatContext);
}

main.cpp

int main(int argc,char **argv)
{
    av_log_set_level(AV_LOG_TRACE);

    QFile file("rawDataOfPcmAlawType.bin");
    if (!file.open(QIODevice::ReadOnly)) {
        return EXIT_FAILURE;
    }
    QByteArray rawData(file.readAll());

    AudioGenerater generator;
    generator.generateAudioFileWithOptions(
               "test.mka",rawData,1,64000,8000,AV_SAMPLE_FMT_S16);

    return 0;
}

这是重要,您可以帮助我找到在pcm_alaw音频文件中录制MKA或其他数据格式的最合适方法。

我问每个知道什么都可以帮助的人(实施该项目的时间太少了)

解决方法

这些有用的链接将为您提供帮助:

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res