----------------------------------------
date: 2022-04-01
author:hjjdebug
----------------------------------------

decode_audio.c 解读
----------------------------------------
decode_audio, 它能把一个音频编码文件解出成原始音频数据,并写到文件中.
原始音频数据怎样播放? 您可以用ffplay, 但要传递给它参数,见后.
下面演示了如何从文件中读取,分析和写入文件的过程.
1.  pkt = av_packet_alloc(); //分配一个包

2.  codec = avcodec_find_decoder(AV_CODEC_ID_AAC); //查找一种codec
3.  c = avcodec_alloc_context3(codec); 为某codec 分配一个上下文
4.  if (avcodec_open2(c, codec, NULL) < 0)  ; // 打开codec
5. 打开输入文件和输出文件
    f = fopen(filename, "rb");
    outfile = fopen(outfilename, "wb");

6. if (!(decoded_frame = av_frame_alloc()))  //分配一个frame   
    
7. 读数据到缓存
    data_size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
    AUDIO_INBUF_SIZE 可是20480, 缓存不小!
    读到了20480数据,现在开始分析它.

8.  parser = av_parser_init(codec->id); //初始化parser, 针对某种codec的parser
9.  ret = av_parser_parse2(parser, codec_ctx, &pkt->data, &pkt->size,
                               data, data_size,
                               AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
    输入参数:数据指针(data),数据大小(data_size)
    输出参数:pkt->data, pkt->size  //数据被分析到packet 中
    其它参数:parser context, codec context, 均为输入参数.
    返回值, 对aac 来讲返回固定的928 长度.
    即每次分析928字节进入pkt,然后把data指针和data_size进行调整以便继续后续分析

10. decode(c, pkt, decoded_frame, outfile);
    解码pkt 到decoded_frame 并写入outfile, 这是用户的代码了. 不过还是要调用ffmpeg 接口.
    具体如下:

11. 解码过程,发送包,收获frame .
    ret = avcodec_send_packet(dec_ctx, pkt);
   ret = avcodec_receive_frame(dec_ctx, frame);
   send_packet, receive_frame 将压缩包经codec 解开到 frame.
    然后: 获取采样点的大小.(由sample format 得到)
     data_size = av_get_bytes_per_sample(dec_ctx->sample_fmt);
    将frame 解出的原始数据写到文件.
        for (i = 0; i < frame->nb_samples; i++)
            for (ch = 0; ch < dec_ctx->channels; ch++)
                fwrite(frame->data[ch] + data_size*i, 1, data_size, outfile);

//frame 中包含几个channel的数据,由dec_ctx->channel 确定, 目前能支持到8个通道
//每个采用点的大小(data_size), 由采样格式确定 dec_ctx->sample_fmt
//而frame->nb_samples, 当然也是从dec_ctx中获取的,保存到frame 结构中了。
如此即可将解出的frame各channel数据交错写到输出文件中了.

12. 当缓冲的数据小于4096时,再从文件继续读数据塞满缓冲区, 直到data_size 消耗为0,解码完毕.

13     要想播放这个原始数据音频文件,需要记录下它的数据格式:
ret = get_format_from_sample_fmt(&fmt, sfmt))// 从sfmt 获取字符串format
sfmt 是源format, 是 dec_ctx->sample_fmt

ffplay -f f32le -ac 2 -ar 44100 Audio.data
f32le: aac 的采样格式 (sample_fmt)
44100: aac 的采样率        (sample_rate)
2   : aac 的采样通道数    (channels)

从此,你可以了解到音频解码的流程.

这里还要补充一点, decode在 avcodec_send_packet 之后, dec_ctx的信息才补充完整,channels,sample_rate 才有了值!
    是的,这是因为 codec 本身并不知道有多少channels, sample_rate是多少,codec 只负责解码,它知道数据 pix的format,
    但收到数据包后ctx就不一样了, ctx 会存储具体的数据流信息如channels,sample_rate等,就是所谓的流信息

decode_video.c 解读
----------------------------------------
相较decode_audio.c,
一致的地方都是: 用指定的codec 来打开codec_ctx.
具体为由codecID找到codec, 分配codec_ctx, 打开codec,初始化parser,
分配包,分配frame,打开输入文件.

分析一下不同的地方
1. 首先这个inbuf 的buffer size 只有4096, 而不是音频的20480
2. 没有打开输出文件.每一个frame 对应一个输出文件.
3. 从输入文件读入一次数据4096, 分析缓存中数据消耗4096,但可能并
不能构成一个pkt, pkt->size=0, 会继续读入数据,分析数据,直到pkt->size!=0.
哇!这一次一下子成了25709, 可见也是多个4096 供给的.
然后进行decode.
有可能把packet 发过去,并不能解出frame, 而是EAGAIN, 还需要继续供给packet
parser 分析每次消耗并不一定是4096, 它以能形成packet为准则.
构不成frame 也没问题,反正dec_ctx 会记录.
解出了frame, 由dec_ctx->frame_number 构成输出文件名,将frame 中的数据写入到文件.
数据要素是frame->data, frame->linesize,frame->width,frame-height.
frame->data 是8个指针, 传第一个就够了.
frame->linesize是8个整数,传第一个就够了.
然后打开一个文件,记录下xsize,ysize, 然后书写二进制数据,按行写.每次写一行.

补充:
问1:parser 读到一个packet, 此时packet中有什么?
答1: parser可能要经过若干次数据输入才能形成一个packet,此时只有packet->data,packet-size是有效的.
问2:解码是send_packet, receive_frame, frame->width,frmae->height是如何得到的?
答2: 发过去一个packet, 可能并不能形成一个有效的frame,此时会返回EAGAIN,如果得到了frame,
    此时也会填充好frame->width,height参数及data,linesize参数等,称为已经解出了frame,
    此时再看ctx, 相关的数据也已经填充好. 看起来一荣俱荣,一损俱损,是同时发生的。

decode_audio.c 解读/decode_video.c 解读相关推荐

  1. vins 解读_代码解读 | VINS 视觉前端

    AI 人工智能 代码解读 | VINS 视觉前端 本文作者是计算机视觉life公众号成员蔡量力,由于格式问题部分内容显示可能有问题,更好的阅读体验,请查看原文链接:代码解读 | VINS 视觉前端 v ...

  2. vins 解读_VINS-mono详细解读

    VINS-mono详细解读 极品巧克力 前言 Vins-mono是香港科技大学开源的一个VIO算法,https://github.com/HKUST-Aerial-Robotics/VINS-Mono ...

  3. EMANet:Expectation-Maximization Attention Networks for Semantic Segmentation论文解读和代码解读

    官方项目地址:含论文和代码 来自北大才子 立夏之光的 ICCV Oral ,理论很漂亮.属于Non local方式 Updated on 2020.1.6 最近一直有人私信我,这个attention ...

  4. 【lidar】3D目标检测PointPillars:论文解读、代码解读、部署实现(2)

    PointPillars部署:TensorRT推理实现,下载地址:添加链接描述 PointPillars 高度优化的点云目标检测网络PointPillars.主要通过tensorrt对网络推理段进行了 ...

  5. 【lidar】3D目标检测PointPillars:论文解读、代码解读、部署实现(1)

    Abstract 点云中的目标检测是自动驾驶等机器人应用中的一个重要方面.在本文中,作者思考了将点云编码成适合下游检测pipeline的格式问题.最近的文献提出了两种类型的编码器:固定编码器往往更快, ...

  6. VINS-mono详细解读与实现

    VINS-mono详细解读 VINS-mono详细解读 前言 Vins-mono是香港科技大学开源的一个VIO算法,https://github.com/HKUST-Aerial-Robotics/V ...

  7. mysql 4.1.10_Mysql4.1.10初级解读

    Mysql4.1.10初级解读 ※※※※※※※※※※※※※※Mysql 初级解读 (所用版本:4.1.10)※※※※※※※※※※※※※※ 安装注意事项 在安装的过程中,请记好您的密码,这是将来登录my ...

  8. Nature子刊:微生物来源分析包SourceTracker——结果解读和使用教程

    文章目录 SourceTracker有什么用? 软件简介 软件结果解读 原文解读 文章实战解读 软件安装 输入文件准备 实验设计 OTU表 代码中文解读 Reference 猜你喜欢 写在后面 前一阵 ...

  9. 【C 语言】指针 与 数组 ( 指针 | 数组 | 指针运算 | 数组访问方式 | 字符串 | 指针数组 | 数组指针 | 多维数组 | 多维指针 | 数组参数 | 函数指针 | 复杂指针解读)

    相关文章链接 : 1.[嵌入式开发]C语言 指针数组 多维数组 2.[嵌入式开发]C语言 命令行参数 函数指针 gdb调试 3.[嵌入式开发]C语言 结构体相关 的 函数 指针 数组 4.[嵌入式开发 ...

最新文章

  1. Java中的实现马赛克效果以及灰度效果----整张图片
  2. java 对变量加锁_Java最全锁剖析:独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁...
  3. hdu3786 Floyd或搜索 水题
  4. Python内置函数(44)——len
  5. minitab怎么算西格玛水平_西格玛和西格玛水平
  6. hexo本地博客的转移
  7. .读取excel表格(JAVA)
  8. python一共多少模块,python常见模块有哪些
  9. 视频直播app源码,可拖拽悬浮球
  10. 直播企业掀“冲击IPO”浪潮,为何老玩家成受益者?
  11. UE4 替换文件尝试解决 光照构建失败 Lighting build failed. Swarm failed to kick off
  12. Python站内文章精选大集合!
  13. Qt配置OpenCV环境变量
  14. 免费图床,看这一篇就够了!
  15. Android开发艺术探索完结篇——天道酬勤
  16. 436分复试被刷!山东大学软件学院
  17. Sprite Kit 动作系统
  18. 七宗罪也许每个人都有
  19. php7的安装方法,php7 iis安装方法详解(图文)
  20. 微搭低代码数据源新能力详解

热门文章

  1. 使用python输出所有汉字的拼音hàn-zì-pīn-yīn
  2. vb毕业设计——基于vb+VB.NET的媒体播放器设计与实现(毕业论文+程序源码)——媒体播放器
  3. 硕士发表SCI论文84篇遭质疑?!本人霸气回应:有无造假随便查!没有拼爹!...
  4. 22、Java——汽车租赁系统(对象+集合)
  5. 世界上最大的全可动射电望远镜在中国开工建设
  6. 用CSS样式完成作业
  7. Python零基础学习-开课吧
  8. 课得软件丨成都web前端培训班哪儿好?
  9. 【PHP】`异客塞尔`世界 与 神奇的字符串++
  10. 1985年的图灵奖获得者-Richard Manning Karp