ffmpeg 解析h264裸流数据 并转成cv::Mat

来,先开代码。

#pragma once

#include <memory>
#include <mutex>
#include <opencv4/opencv2/opencv.hpp>

extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}

namespace Base
{

    class FFmpegStreamDecoder
    {
    public:
        int32_t Init(int width,int height);

        int32_t DeInit();

        int32_t Decode(const uint8_t *data, size_t length,cv::Mat& bgrMat);

    private:
        std::mutex decode_mutex;
        AVCodecContext *pCodecCtx = nullptr;
        AVCodec *pCodec = nullptr;
        AVCodecParserContext *pCodecParserCtx = nullptr;
        SwsContext *pSwsCtx = nullptr;

        AVFrame *pFrameYUV = nullptr;
        AVFrame *pFrameRGB = nullptr;
        uint8_t *rgbBuf = nullptr;
        size_t bufSize = 0;
        int32_t decode_width;
        int32_t decode_hight;

        std::mutex image_mutex;
    };

}
#include "FFmpegDecoder.h"
#include <unistd.h>
#include "logger.h"
#include "opencv2/opencv.hpp"

namespace Base
{

    int32_t FFmpegStreamDecoder::Init(int width,int height)
    {
        avcodec_register_all();

        pCodec = avcodec_find_decoder_by_name("h264_nvv4l2dec");
        //pCodec = avcodec_find_decoder(AV_CODEC_ID_H264);
        
        if (!pCodec)
        {
            ERROR("pCodec: %p", pCodec);
            return -2;
        }

        pCodecParserCtx = av_parser_init(pCodec->id);
        if (!pCodecParserCtx)
        {
            return -3;
        }

        pCodecCtx = avcodec_alloc_context3(pCodec);
        pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
        pCodecCtx->width = width;
        pCodecCtx->height = height;
        pCodecCtx->flags2 |= AV_CODEC_FLAG2_SHOW_ALL;
        if (!pCodecCtx)
        {
            return -1;
        }
        pCodecCtx->thread_count = 4;

        auto ret = avcodec_open2(pCodecCtx, pCodec, nullptr);
        if (ret < 0)
        {
            char buferr[32];
            ERROR("avcodec open2 failed: %d, %s", ret,
                  av_make_error_string(buferr, 32, ret));
            return -6;
        }

        pFrameYUV = av_frame_alloc();
        if (!pFrameYUV)
        {
            return -4;
        }

        pFrameRGB = av_frame_alloc();
        if (!pFrameRGB)
        {
            return -5;
        }

        pSwsCtx = nullptr;

        return 0;
    }

    int32_t FFmpegStreamDecoder::DeInit()
    {
        if (nullptr != pSwsCtx)
        {
            sws_freeContext(pSwsCtx);
            pSwsCtx = nullptr;
        }

        if (nullptr != pFrameYUV)
        {
            av_free(pFrameYUV);
            pFrameYUV = nullptr;
        }

        if (nullptr != pCodecParserCtx)
        {
            av_parser_close(pCodecParserCtx);
            pCodecParserCtx = nullptr;
        }

        if (nullptr != pCodec)
        {
            avcodec_close(pCodecCtx);
            pCodec = nullptr;
        }

        if (nullptr != pCodecCtx)
        {
            av_free(pCodecCtx);
            pCodecCtx = nullptr;
        }

        if (nullptr != rgbBuf)
        {
            av_free(rgbBuf);
            rgbBuf = nullptr;
        }

        if (nullptr != pFrameRGB)
        {
            av_free(pFrameRGB);
            pFrameRGB = nullptr;
        }
        return 0;
    }

    int32_t FFmpegStreamDecoder::Decode(const uint8_t *data, size_t length,cv::Mat& rgbMat)
    {
        const uint8_t *pData = data;
        int remainingLen = length;
        int processedLen = 0;

        std::lock_guard<std::mutex> l(decode_mutex);
        AVPacket pkt;
        av_init_packet(&pkt);
        while (remainingLen > 0)
        {
            if (!pCodecParserCtx || !pCodecCtx)
            {
                break;
            }
            processedLen = av_parser_parse2(
                pCodecParserCtx, pCodecCtx, &pkt.data, &pkt.size, pData,
                remainingLen, AV_NOPTS_VALUE, AV_NOPTS_VALUE, AV_NOPTS_VALUE);
            remainingLen -= processedLen;
            pData += processedLen;

            if (pkt.size > 0)
            {
                int gotPicture = 0;
                avcodec_decode_video2(pCodecCtx, pFrameYUV, &gotPicture, &pkt);

                if (!gotPicture)
                {
                    continue;
                }
                else
                {
                    if (pFrameYUV->width != decode_width ||
                        pFrameYUV->height != decode_hight)
                    {
                        decode_width = pFrameYUV->width;
                        decode_hight = pFrameYUV->height;
                        if (nullptr != pSwsCtx)
                        {
                            sws_freeContext(pSwsCtx);
                            pSwsCtx = nullptr;
                        }
                        if (nullptr != rgbBuf)
                        {
                            av_free(rgbBuf);
                            rgbBuf = nullptr;
                        }
                        INFO("New H264 Width: %d, Height: %d", decode_width,
                             decode_hight);
                    }
                    int w = decode_width;
                    int h = decode_hight;

                    if (nullptr == pSwsCtx)
                    {
                        pSwsCtx = sws_getContext(w, h, pCodecCtx->pix_fmt, w, h,
                                                 AV_PIX_FMT_RGB24, 4, nullptr,
                                                 nullptr, nullptr);
                    }

                    if (nullptr == rgbBuf)
                    {
                        bufSize = avpicture_get_size(AV_PIX_FMT_RGB24, w, h);
                        rgbBuf = (uint8_t *)av_malloc(bufSize);
                        avpicture_fill((AVPicture *)pFrameRGB, rgbBuf,
                                       AV_PIX_FMT_RGB24, w, h);
                    }

                    if (nullptr != pSwsCtx && nullptr != rgbBuf)
                    {
                        sws_scale(pSwsCtx, (uint8_t const *const *)pFrameYUV->data,
                                  pFrameYUV->linesize, 0, pFrameYUV->height,
                                  pFrameRGB->data, pFrameRGB->linesize);

                        pFrameRGB->height = h;
                        pFrameRGB->width = w;

                        if (pFrameRGB->data[0])
                        {
                            cv::Mat tmp(h, w, CV_8UC3, pFrameRGB->data[0], w * 3);
                            //cv::Mat cvtmp;
                           // cvtColor(tmp, cvtmp, cv::COLOR_RGB2BGR);
                            rgbMat = tmp;
                        }
                    }
                }
            }
            av_free_packet(&pkt);
        }
        return 0;
    }

} 

使用:

1,初始化
auto ret = ffmpegDecoderPtr->Init(width, height);

2,解码图片

ErrorCode ESDKManager::StreamCallback(const uint8_t *data, size_t len)
    {
        InfoL << "StreamCallback 成功! " << len;
        cv::Mat bgrImage;
        if (ffmpegDecoderPtr->Decode(data, len, bgrImage) == 0)
        {
            std::cout << "decodeer ok " << std::endl;

            if (bgrImage.empty())
            {
                return kOk;
            }
        }
        return kOk;
    }

3,析构
ffmpegDecoderPtr->DeInit();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

土拨鼠不是老鼠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值