基于ffmpeg对h265编码数据进行解码成图片保存

头文件:

// cpu_h265_decoder.h
#pragma once

#ifndef _CPU_H265_DECODING_HEADER_
#define _CPU_H265_DECODING_HEADER_


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

#include <vector>
#include <iostream>


class CPUDecodeH265 {
public:
    CPUDecodeH265() = default;

    ~CPUDecodeH265();

    bool init_decoder();

    bool cpu_h265_decode_process_bgr(const std::vector<uint8_t> &in_data, std::vector<uint8_t> &out_data,
                                     uint32_t &out_width, uint32_t &out_height, int64_t *timestamp = NULL);

private:
    const AVCodec *codec_ptr_;
    AVCodecContext *codec_context_ptr_ = nullptr;
    AVCodecParserContext *parser_ptr_ = nullptr;
    AVPacket *pkt_ptr_ = nullptr;
    AVFrame *frame_ptr_ = nullptr;
    AVFrame *rgb_frame_ptr_ = nullptr;
    SwsContext *sws_ctx = nullptr;
    int rgb_num_bytes = 0;
    uint8_t *rgb_out_data_ = nullptr;
};


#endif // _CPU_H265_DECODING_HEADER_

cpp文件:

// // cpu_h265_decoder.cpp
#include "cpu_h265_decoder.h"

CPUDecodeH265::~CPUDecodeH265() {
    avcodec_close(codec_context_ptr_);
    av_frame_free(&frame_ptr_);
    av_frame_free(&rgb_frame_ptr_);
    av_packet_free(&pkt_ptr_);
    av_free(codec_context_ptr_);
    sws_freeContext(sws_ctx);
    if(rgb_out_data_){
        av_free(rgb_out_data_);
        rgb_out_data_ = nullptr;
    }
}

bool CPUDecodeH265::init_decoder() {
    avcodec_register_all();
    // 查找解码器
    codec_ptr_ = avcodec_find_decoder(AV_CODEC_ID_HEVC);
    if(!codec_ptr_){
        std::cout<<"Codec not found" << std::endl;
        return false;
    }

    // 创建一个解码器上下文
    codec_context_ptr_ = avcodec_alloc_context3(codec_ptr_);
    if (!codec_context_ptr_) {
        std::cout<<"Could not allocate video codec context" << std::endl;
        return false;
    }

//    //
//    parser_ptr_ = av_parser_init(codec_ptr_->id);
//    if (!parser_ptr_)
//    {
//        std::cout<<"h265 parser not found. " << std::endl;
//        return false;
//    }

    // 用于将输入数据封装成一个AVPacket
    pkt_ptr_ = av_packet_alloc();
    if(!pkt_ptr_) {
        std::cout<< "could not allocate a AVPacket. " << std::endl;
        return false;
    }

    av_init_packet(pkt_ptr_);

    // 打开解码器
    auto ret = avcodec_open2(codec_context_ptr_, codec_ptr_, NULL);
    if(ret<0){
        std::cout<< "could not open codec. " << std::endl;
        return false;
    }

    // 用于接收解码后的输出数据
    frame_ptr_ = av_frame_alloc();
    if(!frame_ptr_) {
        std::cout<< "could not allocate video frame. " << std::endl;
        return false;
    }

    rgb_frame_ptr_ = av_frame_alloc();
    if(!rgb_frame_ptr_) {
        std::cout<< "could not allocate video rgb frame. " << std::endl;
        return false;
    }
    rgb_frame_ptr_->format = AV_PIX_FMT_RGB24;
    return true;
}


bool CPUDecodeH265::cpu_h265_decode_process_bgr(const std::vector<uint8_t> &in_data, std::vector<uint8_t> &out_data,
                                                uint32_t &out_width, uint32_t &out_height, int64_t *timestamp) {
    auto src_data = in_data;
    pkt_ptr_->data = src_data.data();
    pkt_ptr_->size = src_data.size();
    int count=0;
        if(pkt_ptr_->size){
            std::cout<<"pkt_ptr_->size = " << pkt_ptr_->size << std::endl;
            int ret = avcodec_send_packet(codec_context_ptr_, pkt_ptr_);
            std::cout<<"count:"<< count<< ", avcodec_send_packet  ret="<<ret << std::endl;
            if(ret < 0) {
                std::cout << "Error sending a packet for decoding, the res of avcodec_send_packet=" << ret << std::endl;
                return false;
            }
            auto frame_ret = avcodec_receive_frame(codec_context_ptr_, frame_ptr_);
            std::cout<<"count:"<< count<< ", avcodec_receive_frame  frame_ret="<<frame_ret << std::endl;
            if (frame_ret < 0) {
                std::cout<< "Error during decoding. " << std::endl;
                return false;
            } else if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){
                return false;
            }

            // init 创建一个用于图像缩放和格式转换的上下文, 并为rgb_frame分配空间
            if(sws_ctx == nullptr){
                sws_ctx = sws_getContext(frame_ptr_->width, frame_ptr_->height, static_cast<AVPixelFormat>(frame_ptr_->format), // 源图像的宽、高和像素格式
                                                            frame_ptr_->width, frame_ptr_->height, AV_PIX_FMT_BGR24, // 目标图像的宽、高和像素格式
                                                            SWS_BILINEAR, nullptr, nullptr, nullptr); // 其他可选参数,这里使用默认值
                rgb_frame_ptr_->height = frame_ptr_->height;
                rgb_frame_ptr_->width = frame_ptr_->width;
                av_frame_get_buffer(rgb_frame_ptr_, 0);
            }

            sws_scale(sws_ctx, frame_ptr_->data, frame_ptr_->linesize, 0, frame_ptr_->height, rgb_frame_ptr_->data, rgb_frame_ptr_->linesize);
//            std::cout<< "-----success to convert to rgb fame"<< std::endl;
            auto rgb_out_data_size = av_image_get_buffer_size(static_cast<AVPixelFormat>(rgb_frame_ptr_->format), rgb_frame_ptr_->width, rgb_frame_ptr_->height, 1);
//            std::cout<< "-----rgb_out_data_size="<<rgb_out_data_size<< std::endl;
            if(rgb_out_data_ == nullptr) {
                rgb_out_data_ = static_cast<uint8_t *>(av_malloc(rgb_out_data_size));
            }
            for(int y = 0; y<rgb_frame_ptr_->height; y++) {
                memcpy(rgb_out_data_ + y*rgb_frame_ptr_->width*3, rgb_frame_ptr_->data[0] + y*rgb_frame_ptr_->linesize[0], rgb_frame_ptr_->width * 3);
            }
            out_height = rgb_frame_ptr_->height;
            out_width = rgb_frame_ptr_->width;
            out_data.assign(rgb_out_data_, rgb_out_data_ + rgb_out_data_size);
            memset(rgb_out_data_, 0, rgb_out_data_size);
            if(!out_data.size()){
                return false;
            }
        }
    av_packet_unref(pkt_ptr_);
    return true;
}

main 函数:

#include cpu_h265_decoder.h
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/core/core.hpp"
#include "opencv2/opencv.hpp"
#include "opencv2/imgproc/imgproc.hpp"


int mian(int argc, char ** argv){
std::unique_ptr<CPUDecodeH265> h265_decoder_;
h265_decoder_ = std::make_unique<CPUDecodeH265>();
bool h265_res = h265_decoder_->init_decoder();
if(!h265_res) {
    printf("h265 decoder init_decoder failure\n");
    exit(0);
}
std::vector<uint8_t> data_h265; // h265编码后的数据,入参
std::vector<uint8_t> out_data;
auto ret = h265_decoder_->cpu_h265_decode_process_bgr(data_h264, out_data, out_width, out_height);
if(ret){
cv::Mat img(out_height, out_width, out_data.data());
cv::imshow("decode_img", img);
cv::waitKey(0);
cv::destroyAllWindows();
}


return 0;
}

CMakeLists.txt:

cmake_minimum_required(VERSION 3.8)
project(cpu_decode_h265_test)
set(CMAKE_CXX_STANDARD 17)
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

include_directories(${CMAKE_CURRENT_SOURCE_DIR})

#OpenCV
include_directories(thirdparty/opencv_4.4.0/include/opencv4/)
link_directories(thirdparty/opencv_4.4.0/lib/)
set(OpenCV_LIBRARIES opencv_core opencv_imgcodecs opencv_highgui opencv_imgproc opencv_video
		opencv_videoio opencv_calib3d opencv_features2d opencv_flann)


#ffmpeg
include_directories(thirdparty/ffmpeg_4.2.9/include)
link_directories(thirdparty/ffmpeg_4.2.9/lib)

add_library(cpu_h265_decoder_x86_64
		cpu_h265_decoder.cpp)
target_link_libraries(		cpu_h265_decoder_x86_64
		avcodec
		avutil
		swresample
		swscale

add_executable(${PROJECT_NAME} main.cpp
		cpu_h265_decoder.cpp
		)
target_link_libraries(${PROJECT_NAME}
		avcodec
		avutil
		swresample
		swscale
     ${OpenCV_LIBRARIES}
		)




  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值