音视频开发-FFmpeg
音视频开发是个非常复杂的,庞大的开发话题,初涉其中,先看一下结合 OEIP(开源项目) 新增例子.
可以打开flv,mp4类型文件,以及rtmp协议音视频数据,声音的播放使用SDL。
把采集的麦/声卡数据混合并与采集的视频信息写入媒体文件或是RMTP协议中。
图片主要属性
包含长/宽/通道数/像素格式(U8/U16/F32),以及排列格式RGBA/YUV。其中通道与像素格式,如在opencv中,CV_8UC1/CV_8UC4,表示1个通道与4个通道的U8格式。而排列格式,简单的分为RGBA类的,如BGRA,BGR,R这些,一般用于游戏里的纹理,RGBA/BGR/R本身有表示通道格式的意思,所以后面组合RGBA32,RGBAF32用来表示通道像素里数据格式。而YUV类型,一般用在媒体类型,如采集设备,音视频文件,推拉流传输等,YUV格式有二个组成部分。一是UV对应像素个数,如YUV420,YUV422,YUV444,他们的相同点就是一个像素点对应一个Y,不同点是,如YUV420表示一个U/V对应4个像素点,422一个UV对应二个像素点,UV444则表示一个UV对应一个像素点,YUV像素点数据格式一般是U8。
我们可以来比较一些常用格式最终占用字节大小,如1080P下。
- RGBA32 1920*1080*4=8,294,400 其中4是每个像素包含RGBA四个通道。
- YUV420 1920*1080 + 980*540*2 前面是Y占用大小,后面是UV占用大小。
- YUV422 1920*1080 + 980*1080*2 前面是Y占用大小,后面是UV占用大小
- YUV444 1920*1080*3 每个像素一个YUV三通道。
第二是排序格式,如YUV420可以细分YUV420I,YUV420P,YUV420SP(NV12),简单来说,后缀是P是表示YUV这三个分开存放,而SP是Y单独分开,UV交织在一起,而I就更简单了,YUV交织在一起,简单来说,和RGBA格式差不多排列。
YUV420P/YUV422P 一般用来视频文件与推拉流传输上,我想可能原因是Y用来表示亮度,人眼最敏感部分,早期黑白电视只有Y大家一样能看,这种格式最方便兼容,直接把UV丢弃就行,Y/U/V可能在内存分布上不连续。其中YUV420I/YUV422I 这种交织的一般是采集设备所用,内存上连续,方便处理,YUV420SP(NV12) 这种一般也是采集设备所有,这种格式简单来说,一是方便只使用Y,二是UV可以和Y的宽度统一,后面align的话,YUV也是统一一个,内存上也方便连续。
音频基本属性如下
采样率:如人耳听到最高频率是22kHz,如要完全重现频率,需要采样率是频率*2,所以一般来说44100是很常见的采样率。
声道数:常见单声道,双声道,也有不常见的更多声道。
数据格式:一般是S16(16位有符号整合),F32(32位浮点),别的不算常用如U8,D64,这二个表示的分贝范围一个太小,一个太大。
和图像类型,多个声道的表示方法也有P(平面),I(交织),类似,音频采集数据一般是I,传输P,在OEIP项目中,相应格式一般都转成单声道S16,也就不需要管理是P还是I。
音视频开发基本概念
有了上面基本认识,我们再来认识一些概念(以下是本人的一些基本理解,如果有错,欢迎大家指出)。
编码:把原始音视频数据压缩,简单来说,1080PYUV420的大小1920*1080*3/2=3,110,400 Byte,1秒25桢的话就有差不多78M。视频如YUV->H264,音频PCM->ACC过程就是编码。在FFmpeg中,类似过程就是AVFrame->AVPacket
解码:把压缩后的音视频转换成原始音视频数据,H264->YUV,ACC->PCM过程。在FFmpeg中,就是AVPacket->AVFrame.
在编码与解码中,图像每桢原始大小取决原始图像大小根据长宽,像素排序和格式组成,而音频每桢对于特定编解码器是每个通道固定多少采样点,如AAC是1024(也有特殊情况2048的),MP3是1152,相应字段在AVFrame.nb_sampes,AVCodecContext.frame_size里表示.这样AAC中双通道 U16每桢数据量就在2*sizeof(U16)*1024.而码率决定了编码质量,一般情况下,码率高质量好,但是生成文件或是网络占用就好,合适的码率网上有介绍,1080P下一般用4M的码率,你用1M也行,但是画面动的时候可能就糊了,码率控制也有不同的控制策略,根据需求选择自己的控制策略,这部分网上有详细的讲解。
媒体文件:FLV/MP4这些,不同媒体格式把编码的信息用不同的方式保存,不同媒体格式支持不同的编码格式,大部媒体格式都支持h264/acc编码信息,所以这二个编码格式比较常用。
多媒体协议:RTMP/RTSP这些,在媒体文件之上封装网络传输与控制的相关信息。
音视频流:流分为音频流,视频流,字幕流等等这些,其中 媒体文件里可能包含一个或多个音视频流,而每个视频流是相同属性(长宽,像素格式等)的原始视频数据编码成的信息流。
复用:举个例子,把一个音频流与一个视频流合成一个媒体文件,就是复用。
解复用:如上,把一个媒体文件分解成相应的音频流与视频流。
FFmpeg主要对象
AVFormatContext:多媒体协议或是媒体文件,如果是协议,会解析出协议里包含的媒体文件信息,这个类主要如今读/写压缩包,读/写文件头与文件尾等方法。你可以把这对象认为是一个媒体文件。
AVCodec:编解码,注意编码与解码或是用同一codecId,但是对象不同,这个对象主要包含一些函数指针,告诉如何把frame->packet/packet->frame.
AVCodecContext:编解码环境,简单来说,AVCodec是说如何编解码,这个就是告诉他相应属性设置,如对应视频来说,长宽,以及编码相应设置是否包含B桢,GOP是多少都在这,可以这么理解,我们假设AVCodec与AVCodecContext如果是一个类,那么AVCodec相当于里面的方法集合,AVCodecContext相当于里面的变量集合。
AVStream:媒体文件一般来说至少包含一个音频流或是视频流,在复用/解复用到编解码之间是个承上启下的关系。你可以理解AVStream包含音视频编码的信息列表。AVStream也要包含相应的AVCodecContext包含的编解码信息,后面会讲这二者信息在复用与解复用从那复制到那。
AVFrame:音视频原始信息,包含一个定长的数据信息。
AVPacket:音视频编码信息,包含一个不定长的数据信息。
FFmpeg常见API分析
读一个媒体文件相应动作与API解析。
avformat_open_input 根据媒体文件/协议地址打开AVFormatContext。
avformat_find_stream_info 查找AVFormatContext里对应的音视频流索引。
avcodec_find_decoder 根据索引打开对应音频与视频流解码器。
avcodec_alloc_context3 根据解码器生成解码器环境。
avcodec_parameters_to_context 把流的解码器参数(图像长宽,音频基本属性以及frame_size)复制到解码器环境.
avcodec_open2 打开解码器环境。
av_read_frame 从媒体文件AVFormatContext读每个AVPacket。
avcodec_send_packet 根据对应AVPacket的索引,发给对应流的解码器解码。
avcodec_receive_frame 得到解码器解码后的原始数据,如在视频流中,因P桢B桢关系,一个AVPacket并不一定能得到一个AVFrame,比如P桢要考虑前后,所以可能到后几个Packet的时候,一下读出多桢数据,所以avcodec_send_packet/avcodec_receive_frame的写法会是这样一个情况。
写入媒体文件相应动作与API解析(非IO模式):
avformat_alloc_output_context2 根据对应格式生成一个AVFormatContext,不同格式会固定一些数据,比如上FLV格式,音频流与视频流的时间基就是毫秒,我试着改过这值,后面也会在avformat_write_header之后重新改回来。
avcodec_find_encoder/avcodec_find_encoder_by_name 选择自己想要的编码器。
avcodec_alloc_context3 选择选择的编码器生成编码器环境,不同与上面 的解码过程,这里我们要自己填充相应信息,如图像编码需要知道长宽,码率,gop等设置。
avcodec_open2 打开解码器环境。
avformat_new_stream 生成相应音视频流信息,填充对应编码器到AVFormatContext里。
avcodec_parameters_from_context 把编码器设置的参数复制到流中。
avio_open 协议的解析以及协议的操作指针,如何读写协议信息,协议头,协议内容等。
avformat_write_header 写入头信息。
avcodec_send_frame 把末压缩数据给编码器。
avcodec_receive_packet 拿到编码后的数据,和解码类似,P桢决定不可能一Frame一packet,可能要前后几个Frame,才能得到一系列的packet.
av_interleaved_write_frame 把编码后的音视频数据交叉写入媒体文件中
av_write_trailer 结束写入,根据写入的所有数据填充一部分需要计算的值。
还有一种IO模式,可以利用关键桢图像与音频数据直接写入IO中,然后直接从桢中读取相应音视频流的属性拿来直接用,用来不确定视频流长宽等情况下使用。
从API可以看读写的差异,读的媒体文件AVFormatContext里面的信息全有,读到流,从流里得到解码信息,打开解码器,从AVFormatContext读每个包,用解码器解码包。写入媒体文件就是生成一个空白的AVFormatContext,然后打开选择的编码器,生成流,然后写入流中每桢数据,使用编码器编码后定稿文件。
图像上相关的坑,媒体文件一般使用是YUV的P格式,这个格式YUV分块保存,还有相应align的概念,举个例子,假设你宽是1080,但是在YUV分块中,Y宽度可能是1088(假设当时使用32定齐),其中每行数据索引处1080-1087以0填充,相应的图像处理我全部提出来在OEIP处理,在OEIP中图像数据全给GPU处理,需要的是紧湊数据,所以需要用av_image_copy_to_buffer/av_image_fill_arrays处理。
音频上相关的坑,媒体文件多声道也是用的P格式,而音频采集与播放设备一般用的I格式,所以一般要用swr_convert转换,音频播放使用SDL库,就几个API调用就行,在这就不说了,可以查看相应OEIP里的代码处理,音频采集Winodws用的是WASAPI。
时间基的概念:音视频流都有一个时间基的概念,这个比较重要,flv的音视频都是(1,1000),如果是mp4,视频的时间基为(1,90000),音频一般设为对应采样率。时间基,你可以简单理解为1秒内刻度,flv的流对应就是毫秒,而mp4视频流的时间基对应的是1/90毫秒,什么意义了,比如你视频对应的是25桢,在flv里,每桢相隔40个时间基,而在mp4里,相隔360个时间基,在编码时,我们需要把frams上的pts/dts/duration以对应时间基为单位,注意转换,在OEIP中,我们把所有转出/转入与用户有关的时间全是毫秒,其中转换我们内部自己处理。
故到此 OEIP 中,可用的输入输出源新增媒体文件/协议,同样,这些功能在Unity3D/UE4里很方便展示,比如把媒体文件/协议里的内容直接展示成对应Unity3D/UE4里的Texture2D显示,或是把Unity3D/UE4里的Texture2D/RTT里的数据保存视频或是推送出去。
参考:
https://www.cnblogs.com/leisure_chn/category/1351812.html 叶余 FFmpeg开发
音视频开发-FFmpeg的更多相关文章
- WebRTC 音视频开发
WebRTC 音视频开发 webrtc Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键? 摘要: 本文主要介绍WebRTC端到端监控(我们翻译 ...
- Android 音视频开发学习思路
Android 音视频开发这块目前的确没有比较系统的教程或者书籍,网上的博客文章也都是比较零散的.只能通过一点点的学习和积累把这块的知识串联积累起来. 初级入门篇: Android 音视频开发(一) ...
- Android 音视频开发入门指南
Android 音视频从入门到提高 —— 任务列表 http://blog.51cto.com/ticktick/1956269(以这个学习为基础往下面去学习) Android 音视频开发学习思路-- ...
- 转:Android IOS WebRTC 音视频开发总结 (系列文章集合)
随笔分类 - webrtc Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键? 摘要: 本文主要介绍WebRTC端到端监控(我们翻译和整理的,译 ...
- moviepy音视频开发:音频剪辑基类AudioClip
☞ ░ 前往老猿Python博文目录 ░ 一.背景知识介绍 1.1.声音三要素: 音调:人耳对声音高低的感觉称为音调(也叫音频).音调主要与声波的频率有关.声波的频率高,则音调也高. 音量:也就是响度 ...
- Android 音视频开发(一):PCM 格式音频的播放与采集
什么是 PCM 格式 声音从模拟信号转化为数字信号的技术,经过采样.量化.编码三个过程将模拟信号数字化. 采样 顾名思义,对模拟信号采集样本,该过程是从时间上对信号进行数字化,例如每秒采集 44100 ...
- 【秒懂音视频开发】02_Windows开发环境搭建
音视频开发库的选择 每个主流平台基本都有自己的音视频开发库(API),用以处理音视频数据,比如: iOS:AVFoundation.AudioUnit等 Android:MediaPlayer.Med ...
- Android音视频开发(1):H264 基本原理
前言 H264 视频压缩算法现在无疑是所有视频压缩技术中使用最广泛,最流行的.随着 x264/openh264 以及 ffmpeg 等开源库的推出,大多数使用者无需再对H264的细节做过多的研究,这大 ...
- Android IOS WebRTC 音视频开发总结(八十五)-- 使用WebRTC广播网络摄像头视频(下)
本文主要介绍WebRTC (我们翻译和整理的,译者:weizhenwei,校验:blacker),最早发表在[编风网] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID:bl ...
随机推荐
- 对于页面适配,你应该使用px还是rem
css中的单位很多,%.px.em.rem,以及比较新的vw.vh等.每个单位都有特定的用途,比如当需要设置一个矩形的宽高比为16:9,并且随屏幕宽度自适应时,除了用%,其他单位是很难做到的.所以不存 ...
- 微信小程序结构目录、配置介绍、视图层(数据绑定,运算,列表渲染,条件渲染)
目录 一.小程序结构目录 1.1 小程序文件结构和传统web对比 1.2 基本的项目目录 二.配置介绍 2.1 配置介绍 2.2 全局配置app.json 2.3 page.json 三.视图层 3. ...
- Vue+axios(interceptors) 实现http拦截 + router路由拦截 (双拦截)+ 请求自带loading效果
axios interceptors 拦截器 //interceptors.js // vue axios配置 发起请求加载loading请求结束关闭loading // http request 请 ...
- 手写Promise原理
我的promise能实现什么? 1:解决回调地狱,实现异步 2:可以链式调用,可以嵌套调用 3:有等待态到成功态的方法,有等待态到失败态的方法 4:可以衍生出周边的方法,如Promise.resolv ...
- 【vue】---- v-model在自定义组件中的使用
1. v-model简介 可以用 v-model 指令在表单 <input>.<textarea> 及 <select> 元素上创建双向数据绑定,它的本质是一个语法 ...
- 【剑指Offer】简单部分每日五题 - Day 1
今天开始更新leetcode上<剑指Offer>的题解,先从简单难度开始.预计按下列顺序更新: 简单难度:每日5题 中等难度:每日3题 困难难度:每日1题 17 - 打印从1到最大的n位数 ...
- vue-cli实现最简单的全选、全不选、反选功能。不容错过呦!!!!!话不多说直接上代码。。。。
<template> <div class="hello"> <input type="button" name="al ...
- java面试题汇总四
第三部分 Java SE基础 3.1 java多线程 3.1.1 线程的实现方式,怎么启动线程怎么区分线程? 1.线程的实现方式: 有 4 种方式可以用来创建线程: 2.继承 Thread 类 2 ...
- IPv6 时代如何防御 DDoS 攻击?
在互联网世界,每台联网的设备都被分配了一个用于标识和位置定义的 IP 地址.20 世纪 90 年代以来互联网的快速发展,联网设备所需的地址远远多于可用 IPv4 地址的数量,导致了 IPv4 地址耗尽 ...
- 详解POI的使用方法(DOM和SAX的方式)及存在的不足
简介 Apache POI是一套基于 OOXML 标准(Office Open XML)和 OLE2 标准来读写各种格式文件的 Java API,也就是说只要是遵循以上标准的文件,POI 都能够进行读 ...