#include "FormatIn.hpp" #include #include extern "C"{ #include #include #include #include #include #include #include } #include "../log/log.hpp" #include "../configure/conf.hpp" #include "../property/VideoProp.hpp" #include "../../common/gpu/info.h" using namespace logif; namespace ffwrapper{ FormatIn::FormatIn(bool hw) :ctx_(NULL) ,dec_ctx_(NULL) ,vs_idx_(-1) ,as_idx_(-1) ,hw_accl_(hw) ,io_ctx_(NULL) ,read_io_buff_(NULL) ,read_io_buff_size_(32768) ,handle_gb28181(NULL) ,fps_(25.0) {} FormatIn::~FormatIn() { if(io_ctx_){ if(read_io_buff_){ // av_free(read_io_buff_); read_io_buff_ = NULL; } avio_context_free(&io_ctx_); io_ctx_ = NULL; } if(ctx_){ if (!ctx_->oformat){ avformat_free_context(ctx_); }else{ avformat_close_input(&ctx_); } ctx_ = NULL; if(dec_ctx_){ avcodec_close(dec_ctx_); dec_ctx_ = NULL; } } if (handle_gb28181){ delete handle_gb28181; } } //////////////////////////////////////////////////////////////////////// int FormatIn::openWithCustomIO(void *opaque, read_packet fn, AVDictionary **options/*=NULL*/){ ctx_ = avformat_alloc_context(); if(!ctx_){ logIt("open with custom io create format error\n"); return -1; } read_io_buff_ = (uint8_t*)av_malloc(read_io_buff_size_); if(!read_io_buff_){ logIt("open with custom io alloc read io buff error\n"); return -1; } io_ctx_ = avio_alloc_context(read_io_buff_, read_io_buff_size_, 0, opaque, fn, NULL, NULL);//opaque if(!io_ctx_){ logIt("open with custom io create custom avio error\n"); return -1; } ctx_->pb = io_ctx_; auto err = av_probe_input_buffer(ctx_->pb, &ctx_->iformat, NULL, NULL, 0, read_io_buff_size_); if(err != 0){ logIt("open with custom io prob input buffer error:%d\n", err); logIt("custom io failed:%s", getAVErrorDesc(err).c_str()); return -1; } return 0; } int FormatIn::openGb28181(const char *filename, AVDictionary **options){ std::string fn = filename; //GB28181API gb28181(fn); if (handle_gb28181){ delete handle_gb28181; } handle_gb28181 = new GB28181API; if(handle_gb28181->addCamera(fn) == -1){ logIt("do addCamera Error\n"); return -1; } int ret = openWithCustomIO(handle_gb28181, handle_gb28181->readData, options); if(ret < 0){ logIt("do openWithCustomIO failed:%d",ret); }else{ ret = avformat_open_input(&ctx_, "", NULL, options); } // if(ret < 0){ // logIt("open %s failed:%s",filename, // getAVErrorDesc(ret).c_str()); // } return ret; } ///////////////////////////////////////////////////////////////////////// int FormatIn::open(const char *filename, AVDictionary **options){ const int ret = avformat_open_input(&ctx_, filename, NULL, options); // if(ret < 0){ // logIt("open %s failed:%s",filename, // getAVErrorDesc(ret).c_str()); // } return ret; } bool FormatIn::findStreamInfo(AVDictionary **options){ const int ret = avformat_find_stream_info(ctx_, options); if(ret < 0){ logIt("find %s stream info failed:%s", ctx_->filename,getAVErrorDesc(ret).c_str()); return false; } // logIt("there are %d stream", ctx_->nb_streams); for (int i = 0; i < ctx_->nb_streams; ++i) { auto type = ctx_->streams[i]->codecpar->codec_type; logIt("there are %d stream, stream %d, type %d", ctx_->nb_streams, i, type); if (type == AVMEDIA_TYPE_VIDEO){ vs_idx_ = i; auto in = ctx_->streams[i]; if(in->avg_frame_rate.num >=1 && in->avg_frame_rate.den >= 1){ fps_ = av_q2d(in->avg_frame_rate); }else if(in->r_frame_rate.num >=1 && in->r_frame_rate.den >= 1){ fps_ = av_q2d(in->r_frame_rate); } logIt("in stream video fps %f, time_base: %d : %d", fps_, in->time_base.num, in->time_base.den); } if (type == AVMEDIA_TYPE_AUDIO){ auto in = ctx_->streams[i]; logIt("in stream audio %d time_base: %d : %d", in->codecpar->codec_id, in->time_base.num, in->time_base.den); if (in->codecpar->codec_id == AV_CODEC_ID_AAC) as_idx_ = i; else logIt("record not support audio codec: %d", in->codecpar->codec_id); } } return true; } const bool FormatIn::IsHEVC()const{ return ctx_->streams[vs_idx_]->codecpar->codec_id == AV_CODEC_ID_HEVC; } bool FormatIn::openCodec(AVDictionary **options){ if (vs_idx_ == -1) return false; AVStream *s = ctx_->streams[vs_idx_]; AVCodecParameters *codecpar = s->codecpar; AVCodec *dec = NULL; bool flag = false; AVDictionary *avdic = NULL; int idle_gpu = -1; for (int i = 0; i < 2; ++i) { if(hw_accl_){ idle_gpu = gpu::getGPU(100); if(idle_gpu < 0){ logIt("NO GPU RESOURCE TO DECODE"); hw_accl_ = false; continue; } if(codecpar->codec_id == AV_CODEC_ID_H264){ dec = avcodec_find_decoder_by_name("h264_cuvid"); }else if(codecpar->codec_id == AV_CODEC_ID_H265){ dec = avcodec_find_decoder_by_name("hevc_cuvid"); } if(!dec){ hw_accl_ = false; continue; }else{ av_dict_set(&avdic, "gpu", std::to_string(idle_gpu).c_str(), 0); } }else{ dec = avcodec_find_decoder(codecpar->codec_id); } if(dec){ if(avdic){ options = &avdic; logIt("DECODE USE GPU %d", idle_gpu); } flag = allocCodec(dec, s, options); if(avdic){ av_dict_free(&avdic); } if(flag){ logIt("use decoder %s\n", dec->name); break; }else{ av_free(dec_ctx_); dec_ctx_ = NULL; hw_accl_ = false; } } } return flag; } bool FormatIn::allocCodec(AVCodec *dec, AVStream *s, AVDictionary **options){ AVCodecParameters *codecpar = s->codecpar; dec_ctx_ = avcodec_alloc_context3(dec); if (!dec_ctx_){ logIt("avcodec_alloc_context3 error"); return false; } int ret = avcodec_parameters_to_context(dec_ctx_, codecpar); if(ret < 0){ logIt("avcodec_parameters_to_context error : %s", getAVErrorDesc(ret).c_str()); return false; } av_codec_set_pkt_timebase(dec_ctx_, s->time_base); dec_ctx_->framerate = av_guess_frame_rate(ctx_, s, NULL); dec_ctx_->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; ret = avcodec_open2(dec_ctx_,dec, options); if(ret < 0){ logIt("open input %s codec failed:%s", ctx_->filename,getAVErrorDesc(ret).c_str()); return false; } return true; } AVStream *FormatIn::getStream(int type/*=-1*/){ if (type == -1){ return ctx_->streams[vs_idx_]; } if (vs_idx_ > -1 && type == ctx_->streams[vs_idx_]->codecpar->codec_type) return ctx_->streams[vs_idx_]; if (as_idx_ > -1 && type == ctx_->streams[as_idx_]->codecpar->codec_type) return ctx_->streams[as_idx_]; return NULL; } AVCodecContext *FormatIn::getCodecContext(int type){ return dec_ctx_; } bool FormatIn::isVideoPkt(AVPacket *pkt){ if (pkt->stream_index == vs_idx_){ return true; } return false; } bool FormatIn::isAudioPkt(AVPacket *pkt){ if (pkt->stream_index == as_idx_){ return true; } return false; } bool FormatIn::notVideoAudio(AVPacket *pkt){ return !isVideoPkt(pkt) && !isAudioPkt(pkt); } int FormatIn::readPacket(AVPacket *pkt_out){ auto flag = av_read_frame(ctx_, pkt_out); return flag; } int FormatIn::decode(AVFrame* frame, AVPacket *pkt){ AVStream *in = getStream(); av_packet_rescale_ts(pkt, in->time_base, in->codec->time_base); int ret = avcodec_send_packet(dec_ctx_, pkt); if(ret < 0){ logIt("avcodec_send_packet error : %s", getAVErrorDesc(ret).c_str()); return -1; } while (ret >= 0) { ret = avcodec_receive_frame(dec_ctx_, frame); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { break; } else if (ret < 0) { logIt("decode frame failed : %s", getAVErrorDesc(ret).c_str()); return -1; }else{ return 0; } } return -2; } }