当前位置: 首页 > news >正文

FFMPEG4.0 音频解码解封装

FFMPEG 4.0 for Android 准备工作

下面的函数方法基于最新的FFMPEG 4.0(4.X):

音频的原始数据是pcm编码,关于PCM编码的相关信息请看这篇文章:https://www.jianshu.com/p/cfb3d4dc3676

本文的解码就是要把原始文件中的音频部分提取出来解码生成PCM文件,以下是正文,将会去除逻辑相关代码,按照流程顺序用最基础的方法展现,方便大家掌握用法:

一、获取多媒体文件的信息
1.声明并分配内存格式信息的Context
avformat_context = avformat_alloc_context();
2.打开文件读取头信息
avformat_open_input(&avformat_context,src_name,NULL,NULL);其中avformat_context如果没有被声明分配内存,此方法会给分配。
3.某些格式没有头信息,需要读取数据来分析
avformat_find_stream_info(avformat_context,NULL);
二、解码设置
4.找到你想要的数据流,可用方法av_find_best_stream代替:

    int audio_stream_index = 0;
    //like av_find_best_stream
    for(i = 0;i<avformat_context->nb_streams;i++) {
        if(avformat_context->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
            audio_stream_index = i;
            av_log(NULL,AV_LOG_ERROR,"find audio stream index = %d\n",audio_stream_index);
            break;
        }
    }
    AVStream *stream = avformat_context->streams[audio_stream_index];

5.从数据流信息中得到×××信息,生成×××
codec = avcodec_find_decoder(stream-&gt;codecpar-&gt;codec_id);
6.声明解码Context。
codec_ctx = avcodec_alloc_context3(codec);
7.把stream信息中的参数拷贝到解码Context中。
ret = avcodec_parameters_to_context(codec_ctx,stream-&gt;codecpar);
8.打开×××
avcodec_open2(codec_ctx, codec, NULL);
三、进行数据流解封装解码
9.声明数据包packet与数据帧frame

    frame = av_frame_alloc();
    pkt = av_packet_alloc();

10.读取数据包
av_read_frame(avformat_context,pkt)
11.发送数据包
avcodec_send_packet(codec_ctx,pkt);
12.接收解码后的数据帧,需要注意的是一个数据包可能解压出多个数据帧,所以需要循环读取
avcodec_receive_frame(codec_ctx,frame)//读取一帧
一个packet的解码范例:

    while((ret = avcodec_receive_frame(codec_ctx,frame)) >= 0) {
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
            return;
        int data_size = av_get_bytes_per_sample(codec_ctx->sample_fmt);
        LOGV("data_size = %d,line0 = %d,codec_ctx->channels = %d\n",data_size * frame->nb_samples,frame->linesize[0],codec_ctx->channels);
        int i,ch = 0;
        for(i = 0;i<frame->nb_samples;i++)
        {
            for(ch = 0;ch<codec_ctx->channels;ch++)
            {
                fwrite(frame->extended_data[ch] + data_size*i,1,data_size,outfile);
            }
        }
    }

13.每种采样格式的数据大小都是固定的
int data_size = av_get_bytes_per_sample(codec_ctx->sample_fmt);得到的是此格式每个采样的字节大小。
frame->linesize[0]内存储的是frame单声道的字节大小,=data_size*frame->nb_samples
14.解码得到的每帧数据都有多个样本,每帧数据可能有多个通道
//下面的代码针对的是planar类型格式。

        for(i = 0;i<frame->nb_samples;i++)
        {
            for(ch = 0;ch<codec_ctx->channels;ch++)
            {
                fwrite(frame->extended_data[ch] + data_size*i,1,data_size,outfile);
            }
        }

音频格式存储分为两种类型,分别为packed和planar,区别为格式后面是否带p
带P和不带P的数据类型的区别:

P表示Planar(平面),声道分开存放。其数据格式排列方式为 :*
LLLLLLRRRRRRLLLLLLRRRRRRLLLLLLRRRRRRL...(每个LLLLLLRRRRRR为一个音频帧)
而不带P的数据格式(即交错排列)排列方式为:
LRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRL...(每个LR为一个音频样本)

目前的音频一般是planar格式,packed格式的数据存在一列之中,左右声道交替存放。
planar格式声道的数据存在各自的数组中,生成PCM文件时需要注意左右声道加起来才是一个完整的采样点。
对于音频,使用extended_data,data注意是给视频用的,虽然单纯的音频文件在声道较少时也是能用的,但是官方不推荐用。

转载于:https://blog.51cto.com/4095821/2402550

相关文章:

  • python 基础使用list、dict、set、可变与不可变对象
  • Nginx 400错误研究
  • JavaScript函数使用知识点回顾
  • Unity移动端实时阴影绘制
  • 6.2docker(二)
  • jsp直接返回验证码
  • iis7负载均衡
  • 目录服务不能与此服务器复制,因为距上一次与此服务器复制的时间已经超过了 tombstone 生存时间。...
  • linux命令 route
  • 基于 HTML5 WebGL 的 3D 场景中的灯光效果
  • httptomcat
  • MySQL常用命令(转)
  • Head Html Css 第二版笔记
  • 比较快速排序,冒泡排序,双向冒泡排序的执行效率
  • 如何在vue-cli 3.x中使用jquery
  • 【108天】Java——《Head First Java》笔记(第1-4章)
  • CSS盒模型深入
  • github指令
  • JavaScript设计模式之工厂模式
  • Js基础知识(一) - 变量
  • mongodb--安装和初步使用教程
  • MQ框架的比较
  • MyEclipse 8.0 GA 搭建 Struts2 + Spring2 + Hibernate3 (测试)
  • Odoo domain写法及运用
  • python学习笔记-类对象的信息
  • 阿里云Kubernetes容器服务上体验Knative
  • 力扣(LeetCode)56
  • 买一台 iPhone X,还是创建一家未来的独角兽?
  • 爬虫模拟登陆 SegmentFault
  • 浅谈web中前端模板引擎的使用
  • 手机端车牌号码键盘的vue组件
  • 由插件封装引出的一丢丢思考
  • 正则表达式-基础知识Review
  • ​LeetCode解法汇总2808. 使循环数组所有元素相等的最少秒数
  • ​ubuntu下安装kvm虚拟机
  • (2020)Java后端开发----(面试题和笔试题)
  • (超详细)语音信号处理之特征提取
  • (附源码)springboot 个人网页的网站 毕业设计031623
  • (七)Knockout 创建自定义绑定
  • (四)docker:为mysql和java jar运行环境创建同一网络,容器互联
  • (续)使用Django搭建一个完整的项目(Centos7+Nginx)
  • (一)eclipse Dynamic web project 工程目录以及文件路径问题
  • (一)使用IDEA创建Maven项目和Maven使用入门(配图详解)
  • (转)VC++中ondraw在什么时候调用的
  • (转)大型网站架构演变和知识体系
  • **PHP分步表单提交思路(分页表单提交)
  • ./mysql.server: 没有那个文件或目录_Linux下安装MySQL出现“ls: /var/lib/mysql/*.pid: 没有那个文件或目录”...
  • .bat批处理(七):PC端从手机内复制文件到本地
  • .net MVC中使用angularJs刷新页面数据列表
  • .NET 使用 XPath 来读写 XML 文件
  • .NET3.5下用Lambda简化跨线程访问窗体控件,避免繁复的delegate,Invoke(转)
  • .net6解除文件上传限制。Multipart body length limit 16384 exceeded
  • .NET关于 跳过SSL中遇到的问题
  • .NET是什么
  • .NET项目中存在多个web.config文件时的加载顺序