FFmpeg解码H264视频裸流(直接可用)

这篇具有很好参考价值的文章主要介绍了FFmpeg解码H264视频裸流(直接可用)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、写在前面

此文章主要包含解码H264视频流数据,主要有以下几点:

1、H264视频帧为Annex B格式,若使用AVCC格式可自行研究;

2、H264视频裸流,非解码视频文件(若有需要我后期可添加这部分代码);

3、支持输出RGB24或YUV420格式,其他可自行修改;

4、FFmpeg官网代码迭代及接口变更较大,代码适应于FFmpeg3.4.2"Cantor"、3.3.7"Hilbert"等版本,较旧接口请看旧版本代码;

2、新版本

FFmpegVideoDecoder.h

#include <libavcodec/avcodec.h>
 
/**
 视频流解码器初始化
 @param ctx 解码参数结构体AVCodecParameters
 @see FFmpeg_H264DecoderInit,此为解码H264视频流
 @return 初始化成功返回0,否则<0
 */
int FFmpeg_VideoDecoderInit(AVCodecParameters *ctx);
 
/**
 H264视频流解码器初始化
 @return 初始化成功返回0,否则<0
 */
int FFmpeg_H264DecoderInit(void);
 
/**
 释放解码器
 @return 初始化成功返回0,否则<0
 */
int FFmpeg_VideoDecoderRelease(void);
 
//return 0:暂未收到解码数据,-1:解码失败,1:解码成功
 
/**
 解码视频流数据
 @param inbuf 视频裸流数据
 @param inbufSize 视频裸流数据大小
 @param framePara 接收帧参数数组:{width,height,linesize1,linesiz2,linesize3}
 @param outRGBBuf 输出RGB数据(若已申请内存)
 @param outYUVBuf 输出YUV数据(若已申请内存)
 @return 成功返回解码数据帧大小,否则<=0
 */
int FFmpeg_H264Decode(unsigned char * inbuf, int inbufSize, int *framePara, unsigned char *outRGBBuf, unsigned char **outYUVBuf);

FFmpegVideoDecoder.c

#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include "FFmpegVideoDecoder.h"
 
struct AVCodecContext *pAVCodecCtx_decoder = NULL;
struct AVCodec *pAVCodec_decoder;
struct AVPacket mAVPacket_decoder;
struct AVFrame *pAVFrame_decoder = NULL;
struct SwsContext* pImageConvertCtx_decoder = NULL;
struct AVFrame *pFrameYUV_decoder = NULL;
 
int FFmpeg_VideoDecoderInit(AVCodecParameters *codecParameters)
{
    if (!codecParameters) {
        CPrintf("Source codec context is NULL.");   //CPrintf需替换为printf
        return -1;
    }
    FFmpeg_VideoDecoderRelease();
    avcodec_register_all();
    
    pAVCodec_decoder = avcodec_find_decoder(codecParameters->codec_id);
    if (!pAVCodec_decoder) {
        CPrintf1("Can not find codec:%d\n", codecParameters->codec_id);
        return -2;
    }
    
    pAVCodecCtx_decoder = avcodec_alloc_context3(pAVCodec_decoder);
    if (!pAVCodecCtx_decoder) {
        CPrintf("Failed to alloc codec context.");
        FFmpeg_VideoDecoderRelease();
        return -3;
    }
    
    if (avcodec_parameters_to_context(pAVCodecCtx_decoder, codecParameters) < 0) {
        CPrintf("Failed to copy avcodec parameters to codec context.");
        FFmpeg_VideoDecoderRelease();
        return -3;
    }
 
    
    if (avcodec_open2(pAVCodecCtx_decoder, pAVCodec_decoder, NULL) < 0){
        CPrintf("Failed to open h264 decoder");
        FFmpeg_VideoDecoderRelease();
        return -4;
    }
    
    av_init_packet(&mAVPacket_decoder);
    
    pAVFrame_decoder = av_frame_alloc();
    pFrameYUV_decoder = av_frame_alloc();
    
    return 0;
}
 
int FFmpeg_H264DecoderInit()
{
    avcodec_register_all();
    AVCodec *pAVCodec = avcodec_find_decoder(AV_CODEC_ID_H264);
    if (!pAVCodec){
        CPrintf("can not find H264 codec\n");
        return -1;
    }
 
    AVCodecContext *pAVCodecCtx = avcodec_alloc_context3(pAVCodec);
    if (pAVCodecCtx == NULL) {
        CPrintf("Could not alloc video context!\n");
        return -2;
    }
    
    AVCodecParameters *codecParameters = avcodec_parameters_alloc();
    if (avcodec_parameters_from_context(codecParameters, pAVCodecCtx) < 0) {
        CPrintf("Failed to copy avcodec parameters from codec context.");
        avcodec_parameters_free(&codecParameters);
        avcodec_free_context(&pAVCodecCtx);
        return -3;
    }
    
    int ret = FFmpeg_VideoDecoderInit(codecParameters);
    avcodec_parameters_free(&codecParameters);
    avcodec_free_context(&pAVCodecCtx);
    
    return ret;
}
 
int FFmpeg_VideoDecoderRelease() {
    if (pAVCodecCtx_decoder != NULL) {
        avcodec_free_context(&pAVCodecCtx_decoder);
        pAVCodecCtx_decoder = NULL;
    }
    
    if (pAVFrame_decoder != NULL) {
        av_packet_unref(&mAVPacket_decoder);
        av_free(pAVFrame_decoder);
        pAVFrame_decoder = NULL;
    }
    
    if (pFrameYUV_decoder) {
        av_frame_unref(pFrameYUV_decoder);
        av_free(pFrameYUV_decoder);
        pFrameYUV_decoder = NULL;
    }
    
    if (pImageConvertCtx_decoder) {
        sws_freeContext(pImageConvertCtx_decoder);
    }
    
    av_packet_unref(&mAVPacket_decoder);
    
    return 0;
}
 
int FFmpeg_H264Decode(unsigned char *inbuf, int inbufSize, int *framePara, unsigned char *outRGBBuf, unsigned char **outYUVBuf)
{
    if (!pAVCodecCtx_decoder || !pAVFrame_decoder || !inbuf || inbufSize<=0 || !framePara || (!outRGBBuf && !outYUVBuf)) {
        return -1;
    }
    av_frame_unref(pAVFrame_decoder);
    av_frame_unref(pFrameYUV_decoder);
    
    framePara[0] = framePara[1] = 0;
    mAVPacket_decoder.data = inbuf;
    mAVPacket_decoder.size = inbufSize;
    
    int ret = avcodec_send_packet(pAVCodecCtx_decoder, &mAVPacket_decoder);
    if (ret == 0) {
        ret = avcodec_receive_frame(pAVCodecCtx_decoder, pAVFrame_decoder);
        if (ret == 0) {
            framePara[0] = pAVFrame_decoder->width;
            framePara[1] = pAVFrame_decoder->height;
            
            if (outYUVBuf) {
                *outYUVBuf = (unsigned char *)pAVFrame_decoder->data;
                framePara[2] = pAVFrame_decoder->linesize[0];
                framePara[3] = pAVFrame_decoder->linesize[1];
                framePara[4] = pAVFrame_decoder->linesize[2];
            } else if (outRGBBuf) {
                pFrameYUV_decoder->data[0] = outRGBBuf;
                pFrameYUV_decoder->data[1] = NULL;
                pFrameYUV_decoder->data[2] = NULL;
                pFrameYUV_decoder->data[3] = NULL;
                int linesize[4] = { pAVCodecCtx_decoder->width * 3, pAVCodecCtx_decoder->height * 3, 0, 0 };
                pImageConvertCtx_decoder = sws_getContext(pAVCodecCtx_decoder->width, pAVCodecCtx_decoder->height, AV_PIX_FMT_YUV420P, pAVCodecCtx_decoder->width, pAVCodecCtx_decoder->height, AV_PIX_FMT_RGB24, SWS_FAST_BILINEAR, NULL, NULL, NULL);
                sws_scale(pImageConvertCtx_decoder, (const uint8_t* const *) pAVFrame_decoder->data, pAVFrame_decoder->linesize, 0, pAVCodecCtx_decoder->height, pFrameYUV_decoder->data, linesize);
                sws_freeContext(pImageConvertCtx_decoder);
                
                return 1;
            }
        } else if (ret == AVERROR(EAGAIN)) {
            return 0;
        } else {
            return -1;
        }
    }
    
    return 0;
}

3、旧版本

FFmpegVideoDecoder.h

int FFmpeg_VideoDecoderInit(AVCodecContext *ctx);
int FFmpeg_H264DecoderInit(void);
int FFmpeg_VideoDecoderRelease(void);
int FFmpeg_H264Decode(unsigned char * inbuf, int inbufSize, int *framePara, unsigned char *outRGBBuf, unsigned char **outYUVBuf);

FFmpegVideoDecoder.c

#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include "FFmpegVideoDecoder.h"
 
struct AVCodecContext *pAVCodecCtx = NULL;
struct AVCodec *pAVCodec;
struct AVPacket mAVPacket;
struct AVFrame *pAVFrame = NULL;
struct SwsContext* pImageConvertCtx = NULL;
struct AVFrame *pFrameYUV = NULL;
 
int FFmpeg_VideoDecoderInit(AVCodecContext *ctx)
{
    if (!ctx) {
        cv_printf("Source codec context is NULL.");     //cv_printf需替换为printf
        return -1;
    }
    FFmpeg_VideoDecoderRelease();
    avcodec_register_all();
    
    pAVCodec = avcodec_find_decoder(ctx->codec_id);
    if (!pAVCodec) {
        cv_printf("Can not find codec:%d\n", ctx->codec_id);
        return -2;
    }
    
    pAVCodecCtx = avcodec_alloc_context3(pAVCodec);
    if (!pAVCodecCtx || avcodec_copy_context(pAVCodecCtx, ctx) != 0) {
        cv_printf("Failed to alloc codec context.");
        FFmpeg_VideoDecoderRelease();
        return -3;
    }
    
    if (avcodec_open2(pAVCodecCtx, pAVCodec, NULL) < 0){
        cv_printf("Failed to open h264 decoder");
        FFmpeg_VideoDecoderRelease();
        return -4;
    }
    
    av_init_packet(&mAVPacket);
    
    pAVFrame = av_frame_alloc();
    pFrameYUV = av_frame_alloc();
    
    return 0;
}
 
int FFmpeg_H264DecoderInit()
{
    avcodec_register_all();
    AVCodec *pAVCodec = avcodec_find_decoder(AV_CODEC_ID_H264);
    if (!pAVCodec){
        cv_printf("can not find H264 codec\n");
        return -1;
    }
    
    AVCodecContext *pAVCodecCtx = avcodec_alloc_context3(pAVCodec);
    int ret = FFmpeg_VideoDecoderInit(pAVCodecCtx);
    
    if (pAVCodecCtx || ret < 0) {
        avcodec_free_context(&pAVCodecCtx);
        pAVCodecCtx = NULL;
    }
    
    return ret;
}
 
int FFmpeg_VideoDecoderRelease() {
    if (pAVCodecCtx != NULL) {
        avcodec_close(pAVCodecCtx);
        avcodec_free_context(&pAVCodecCtx);
        pAVCodecCtx = NULL;
    }
    
    if (pAVFrame != NULL) {
        av_packet_unref(&mAVPacket);
        av_free(pAVFrame);
        pAVFrame = NULL;
    }
    
    if (pFrameYUV) {
        av_frame_unref(pFrameYUV);
        av_free(pFrameYUV);
        pFrameYUV = NULL;
    }
    
    if (pImageConvertCtx) {
        sws_freeContext(pImageConvertCtx);
    }
    
    av_packet_unref(&mAVPacket);
    
    return 0;
}
 
int FFmpeg_H264Decode(unsigned char * inbuf, int inbufSize, int *framePara, unsigned char *outRGBBuf, unsigned char **outYUVBuf)
{
    av_frame_unref(pAVFrame);
    av_frame_unref(pFrameYUV);
    
    framePara[0] = framePara[1] = 0;
    mAVPacket.data = inbuf;
    mAVPacket.size = inbufSize;
    
    if (inbuf==NULL || inbufSize<=0) {
        return -1;
    }
    
    int len = -1, got_picture = 0;
    len = avcodec_decode_video2(pAVCodecCtx, pAVFrame, &got_picture, &mAVPacket);
    if (len < 0) {
        cv_printf("解码错误:%d\n",len);
        return len;
    }
   
    if (got_picture > 0) {
        framePara[0] = pAVFrame->width;
        framePara[1] = pAVFrame->height;
        
        if (outYUVBuf) {
            *outYUVBuf = (unsigned char *)pAVFrame->data;
            framePara[2] = pAVFrame->linesize[0];
            framePara[3] = pAVFrame->linesize[1];
            framePara[4] = pAVFrame->linesize[2];
        } else if (outRGBBuf) {
            pFrameYUV->data[0] = outRGBBuf;
            pFrameYUV->data[1] = NULL;
            pFrameYUV->data[2] = NULL;
            pFrameYUV->data[3] = NULL;
            int linesize[4] = { pAVCodecCtx->width * 3, pAVCodecCtx->height * 3, 0, 0 };
            pImageConvertCtx = sws_getContext(pAVCodecCtx->width, pAVCodecCtx->height, AV_PIX_FMT_YUV420P, pAVCodecCtx->width, pAVCodecCtx->height, AV_PIX_FMT_RGB24, SWS_FAST_BILINEAR, NULL, NULL, NULL);
            sws_scale(pImageConvertCtx, (const uint8_t* const *) pAVFrame->data, pAVFrame->linesize, 0, pAVCodecCtx->height, pFrameYUV->data, linesize);
            sws_freeContext(pImageConvertCtx);
        }
    }
    
    return len;
}

版权声明:本文为CSDN博主「W2Y」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:FFmpeg解码H264视频裸流(直接可用)-CSDN博客

★文末名片可以免费领取音视频开发学习资料,内容包括(FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)以及音视频学习路线图等等。

见下方!↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

 文章来源地址https://www.toymoban.com/news/detail-858055.html

到了这里,关于FFmpeg解码H264视频裸流(直接可用)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 音视频处理 ffmpeg中级开发 H264编码

    libavcodec/avcodec.h 常用的数据结构 AVCodec 编码器结构体 AVCodecContext 编码器上下文 AVFrame 解码后的帧 结构体内存的分配和释放 av_frame_alloc 申请 av_frame_free() 释放 avcodec_alloc_context3() 创建编码器上下文 avcodec_free_context() 释放编码器上下文 解码步骤 avcodec_find_decoder 查找解码器 avcod

    2024年02月01日
    浏览(59)
  • ffmpeg学习日记604-指令-将视频格式转为H264格式

    ffmpeg学习日记604-指令-将视频格式转为H264格式 在第四篇中,想要解码视频,缺没有弄清楚怎样的一个数据流,现在又明晰了一点,所谓的h264编解码,并不是直接将视频格式,通过h264编解码为视频原始数据流,这种说法是错误的,而是应该将视频格式转换为h264的数据流,然后

    2024年02月11日
    浏览(36)
  • 【音视频处理】转编码H264 to H265,FFmpeg,代码分享讲解

    大家好,欢迎来到停止重构的频道。 本期我们讨论音视频文件 转编码 ,如将视频H264转H265等。 内容中所提及的 代码都会放在GitHub ,感兴趣的小伙伴可以到GitHub下载。 我们按这样的顺序展开讨论:​ 1、  编码的作用  2、  转编码的工作原理 3、  编解码器安装  4、  示

    2024年02月11日
    浏览(38)
  • FFmpeg 解码 H.264 视频出现花屏和马赛克的解决办法

    发送数据包太大,超过了 FFmpeg 的默认最大值。 网络情况较差时,因网络状况出现的丢包。 解码出错。 包乱序。 一种方法是控制播放源的发送数据大小,但这极大浪费了当前的网络带宽,非优选方案。 更好的做法是扩大接收端的接收缓冲区,其修改方法为: 在 FFmpeg 的源码

    2024年04月26日
    浏览(28)
  • wireshark导出H264裸流

    下载抓包工具:首先,您需要下载并安装一个网络抓包工具,例如Wireshark(https://www.wireshark.org)或tcpdump(https://www.tcpdump.org)。这些工具可用于捕获网络流量并保存为pcap或pcapng文件。在这里插入代码片 打开抓包工具:打开所选择的抓包工具,并启动网络监控。 下载rtp_h264

    2024年02月15日
    浏览(28)
  • FFmpeg4入门13:h264编码为mp4

    上一篇将yuv源视频文件编码为 *.h264 的由libx264实现压缩的文件,将源文件从55M编码为620KB,但是h264文件只有视频数据,而且使用范围不太广。那么就需要进一步的封装,在此选用最常用的mp4格式为例。 随便选一个mp4格式文件,用FFmpeg4入门4:解析视频并输出视频信息或者ffp

    2023年04月10日
    浏览(68)
  • 使用NVIDIA GPU FFmpeg转码 YUV to H264(成功)

    NVIDIA官方教程:链接,本篇内容主要参考2.2 Software Setup。 确保nvidia-smi能够正常使用: 注意要与显卡驱动版本对应,验证toolkit是否正确安装: 下载地址 编译方法:解压进入文件夹后 验证安装          显示版本号证明安装成功: 下载地址 配置方法: 进入ffmpeg-x.x文件夹

    2024年02月06日
    浏览(35)
  • Android 引入FFmpeg 读取RTSP流 解封装获取H264原始数据

    之前 写了Android中怎么引入FFMmpeg的例子 。 本编文章将会写一个简单的demo实现ffmpeg拉去rtsp流并在界面中打印前五个字节 懒得往下细看的可以点击这里下载工程 基于andorid studio  实际效果下图: android 用ffmpeg 拉取rtsp流 解出h264数据 看下目录结构: 很简单 应用进去之后有一个

    2024年02月03日
    浏览(38)
  • FFmpeg命令行进行UDP、RTP推流(H264、TS),使用ffplay\VLC接收验证

            使用行FFmpeg命令进行UDP、RTP推流(H264、TS),ffplay接收我们在开发网络程序时经常用到UDP或RTP来发送和接收流媒体,而开发程序完毕需要搭建一个环境测试,这时候可能你需要一个推流端或接收端。对于推流端,我们可以借助FFmpeg工具轻松完成该功能,只需要敲一

    2024年02月05日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包