博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
fmpeg(ignore)------主要函数=通用+解码+编码
阅读量:3920 次
发布时间:2019-05-23

本文共 6617 字,大约阅读时间需要 22 分钟。

在这里插入图片描述
FFMpeg 中比较重要的函数以及数据结构如下:

1. 数据结构:

(1) AVFormatContext

(2-0) AVIOContext
(2) AVOutputFormat
(3) AVInputFormat
(4) AVCodecContext
(5) AVCodec

【查找编解码器】  //遍历AVCodec链表并且获得符合条件的元素 然后返回符合的编解码器AVCodec *avcodec_find_encoder(enum AVCodecID id)	{
return find_encdec(id, 1);}AVCodec *avcodec_find_decoder(enum AVCodecID id) {
return find_encdec(id, 0);}调用同一个查找函数find_encdec() 传参0/1表示找的是编码器or解码器 //类似的:AVCodec *avcodec_find_decoder_by_name(const char *name);//根据解码器名称查找解码器并返回AVCodec //pCodec=avcodec_find_encoder(pCodecCtx->codec_id);【根据指定解码器ID查找相应的编码器并返回AVCodec】static AVCodec *find_encdec(enum AVCodecID id, 【编or解】int encoder)循环会遍历AVCodec结构的【全局变量】链表,逐一比较输入的ID和每一个编码器的ID,直到找到ID取值相等的编码器int av_codec_is_encoder(const AVCodec *codec);int av_codec_is_encoder(const AVCodec *codec) 判定是否是编解码器 返回int

(6) AVFrame

(7) AVPicture
(8) AVPacket
(9) AVStream
(10)SwsContext视频分辩率、色彩空间变换时所需要的上下文句柄。
(11)AVCodecParser

通用

void av_register_all(void)		注册所有东西void avcodec_register_all(void) 注册编解码器int avformat_network_init(void); 加载socket库以及网络加密协议相关的库int avio_open2(	创建的AVIOContext **s, 文件地址const char *url, 打开方式int flags,				const AVIOInterruptCB *int_cb, AVDictionary **options);//≈≈≈avio_open2int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options); 使用AVCodec初始化AVCodecContext  即打开解码器

解码

avformat_open_input为AVFormatContext对象分配内存,打开指定的文件(自动检测格式)并读取文件头,将存储在其中的信息导出到AVFormatContext *s。有些格式没有文件头,或者没有在其中存储足够的信息,因此建议您调用avformat_find_stream_info()函数,该函数尝试读取和解码几个帧以查找丢失的信息。

初始化:	1.先进行avformat_alloc_context→→→得到一个AVFormatContext	2.int avformat_open_input(得到的AVFormatContext **ps, 							打开URL:const char *filename, 							指定输入格式AVInputFormat *fmt, 							额外参数AVDictionary **options);//av_open_input_file(&pFormatCtx, filename, NULL, 0, NULL)函数读取文件的头部并且把信息保存到我们给的AVFormatContext结构体中。最后三个参数用来指定文件格式,缓冲大小和格式参数,但如果把它们设置为空NULL或者0,libavformat将自动检测这些参数。//av_open_input_file 只是检测了文件的头部//所以接着 av_find_stream_info(pFormatCtx) 函数负责检查在文件中的流的信息。 作用是为pFormatCtx->streams填充上正确的信息。int avformat_find_stream_info(输入的AVFormatContext *ic, 额外选项AVDictionary **options); 	检查并给每个媒体流(音频/视频)的AVStream结构体赋值/*		读取一部分视音频数据并且获得一些相关的信息		【如各媒体流对应编解码器的类型AVMediaType和ID:CodecID】		{			1.查找解码器:find_decoder() //若有解码器or类型则直接返回 若没有则调用avcodec_find_decoder(codec_id)遍历找到解码器			2.打开解码器:avcodec_open2()			3.读取完整的一帧压缩编码的数据:read_frame_internal()				//av_read_frame()内部实际上就是调用的read_frame_internal()。			4.解码一些压缩编码数据:try_decode_frame()		}*/找到要处理的stream[videoindex]	videoindex=-1;	for(i=0; i
nb_streams; i++) if(pFormatCtx->streams[i]->codec->codec_type==目标枚举类型AVMEDIA_TYPE_VIDEO){
videoindex=i;break;}pCodecCtx找到并打开编解码器 pCodecCtx=pFormatCtx->streams[videoindex]->codec; pCodec=avcodec_find_decoder(pCodecCtx->codec_id); avcodec_open2(pCodecCtx, pCodec,NULL) 打开解码器 即用pCodec去初始化pCodeCtxpFrame=av_frame_alloc(); 解码得到pFrameYUV=av_frame_alloc(); 转换成YUV格式packet=(AVPacket *)av_malloc(sizeof(AVPacket));输出打印校验信息 av_dump_format(pFormatCtx,0,filepath,0); 设置并得到视频分辩率、色彩空间变换时所需要的上下文句柄 img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL); 循环提取出一帧数据并转换: while(av_read_frame(pFormatCtx, packet)>=0) 从AVFormatContext中读取一帧数据AVPacket {
if(packet->stream_index==videoindex) 必须属于指定的stream {
ret = avcodec_decode_video2(pCodecCtx, 输出pFrame, &got_picture, 输入packet); 解码一帧视频数据:AVPacket→AVFrame if(ret < 0){
printf("Decode Error.\n");return -1;} if(got_picture){
SDL_LockYUVOverlay(bmp); 锁定 pFrameYUV->data[0]=bmp->pixels[0]; pFrameYUV->data[1]=bmp->pixels[2]; pFrameYUV->data[2]=bmp->pixels[1]; pFrameYUV->linesize[0]=bmp->pitches[0]; pFrameYUV->linesize[1]=bmp->pitches[2]; pFrameYUV->linesize[2]=bmp->pitches[1]; sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize); SDL_UnlockYUVOverlay(bmp); SDL_DisplayYUVOverlay(bmp, &rect); //Delay 40ms SDL_Delay(40); } } av_free_packet(packet); } FIX: Flush Frames remained in Codec 类似上面的循环 输出余下的数据清理 SDL_Quit(); av_free(pFrameYUV); avcodec_close(pCodecCtx); avformat_close_input(&pFormatCtx);

编码

初始化:int avformat_alloc_output_context2(	初始化并得到的AVFormatContext **avctx, 									指定输出格式AVOutputFormat *oformat,                               	  	输出格式const char *format,                                 	输出文件名const char *filename) {
1)avformat_alloc_context初始化默认AVFormatContext。 2)若输入AVOutputFormat→→给予AVOutputFormat的oformat。 反之(无参数2),调用av_guess_format(使用参数34)推测输出的AVOutputFormat。然后给予AVOutputFormat的oformat。}编码:int avcodec_encode_video2( AVCodecContext *avctx, 输出AVPacket *avpkt, 输入const AVFrame *frame, 编码成功标志位int *got_packet_ptr); 输出:写视频文件头 int avformat_write_header(用于输出的AVFormatContext *s,额外选项 AVDictionary **options);写视频数据 int av_write_frame(用于输出的AAVFormatContext *s, 等待输出的AVPacket *pkt); 写视频文件尾 int av_write_trailer(用于输出的AVFormatContext *s);

sws 1.图像色彩空间转换;2.分辨率缩放;3.前后图像滤波处理。

sws_getContext():初始化SwsContextsws_scale():处理图像数据 转换图像格式sws_freeContext():释放1.初始化struct SwsContext *sws_getContext(源&目标的宽高、像素格式+flag+输入/输出图像滤波器信息+param)	sws_getContext(w, h, YV12, w, h, NV12, 0, NULL, NULL, NULL);      // YV12->NV12 色彩空间转换	sws_getContext(w, h, YV12, w/2, h/2, YV12, 0, NULL, NULL, NULL);  // YV12图像缩小到原图1/4	sws_getContext(w, h, YV12, 2w, 2h, YN12, 0, NULL, NULL, NULL);    // YV12图像放大到原图4倍,并转换为NV12结构函数返回SwsContext结构体,定义了基本变换信息。
2.转换int sws_scale(	struct SwsContext *c,				源数据的通道指针const uint8_t *const srcSlice[],   //Y U V分别对应一个通道指针 [R+G+B]+[R+G+B]... 故只占用一个通道 维数=1              	源数据的每一行起始位置const int srcStride[],               	起始位置int srcSliceY,               	处理行数int srcSliceH,              	输出数据的通道指针uint8_t *const dst[],               	输出数据通道行字节数const int dstStride[]);stride定义下一行的起始位置。stride和width不一定相同,这是因为:1.由于数据帧存储的对齐,有可能会向每行后面增加一些填充字节这样 stride = width + N;2.packet色彩空间下,每个像素几个通道数据混合在一起,例如RGB24,每个像素3字节连续存放,因此下一行的位置需要跳过3*width字节。srcSlice和srcStride的维数相同,由srcFormat值来。csp       维数        宽width      跨度stride      高YUV420     3        w, w/2, w/2    s, s/2, s/2   h, h/2, h/2YUYV       1        w, w/2, w/2   2s, 0, 0       h, h, hNV12       2        w, w/2, w/2    s, s, 0       h, h/2RGB24      1        w, w,   w     3s, 0, 0       h, 0, 0           参数int srcSliceY, int srcSliceH,定义在输入图像上处理区域,srcSliceY是起始位置,srcSliceH是处理多少行。如果srcSliceY=0,srcSliceH=height,表示一次性处理完整个图像。这种设置是为了多线程并行,例如可以创建两个线程,第一个线程处理 [0, h/2-1]行,第二个线程处理 [h/2, h-1]行。并行处理加快速度。参数uint8_t *const dst[], const int dstStride[]定义输出图像信息(输出的每个通道数据指针,每个通道行字节数)
3.释放sws_scalevoid sws_freeContext(struct SwsContext *swsContext);

转载地址:http://ryhrn.baihongyu.com/

你可能感兴趣的文章
实现业务数据的同步迁移 · 思路一
查看>>
龙芯开源社区上线.NET主页
查看>>
eShopOnContainers 知多少[11]:服务间通信之gRPC
查看>>
闲谈设计模式
查看>>
平台or职位,你怎么选?
查看>>
骚年快答 | 技术中台与业务中台都是啥?
查看>>
骚年快答 | 微服务架构中的BFF到底是啥?
查看>>
设计模式之适配器模式
查看>>
如何利用Gitlab-CI持续部署到远程机器?
查看>>
.NET Core + K8S + Loki 玩转日志聚合
查看>>
ASP.NET Core中的分布式缓存
查看>>
在ASP.NET Core中创建自定义端点可视化图
查看>>
五年了,别再把务虚会开 “虚” 了
查看>>
一文看懂"async"和“await”关键词是如何简化了C#中多线程的开发过程
查看>>
每天都在支付,你真的了解信息流和资金流?
查看>>
.Net Core 自定义配置源从配置中心读取配置
查看>>
设计模式之享元模式
查看>>
单例模式最佳实践
查看>>
.NET Core + Spring Cloud:服务注册与发现
查看>>
今天你内卷了吗?
查看>>