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

news2024/11/13 14:47:37

编码的大概流程见下图

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)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓ 

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

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

相关文章

NoSQL 数据建模错误会降低性能

数据建模错误是破坏性能的最简单方法之一。当您使用 NoSQL 时&#xff0c;特别容易搞砸&#xff0c;&#xff08;讽刺的是&#xff09;NoSQL 往往用于对性能最敏感的工作负载。NoSQL 数据建模最初可能看起来非常简单&#xff1a;只需对数据进行建模以适应应用程序的访问模式。但…

SAP 如何检查已安装的SAP UI5 版本

第一个方法是直接从FLP中查看 但是部分高版本的FLP中没有这个about&#xff0c; 那么在当前界面可以使用&#xff1a;CTRL ALT SHIFT S 查看当前版本 根据此版本&#xff0c;去进行你的UI5的开发吧

字符串函数-C语言

介绍 字符串函数&#xff0c;简单说&#xff0c;就是处理字符串的函数&#xff0c;头文件是string.h&#xff0c;以下是今天的讲解中会讲到的一系列字符串函数 头文件&#xff1a;#include<string.h>strlen&#xff1a;求字符串长度strcpy&#xff1a;拷贝字符串strcat&…

物联网实训室虚拟仿真软件建设方案

一、概述 物联网实训室虚拟仿真软件旨在紧密围绕立德树人的根本任务&#xff0c;充分依托先进的数字技术&#xff0c;并对接物联网行业的发展趋势和人才需求。通过对比真实企业工作环境&#xff0c;融合创新创业教育基因&#xff0c;秉承虚拟仿真技术与教育教学深度融合的理念&…

艺海泛舟——尹星从艺六十年作品展暨学术交流首展作品(二)

简历&#xff1a; 1944年1月25日出生于山西省阳高县&#xff0c;内蒙古师范学院艺术系美术专业&#xff0c;师从水彩之父李剑晨&#xff0c;北京京华美术学院创立者邱石冥&#xff0c;徐坚。与吴冠中&#xff0c;朱德群&#xff0c;赵无极&#xff0c;杨飞云是同门。擅长&…

解决CentOS下PHP system命令unoconv转PDF提示“Unable to connect or start own listener“

centos系统下&#xff0c;用php的system命令unoconv把word转pdf时提示Unable to connect or start own listene的解决办法 unoconv -o /foo/bar/public_html/upload/ -f pdf /foo/bar/public_html/upload/test.docx 2>&1 上面这个命令在shell 终端能执行成功&#xff0c…

优测云服务平台- 探索性测试策略分享

版权声明&#xff1a;本文作者 优测团队测试专家 郑凯泽 南明玮。 探索性测试是对常规的系统测试、新需求测试及专项测试的重要补充&#xff0c;往往能在短时间内发现更多的问题&#xff0c;一起来看看优测测试专家的分享吧~ 一、背景 优测团队长期承接腾讯社交产品、办公产…

​在做接口测试的时候,如果接口还没有开发好,你这边应该怎么去介入测试?

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

机械臂仿真之vrep如添加视觉传感器

基于视觉的机械臂作业任务&#xff0c;如何在vrep中加入视觉传感器&#xff0c;并获取画面&#xff1f;

【elementUI】el-tab相关问题

Tabs 标签页 分隔内容上有关联但属于不同类别的数据集合。 <template><el-tabs v-model"activeName" tab-click"handleClick"><el-tab-pane label"用户管理" name"first">用户管理</el-tab-pane><el-tab-p…

什么是云安全?如何制定云安全战略

云计算允许组织通过互联网按需向其客户、合作伙伴或员工提供关键业务应用程序、服务和资源&#xff0c;换句话说&#xff0c;不再需要物理维护资源&#xff0c;每当通过 Internet 从计算机访问文件或服务时&#xff0c;都是在访问云。 迁移到云可以帮助企业增强安全性、简化运…

zemax之初级像差理论与像差校正——球差

一、初级像差理论 1.1厚透镜初级像差 由于结构和机械强度的需要&#xff0c;任何光学透镜都具有一定厚度。对于正透镜其边缘厚度一般不应小于3mm&#xff1b;对于负透镜&#xff0c;中心厚度不应小于透镜孔径1/10~1/15&#xff0c;以防止安装和固定变形。 除此之外透镜的厚度…

为什么要在项目中使用TypeScript?

随着越来越多的开发人员采用TypeScript&#xff0c;人们需要了解在下一个项目中应该使用TypeScript的原因。尽管它在早期应用中遇到了一些阻力&#xff0c;但在过去十年&#xff0c;它迅速成为一种广泛使用的编程语言。 以下介绍如何使用TypeScript以及它给开发人员带来的一些好…

每日一练 | 华为认证真题练习Day140

1、如图所示&#xff0c;网络管理员希望将SWA与SWB之间的两条物理链路手工聚合成一条Eth-trunk链路&#xff1b;下列描述正确的是&#xff08;&#xff09;。 A. 不能被聚合 B. 聚合后可以正常工作 C. 可以聚合&#xff0c;聚合后只有GE端口能收发数据 D. 可以聚合&#xff…

选择合适的企业邮箱供应商的策略与技巧

如果您的公司是一个业务遍布全球的组织&#xff0c;选择合适的企业邮箱供应商将是一个重要的决策。 以下是在选择全球适用的企业邮箱供应商时应考虑的关键因素&#xff1a; 全球覆盖和数据中心位置&#xff1a;确保企业邮箱供应商在您业务遍及的国家和地区均具备良好的服务覆盖…

功能全面又强大的同步备份软件,你找到了吗?

随着企业规模的不断扩大&#xff0c;许多企业都会拥有自己的数据中心。因此每日员工都需要在服务器与服务中心之间调取文件&#xff0c;同时还需要对每日新增的业务数据进行实时同步。如果量比较小&#xff0c;一般问题不大&#xff1b;一旦数据比较大&#xff0c;量也比较大&a…

(Ant X6)子组件里的流程图画布无法显示

(Ant X6)子组件里的流程图画布无法显示 问题背景&#xff1a;侧导航页面都是子组件,建模页面的画布无法显示 解决前&#xff1a; 解决后&#xff1a; 解决思路&#xff1a;点击建模菜单时再次加载对应组件 在 Vue 中&#xff0c;每个组件都有一个唯一的 key 属性。当组件的 ke…

强化学习-DQN

网上看来很多&#xff0c;但是还是觉得这篇文章将得最好&#xff1a; 可视化强化学习解释 - Deep Q Networks&#xff0c;循序渐进 |Ketan Doshi 博客 (ketanhdoshi.github.io)

VirtualBox 7.0.8(虚拟机软件)

VirtualBox是一款开源的虚拟机软件&#xff0c;它是使用Qt编写&#xff0c;在Sun被Oracle收购后正式更名成Oracle VM VirtualBox。它可以在VirtualBox上安装并且执行Solaris、Windows、DOS、Linux、OS/2 Warp、BSD等系统作为客户端操作系统。使用者可以在VirtualBox上安装并且运…

Maven下载与安装教程

一、下载 Maven 进入 Maven 官网&#xff1a;maven.apache.org/download.cgi 选择 .zip 文件下载&#xff0c;最新版本是 3.9.5 二、安装 Maven 将 .zip 文件解压到没有中文没有空格的路径下。例如下图&#xff0c;在创建一个repository的空文件夹在他的下面&#xff0c;用于…