2024-06-19 06:35:05 +00:00
# include "HardH264FFmpegDecode.h"
2024-06-19 06:41:40 +00:00
# include <iostream>
2024-06-19 06:35:05 +00:00
using namespace std ;
2024-06-19 06:41:40 +00:00
HardH264FFmpegDecode : : HardH264FFmpegDecode ( )
2024-06-19 06:35:05 +00:00
{
2024-06-19 06:41:40 +00:00
;
2024-06-19 06:35:05 +00:00
}
2024-06-19 06:41:40 +00:00
HardH264FFmpegDecode : : ~ HardH264FFmpegDecode ( )
2024-06-19 06:35:05 +00:00
{
2024-06-19 06:41:40 +00:00
;
2024-06-19 06:35:05 +00:00
}
2024-06-19 06:41:40 +00:00
// int HardH264FFmpegDecode::HardH264FFmpegDecoderInit(unsigned int uiWidth, unsigned int uiHeight, unsigned int uiFrameRate)
// {
// uiWidth_ = uiWidth; uiHeight_ = uiHeight;
// uiFrameRate_ = uiFrameRate;
// iFrameFinished_ = 0;
// av_log_set_level(AV_LOG_ERROR);
// // AVCodecID codec_id = AV_CODEC_ID_H264; //解码H264
// // pCodec_ = avcodec_find_decoder(codec_id); //获取解码器
// pCodec_ = avcodec_find_decoder_by_name(NVIDIA_H264_DECODER);
// if (!pCodec_) {
// fprintf(stderr, "Codec '%s' not found\n", pCodec_->long_name);
// exit(1);
// }
// printf("Codec found with name %d(%s)\n", pCodec_->id, pCodec_->long_name);
// //创建上下文
// pCodecCtx_ = avcodec_alloc_context3(pCodec_);
// if (!pCodecCtx_){
// fprintf(stderr, "Could not allocate video codec context\n");
// exit(1);
// }
// //创建解析器
// pCodecParserCtx_ = av_parser_init(pCodec_->id);
// if (!pCodecParserCtx_){
// fprintf(stderr, "parser not found\n");
// exit(1);
// }
// //if(pCodec_->capabilities&CODEC_CAP_TRUNCATED)
// // pCodecCtx_->flags|= CODEC_FLAG_TRUNCATED;
// //打开解码器
// int ret = avcodec_open2(pCodecCtx_, pCodec_, nullptr);
// if (ret < 0) {
// fprintf(stderr, "Could not open codec\n");
// printf("avcodec_open2 ret is: %d\n",ret);
// exit(1);
// }
// //分配packet
// pPacket_ = av_packet_alloc();
// if (!pPacket_){
// fprintf(stderr, "Could not allocate video packet\n");
// exit(1);
// }
// // av_init_packet(pPacket_);
// //分配frame
// pSrcFrame_ = av_frame_alloc();
// if (!pSrcFrame_) {
// fprintf(stderr, "Could not allocate video src pFrame\n");
// exit(1);
// }
// pDstFrame_ = av_frame_alloc();
// if (!pDstFrame_) {
// fprintf(stderr, "Could not allocate video dst pFrame\n");
// exit(1);
// }
// printf("after align down video_width: %d, video_height: %d\n", uiWidth_, uiHeight_);
// //初始化解析器参数
// pCodecCtx_->time_base.num = 1;
// pCodecCtx_->frame_number = 1; //每包一个视频帧
// pCodecCtx_->codec_type = AVMEDIA_TYPE_VIDEO;
// pCodecCtx_->bit_rate = 0;
// pCodecCtx_->time_base.den = uiFrameRate_;//帧率
// pCodecCtx_->width = uiWidth_; //视频宽
// pCodecCtx_->height = uiHeight_; //视频高
// // pCodecCtx_->pix_fmt = AV_PIX_FMT_YUV420P;
// int bufferSize = av_image_get_buffer_size(AV_PIX_FMT_YUV420P,
// pCodecCtx_->width,
// pCodecCtx_->height, 1);
// pu8OutBuffer_ = (unsigned char *) av_malloc(bufferSize);
// av_image_fill_arrays(pDstFrame_->data,
// pDstFrame_->linesize,
// pu8OutBuffer_,
// AV_PIX_FMT_YUV420P,
// pCodecCtx_->width,
// pCodecCtx_->height, 1);
// printf("pDstFrame_->linesize: %d, bufferSize: %d\n", pDstFrame_->linesize, bufferSize);
// pSwsContext_ = sws_getContext(pCodecCtx_->width, pCodecCtx_->height, pCodecCtx_->pix_fmt,
// pCodecCtx_->width, pCodecCtx_->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, nullptr, nullptr, nullptr);
// printf("pCodecCtx_->width: %d, pCodecCtx_->height: %d, pCodecCtx_->pix_fmt: %d\n", pCodecCtx_->width, pCodecCtx_->height, pCodecCtx_->pix_fmt);
// return 0;
// }
int HardH264FFmpegDecode : : HardH264FFmpegDecoderInit ( unsigned int width , unsigned int height , unsigned int frame_rate )
2024-06-19 06:35:05 +00:00
{
2024-06-19 06:41:40 +00:00
width_ = width ;
height_ = height ;
frame_rate_ = frame_rate ;
frameFinished_ = 0 ;
2024-06-19 06:35:05 +00:00
av_log_set_level ( AV_LOG_ERROR ) ;
2024-06-19 06:41:40 +00:00
avcodec_register_all ( ) ; // 注册编解码器
avformat_network_init ( ) ; // 注册网络格式,如果为本地文件则可以去掉该代码
2024-06-19 06:35:05 +00:00
// AVCodecID codec_id = AV_CODEC_ID_H264; //解码H264
// pCodec_ = avcodec_find_decoder(codec_id); //获取解码器
pCodec_ = avcodec_find_decoder_by_name ( NVIDIA_H264_DECODER ) ;
2024-06-19 06:41:40 +00:00
if ( ! pCodec_ )
{
// fprintf(stderr, "Codec '%s' not found\n", pCodec_->long_name);
2024-06-19 06:35:05 +00:00
exit ( 1 ) ;
}
2024-06-19 06:41:40 +00:00
// printf("Codec found with name %d(%s)\n", pCodec_->id, pCodec_->long_name);
2024-06-19 06:35:05 +00:00
2024-06-19 06:41:40 +00:00
// 创建上下文
2024-06-19 06:35:05 +00:00
pCodecCtx_ = avcodec_alloc_context3 ( pCodec_ ) ;
2024-06-19 06:41:40 +00:00
if ( ! pCodecCtx_ )
{
// fprintf(stderr, "Could not allocate video codec context\n");
2024-06-19 06:35:05 +00:00
exit ( 1 ) ;
}
2024-06-19 06:41:40 +00:00
// 创建解析器
2024-06-19 06:35:05 +00:00
pCodecParserCtx_ = av_parser_init ( pCodec_ - > id ) ;
2024-06-19 06:41:40 +00:00
if ( ! pCodecParserCtx_ )
{
// fprintf(stderr, "parser not found\n");
2024-06-19 06:35:05 +00:00
exit ( 1 ) ;
}
2024-06-19 06:41:40 +00:00
// if(pCodec_->capabilities&CODEC_CAP_TRUNCATED)
// pCodecCtx_->flags|= CODEC_FLAG_TRUNCATED;
2024-06-19 06:35:05 +00:00
2024-06-19 06:41:40 +00:00
// 打开解码器
2024-06-19 06:35:05 +00:00
int ret = avcodec_open2 ( pCodecCtx_ , pCodec_ , nullptr ) ;
2024-06-19 06:41:40 +00:00
if ( ret < 0 )
{
// fprintf(stderr, "Could not open codec\n");
// printf("avcodec_open2 ret is: %d\n",ret);
2024-06-19 06:35:05 +00:00
exit ( 1 ) ;
}
2024-06-19 06:41:40 +00:00
// 初始化解析器参数
pCodecCtx_ - > time_base . num = 1 ;
pCodecCtx_ - > frame_number = 1 ; // 每包一个视频帧
pCodecCtx_ - > codec_type = AVMEDIA_TYPE_VIDEO ;
pCodecCtx_ - > bit_rate = 0 ;
pCodecCtx_ - > time_base . den = frame_rate_ ; // 帧率
pCodecCtx_ - > width = width_ ; // 视频宽
pCodecCtx_ - > height = height_ ; // 视频高
// 分配frame
pFrame_ = av_frame_alloc ( ) ;
if ( ! pFrame_ )
{
// fprintf(stderr, "Could not allocate video frame\n");
2024-06-19 06:35:05 +00:00
exit ( 1 ) ;
}
2024-06-19 06:41:40 +00:00
// 分配packet
pPacket_ = av_packet_alloc ( ) ;
if ( ! pPacket_ )
{
// fprintf(stderr, "Could not allocate video packet\n");
2024-06-19 06:35:05 +00:00
exit ( 1 ) ;
}
2024-06-19 06:41:40 +00:00
// av_init_packet(pPacket_);
2024-06-19 06:35:05 +00:00
return 0 ;
}
2024-06-19 06:41:40 +00:00
2024-06-19 06:35:05 +00:00
int HardH264FFmpegDecode : : HardH264FFmpegDecoderDeInit ( )
{
2024-06-19 06:41:40 +00:00
if ( pu8OutBuffer_ ) {
2024-06-19 06:35:05 +00:00
av_free ( pu8OutBuffer_ ) ;
pu8OutBuffer_ = nullptr ;
}
2024-06-19 06:41:40 +00:00
if ( pSrcFrame_ ) {
av_frame_free ( & pSrcFrame_ ) ;
pSrcFrame_ = nullptr ;
}
if ( pDstFrame_ ) {
av_frame_free ( & pDstFrame_ ) ;
pDstFrame_ = nullptr ;
}
if ( pPacket_ ) {
av_packet_free ( & pPacket_ ) ;
2024-06-19 06:35:05 +00:00
pPacket_ = nullptr ;
}
2024-06-19 06:41:40 +00:00
if ( pCodecParserCtx_ ) {
av_parser_close ( pCodecParserCtx_ ) ;
pCodecParserCtx_ = nullptr ;
}
if ( pCodecCtx_ ) {
avcodec_close ( pCodecCtx_ ) ;
av_free ( pCodecCtx_ ) ;
pCodecCtx_ = nullptr ;
}
if ( pSwsContext_ ) {
sws_freeContext ( pSwsContext_ ) ;
pSwsContext_ = nullptr ;
}
2024-06-19 06:35:05 +00:00
}
int HardH264FFmpegDecode : : HardH264FFmpegDecoderFilterGraph ( AVFilterGraph * pGraph , AVFilterContext * pSourceCtx , AVFilterContext * pSinkCtx )
{
int ret ;
AVFilterInOut * pOutputs = nullptr , * pInputs = nullptr ;
if ( ( ret = avfilter_link ( pSourceCtx , 0 , pSinkCtx , 0 ) ) > = 0 ) {
2024-06-19 06:41:40 +00:00
ret = avfilter_graph_config ( pGraph , nullptr ) ;
2024-06-19 06:35:05 +00:00
}
avfilter_inout_free ( & pOutputs ) ;
avfilter_inout_free ( & pInputs ) ;
return ret ;
}
int HardH264FFmpegDecode : : HardH264FFmpegDecoderConfigureVideoFilters ( AVFilterGraph * pGraph , AVFilterContext * & pDecoderFilterIn , AVFilterContext * & pDecoderFilterOut , const int iWidth , const int iHeight , const int iFormat )
{
int iPixFormats [ 2 ] = { AV_PIX_FMT_YUV420P , AV_PIX_FMT_NONE } ;
char BufferSrcArgs [ 256 ] = { 0 } ;
AVFilterContext * pFiltSrc = nullptr , * pFiltDst = nullptr ;
int ret ;
snprintf ( BufferSrcArgs , sizeof ( BufferSrcArgs ) ,
" video_size=%dx%d:pix_fmt=%d:time_base=1/1200000 " ,
iWidth , iHeight , iFormat ) ;
if ( ( ret = avfilter_graph_create_filter ( & pFiltSrc ,
2024-06-19 06:41:40 +00:00
avfilter_get_by_name ( " buffer " ) , " ffplay_buffer " , BufferSrcArgs ,
nullptr , pGraph ) ) < 0 ) {
2024-06-19 06:35:05 +00:00
goto fail ;
}
ret = avfilter_graph_create_filter ( & pFiltDst ,
2024-06-19 06:41:40 +00:00
avfilter_get_by_name ( " buffersink " ) ,
" ffplay_buffersink " , nullptr , nullptr , pGraph ) ;
2024-06-19 06:35:05 +00:00
if ( ret < 0 ) {
goto fail ;
}
if ( ( ret = av_opt_set_int_list ( pFiltDst , " pix_fmts " , iPixFormats , AV_PIX_FMT_NONE , AV_OPT_SEARCH_CHILDREN ) ) < 0 ) {
goto fail ;
}
if ( ( ret = HardH264FFmpegDecoderFilterGraph ( pGraph , pFiltSrc , pFiltDst ) ) < 0 ) {
goto fail ;
}
pDecoderFilterIn = pFiltSrc ;
pDecoderFilterOut = pFiltDst ;
2024-06-19 06:41:40 +00:00
fail :
2024-06-19 06:35:05 +00:00
return ret ;
}
int HardH264FFmpegDecode : : HardH264FFmpegDecoder ( AVCodecContext * pDecCtx , AVFrame * pFrame , AVPacket * pPkt , void * pOutputData , unsigned int * puiOutputDataSize )
{
2024-06-19 06:41:40 +00:00
int ret ;
AVFilterGraph * pDecoderGraph = nullptr ;
2024-06-19 06:35:05 +00:00
ret = avcodec_send_packet ( pDecCtx , pPkt ) ; //接收packet解码
if ( ret < 0 ) {
fprintf ( stderr , " Error sending a packet for decoding \n " ) ;
exit ( 1 ) ;
}
while ( ret > = 0 ) {
ret = avcodec_receive_frame ( pDecCtx , pFrame ) ; //解码
if ( ret = = AVERROR ( EAGAIN ) | | ret = = AVERROR_EOF ) {
2024-06-19 06:41:40 +00:00
fprintf ( stderr , " During decoding eof \n " ) ;
2024-06-19 06:35:05 +00:00
return - 1 ;
}
else if ( ret < 0 ) {
fprintf ( stderr , " Error during decoding \n " ) ;
exit ( 1 ) ;
}
//printf("saving frame %3d\n", pDecCtx->frame_number);
fflush ( stdout ) ;
2024-06-19 06:41:40 +00:00
AVFilterContext * pDecoderFilterIn = nullptr , * pDecoderFilterOut = nullptr ;
2024-06-19 06:35:05 +00:00
// pFrame->width = ALIGN_DOWN(pFrame->width, 32);
// pFrame->height = ALIGN_DOWN(pFrame->height, 32);
// printf("pFrame->width: %d\tpFrame->height: %d\n", pFrame->width, pFrame->height);
2024-06-19 06:41:40 +00:00
2024-06-19 06:35:05 +00:00
pDecoderGraph = avfilter_graph_alloc ( ) ;
HardH264FFmpegDecoderConfigureVideoFilters ( pDecoderGraph , pDecoderFilterIn , pDecoderFilterOut , pFrame - > width , pFrame - > height , pFrame - > format ) ;
2024-06-19 06:41:40 +00:00
if ( pFrame - > format ! = AV_PIX_FMT_YUV420P ) {
2024-06-19 06:35:05 +00:00
DUMP_FRAME ( pFrame ) ;
2024-06-19 06:41:40 +00:00
ret = av_buffersrc_add_frame ( pDecoderFilterIn , pFrame ) ;
2024-06-19 06:35:05 +00:00
ret = av_buffersink_get_frame_flags ( pDecoderFilterOut , pFrame , 0 ) ;
DUMP_FRAME ( pFrame ) ;
2024-06-19 06:41:40 +00:00
int iSize = pFrame - > width * pFrame - > height ;
memcpy ( pOutputData , pFrame - > data [ 0 ] , iSize ) ; //Y
memcpy ( pOutputData + iSize , pFrame - > data [ 1 ] , iSize / 4 ) ; //U
memcpy ( pOutputData + iSize + iSize / 4 , pFrame - > data [ 2 ] , iSize / 4 ) ; //V
* puiOutputDataSize = iSize * 3 / 2 ;
return iSize * 3 / 2 ;
}
}
return 0 ;
2024-06-19 06:35:05 +00:00
}
2024-06-19 06:41:40 +00:00
// int HardH264FFmpegDecode::HardH264FFmpegDecoderV2(AVCodecContext *pDecCtx, SwsContext *pSwsCtx, AVFrame *pSrcFrame, AVFrame *pDstFrame, AVPacket *pPkt, void* pOutputData,unsigned int* puiOutputDataSize)
// {
// std::cout << "HardH264FFmpegDecoderV2--in " << std::endl;
// int ret;
// ret = avcodec_send_packet(pDecCtx, pPkt); //接收packet解码
// if (ret < 0) {
// fprintf(stderr, "Error sending a packet for decoding\n");
// exit(1);
// }
// std::cout << "HardH264FFmpegDecoderV2--in " << std::endl;
// while (ret >= 0) {
// ret = avcodec_receive_frame(pDecCtx, pSrcFrame); //解码
// if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){
// fprintf(stderr, "During decoding eof\n");
// return -1;
// }
// else if (ret < 0) {
// fprintf(stderr, "Error during decoding\n");
// exit(1);
// }
// // pDecCtx->width = ALIGN_DOWN(pDecCtx->width, 32);
// // pDecCtx->height = ALIGN_DOWN(pDecCtx->height, 32);
// sws_scale(pSwsCtx,
// (const uint8_t *const *)pSrcFrame->data,
// pSrcFrame->linesize,
// 0,
// pDecCtx->height,
// pDstFrame->data,
// pDstFrame->linesize);
// //printf("saving frame %3d\n", pDecCtx->frame_number);
// fflush(stdout);
// int iSize = pDecCtx->width * pDecCtx->height;
// memcpy(pOutputData, pDstFrame->data[0], iSize); //Y
// memcpy(pOutputData+iSize, pDstFrame->data[1], iSize/4); //U
// memcpy(pOutputData+iSize+iSize/4, pDstFrame->data[2], iSize/4); //V
// *puiOutputDataSize = iSize*3/2;
// return iSize*3/2;
// }
// return 0;
// }
int HardH264FFmpegDecode : : HardH264FFmpegDecoderV2 ( AVCodecContext * pDecCtx , AVFrame * pSrcFrame , AVPacket * pPkt , void * pOutputData , unsigned int * puiOutputDataSize )
2024-06-19 06:35:05 +00:00
{
int ret ;
2024-06-19 06:41:40 +00:00
ret = avcodec_send_packet ( pDecCtx , pPkt ) ; // 接收packet解码
if ( ret < 0 )
{
// fprintf(stderr, "Error sending a packet for decoding\n");
2024-06-19 06:35:05 +00:00
exit ( 1 ) ;
}
2024-06-19 06:41:40 +00:00
while ( ret > = 0 )
{
ret = avcodec_receive_frame ( pDecCtx , pSrcFrame ) ; // 解码
if ( ret = = AVERROR ( EAGAIN ) | | ret = = AVERROR_EOF )
{
// fprintf(stderr, "During decoding eof\n");
2024-06-19 06:35:05 +00:00
return - 1 ;
}
2024-06-19 06:41:40 +00:00
else if ( ret < 0 )
{
// fprintf(stderr, "Error during decoding\n");
2024-06-19 06:35:05 +00:00
exit ( 1 ) ;
}
2024-06-19 06:41:40 +00:00
////printf("saving frame %3d\n", pDecCtx->frame_number);
// fflush(stdout);
2024-06-19 06:35:05 +00:00
2024-06-19 06:41:40 +00:00
memcpy ( pOutputData , pSrcFrame - > data [ 0 ] , pSrcFrame - > width * pSrcFrame - > height ) ; // Y
memcpy ( pOutputData + pSrcFrame - > width * pSrcFrame - > height , pSrcFrame - > data [ 1 ] , pSrcFrame - > width * pSrcFrame - > height / 4 ) ; // U
memcpy ( pOutputData + pSrcFrame - > width * pSrcFrame - > height + pSrcFrame - > width * pSrcFrame - > height / 4 , pSrcFrame - > data [ 2 ] , pSrcFrame - > width * pSrcFrame - > height / 4 ) ; // V
* puiOutputDataSize = pSrcFrame - > width * pSrcFrame - > height * 3 / 2 ;
return pSrcFrame - > width * pSrcFrame - > height * 3 / 2 ;
2024-06-19 06:35:05 +00:00
}
return 0 ;
}