FFMPEG实现H264的解码(从源代码角度)

简介: 农历2014年底了,将前段时间工作中研究的FFMPEG解码H264流程在此做一下整理,也算作年终技术总结了! H264解码原理: H264的原理参考另一篇博文 http://blog.csdn.net/rootusers/article/details/43563133 H264分为NAL(...

农历2014年底了,将前段时间工作中研究的FFMPEG解码H264流程在此做一下整理,也算作年终技术总结了!

H264解码原理:

H264的原理参考另一篇博文 http://blog.csdn.net/rootusers/article/details/43563133

H264分为NAL(网络抽象层)和VCL(视频编码层)

 

解码器的总框架:

解码器的流程为:将NAL数据位流输入到H264的解码器中,熵解码模块解码后输出量化系数X;系数经过反量化和反变换得到残差数据R;解码器使用从码流中解码的头信息生成预测块Pred,然后Pred与残差R求和得到块数据dF;每个块dF通过去除块效应的滤波得到解码图像的重建块F。

 

FFMPEG源代码解析:

FFMPEG中对于codec的注册和初始化在另一篇博文中有介绍,在这里不在涉及了:av_register_all

FFMPEG处理h264的模块主要是在h264.c中。

 

解码的主函数为:

主函数中的avcodec_init(),avcodec_register_all()等函数都是直接拿去的FFMPGE的源代码实现的,这个工程对于理解FFMPEG的解码流程有很大的作用。

 

[cpp]  view plain  copy
 
 print?
  1. int main(){  
  2.     FILE * inp_file;  
  3.     FILE * out_file;  
  4.   
  5.     int i;  
  6.     int nalLen;         /*NAL 长度*/  
  7.     unsigned char* Buf; /*H.264码流*/  
  8.     int  got_picture;       /*是否解码一帧图像*/  
  9.     int  consumed_bytes; /*解码器消耗的码流长度*/  
  10.     int cnt=0;  
  11.   
  12.     AVCodec *codec;           /* 编解码CODEC*/  
  13.     AVCodecContext *c;        /* 编解码CODEC context*/  
  14.     AVFrame *picture;         /* 解码后的图像*/     
  15.   
  16.     /*输出和输出的文件*/  
  17.     inp_file = fopen("test.h264", "rb");  
  18.     out_file = fopen("test.yuv", "wb");  
  19.   
  20.     nalLen = 0;  
  21.     /*分配内存,并初始化为0*/  
  22.     Buf = (unsigned char*)calloc ( 500*1024, sizeof(char));  
  23.   
  24.     /*CODEC的初始化,初始化一些常量表*/  
  25.     avcodec_init();   
  26.       
  27.     /*注册CODEC*/  
  28.     avcodec_register_all();   
  29.   
  30.     /*查找 H264 CODEC*/  
  31.     codec = avcodec_find_decoder(CODEC_ID_H264);  
  32.   
  33.     if (!codec)  return 0;   
  34.       
  35.     /*初始化CODEC的默认参数*/  
  36.     c = avcodec_alloc_context();   
  37.       
  38.     if(!c)  return 0;  
  39.       
  40.     /*1. 打开CODEC,这里初始化H.264解码器,调用decode_init本地函数*/  
  41.     if (avcodec_open(c, codec) < 0)  return 0;    
  42.       
  43.     /*为AVFrame申请空间,并清零*/  
  44.         picture   = avcodec_alloc_frame();  
  45.     if(!picture)    return 0;  
  46.       
  47.     /*循环解码*/  
  48.     while(!feof(inp_file))  {  
  49.         /*从码流中获得一个NAL包*/  
  50.         nalLen = getNextNal(inp_file, Buf);  
  51.   
  52.         /*2. NAL解码,调用decode_frame本地函数*/  
  53.         consumed_bytes= avcodec_decode_video(c, picture, &got_picture, Buf, nalLen);  
  54.   
  55.         cnt++;  
  56.         /*输出当前的解码信息*/  
  57.         printf("No:=%4d, length=%4d\n",cnt,consumed_bytes);  
  58.           
  59.         /*返回<0 表示解码数据头,返回>0,表示解码一帧图像*/  
  60.         if(consumed_bytes > 0)  
  61.         {  
  62.             /*从二维空间中提取解码后的图像*/  
  63.             for(i=0; i<c->height; i++)  
  64.                 fwrite(picture->data[0] + i * picture->linesize[0], 1, c->width, out_file);  
  65.             for(i=0; i<c->height/2; i++)  
  66.                 fwrite(picture->data[1] + i * picture->linesize[1], 1, c->width/2, out_file);  
  67.             for(i=0; i<c->height/2; i++)  
  68.                 fwrite(picture->data[2] + i * picture->linesize[2], 1, c->width/2, out_file);  
  69.         }  
  70.   
  71.     }  
  72.   
  73.     /*关闭文件*/  
  74.     if(inp_file)    fclose(inp_file);  
  75.     if(out_file)    fclose(out_file);  
  76.   
  77.     /*3. 关闭CODEC,释放资源,调用decode_end本地函数*/  
  78.     if(c) {  
  79.         avcodec_close(c);   
  80.         av_free(c);  
  81.         c = NULL;  
  82.     }   
  83.     /*释放AVFrame空间*/  
  84.     if(picture) {  
  85.         av_free(picture);  
  86.         picture = NULL;  
  87.     }  
  88.     /*释放内存*/  
  89.     if(Buf) {  
  90.         free(Buf);  
  91.         Buf = NULL;  
  92.     }      
  93.   
  94.     return 0;  
  95. }  

 

 

本工程是参考的网上的很多资料来改写的,因为开源,我们才会变的更优秀,希望所有的开发者都积极分享自己的音视频开发经验。向开源项目致敬。

源代码下载:

http://download.csdn.net/detail/rootusers/8428977

from:http://blog.csdn.net/rootusers/article/details/43560913

目录
相关文章
|
4月前
|
算法 数据处理 开发者
FFmpeg库的使用与深度解析:解码音频流流程
FFmpeg库的使用与深度解析:解码音频流流程
73 0
|
4月前
|
存储 编解码 数据处理
【FFmpeg 视频基本格式】深入理解FFmpeg:从YUV到PCM,解码到编码(三)
【FFmpeg 视频基本格式】深入理解FFmpeg:从YUV到PCM,解码到编码
156 0
|
4月前
|
存储 编解码 数据处理
【FFmpeg 视频基本格式】深入理解FFmpeg:从YUV到PCM,解码到编码(二)
【FFmpeg 视频基本格式】深入理解FFmpeg:从YUV到PCM,解码到编码
172 0
|
2月前
|
数据采集 大数据 Python
FFmpeg 在爬虫中的应用案例:流数据解码详解
在大数据背景下,网络爬虫与FFmpeg结合,高效采集小红书短视频。需准备FFmpeg、Python及库如Requests和BeautifulSoup。通过设置User-Agent、Cookie及代理IP增强隐蔽性,解析HTML提取视频链接,利用FFmpeg下载并解码视频流。示例代码展示完整流程,强调代理IP对避免封禁的关键作用,助你掌握视频数据采集技巧。
FFmpeg 在爬虫中的应用案例:流数据解码详解
|
2月前
|
语音技术 C语言 Windows
语音识别------ffmpeg的使用01,ffmpeg的安装,会做PPT很好,ffmpeg不具备直接使用,只可以操作解码数据,ffmpeg用C语言写的,得学C语言,ffmpeg的安装
语音识别------ffmpeg的使用01,ffmpeg的安装,会做PPT很好,ffmpeg不具备直接使用,只可以操作解码数据,ffmpeg用C语言写的,得学C语言,ffmpeg的安装
|
3月前
|
Linux 编解码 Python
FFmpeg开发笔记(二十四)Linux环境给FFmpeg集成AV1的编解码器
AV1是一种高效免费的视频编码标准,由AOM联盟制定,相比H.265压缩率提升约27%。各大流媒体平台倾向使用AV1。本文介绍了如何在Linux环境下为FFmpeg集成AV1编解码库libaom、libdav1d和libsvtav1。涉及下载源码、配置、编译和安装步骤,包括设置环境变量以启用这三个库。
167 3
FFmpeg开发笔记(二十四)Linux环境给FFmpeg集成AV1的编解码器
|
3月前
|
编解码 Linux 计算机视觉
python 调用ffmpeg使用usb摄像头录制视频,输出h264格式,自动获取摄像头的最佳帧率和最大画面尺寸
使用 Python 调用 FFmpeg 进行 USB 摄像头视频录制,需先确保安装 FFmpeg 和 Python 的 `subprocess` 模块。代码示例展示了如何自动获取摄像头的最佳帧率和最大分辨率,然后录制视频。首先通过 FFmpeg 列出摄像头格式获取信息,解析出帧率和分辨率,选择最优值。之后调用 FFmpeg 命令录制视频,设置帧率、分辨率等参数。注意 `/dev/video0` 是 Linux 的摄像头设备路径,Windows 系统需相应调整。代码中未直接实现自动获取最佳参数,通常需要借助其他库如 OpenCV。
|
4月前
|
编解码 5G Linux
FFmpeg开发笔记(二十一)Windows环境给FFmpeg集成AVS3解码器
AVS3是中国首个8K及5G视频编码标准,相比AVS2和HEVC性能提升约30%。解码器libuavs3d支持8K/60P视频实时解码,兼容多种平台。《FFmpeg开发实战》书中介绍了在Windows环境下如何集成libuavs3d到FFmpeg。集成步骤包括下载源码、使用Visual Studio 2022编译、调整配置、安装库文件和头文件,以及重新配置和编译FFmpeg以启用libuavs3d。
77 0
FFmpeg开发笔记(二十一)Windows环境给FFmpeg集成AVS3解码器
|
4月前
|
编解码 Linux 5G
FFmpeg开发笔记(二十)Linux环境给FFmpeg集成AVS3解码器
AVS3,中国制定的第三代音视频标准,是首个针对8K和5G的视频编码标准,相比AVS2和HEVC性能提升约30%。uavs3d是AVS3的解码器,支持8K/60P实时解码,且在各平台有优秀表现。要为FFmpeg集成AVS3解码器libuavs3d,需从GitHub下载最新源码,解压后配置、编译和安装。之后,重新配置FFmpeg,启用libuavs3d并编译安装,通过`ffmpeg -version`确认成功集成。
73 0
FFmpeg开发笔记(二十)Linux环境给FFmpeg集成AVS3解码器
|
4月前
|
存储 缓存 调度
FFmpeg开发笔记(十九)FFmpeg开启两个线程分别解码音视频
《FFmpeg开发实战》第10章示例playsync.c在处理音频流和视频流交错的文件时能实现同步播放,但对于分开存储的格式,会出现先播放全部声音再快速播放视频的问题。为解决此问题,需改造程序,增加音频处理线程和队列,以及相关锁,先将音视频帧读入缓存,再按时间戳播放。改造包括声明新变量、初始化线程和锁、修改数据包处理方式等。代码修改后在playsync2.c中,编译运行成功,控制台显示日志,SDL窗口播放视频并同步音频,证明改造有效。
75 0
FFmpeg开发笔记(十九)FFmpeg开启两个线程分别解码音视频