#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 "../data/CodedData.hpp" #include "../data/FrameData.hpp" #include "../../common/gpu/info.h" #include "PsToEs.hpp" using namespace logif; namespace ffwrapper{ FormatIn::FormatIn(bool hw) :ctx_(NULL) ,dec_ctx_(NULL) ,vs_idx_(-1) ,hw_accl_(hw) ,io_ctx_(NULL) ,read_io_buff_(NULL) ,read_io_buff_size_(32768) {} 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_){ avformat_close_input(&ctx_); avformat_free_context(ctx_); ctx_ = NULL; if(dec_ctx_){ avcodec_close(dec_ctx_); dec_ctx_ = NULL; } } } //////////////////////////////////////////////////////////////////////// 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"); 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"); 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"); 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", err); logIt("failed:%s", getAVErrorDesc(err).c_str()); return -1; } return 0; } int FormatIn::openGb28181(const char *filename, AVDictionary **options){ std::string fn = filename; addCamera(fn); int ret = openWithCustomIO(NULL, readData, options); if(ret < 0){ logIt("do openWithCustomIO failed:%d",ret); } 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; } for (int i = 0; i < ctx_->nb_streams; ++i) { switch(ctx_->streams[i]->codecpar->codec_type){ case AVMEDIA_TYPE_VIDEO: vs_idx_ = i; break; default: break; } } return true; } bool FormatIn::openCodec(const int type, AVDictionary **options){ int stream_index = -1; switch(type){ case AVMEDIA_TYPE_VIDEO: stream_index = vs_idx_; break; default: break; } if(stream_index < 0){ logIt("open input %s codec need correct stream",ctx_->filename); return false; } AVStream *s = ctx_->streams[stream_index]; 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); // av_dict_set(&avdic, "gpu", std::to_string(2).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){ return ctx_->streams[vs_idx_]; } AVCodecContext *FormatIn::getCodecContext(int type){ return dec_ctx_; } bool FormatIn::readPacket(AVPacket &pkt_out, int stream_index){ bool founded = false; while (!founded){ const int ret = av_read_frame(ctx_, &pkt_out); if(ret < 0){ logIt("read frame from %s failed:%s", ctx_->filename,getAVErrorDesc(ret).c_str()); return false; } if(pkt_out.stream_index == stream_index){ founded = true; }else{ av_free_packet(&pkt_out); av_init_packet(&pkt_out); pkt_out.data = NULL; pkt_out.size = 0; } } pkt_out.stream_index = 0; return true; } bool FormatIn::readPacket(std::shared_ptr &data, int stream_index){ AVPacket &pkt(data->getAVPacket()); return readPacket(pkt, getStream()->index); } 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 1; } } return 0; } int FormatIn::decode(std::shared_ptr &frame_data, std::shared_ptr &data){ AVFrame *frame = frame_data->getAVFrame(); AVPacket &pkt(data->getAVPacket()); return decode(frame, pkt); } int FormatIn::readFrame(AVFrame* &frame){ auto data(std::make_shared()); if(!readPacket(data)){ return -1; } AVPacket &pkt(data->getAVPacket()); return decode(frame, pkt); } int FormatIn::readFrame(std::shared_ptr &frame_data){ AVFrame *frame(frame_data->getAVFrame()); return readFrame(frame); } }