| | |
| | | #include "../configure/conf.hpp" |
| | | |
| | | #include "../property/VideoProp.hpp" |
| | | #include "../data/CodedData.hpp" |
| | | #include "../data/FrameData.hpp" |
| | | |
| | | #include "../../common/gpu/info.h" |
| | | |
| | |
| | | :ctx_(NULL) |
| | | ,dec_ctx_(NULL) |
| | | ,vs_idx_(-1) |
| | | ,as_idx_(-1) |
| | | ,prop_(NULL) |
| | | ,hw_accl_(hw) |
| | | ,io_ctx_(NULL) |
| | | ,read_io_buff_(NULL) |
| | | ,read_io_buff_size_(32768) |
| | | ,handle_gb28181(NULL) |
| | | ,fps_(25.0) |
| | | {} |
| | | |
| | | FormatIn::FormatIn(const VideoProp &prop, bool hw/*=true*/) |
| | | :ctx_(NULL) |
| | | ,dec_ctx_(NULL) |
| | | ,vs_idx_(-1) |
| | | ,as_idx_(-1) |
| | | ,prop_(NULL) |
| | | ,hw_accl_(hw) |
| | | ,io_ctx_(NULL) |
| | | ,read_io_buff_(NULL) |
| | | ,read_io_buff_size_(32768) |
| | | ,handle_gb28181(NULL) |
| | | ,fps_(25.0) |
| | | { |
| | | prop_ = new VideoProp; |
| | | *prop_ = prop; |
| | | } |
| | | |
| | | 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; |
| | | logIt("free format in"); |
| | | if (prop_) delete prop_; |
| | | |
| | | if(dec_ctx_){ |
| | | avcodec_close(dec_ctx_); |
| | | avcodec_free_context(&dec_ctx_); |
| | | dec_ctx_ = NULL; |
| | | } |
| | | |
| | | if(ctx_){ |
| | | avformat_close_input(&ctx_); |
| | | avformat_free_context(ctx_); |
| | | ctx_ = NULL; |
| | | if(dec_ctx_){ |
| | | avcodec_close(dec_ctx_); |
| | | dec_ctx_ = NULL; |
| | | } |
| | | } |
| | | |
| | | if (handle_gb28181){ |
| | | delete handle_gb28181; |
| | | } |
| | | |
| | | if(io_ctx_){ |
| | | av_freep(&io_ctx_->buffer); |
| | | av_freep(&io_ctx_); |
| | | io_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"); |
| | | 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"); |
| | | logIt("open with custom io create custom avio error\n"); |
| | | return -1; |
| | | } |
| | | |
| | | ctx_ = avformat_alloc_context(); |
| | | if(!ctx_){ |
| | | logIt("open with custom io create format 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", err); |
| | | logIt("failed:%s", getAVErrorDesc(err).c_str()); |
| | | return -1; |
| | | } |
| | | // auto err = av_probe_input_buffer(ctx_->pb, &ctx_->iformat, NULL, NULL, 0, 0); |
| | | // if(err != 0){ |
| | | // logIt("open with custom io prob input buffer error:%d err: %s\n", err, getAVErrorDesc(err).c_str()); |
| | | // return -1; |
| | | // } |
| | | |
| | | return 0; |
| | | } |
| | |
| | | |
| | | std::string fn = filename; |
| | | //GB28181API gb28181(fn); |
| | | handle_gb28181.addCamera(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((void *)&handle_gb28181, handle_gb28181.readData, options); |
| | | 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); |
| | | } |
| | | |
| | | ret = avformat_open_input(&ctx_, "", NULL, options); |
| | | if(ret < 0){ |
| | | logIt("open %s failed:%s",filename, |
| | | getAVErrorDesc(ret).c_str()); |
| | | |
| | | } |
| | | // 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()); |
| | | |
| | | } |
| | | // if(ret < 0){ |
| | | // logIt("open %s failed:%s",filename, |
| | | // getAVErrorDesc(ret).c_str()); |
| | | // } |
| | | |
| | | return ret; |
| | | } |
| | |
| | | return false; |
| | | } |
| | | |
| | | // logIt("there are %d stream", ctx_->nb_streams); |
| | | |
| | | for (int i = 0; i < ctx_->nb_streams; ++i) |
| | | { |
| | | switch(ctx_->streams[i]->codecpar->codec_type){ |
| | | case AVMEDIA_TYPE_VIDEO: |
| | | vs_idx_ = i; |
| | | break; |
| | | auto type = ctx_->streams[i]->codecpar->codec_type; |
| | | logIt("there are %d stream, stream %d, type %d", ctx_->nb_streams, i, type); |
| | | |
| | | default: |
| | | break; |
| | | if (type == AVMEDIA_TYPE_VIDEO){ |
| | | vs_idx_ = i; |
| | | |
| | | auto in = ctx_->streams[i]; |
| | | if(in->r_frame_rate.num >=1 && in->r_frame_rate.den >= 1){ |
| | | fps_ = av_q2d(in->r_frame_rate); |
| | | }else if(in->avg_frame_rate.num >=1 && in->avg_frame_rate.den >= 1){ |
| | | fps_ = av_q2d(in->avg_frame_rate); |
| | | } |
| | | logIt("in stream video fps %f, time_base: %d : %d, size: %dx%d", fps_, in->time_base.num, in->time_base.den, in->codecpar->width, in->codecpar->height); |
| | | } |
| | | 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; |
| | | } |
| | | |
| | | 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); |
| | | const bool FormatIn::IsHEVC()const{ |
| | | return ctx_->streams[vs_idx_]->codecpar->codec_id == AV_CODEC_ID_HEVC; |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | bool FormatIn::openCodec(AVDictionary **options){ |
| | | if (vs_idx_ == -1) return false; |
| | | |
| | | AVStream *s = ctx_->streams[stream_index]; |
| | | AVStream *s = ctx_->streams[vs_idx_]; |
| | | |
| | | AVCodecParameters *codecpar = s->codecpar; |
| | | AVCodec *dec = NULL; |
| | |
| | | for (int i = 0; i < 2; ++i) |
| | | { |
| | | if(hw_accl_){ |
| | | idle_gpu = gpu::getGPU(100); |
| | | idle_gpu = gpu::getGPUPrior(350, 896, 0); |
| | | // idle_gpu = gpu::getGPU(300); |
| | | if (prop_->gpu_index_ > -1){ |
| | | idle_gpu = prop_->gpu_index_; |
| | | } |
| | | 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"); |
| | | } |
| | | |
| | | std::string codec_name(avcodec_get_name(codecpar->codec_id)); |
| | | codec_name += "_cuvid"; |
| | | dec = avcodec_find_decoder_by_name(codec_name.c_str()); |
| | | |
| | | 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); |
| | |
| | | return true; |
| | | } |
| | | |
| | | AVStream *FormatIn::getStream(int type){ |
| | | return ctx_->streams[vs_idx_]; |
| | | 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::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; |
| | | } |
| | | bool FormatIn::isVideoPkt(AVPacket *pkt){ |
| | | if (pkt->stream_index == vs_idx_){ |
| | | return true; |
| | | } |
| | | pkt_out.stream_index = 0; |
| | | return true; |
| | | |
| | | return false; |
| | | } |
| | | |
| | | bool FormatIn::readPacket(std::shared_ptr<CodedData> &data, int stream_index){ |
| | | |
| | | AVPacket &pkt(data->getAVPacket()); |
| | | return readPacket(pkt, getStream()->index); |
| | | bool FormatIn::isAudioPkt(AVPacket *pkt){ |
| | | if (pkt->stream_index == as_idx_){ |
| | | return true; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | int FormatIn::decode(AVFrame* &frame, AVPacket &pkt){ |
| | | 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); |
| | | 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; |
| | |
| | | logIt("decode frame failed : %s", getAVErrorDesc(ret).c_str()); |
| | | return -1; |
| | | }else{ |
| | | return 1; |
| | | return 0; |
| | | } |
| | | } |
| | | return 0; |
| | | return -2; |
| | | } |
| | | |
| | | int FormatIn::decode(std::shared_ptr<FrameData> &frame_data, |
| | | std::shared_ptr<CodedData> &data){ |
| | | |
| | | AVFrame *frame = frame_data->getAVFrame(); |
| | | AVPacket &pkt(data->getAVPacket()); |
| | | |
| | | return decode(frame, pkt); |
| | | } |
| | | |
| | | int FormatIn::readFrame(AVFrame* &frame){ |
| | | |
| | | auto data(std::make_shared<CodedData>()); |
| | | if(!readPacket(data)){ |
| | | return -1; |
| | | } |
| | | |
| | | AVPacket &pkt(data->getAVPacket()); |
| | | |
| | | return decode(frame, pkt); |
| | | } |
| | | |
| | | int FormatIn::readFrame(std::shared_ptr<FrameData> &frame_data){ |
| | | |
| | | AVFrame *frame(frame_data->getAVFrame()); |
| | | |
| | | return readFrame(frame); |
| | | } |
| | | |
| | | |
| | | } |