ffmpeg学习之音频解码数据

news2025/1/18 11:45:21

音频数据经过解码后会被保存为,pcm数据格式。而对应的处理流程如下所示。

avcodec_find_encoder() 

/**
 * 查找具有匹配编解码器ID的已注册编码器.
 *
 * @param id AVCodecID of the requested encoder
 * @return An encoder if one was found, NULL otherwise.
 */
const AVCodec *avcodec_find_encoder(enum AVCodecID id);

avcodec_find_encoder_by_name() 

/**
 * 查找具有指定名称的已注册编码器.
 *
 * @param name name of the requested encoder
 * @return An encoder if one was found, NULL otherwise.
 */
const AVCodec *avcodec_find_encoder_by_name(const char *name);

avcodec_alloc_context3() 

/**
分配AVCodecContext并将其字段设置为默认值。该应使用avcodec_free_context()释放结果结构。
 *
 * @param codec if non-NULL, allocate private data and initialize defaults
 *              for the given codec. It is illegal to then call avcodec_open2()
 *              with a different codec.
 *              If NULL, then the codec-specific defaults won't be initialized,
 *              which may result in suboptimal default settings (this is
 *              important mainly for encoders, e.g. libx264).
 *
 * @return An AVCodecContext filled with default values or NULL on failure.
 */
AVCodecContext *avcodec_alloc_context3(const AVCodec *codec);

 设置对应音频编码的数据类型

    codec_ctx->sample_fmt = AV_SAMPLE_FMT_S16;          //输入音频的采样大小
    codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO;    //输入音频的channel layout
    codec_ctx->channels = 2;                            //输入音频 channel 个数
    codec_ctx->sample_rate = 44100;                     //输入音频的采样率
    codec_ctx->bit_rate = 0; //AAC_LC: 128K, AAC HE: 64K, AAC HE V2: 32K
    codec_ctx->profile = FF_PROFILE_AAC_HE_V2; //阅读 ffmpeg 代码

设置编码的frame的相关参数

//set parameters
    frame->nb_samples     = 512;                //单通道一个音频帧的采样数
    frame->format         = AV_SAMPLE_FMT_S16;  //每个采样的大小
    frame->channel_layout = AV_CH_LAYOUT_STEREO; //channel layout

整个代码:

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
 extern "C"{
    
    
    #include <libavcodec/avcodec.h>
    #include <libavutil/channel_layout.h>
    #include <libavutil/common.h>
    #include <libavutil/frame.h>
    #include <libavutil/samplefmt.h>
 }

   

 
/* check that a given sample format is supported by the encoder */
static int check_sample_fmt(const AVCodec *codec, enum AVSampleFormat sample_fmt)
{
    const enum AVSampleFormat *p = codec->sample_fmts;
 
    while (*p != AV_SAMPLE_FMT_NONE) {
        if (*p == sample_fmt)
            return 1;
        p++;
    }
    return 0;
}
 
/* just pick the highest supported samplerate */
static int select_sample_rate(const AVCodec *codec)
{
    const int *p;
    int best_samplerate = 0;
 
    if (!codec->supported_samplerates)
        return 44100;
 
    p = codec->supported_samplerates;
    while (*p) {
        if (!best_samplerate || abs(44100 - *p) < abs(44100 - best_samplerate))
            best_samplerate = *p;
        p++;
    }
    return best_samplerate;
}
 
/* select layout with the highest channel count */
static int select_channel_layout(const AVCodec *codec, AVChannelLayout *dst){

    const AVChannelLayout *p, *best_ch_layout;
    int best_nb_channels   = 0;
 
    if (!codec->ch_layouts){
        AVChannelLayout src = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO;
        return av_channel_layout_copy(dst,&src);
    }
      
 
    p = codec->ch_layouts;
    while (p->nb_channels) {
        int nb_channels = p->nb_channels;
 
        if (nb_channels > best_nb_channels) {
            best_ch_layout   = p;
            best_nb_channels = nb_channels;
        }
        p++;
    }
    return av_channel_layout_copy(dst, best_ch_layout);
}
 
static void encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *pkt,
                   FILE *output)
{
    int ret;
 
    /* send the frame for encoding */
    ret = avcodec_send_frame(ctx, frame);
    if (ret < 0) {
        fprintf(stderr, "Error sending the frame to the encoder\n");
        exit(1);
    }
 
    /* read all the available output packets (in general there may be any
     * number of them */
    while (ret >= 0) {
        ret = avcodec_receive_packet(ctx, pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
            return;
        else if (ret < 0) {
            fprintf(stderr, "Error encoding audio frame\n");
            exit(1);
        }
 
        fwrite(pkt->data, 1, pkt->size, output);
        av_packet_unref(pkt);
    }
}
 
int main(int argc, char **argv)
{
    // 对应文件的编码数据
    const char *filename;

    // 编码器
    const AVCodec *codec;

    // 编码器上下文
    AVCodecContext *c= NULL;

    // 保存未曾解码的数据
    AVFrame *frame;
    // 对应的保存数据
    AVPacket *pkt;
    int i, j, k, ret;
    FILE *f;
    uint16_t *samples;
    float t, tincr;
 
    if (argc <= 1) {
        fprintf(stderr, "Usage: %s <output file>\n", argv[0]);
        return 0;
    }
    // 获得输出文件
    filename = argv[1];
 
    // 找到对应的编码器
    codec = avcodec_find_encoder(AV_CODEC_ID_MP2);
    if (!codec) {
        fprintf(stderr, "Codec not found\n");
        exit(1);
    }
    // 使用默认值设置编码器的内容数据
    c = avcodec_alloc_context3(codec);
    if (!c) {
        fprintf(stderr, "Could not allocate audio codec context\n");
        exit(1);
    }
 
    // 设置编码器的相关信息
    // 设置编码器的比特率
    c->bit_rate = 64000;
 
    // /采样的数据类型
    c->sample_fmt = AV_SAMPLE_FMT_S16;
    if (!check_sample_fmt(codec, c->sample_fmt)) {
        fprintf(stderr, "Encoder does not support sample format %s",
                av_get_sample_fmt_name(c->sample_fmt));
        exit(1);
    }
 
    // 对应的采样频率
    c->sample_rate    = select_sample_rate(codec);
    // 设置对应布局
    ret = select_channel_layout(codec, &c->ch_layout);
    if (ret < 0)
        exit(1);
 
    // 打开对应的编码器
    if (avcodec_open2(c, codec, NULL) < 0) {
        fprintf(stderr, "Could not open codec\n");
        exit(1);
    }
 
    f = fopen(filename, "wb");
    if (!f) {
        fprintf(stderr, "Could not open %s\n", filename);
        exit(1);
    }
 
    /* packet for holding encoded output */
    pkt = av_packet_alloc();
    if (!pkt) {
        fprintf(stderr, "could not allocate the packet\n");
        exit(1);
    }
 
    /* frame containing input raw audio */
    frame = av_frame_alloc();
    if (!frame) {
        fprintf(stderr, "Could not allocate audio frame\n");
        exit(1);
    }
    // 设置单通道数据采样大小
    frame->nb_samples     = c->frame_size;
    // 数据采样的大小
    frame->format         = c->sample_fmt;
    // 设置对用的通道大小
    ret = av_channel_layout_copy(&frame->ch_layout, &c->ch_layout);
    if (ret < 0)
        exit(1);
 
    /* 设置对应数据的缓冲区 */
    ret = av_frame_get_buffer(frame, 0);
    if (ret < 0) {
        fprintf(stderr, "Could not allocate audio data buffers\n");
        exit(1);
    }
 
    /* encode a single tone sound */
    t = 0;
    tincr = 2 * M_PI * 440.0 / c->sample_rate;
    for (i = 0; i < 200; i++) {
        /* make sure the frame is writable -- makes a copy if the encoder
         * kept a reference internally */
        ret = av_frame_make_writable(frame);
        if (ret < 0)
            exit(1);
        samples = (uint16_t*)frame->data[0];
 
        for (j = 0; j < c->frame_size; j++) {
            samples[2*j] = (int)(sin(t) * 10000);
 
            for (k = 1; k < c->ch_layout.nb_channels; k++)
                samples[2*j + k] = samples[2*j];
            t += tincr;
        }
        encode(c, frame, pkt, f);
    }
 
    /* flush the encoder */
    encode(c, NULL, pkt, f);
 
    fclose(f);
 
    av_frame_free(&frame);
    av_packet_free(&pkt);
    avcodec_free_context(&c);
 
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/768916.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C# 移除链表元素

203 移除链表元素 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,6,3,4,5,6], val 6 输出&#xff1a;[1,2,3,4,5] 示例 2&#x…

机器学习(14)--XGBoost

目录 一、概述 二、CART、GB、GBDT 1、CART 2、BT&#xff08;Boosting Tree提升树&#xff09; 3、GBDT&#xff08;梯度提升树&#xff09; 4、GBDT在sklearn中的损失函数 三、Sklearn中的GBDT 1、加载模块 2、划分数据集 3、建模 4、与随机森林和线性回归对比 5…

Redis可视化工具 - Another Redis Desktop Manager 安装与使用详细步骤

一、下载安装 Another Redis Desktop Manager AnotherRedisDesktopManager 发行版 - Gitee.com&#xff08;gitee&#xff09; 2. 安装 以管理员身份运行下载的安装包 选择是为所有用户还是当前用户安装&#xff0c;按需选择 选择安装位置&#xff0c;点击安装进行安装 安装…

uni-app实现emoj表情包发送(nvue版)

uni-app实现表情包发送&#xff0c; vue实现思路直接使用grideview网格布局加载emoj表情包即可实现&#xff0c;很简单&#xff0c;但是nvue稍微复杂&#xff0c;这里采用的方案是nvue提供的组件list 看效果 代码 <template><view style"margin-right: 10rpx;m…

跨项目实时通信——Broadcast Channel

一、背景 在日常开发中&#xff0c;肯定会遇到一些需要跨项目实时通信的场景。比如在浏览器中新开两个tab页面&#xff0c;A页面发送消息后&#xff0c;B页面实时监听并触发某些动作。类似的需求有很多&#xff0c;比如实时共享状态等等。那么跨项目/页面/浏览器tab的情况下如…

7.17~7.18

当端口冲突&#xff0c;可以查看&#xff1a;cmd然后输入以下命令 URL包括协议&#xff0c;域名&#xff0c;端口号&#xff0c;文件名&#xff1a; public class netProgramme {//定位一个节点public static void main(String[]args) throws UnknownHostException, Malformed…

flutter开发实战-svga播放svgaplayer_flutter直播礼物特效等效果使用

flutter开发实战-svga播放svgaplayer_flutter直播礼物特效等效果使用 最近开发过程中用到了SVGA进行播放动画&#xff0c;这里记录一下svgaplayer_flutter使用过程。svga可以做一些非常精美的动画&#xff0c;包括直播的刷礼物(火箭、跑车特效动画)等等。 效果图如下 一、SVG…

ACL2023论文-系列1

文章目录 Prompt——1.Generated Knowledge Prompting for Commonsense Reasoning核心论文贡献方法效果的影响因素方法实现 Contrastive learning——A Contrastive Framework for Learning Sentence Representations from Pairwise and Triple-wise Perspective in Angular Sp…

【深度学习笔记】梯度消失与梯度爆炸

本专栏是网易云课堂人工智能课程《神经网络与深度学习》的学习笔记&#xff0c;视频由网易云课堂与 deeplearning.ai 联合出品&#xff0c;主讲人是吴恩达 Andrew Ng 教授。感兴趣的网友可以观看网易云课堂的视频进行深入学习&#xff0c;视频的链接如下&#xff1a; 神经网络和…

labview 子画面插入面板

1.前言 在前面一篇文章中描述了弹框式显示子画面&#xff0c; labview 弹窗(子vi)_weixin_39926429的博客-CSDN博客 本文介绍插入式显示子画面。 本文的主题在以前的文章中介绍过&#xff0c; labview 插入子面板_labview插入子面板_weixin_39926429的博客-CSDN博客 借用…

JVM学习笔记总结

目录 JVM内存区域划分 1、堆&#xff08;线程共享&#xff09; 2、方法区&#xff08;线程共享&#xff09; 3、栈&#xff08;线程私有&#xff09; 4、程序计数器&#xff08;线程私有&#xff09; JVM类加载机制 加载 验证 准备 解析 初始化 双亲委派模型 JVM垃…

入门力扣自学笔记276 C++ (题目编号:874)

874. 模拟行走机器人 题目&#xff1a; 机器人在一个无限大小的 XY 网格平面上行走&#xff0c;从点 (0, 0) 处开始出发&#xff0c;面向北方。该机器人可以接收以下三种类型的命令 commands &#xff1a; -2 &#xff1a;向左转 90 度 -1 &#xff1a;向右转 90 度 1 < …

【数据库高阶语句】

文章目录 MySQL高阶语句一、常用查询1、按关键字排序 二、实操1.创建表2.排序查询&#xff08;默认不指定是升序排序&#xff0c;后面跟desc是降序排序&#xff09;3.order by还可以结合where进行条件过滤&#xff0c;筛选地址是杭州的学生按分数降序排列4.查询学生信息先按兴趣…

走访慰问空巢老人,连接传递浓浓温情

为了弘扬中华民族尊老、敬老、爱老的优良传统&#xff0c;让老人们感受到政府和社会的温暖&#xff0c;在“端午”来临之际&#xff0c;思南县青年志愿者协会联合思南县民慈社会工作服务中心、思南县小荧星幼儿园、思南县小英豪幼儿园到大河坝镇天坝村开展“走访慰问空巢老人&a…

阿里云短信服务API怎么调用

今天来搞一下阿里云短信服务来实现发送短信功能&#xff0c;其实能提供短信发送服务的平台有很多&#xff0c;但这里我选择的是阿里云&#xff0c;因为阿里云的示例还有代码封装的很简洁&#xff0c;使用起来非常简单&#xff0c;上手非常快&#xff0c;那么费话不多说我们直接…

Python案例|使用卷积网络对星系图片进行分类

星系动物园&#xff08;galaxy zoo&#xff09;是由牛津大学等研究机构组织并邀请公众协助的志愿者科学计划&#xff0c;目的是为超过100万个星系图像进行分类。这是天文学中一次规模浩大的公众星空普查活动&#xff0c;大众参与热情高涨&#xff0c;在近十万名志愿者的积极参与…

libevent:windows环境配置+QT使用

目录 libevent是什么 编译 QT使用 测试代码 libevent是什么 Fast portable non-blocking network programming with Libevent http://www.wangafu.net/~nickm/libevent-book/TOC.html 这篇文档讲的很清楚&#xff0c;尤其是Chapter 1: A tiny introduction to asynchro…

c++11 标准模板(STL)(std::basic_istream)(十二)

定义于头文件 <istream> template< class CharT, class Traits std::char_traits<CharT> > class basic_istream : virtual public std::basic_ios<CharT, Traits> 类模板 basic_istream 提供字符流上的高层输入支持。受支持操作包含带格式的…

【C++】vector 模拟笔记

文章目录 成员变量和迭代器reserve()函数易错点迭代器区间初始化易错点迭代器失效整体代码 成员变量和迭代器 下面有vector 存储示意图&#xff1a;vector 是一个左闭又开的空间&#xff0c;_finish 不能存储有效数据。vector 的 iterator 是T 类型的指针&#xff0c;不要认为 …

Python自动获取字母站视频

如果有疑问的话可以在我的谈论群&#xff1a;706128290 来找我 目录 前言 二、编写代码 1.引入库 2.编写主类 3. 自动获取cookies值和生成headers 4.获取命令行参数 运行效果 前言 browser_cookie3 第三方模块 browser_cookie3是browser_cookie模块的分支&#xff0c;…