音视频开发书籍(音视频开发大龄程序员)

FFmpeg是一个开源框架,可用于记录、处理数字音频和视频,并将其转换为流。使用LPL或GPL许可证,它提供了一个完整的解决方案,记录,转换和流式音频和视频。
1.FFmpeg编译选项详解FFmpeg的编译方式和大多数GNU软件类似,都是用configure脚本编译的。
以前,这种方式允许用户在编译前对软件进行裁剪,同时,通过最终运行到
和系统的目标平台的配置。
选项:GNU软件配置项,如安装路径,-prefix=…等。
编译和链接选项:默认配置是生成静态库而不是动态库,比如- disable-static,- enable-shared等。
可执行程序控制选项:决定是否生成FFmpeg、ffplay、ffprobe、ffserver等。
模块控制选项:裁剪编译模块,包括整个库的裁剪,例如-disable-av device;筛选一组模块,例如禁用解码器;切割单个模块,例如-禁用-解复用器。
显示选项[图片上传.(截图2019-09-05,9 . 21 . 53am . png-7df 104-1567646545418-0)]:列出当前源代码支持的各种能力集,比如-List-decoder,-List-encoder。
其他:允许开发者进行深度定制,比如交叉编译环境配置、自定义编译等。
的默认编译生成4个可执行文件和8个静态库。
可执行文件:
1.ffmpeg:转码,流媒体,媒体文件2。ffplay:播放媒体文件需要预编译libSDL 3。ffprobe:获取文件详细信息4。ffserver:作为一个简单的流媒体服务器。
八个静态库:
AVUtil:基本模块之一,基本的音频和视频处理操作。
AVFormat:文件格式(avi、MP4、flv、mov等。)和协议库,封装了协议层、解复用器和复用器层。
AVCodec:编解码器库,如MPEG-4。可以添加其他第三方编解码器作为插件,如libx264、FDK-AAC、lame等。
AVFilter:音视频滤镜库,包括音视频特效的处理。
AVDevice: I/O设备库,比如播放声音或视频的工具ffplay就需要这个类。
SwrRessample:该模块可用于音频重采样,可将数字音频转换成通道、数据格式、采样率等基本信息。
SWScale:这个模块是一个转换图像格式的模块。例如,它可以将YUV数据转换为RGB数据。
PostProc:该模块可用于后处理。我们在使用AVFilter的时候,需要打开这个模块的开关,因为这个模块的一些基本功能会用到Filter。
2.ffmpeg安装(安装命令行工具)Ruby-e ‘ $(curl-fsskraw . github . com/mxcl/home brew/go)’安装家酿brew安装ffmpeg安装FFmpeg中常用的命令行工具:
Ffmpeg是转码媒体文件的命令行工具,ffprobe是查看媒体文件头信息的工具,ffplay是播放媒体文件的工具。
1.ffprobe查看流媒体格式。
先用ffprobe查看一个音频文件:FF Probe ~/desktop/output.mp3时长: 0033600336009.44,比特率: 77 KB/s表示该音频文件时长为09秒44毫秒,开始播放时间为0。整个媒体文件的码率为77Kbit/s流# 0333 6003360音频3360 aac (LC),44100 Hz,单声道,fltp,77 KB/s第一个流是音频流,编码格式为aac格式,采样率为44.1kHz,声道为单声道,采样呈现格式为FLTP)。这个流的比特率是77。有些视频有多个音频文件,例如,普通话或粤语,英语等。然后用ffprobe查看一个视频文件:ff probe ~/Desktop/Aroey.mp4元数据: major _ brand 3360 isom minor _ version 3360 512 compatible _ brands 3360 isom ISO 2 AVC 1mp 41编码器3360 LAFF 58.20.100这一行信息表示这个文件的Metada。Ta信息,比如编码器是Lavf55.12.100,其中LAFF代表FFmpeg输出的文件,后面的数字代表FFmpeg的版本代码。下一行信息如下:Duration 3360 00336009.94,Start 3360 0.00000,Bitrate: 5166 kb/sDuration为0分09秒94毫秒,start time从0 ms开始整个文件的比特率为5166 KBIT/s Stream # 033600(UND)3360 Video 3360 P64(HIGH)(av C1/0x 31637666YUV420P,1080×1920,5100KB/s,29.97FPS,29.97TBR,30TBN,59.94TBC(默认)这一行信息表示第一个流是视频流,编码方式为H264格式(封装格式为AVC1),每一帧的数据为YUV420P格式。分辨率为1080×1920,该码流的码率为5100Kbit/s,帧率为29.97帧/秒(fps为29.97)。其他音频和视频文件信息2。ffplay
Ffplay是一个基于FFmpeg框架和libSDL的媒体文件播放器,libSDL是一个用于音频和视频渲染的库。
Ffplay 32037.mp3播放音频Ffplay在32037.mp3播放视频,业内的ijkplayer是基于ffplay的其他播放相关信息。3.工具
Ffmpeg是一个强大的媒体文件转换工具。它可以转换任何格式的媒体文件,也可以用自己的AudioFilter和VideoFilter进行处理和编辑。
通用参数-f fmt:指定格式(音频或视频格式)。-i filename:指定输入文件名,也可以在Linux: 0.0(屏幕录制)或camera下指定。-y:覆盖现有文件。-t持续时间:指定持续时间。-fs limit_size:设置文件大小的上限。-ss time_off:从指定的时间(以秒为单位),格式为[-] hh: mm: ss [。xxx]也受支持。-re:表示根据帧速率发送,尤其是作为流媒体工具使用时。否则,ffmpeg将以最高速率向流媒体服务器发送数据。-map:指定输出文件的流映射关系。例如,“-map1: 0-map1: 1”要求将第二个输入文件的第一个流和第二个流写入输出文件。如果没有-map选项,ffmpeg采用默认的映射关系。视频参数-b:指定比特率(比特/秒)。ffmpeg自动使用VBR。如果指定了此参数,将使用平均比特率。-bitexact:使用标准比特率。-vb:指定视频比特率(比特/秒)。-r rate:帧速率(fps)。-s size:指定分辨率(320240)。-纵横比:设置视频纵横比(4: 3、16: 9或1.3333、1.7777)。-裁剪大小:设置顶部裁剪大小(以像素为单位)。-cropbottom size:设置底部切割尺寸(以像素为单位)。-cropleft size:设置左侧切割尺寸(以像素为单位)。-cropright size:设置正确的切割尺寸(以像素为单位)。-Paddtop size:设置顶部填充大小(以像素为单位)。-padbottom大小:以像素为单位。-padleft size:左填充(以像素为单位)。-padright size:右填充(以像素为单位)。-padcolor颜色:补色(000000-FFFFFF)。-vn:取消视频的输出。-vcodec编解码器:强制使用编解码器编码和解码方法(“复制”表示不重新编码)。音频参数-ab:设置比特率(单位是bit/s,老版本的单位可能是Kbit/s)。对于MP3格式,建议设置在160Kbit/s以上(单声道80 kbit/s)-AQ质量:设置音频质量(指定编码)。-ar rate:设置音频采样率(单位为Hz)。-ac声道:设置声道数,1为单声道,2为立体声。-安:取消音轨。-acodec codec:指定音频编码(“copy”代表直接复制,无需音频代码转换)。-vol volume:设置录音音量的百分比(默认为256)。使用简单转换格式3360fmpeg-I目的地址。webm决赛。mp4独立视频3360fmpeg-I目的地址。mp4 -vcodec副本-决赛。mp4独立音频3360fmpeg-I目的地址。mp4 -acodec副本-越南最终版。自动幅度控制(Automatic Ampltiude Control的缩写)
3.FFmpeg交叉编译生成IOS/Android的代码API
下载编译FFmpeg所需的脚本文件gas-preprocessor.pl。下载地址3360 https://github.com/libav/gas-preprocessor,并将gas-preprocessor.pl复制到/usr/sbin。(这个要复制到/usr/local/bin)修改文件权限:chmod 777/usr/local/bin/gas-preprocessor . pl下载脚本FFmpeg脚本地址3360 https://github.com/kewlbear/FFmpeg-iOS-build-script解压,找到文件build-ffmpeg.sh执行这个文件:/build-ffmpeg.sh来介绍几个术语:
容器/文件(Container/file):即特定格式的多媒体文件,如MP4、flv、mov等。
媒体流:指时间轴上的一段连续数据,如一段声音数据、一段视频数据或一段字幕数据,可以压缩,也可以不压缩。压缩数据需要与特定的编解码器相关联。
帧/包:通常,媒体流由大量数据帧组成。对于压缩数据,帧对应编解码器的最小处理单元,属于不同媒体流的数据帧交替存储在容器中。
编解码器:编解码器以帧为单位实现压缩数据和原始数据的相互转换。
AVFormatContext是容器或媒体文件级的抽象,包含多个流(音频流、视频流、字幕流等。),而对流的抽象是AVStream;每一个流都会描述这个流的编码格式,编解码格式和编解码器的抽象是AVCodecContext和AVCodec;对于编码器或解码器的输入输出部分,即压缩数据和原始数据的抽象是AVPacket和AVFrame;音视频的处理除了编解码,还必须针对原始数据的处理,也就是AVFrame的处理,这就要用到AVFilter。
情况1:将视频文件解码成单独的PCM文件和YUV文件
//1.注册协议、格式与编解码器//注册网络协议部分av格式_网络_初始化();//注册所有的编解码器、协议、格式av _ register _ all();//2.打开媒体文件源,并设置超时回调(本地磁盘文件也可能是网络媒体资源链接,会涉及RTMP/HTTP等协议的视频源,设置超时时间)AVFormatContext * format CTX=av format _ alloc _ context();AVIOInterruptCB int _ CB={ interrupt _ callback,(_ _ bridge void *)(self)};格式CTX-中断_回调=int _ CBavformat_open_input(formatCtx,path,NULL,NULL);av format _ find _ stream _ info(格式CTX,空);//3.寻找各个流,并且打开对应的解码器for(int I=0;inb _ streamsI){ av stream * stream=format CTX-streams[I];if(av media _ TYPE _ VIDEO==stream-codec-codec _ TYPE){//视频流videoStreamIndex=I;videoCodecCtx=stream-codec;} else if(av media _ TYPE _ AUDIO==stream-codec-codec _ TYPE){//音频流audioStreamIndex=I;audioCodecCtx=stream-codec;} } //打开音频解码器av codec * codec=av codec _ find _ decoder(audioCodecCtx-codec _ id);如果(!编解码器){ //找不到对应的音频解码器} int openCodecErrCode=0;if((openCodecErrCode=av codec _ open 2(codecCtx,codec,NULL)) 0){ //打开音频解码器失败} //打开视频流解码器AVCodec * code C1=AVCodec _ find _ decoder(videoCodecCtx-codec _ id);如果(!编解码器){ //找不到对应的视频解码器} int opencodecerrcode 1=0;if((opencodecerrcode 1=av codec _ open 2(code cctx,codec1,NULL)) 0) { //打开视频解码器失败} //4.初始化解码后数据的结构体//4.1需要分配出解码之后的数据所存放的内存空间SWR context * SWR context=NULLif(audioCodecCtx-sample _ fmt!=AV_SAMPLE_FMT_S16) { //如果不是我们需要的数据格式SWR上下文=SWR _ alloc _ set _ opts(NULL,outputChannel,AV_SAMPLE_FMT_S16,outSampleRate,in_ch_layout,in_sample_fmt,in_sample_rate,0,NULL);如果(!SWR上下文| | SWR _ init(SWR上下文)){ if(SWR上下文){ SWR _ free(SWR上下文);} }音频帧=av codec _ alloc _ frame();} //4.2以及进行格式转换所需要用到的对象AVPicture图片;bool pictureValid=av picture _ alloc(picture,PIX_FMT_YUV420P,videoCodecCtx-width,videoCodecCtx-height)==0;如果(!pictureValid){ //分配失败返回false } SWS context=SWS _ getCachedContext(SWS context,videoCodecCtx-width,videoCodecCtx-height,videoCodecCtx-pix_fmt,videoCodecCtx-width,videoCodecCtx-height,PIX_FMT_YUV420P,SWS _ FAST _双线性,NULL,NULL,NULL);视频帧=av编解码器_ alloc _ frame();//5.读取流内容并且解码//解码器之后,就可以读取一部分流中的数据(压缩数据),然后将压缩数据作为解码器的输入,解码器将其解码为原始数据(裸数据),之后就可以将原始数据写入文件了AVPacket包;int get frame=0;while(true){ if(av _ read _ frame(格式上下文,数据包)){ //文件结束符;} int数据包流索引=数据包。stream _索引;if(packetStreamIndex==videoStreamIndex){ int len=avcodec _ decode _ video 2(videoCodecCtx,videoFrame,gotFrame,packet);if(len 0){ break;} if(get frame){ self-handleVideoFrame();} } else if(packetStreamIndex==audioStreamIndex){ int len=av codec _ decode _ audio 4(audioCodecCtx,audioFrame,gotFrame,packet);if(len 0){ break;} if(get frame){ self-handleVideoFrame();} } } //7、处理解码后的裸数据//裸数据,音频就是脉冲编码调制数据,视频就是YUV数据。
下面将其处理成我们所需要的格式并且进行写文件//7.1 音频裸数据处理//将音频裸数据直接写入文件,比如写入到文件audio.pcm中void * audioDataint numFramesif(SWR上下文){ int bufSize=AV _ samples _ get _ buffer _ size(NULL,channels,(int)(音频帧-nb _ samples * channels),AV_SAMPLE_FMT_S16,1);如果(!_ SWR缓冲区| | _ SWR缓冲区大小bufSize){ SWR缓冲区大小=bufSizeswrBuffer=realloc(_swrBuffer,_ SWR缓冲区大小);} Byte * out ff[2]={ _ SWR缓冲,0 };num frames=SWR _转换(_ SWR上下文,outbuf,(int)(音频帧-nb _样本*通道),(const uint 8 _ t * *)_音频帧-数据,音频帧-nb _样本);audio data=SWR buffer } else { audio data=audio frame-data[0];num frames=音频帧-nb _ samples;} //7.2视频的裸数据的处理//接收到YUV数据,写入文件video.yuv中uint 8 _ t * luma uit 8 _ t * chromabuint 8 _ t * chroma Rif(videocodecxt-PIX _ fmt==AV _ PIX _ FMT _ YUV 420 p | | videocodecxt-PIX _ fmt==AV _ PIX AV _ PIX _ FMT _ yuvj 420 p){ luma=复制帧数据(video frame-data[0],videoFrame-linesize[0],videocodecxt-width,videocodecxt-height);chromaB=copyFrameData(video frame-data[1],videoFrame-linesize[1],videoCodecCtx-width/2,videoCodecCtx-height/2);chromaR=copyFrameData(video frame-data[2],videoFrame-linesize[2],videoCodecCtx-width/2,videoCodecCtx-height/2);}else{ sws_scale(_swsContext,(const uint8_t **)videoFrame-data,videoFrame-linesize,0,videoCodecCtx-height,picture.data,picture。linesize);luma=copyFrameData(图片。data[0],picture.linesize[0],videoCodecCtx-width,videoCodecCtx-height);chromaB=copyFrameData(图片。data[1],picture.linesize[1],videoCodecCtx-width/2,videoCodecCtx-height/2);chromaR=copyFrameData(图片。data[2],picture.linesize[2],videoCodecCtx-width/2,videoCodecCtx-height/2);} //8、关闭所有的资源//退出的时候,要将用到的FFmpeg框架中的资源,包括FFmpeg框架对外的连接资源等全都释放掉//清空所有的音频资源if(SWR缓冲){ free(SWR缓冲);SWR buffer=NULLswrBufferSize=0;} if(SWR上下文){ SWR _ free(SWR上下文);swrContext=NULL} if(音频帧){ av _ free(音频帧);audio frame=NULL } if(audioCodecCtx){ av codec _ close(audioCodecCtx);audioCodecCtx=NULL} //清空所有的视频资源if(SWS context){ SWS _ free context(SWS context);swsContext=NULL } if(pictureValid){ av picture _ free(图片);pictureValid=false} if(视频帧){ av _ free(视频帧);video frame=NULL } if(videoCodecCtx){ av codec _ close(videoCodecCtx);videoCodecCtx=NULL} //关闭连接资源if(格式CTX){ av format _ close _ input(格式CTX);formatCtx=NULL}注册协议、格式与编解码器打开媒体文件源,并设置超时回调(本地磁盘文件也可能是网络媒体资源链接,会涉及RTMP/HTTP等协议的视频源,设置超时时间)寻找各个流(音频视频流),并且打开对应的解码器(音频视频解码器)初始化解码后数据的结构体需要分配出解码之后的数据所存放的内存空间进行格式转换所需要用到的对象读取流内容并且解码。解码器之后,就可以读取一部分流中的数据(压缩数据),然后将压缩数据作为解码器的输入,解码器将其解码为原始数据(裸数据),之后就可以将原始数据写入文件了处理解码后的裸数据。裸数据,音频就是脉冲编码调制数据,视频就是YUV数据。下面将其处理成我们所需要的格式并且进行写文件音频裸数据处理,将音频裸数据直接写入文件,比如写入到文件audio.pcm中视频的裸数据的处理,接收到YUV数据,写入文件video.yuv中关闭所有的资源退出的时候,要将用到的FFmpeg框架中的资源,包括FFmpeg框架对外的连接资源等全都释放掉FFmpeg主要的文件libavformat、libavcodeclibavformat和类库
libav甲酸盐的主要架构
AVFormatContext是API层直接接触的结构,它将封装和解封装格式,以及它的数据部分
它由底层提供,底层使用AVIOContext。这个AVIOContext实际上是在普通I/O上加了一层。
Buffer buffer,再往下就是URLContext,也就是到达协议层。协议层有许多具体的实现,包括
包括rtmp,http,hls,file等。这是libavformat的内部包。
libavcodec的主要架构
我们在这一层可以触及的最顶层结构是AVCodecContext,它包含与实际
与编码和解码相关的部分。首先,AVCodecContext包含在一个AVStream中,它描述了这个流。
编码格式是什么,其中存储了具体的编码格式信息,可以根据编解码器的信息开启编码器或者解码。
,然后使用编码器或解码器在AVPacket和AVFrame之间进行转换(实际上解码或
编码过程),这是FFmpeg最重要的部分。
Mpeg API 1,通用API
Av_register_all分析内部实现会先调用avcodec_register_all注册config.h中所有开放的编解码器,然后注册所有Muxer和Demuxer(也就是封装格式),最后注册所有协议(也就是协议层的东西)。这样,配置过程中的启用或禁用选项将应用于运行时。该函数源代码分析涉及到的源代码文件有:url.c、allformats.c、mux.c、format.c等文件av_find_codec来分析查找解码器。部分是找到编码器avCodec_open2,分析打开编解码器的功能。avcodec_close分析是一个逆过程。在对应的实现文件中找到关闭函数指针所指向的函数,然后函数会调用对应的第三方库的API来关闭对应的编码库2和FFmpeg解码API。
Avformat_open_input分析avformat_open_input会根据提供的文件路径判断文件的格式。其实就是通过这一步,决定了在直播场景下,流媒体客户端中的“第一屏二开”是用哪个demuxeravformat _ find _ stream _ info来分析的。即avcodec_decode分析,与这个函数分析的代码实现密切相关,是解码视频的一部分,解码音频的一部分。avformat_close_input分析会先调用Demuxer中对应的生命周期read_close方法,然后释放AVFormatContext,最后关闭文件或远程网络连接。3.FFmpeg编码API
Avformat_alloc_output_context2分析并调用方法avformat_alloc_context来分配AVFormatContext结构。当然最重要的是根据上一步注册的Muxer和Demuxer部分(也就是封装的格式部分)找到对应的格式。更多音视频免费视频资料可获取后台私信【音视频】

其他教程

ccpc比赛时间2021(2021全球邀请赛)

2022-9-9 1:13:03

其他教程

WPS Office for Mac(WPS for MAC)

2022-9-9 1:15:05

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索