音视频开发:音频fdk-aac编码

编码的大概流程见下图

1.获取编码器: avcodec_find_encoder_by_name("libfdk_aac")

2.检查PCM格式是否被编码器支持

3.创建编码上下文: AVCodecContext *ctx = avcodec_alloc_context3(codec)

4.给上下文设置参数

5.打开编码器: avcodec_open2

6.创建AVFrame: av_frame_alloc

7.创建AVPacket: av_packet_alloc

8.打开文件

9.读取数据,放入AVFrame

10.把AVFrame数据放入编码器: avcodec_send_frame

11.从编码器中获取编码好的数据并放入AVPacket: avcodec_receive_packet

12.写入文件

13.全部读完以后刷新缓冲区

14.释放资源

话不多说,上代码

#include <libavutil/samplefmt.h>
#include <libavcodec/avcodec.h>

typedef struct {

    NSString *filePath;

    int sampleRate;

    enum AVSampleFormat sampleFmt;

    int chLayout;

} AudioEncodeSpec;

//检查编码器是否支持当前采样格式
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;

}

//音频编码
static int encode(AVCodecContext *ctx,

                  AVFrame *frame,

                  AVPacket *pkt,

                  NSFileHandle *writeHandle) {

    int ret = avcodec_send_frame(ctx, frame);

    if (ret < 0) {

        NSLog(@"avcodec_send_frame error");

        return ret;

    }

    //不断从编码器取出编码后的数据

    while (true) {

        ret = avcodec_receive_packet(ctx, pkt);

        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {

            //继续读取数据

            return 0;

        } else if (ret < 0) {//其它

            return ret;

        }

        [writeHandle seekToEndOfFile];

        [writeHandle writeData:[NSData dataWithBytes:pkt->data length:pkt->size]];

        //释放

        av_packet_unref(pkt);

    }

}

+ (void)aacEncode:(AudioEncodeSpec)spec outFilename:(NSString *)outFilename
{

    //返回结果

    int ret = 0;

    //编码器

    AVCodec *codec = avcodec_find_encoder_by_name("libfdk_aac");

    if (!codec) {

        NSLog(@"找不到编码器");

        return;

    }
    //检查输入格式是否支持,fdk-aac只支持16位整数

    if (!check_sample_fmt(codec, spec.sampleFmt)) {

        NSLog(@"采样格式不支持");

        return;

    }

    //编码上下文

    AVCodecContext *ctx = avcodec_alloc_context3(codec);

    if (!ctx) {

        NSLog(@"编码上下文创建失败");

        return;

    }

    //设置PCM参数

    ctx->sample_rate = spec.sampleRate;

    ctx->sample_fmt = spec.sampleFmt;

    ctx->channel_layout = spec.chLayout;

    //固定比特率

    ctx->bit_rate = 44100;

    //规格

    ctx->profile = FF_PROFILE_AAC_HE;

    //打开编码器

    ret = avcodec_open2(ctx, codec, NULL);

    if (ret < 0) {

        NSLog(@"打开编码器失败");

        avcodec_free_context(&ctx);

        return;

    }

    

    //存放编码前的数据

    AVFrame *frame = av_frame_alloc();

    if (!frame) {

        NSLog(@"av_frame_alloc error");

        avcodec_free_context(&ctx);

        return;

    }

    //frame缓冲区的样本帧数量

    frame->nb_samples = ctx->frame_size;

    //采样格式

    frame->format = ctx->sample_fmt;

    //声道布局

    frame->channel_layout = ctx->channel_layout;

    

    //创建缓冲区

    ret = av_frame_get_buffer(frame, 0);

    if (ret < 0) {

        NSLog(@"av_frame_get_buffer error");

        avcodec_free_context(&ctx);

        av_frame_free(&frame);

        return;

    }

    //存放编码后的数据

    AVPacket *pkt = av_packet_alloc();

    if (!pkt) {

        NSLog(@"av_packet_alloc error");

        avcodec_free_context(&ctx);

        av_frame_free(&frame);

        return;

    }


    //创建输出的文件

    NSString *outFilePath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:outFilename];

    NSFileManager *writeManager = [NSFileManager defaultManager];

    if ([writeManager fileExistsAtPath:outFilePath]) {

        [writeManager removeItemAtPath:outFilePath error:nil];

    }

    [writeManager createFileAtPath:outFilePath contents:nil attributes:nil];

    NSFileHandle *writeHandle = [NSFileHandle fileHandleForWritingAtPath:outFilePath];

    

    //打开输入文件

    NSFileHandle *readHandle = [NSFileHandle fileHandleForReadingAtPath:spec.filePath];

    [readHandle seekToFileOffset:0];

    

    NSData *readData = [readHandle readDataOfLength:frame->linesize[0]];

    int len = (int)[readData length];

    frame->data[0] = (uint8_t *)[readData bytes];

    while (len > 0) {

        //从文件中读取的数据,不足以填充frame缓冲区

        if (len < frame->linesize[0]) {

            int bytes = av_get_bytes_per_sample(frame->format);

            int ch = av_get_channel_layout_nb_channels(frame->channel_layout);

            //设置真正有效的样本帧数量

            frame->nb_samples = ret / (bytes * ch);

        }

        if (encode(ctx, frame, pkt, writeHandle) < 0) {

            break;

        }

        readData = [readHandle readDataOfLength:frame->linesize[0]];

        frame->data[0] = (uint8_t *)[readData bytes];

        len = (int)[readData length];

    }

    //刷新缓冲区

    encode(ctx, NULL, pkt, writeHandle);

    //释放资源

    [readHandle closeFile];

    [writeHandle closeFile];

    av_frame_free(&frame);

    av_packet_free(&pkt);

    avcodec_free_context(&ctx);           

    NSLog(@"faac编码完成");

}

本文福利, 免费领取C++音视频学习资料包+学习路线大纲、技术视频/代码,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,编解码,推拉流,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓ 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

GPT-4 惨遭削弱;拼多多市值一度超阿里;雷军回应个人向武汉大学捐款 13 亿元丨 RTE 开发者日报 Vol.96

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE &#xff08;Real Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有…

【VScode】超详细图片讲解下载安装、环境配置、编译执行、调试

这里是目录 VScode是什么&#xff1f;VScode的下载和安装环境介绍安装中文插件 配置VScodeC/C开发环境下载和配置MinGW-w64 编译器套件下载&#xff1a;配置&#xff1a; 安装C/C插件在VScode上编写代码设置C/C编译选项创建执行任务编译执行如果想写其他代码在同一个文件夹在不…

【性能测试】性能测试监控关键指标

系统指标 检测性能测试是否有bug的关键指标 1、系统指标——与用户场景及需求直接相关。 并发用户数&#xff1a;某一物理时刻同时向系统提交请求的用户数。平均响应时间&#xff1a;系统处理事务的响应时间的平均值&#xff0c;对于系统快速响应类页面&#xff0c;一般响应…

vue.js ——Vuex

基本概念 vue进行开发过程中有没有遇到这样一种场景&#xff0c;就是有些时候一些数据是一种通用的共享数据&#xff08;比如登录信息&#xff09;&#xff0c;那么这类数据在各个组件模块中可能都会用到&#xff0c;如果每个组件中都去后台重新获取那么势必会造成性能浪费&am…

Linux介绍

文章目录 前言一、概述 前言 Linux学习笔记。 一、概述 linux怎么读,不下10种 linux是一个开源、免费的操作系统&#xff0c;其稳定性、安全性、处理多并发已经得到业界的认可&#xff0c;目前很多企业级的项目(c/c/php/python/java/go)都会部署到Linux/unix系统上。 常见的…

每日一练2023.11.30——谁先倒【PTA】

题目链接&#xff1a;谁先倒 题目要求&#xff1a; 划拳是古老中国酒文化的一个有趣的组成部分。酒桌上两人划拳的方法为&#xff1a;每人口中喊出一个数字&#xff0c;同时用手比划出一个数字。如果谁比划出的数字正好等于两人喊出的数字之和&#xff0c;谁就输了&#xff0…

『OPEN3D』1.8.1 ICP配准

a目录 1、点到点&#xff08;point2point&#xff09;的配准 2、 点到面&#xff08;point2plane&#xff09;的配准 3、基于颜色的配准(color-icp) 4、点云配准核函数(robust kernel) 前面已经介绍过点云配准的基础理论内容&#xff0c;可以查看之前的文章&#xff1a; 『…

Unity Canvas、Canvas Scaler、Graphic Raycaster、EventSystem 组件详解

文章目录 0. 参考文章1. Canvas1.1 Screen Space-Overlay —— 屏幕空间覆盖模式1.2 Screen Space-Camera —— 相机模式1.3 World Space —— 世界模式 2. Canvas Scaler&#xff1a;控制UI画布的放大缩放的比例2.1 Constant Pixer Size —— 恒定像素2.2 Scale With Screen S…

98.套接字-Socket网络编程1(基础概念)

目录 1.局域网和广域网 2.IP 互联网协议(Internet Protocol) IP的作用 3.查看IP地址 Windows上查看IP ​编辑 Linux上查看IP 4.端口 主要类型&#xff1a; 用途&#xff1a; 示例&#xff1a; 端口的表示&#xff1a; 5.OSI/ISO 网络分层模型 1.局域网和广域网 …

2021年6月3日 Go生态洞察:Fuzzing技术的Beta测试

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

哪吒汽车拔头筹,造车新势力首家泰国工厂投产

中国造车新势力首家泰国工厂投产&#xff01;11月30日&#xff0c;哪吒汽车位于泰国的首家海外工厂——泰国生态智慧工厂正式投产下线新车&#xff0c;哪吒汽车联合创始人兼CEO张勇、哪吒汽车泰国合作伙伴BGAC公司首席执行官万查曾颂翁蓬素等出席仪式。首辆“泰国制造”的哪吒汽…

【Java Web学习笔记】0 - 技术体系的说明

B/S软件开发架构简述 B/S架构 1.B/S框架&#xff0c;意思是前端(Browser浏览器)和服务器端( Server )组成的系统的框架结构。 2. B/S架构也可理解为web架构&#xff0c;包含前端、后端、数据库三大组成部分。 3.示意图 ●前端 前端开发技术工具包括三要素: HTML、CSS和Jav…

基于SpringBoot母婴商城

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本母婴商城系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息&am…

零基础学编程系列,看一下具体中文编程代码是什么样子的

零基础学编程系列&#xff0c;看一下具体中文编程代码是什么样子的 上图 编写一个单选的程序 上图 是单选 按钮的中文编程代码 附&#xff1a;中文编程工具构件工具箱总共22组305个构件&#xff0c;构件明细如下&#xff1a; 文本件16个&#xff1a; &#xff08;普通标签&am…

使用 kubeadm 部署 Kubernetes 集群(一)linux环境准备

一、 初始化集群环境 准备三台 rocky8.8 操作系统的 linux 机器。每台机器配置&#xff1a;4VCPU/4G 内存/60G 硬盘 环境说明&#xff1a; IP 主机名 角色 内存 cpu 192.168.1.63 xuegod63 master 4G 4vCPU 192.168.1.64 xuegod64 worker 4G 4vCPU 192.168.1.62 xuegod62 work…

iptables防火墙之SNAT与DNET

NAT 1.SNAT&#xff1a;让内网可以访问外网 2.DNAT&#xff1a;让外网可以访问到内网的机器 网关服务器&#xff0c;要开启路由功能 内核功能&#xff1a; sysctl -a 列出所有参数 内核参数&#xff0c;然后grep可以查看到默认的内核参数 内核参数配置文件 /etc/sysctl.…

CANDENCE: PCB 中 元器件对齐

PCB 中 元器件对齐 以下面的几个电阻为例&#xff1a; step1&#xff1a;选择以下工具 step2&#xff1a;选中要对齐的器件&#xff0c;右键 Align Components 选择你想要的对齐方式即可

沿着马可·波罗的足迹,看数字云南

刚入行的时候&#xff0c;有位前辈跟我说过一句话&#xff1a;去现场“要像外国人一样去看”&#xff0c;重新审视那些自己可能早已“熟视无睹”的事物。 前不久&#xff0c;我跟随“看见数字云南——云南数字经济媒体探营活动”&#xff0c;奔赴昆明、大理、西双版纳等地&…

键入网址到网页显示,期间发生了什么?(计算机网络)

浏览器首先会对URL进行解析 下面以http://www.server.com/dir1/file1.html为例 当没有路径名时&#xff0c;就代表访问根目录下事先设置的默认文件&#xff0c;也就是 /index.html 或者 /default.html 对URL进行解析之后&#xff0c;浏览器确定了 Web 服务器和文件名&#x…

MySQL之binlog日志

聊聊BINLOG binlog记录什么&#xff1f; MySQL server中所有的搜索引擎发生了更新&#xff08;DDL和DML&#xff09;都会产生binlog日志&#xff0c;记录的是语句的原始逻辑 为什么需要binlog&#xff1f; binlog主要有两个应用场景&#xff0c;一是数据复制&#xff0c;在…