利用ffmpeg将H264流 解码为RGB

简介: <p style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;"></p><pre name="code" class="cpp"><pre name="code" clas

利用H264解码分为几个步骤:

 

注意一点在添加头文件的时候要添加extern "C",不然会出现错误

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. extern "C"  
  2. {  
  3. #include <avcodec.h>  
  4. #include <avformat.h>  
  5. #include <avutil.h>  
  6. #include <swscale.h>  
  7. };  


 

 

这里申明了几个全局变量

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. AVCodec         *pCodec = NULL;  
  2. AVCodecContext  *pCodecCtx = NULL;  
  3. SwsContext      *img_convert_ctx = NULL;  
  4. AVFrame         *pFrame = NULL;  
  5. AVFrame         *pFrameRGB = NULL;  


 

1. 初始化

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. int H264_Init(void)  
  2. {  
  3.     /* must be called before using avcodec lib*/  
  4.     avcodec_init();  
  5.     /* register all the codecs */  
  6.     avcodec_register_all();  
  7.   
  8.     /* find the h264 video decoder */  
  9.     pCodec = avcodec_find_decoder(CODEC_ID_H264);  
  10.     if (!pCodec) {  
  11.         fprintf(stderr, "codec not found\n");  
  12.     }  
  13.     pCodecCtx = avcodec_alloc_context();  
  14.   
  15.     /* open the coderc */  
  16.     if (avcodec_open(pCodecCtx, pCodec) < 0) {  
  17.         fprintf(stderr, "could not open codec\n");  
  18.     }  
  19.     // Allocate video frame  
  20.     pFrame = avcodec_alloc_frame();  
  21.     if(pFrame == NULL)  
  22.         return -1;  
  23.     // Allocate an AVFrame structure  
  24.     pFrameRGB=avcodec_alloc_frame();  
  25.     if(pFrameRGB == NULL)  
  26.         return -1;  
  27.   
  28.   
  29.       
  30.     return 0;  
  31.   
  32. }  

在最早使用的时候没有使用全局变量,初始化中也就只有init和regisger这两个函数,而这样做的下场是,非关键帧全部无法解码,只有关键帧才有办法解码。

2. 解码

解码的时候avcodec_decode_video函数是进行解码操作,在外部定义outputbuf的大小时,pixes*3,outsize是返回的outputbuf的size,值也是pixes*3。

 

在解码的时候这几句话的意义是将YUV420P的数据倒置。在原先使用中,发现解出来的图像居然是中心旋转图,后面在网上找了些办法,觉得这个比较实用。解码实时是很重要的,图像转化完之后也可以讲RGB图再次转化,那样也能成为一个正的图,但是那样效率就明显低了。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. pFrame->data[0] += pFrame->linesize[0] * (pCodecCtx->height-1);  
  2. pFrame->linesize[0] *= -1;  
  3. pFrame->data[1] += pFrame->linesize[1] * (pCodecCtx->height/2 - 1);;  
  4. pFrame->linesize[1] *= -1;  
  5. pFrame->data[2] += pFrame->linesize[2] * (pCodecCtx->height/2 - 1);;  
  6. pFrame->linesize[2] *= -1;  


 

 

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. int H264_2_RGB(unsigned char *inputbuf, int frame_size, unsigned char *outputbuf, unsigned int*outsize)  
  2. {  
  3.       
  4.     int             decode_size;  
  5.     int             numBytes;  
  6.     int             av_result;  
  7.     uint8_t         *buffer = NULL;  
  8.   
  9.     printf("Video decoding\n");  
  10.   
  11.     av_result = avcodec_decode_video(pCodecCtx, pFrame, &decode_size, inputbuf, frame_size);  
  12.     if (av_result < 0)  
  13.     {  
  14.         fprintf(stderr, "decode failed: inputbuf = 0x%x , input_framesize = %d\n", inputbuf, frame_size);  
  15.         return -1;  
  16.     }  
  17.   
  18.     // Determine required buffer size and allocate buffer  
  19.     numBytes=avpicture_get_size(PIX_FMT_BGR24, pCodecCtx->width,  
  20.         pCodecCtx->height);  
  21.     buffer = (uint8_t*)malloc(numBytes * sizeof(uint8_t));  
  22.     // Assign appropriate parts of buffer to image planes in pFrameRGB  
  23.     avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_BGR24,  
  24.         pCodecCtx->width, pCodecCtx->height);  
  25.   
  26.     img_convert_ctx = sws_getCachedContext(img_convert_ctx,pCodecCtx->width,pCodecCtx->height,  
  27.         //PIX_FMT_YUV420P,pCodecCtx->width,pCodecCtx->height,pCodecCtx->pix_fmt,  
  28.         pCodecCtx->pix_fmt,pCodecCtx->width,pCodecCtx->height,PIX_FMT_RGB24 ,  
  29.         SWS_X ,NULL,NULL,NULL) ;  
  30.     if (img_convert_ctx == NULL)   
  31.     {  
  32.   
  33.         printf("can't init convert context!\n") ;  
  34.         return -1;  
  35.     }  
  36.     pFrame->data[0] += pFrame->linesize[0] * (pCodecCtx->height-1);  
  37.     pFrame->linesize[0] *= -1;  
  38.     pFrame->data[1] += pFrame->linesize[1] * (pCodecCtx->height/2 - 1);;  
  39.     pFrame->linesize[1] *= -1;  
  40.     pFrame->data[2] += pFrame->linesize[2] * (pCodecCtx->height/2 - 1);;  
  41.     pFrame->linesize[2] *= -1;  
  42.     sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize,  
  43.         0, 0 - pCodecCtx->width, pFrameRGB->data, pFrameRGB->linesize);  
  44.       
  45.     if (decode_size)  
  46.     {  
  47.         *outsize = pCodecCtx->width * pCodecCtx->height * 3;  
  48.         memcpy(outputbuf, pFrameRGB->data[0], *outsize);  
  49.     }     
  50.   
  51.   
  52.     free(buffer);  
  53.     return 0;  
  54. }  

//解码yuv 修改 PIX_FMT_YUV420P	
memcpy(outputbuf, pFrameRGB->data[2], 720*576/4);
			memcpy(outputbuf, pFrameRGB->data[1], 720*576/4);
			memcpy(outputbuf, pFrameRGB->data[0], 720*576);



3. 释放资源

资源的回收。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void H264_Release(void)  
  2. {  
  3.     avcodec_close(pCodecCtx);  
  4.     av_free(pCodecCtx);  
  5.     av_free(pFrame);  
  6.     av_free(pFrameRGB);  
  7. }  
相关文章
|
6月前
|
数据采集 大数据 Python
FFmpeg 在爬虫中的应用案例:流数据解码详解
在大数据背景下,网络爬虫与FFmpeg结合,高效采集小红书短视频。需准备FFmpeg、Python及库如Requests和BeautifulSoup。通过设置User-Agent、Cookie及代理IP增强隐蔽性,解析HTML提取视频链接,利用FFmpeg下载并解码视频流。示例代码展示完整流程,强调代理IP对避免封禁的关键作用,助你掌握视频数据采集技巧。
FFmpeg 在爬虫中的应用案例:流数据解码详解
|
6月前
|
语音技术 C语言 Windows
语音识别------ffmpeg的使用01,ffmpeg的安装,会做PPT很好,ffmpeg不具备直接使用,只可以操作解码数据,ffmpeg用C语言写的,得学C语言,ffmpeg的安装
语音识别------ffmpeg的使用01,ffmpeg的安装,会做PPT很好,ffmpeg不具备直接使用,只可以操作解码数据,ffmpeg用C语言写的,得学C语言,ffmpeg的安装
|
7月前
|
Linux 编解码 Python
FFmpeg开发笔记(二十四)Linux环境给FFmpeg集成AV1的编解码器
AV1是一种高效免费的视频编码标准,由AOM联盟制定,相比H.265压缩率提升约27%。各大流媒体平台倾向使用AV1。本文介绍了如何在Linux环境下为FFmpeg集成AV1编解码库libaom、libdav1d和libsvtav1。涉及下载源码、配置、编译和安装步骤,包括设置环境变量以启用这三个库。
329 3
FFmpeg开发笔记(二十四)Linux环境给FFmpeg集成AV1的编解码器
|
7月前
|
编解码 Linux 计算机视觉
python 调用ffmpeg使用usb摄像头录制视频,输出h264格式,自动获取摄像头的最佳帧率和最大画面尺寸
使用 Python 调用 FFmpeg 进行 USB 摄像头视频录制,需先确保安装 FFmpeg 和 Python 的 `subprocess` 模块。代码示例展示了如何自动获取摄像头的最佳帧率和最大分辨率,然后录制视频。首先通过 FFmpeg 列出摄像头格式获取信息,解析出帧率和分辨率,选择最优值。之后调用 FFmpeg 命令录制视频,设置帧率、分辨率等参数。注意 `/dev/video0` 是 Linux 的摄像头设备路径,Windows 系统需相应调整。代码中未直接实现自动获取最佳参数,通常需要借助其他库如 OpenCV。
|
8月前
|
编解码 5G Linux
FFmpeg开发笔记(二十一)Windows环境给FFmpeg集成AVS3解码器
AVS3是中国首个8K及5G视频编码标准,相比AVS2和HEVC性能提升约30%。解码器libuavs3d支持8K/60P视频实时解码,兼容多种平台。《FFmpeg开发实战》书中介绍了在Windows环境下如何集成libuavs3d到FFmpeg。集成步骤包括下载源码、使用Visual Studio 2022编译、调整配置、安装库文件和头文件,以及重新配置和编译FFmpeg以启用libuavs3d。
129 0
FFmpeg开发笔记(二十一)Windows环境给FFmpeg集成AVS3解码器
|
8月前
|
编解码 Linux 5G
FFmpeg开发笔记(二十)Linux环境给FFmpeg集成AVS3解码器
AVS3,中国制定的第三代音视频标准,是首个针对8K和5G的视频编码标准,相比AVS2和HEVC性能提升约30%。uavs3d是AVS3的解码器,支持8K/60P实时解码,且在各平台有优秀表现。要为FFmpeg集成AVS3解码器libuavs3d,需从GitHub下载最新源码,解压后配置、编译和安装。之后,重新配置FFmpeg,启用libuavs3d并编译安装,通过`ffmpeg -version`确认成功集成。
149 0
FFmpeg开发笔记(二十)Linux环境给FFmpeg集成AVS3解码器
|
8月前
|
存储 缓存 调度
FFmpeg开发笔记(十九)FFmpeg开启两个线程分别解码音视频
《FFmpeg开发实战》第10章示例playsync.c在处理音频流和视频流交错的文件时能实现同步播放,但对于分开存储的格式,会出现先播放全部声音再快速播放视频的问题。为解决此问题,需改造程序,增加音频处理线程和队列,以及相关锁,先将音视频帧读入缓存,再按时间戳播放。改造包括声明新变量、初始化线程和锁、修改数据包处理方式等。代码修改后在playsync2.c中,编译运行成功,控制台显示日志,SDL窗口播放视频并同步音频,证明改造有效。
139 0
FFmpeg开发笔记(十九)FFmpeg开启两个线程分别解码音视频
|
8月前
|
存储 编解码 编译器
FFmpeg 7.0 正式登场:全新 VVC 解码器
【4月更文挑战第9天】最新版本的流行视频处理软件FFmpeg 7.0,代号为“Dijkstra”,已正式发布。
262 0
|
3月前
|
Linux 开发工具 Android开发
FFmpeg开发笔记(六十)使用国产的ijkplayer播放器观看网络视频
ijkplayer是由Bilibili基于FFmpeg3.4研发并开源的播放器,适用于Android和iOS,支持本地视频及网络流媒体播放。本文详细介绍如何在新版Android Studio中导入并使用ijkplayer库,包括Gradle版本及配置更新、导入编译好的so文件以及添加直播链接播放代码等步骤,帮助开发者顺利进行App调试与开发。更多FFmpeg开发知识可参考《FFmpeg开发实战:从零基础到短视频上线》。
304 2
FFmpeg开发笔记(六十)使用国产的ijkplayer播放器观看网络视频
|
3月前
|
编解码 语音技术 内存技术
FFmpeg开发笔记(五十八)把32位采样的MP3转换为16位的PCM音频
《FFmpeg开发实战:从零基础到短视频上线》一书中的“5.1.2 把音频流保存为PCM文件”章节介绍了将媒体文件中的音频流转换为原始PCM音频的方法。示例代码直接保存解码后的PCM数据,保留了原始音频的采样频率、声道数量和采样位数。但在实际应用中,有时需要特定规格的PCM音频。例如,某些语音识别引擎仅接受16位PCM数据,而标准MP3音频通常采用32位采样,因此需将32位MP3音频转换为16位PCM音频。
110 0
FFmpeg开发笔记(五十八)把32位采样的MP3转换为16位的PCM音频