From 18a05d269516a5e33d8460291c2f93e73d95adce Mon Sep 17 00:00:00 2001 From: zhangmeng <775834166@qq.com> Date: 星期二, 26 十二月 2023 10:45:31 +0800 Subject: [PATCH] GetYUV format is NV12 --- csrc/ffmpeg/format/FormatIn.cpp | 472 +++++++++++++++++++++++++++++++++++------------------------ 1 files changed, 280 insertions(+), 192 deletions(-) diff --git a/csrc/ffmpeg/format/FormatIn.cpp b/csrc/ffmpeg/format/FormatIn.cpp index 3f87d59..120e2c7 100644 --- a/csrc/ffmpeg/format/FormatIn.cpp +++ b/csrc/ffmpeg/format/FormatIn.cpp @@ -2,6 +2,8 @@ #include <stdexcept> #include <unistd.h> +#include <stdlib.h> +#include <time.h> extern "C"{ #include <libavformat/avformat.h> @@ -10,18 +12,15 @@ #include <libavutil/opt.h> #include <libavutil/avassert.h> #include <libavutil/imgutils.h> -#include <libswscale/swscale.h> +#include <libswscale/swscale.h> } #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" - using namespace logif; namespace ffwrapper{ @@ -30,119 +29,83 @@ ,dec_ctx_(NULL) ,vs_idx_(-1) ,as_idx_(-1) - ,hw_accl_(hw) + ,prop_(NULL) ,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*/) + :FormatIn(hw) + { + 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_->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()); + ctx_ = avformat_alloc_context(); + if(!ctx_){ + logIt("open with custom io create format error\n"); return -1; } + + ctx_->pb = io_ctx_; 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; - handle_gb28181->addCamera(fn); - - int ret = openWithCustomIO(handle_gb28181, handle_gb28181->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()); - // } + int ret = avformat_open_input(&ctx_, filename, NULL, options); - return ret; - } - - bool FormatIn::findStreamInfo(AVDictionary **options){ - - const int ret = avformat_find_stream_info(ctx_, options); + 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; + ctx_->filename,getAVErrorDesc(ret).c_str()); + return ret; } - - 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; @@ -152,105 +115,84 @@ }else if(in->avg_frame_rate.num >=1 && in->avg_frame_rate.den >= 1){ fps_ = av_q2d(in->avg_frame_rate); } - logIt("video stream time base %d : %d", in->time_base.num, in->time_base.den); + 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){ - as_idx_ = i; - logIt("audio stream time base %d : %d", ctx_->streams[i]->time_base.num, ctx_->streams[i]->time_base.den); + 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; + + return 0; } - 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; - } + const bool FormatIn::IsAVC1()const{ + if (IsHEVC()) return false; - AVStream *s = ctx_->streams[stream_index]; + char p[100] = {0}; + char *sub = av_fourcc_make_string(p, ctx_->streams[vs_idx_]->codecpar->codec_tag); + const int ret = strcmp(sub, "avc1"); + if (ret == 0) return true; + return false; + } + bool FormatIn::openCodec(AVDictionary **options){ + if (dec_ctx_) return true; + 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; + AVCodecID codec_id = codecpar->codec_id; - 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); + AVCodec *dec = avcodec_find_decoder(codec_id); + + if(dec){ + flag = allocCodec(dec, s, options); + if(*options){ + av_dict_free(options); } - 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; - } + if(!flag){ + av_free(dec_ctx_); + dec_ctx_ = NULL; } + + logIt("use decoder %s\n", dec->name); } - + return flag; } bool FormatIn::allocCodec(AVCodec *dec, AVStream *s, AVDictionary **options){ - AVCodecParameters *codecpar = s->codecpar; + AVCodecParameters *codecpar = NULL; + if(s) 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; + int ret = 0; + if(s && codecpar) { + 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); } - 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); @@ -263,13 +205,15 @@ } AVStream *FormatIn::getStream(int type/*=-1*/){ + if (vs_idx_ < 0 || !ctx_ || ctx_->nb_streams == 0 || !ctx_->streams) return NULL; + if (type == -1){ return ctx_->streams[vs_idx_]; } - if (type == ctx_->streams[vs_idx_]->codecpar->codec_type) + if (vs_idx_ > -1 && type == ctx_->streams[vs_idx_]->codecpar->codec_type) return ctx_->streams[vs_idx_]; - if (type == ctx_->streams[as_idx_]->codecpar->codec_type) + if (as_idx_ > -1 && type == ctx_->streams[as_idx_]->codecpar->codec_type) return ctx_->streams[as_idx_]; return NULL; @@ -279,45 +223,40 @@ return dec_ctx_; } - bool FormatIn::isVideoPkt(AVPacket &pkt){ - if (pkt.stream_index == vs_idx_){ + 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_){ + bool FormatIn::isAudioPkt(AVPacket *pkt){ + if (pkt->stream_index == as_idx_){ return true; } return false; } - bool FormatIn::readPacket(AVPacket &pkt_out){ - - const int ret = av_read_frame(ctx_, &pkt_out); - if(ret < 0){ - return false; - } - - return true; - + bool FormatIn::notVideoAudio(AVPacket *pkt){ + return !isVideoPkt(pkt) && !isAudioPkt(pkt); + } + + int FormatIn::readPacket(AVPacket *pkt_out){ + auto flag = av_read_frame(ctx_, pkt_out); + if (flag < 0) + logIt("======>> av_read_frame error %s", getAVErrorDesc(flag).c_str()); + return flag; } - bool FormatIn::readPacket(std::shared_ptr<CodedData> &data){ - - AVPacket &pkt(data->getAVPacket()); - return readPacket(pkt); - } - - int FormatIn::decode(AVFrame* &frame, AVPacket &pkt){ + 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 (in){ + 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()); + logIt("pkt size %d avcodec_send_packet error : %s", pkt->size, getAVErrorDesc(ret).c_str()); return -1; } while (ret >= 0) { @@ -328,39 +267,188 @@ logIt("decode frame failed : %s", getAVErrorDesc(ret).c_str()); return -1; }else{ - return 1; + return 0; } } + return -2; + } + +////////////////////////////////////////////////////////////////////// + constexpr int bs = 8192; + FormatInGB::FormatInGB() + :FormatIn() + ,gb28181_(NULL) + ,parser_ctx_(NULL) + ,buffer_(NULL) + ,buffer_size_(bs) + { + buffer_ = (unsigned char*)malloc(buffer_size_); + } + + FormatInGB::FormatInGB(const VideoProp &prop) + :FormatInGB() + { + prop_ = new VideoProp; + *prop_ = prop; + } + + FormatInGB::~FormatInGB(){ + if (parser_ctx_){ + av_parser_close(parser_ctx_); + } + if (gb28181_)delete gb28181_; + if (buffer_) free(buffer_); + + for(auto &pkt : q_pkt_){ + av_packet_free(&pkt); + } + q_pkt_.clear(); + } + + static enum AVCodecID codecMap(const int c){ + switch (c) { + case E_VIDEO_STREAM_H264:// = 0, + return AV_CODEC_ID_H264; + case E_VIDEO_STREAM_MPEG2:// = 1, // MPEG4 + // return AV_CODEC_ID_MPEG2VIDEO; + case E_VIDEO_STREAM_MPEG4:// = 2, // MPEG4 + return AV_CODEC_ID_MPEG4; + case E_VIDEO_STREAM_SVAC:// = 3, // SVAC + return AV_CODEC_ID_NONE; + case E_VIDEO_STREAM_3GP:// = 4, // 3GP + return AV_CODEC_ID_NONE; // audio + case E_VIDEO_STREAM_H265:// = 5, //H265 + return AV_CODEC_ID_HEVC; + default: + break; + } + return AV_CODEC_ID_NONE; + } + + int FormatInGB::open(const char *filename, AVDictionary **options){ + if (gb28181_){ + delete gb28181_; + } + + gb28181_ = new GB28181API; + std::string fn = filename; + + if(gb28181_->addCamera(fn) < 0){ + delete gb28181_; + gb28181_ = NULL; + logIt("do addCamera Error\n"); + return -1; + } + for(int i = 0; i < 6; i++){ + if (gb28181_->getDataType() >= 0){ + AVCodecID id = codecMap(gb28181_->getDataType()); + logIt("======>>codec name %s\n", avcodec_get_name(id)); + parser_ctx_ = av_parser_init(id); + if (parser_ctx_) parser_ctx_->flags |= PARSER_FLAG_USE_CODEC_TS; + AVCodec* dec = avcodec_find_decoder(id); + allocCodec(dec, NULL, NULL); + break; + } + usleep(1000000); + } return 0; } - 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; + int FormatInGB::readPacket(AVPacket *pkt_out){ + if (!q_pkt_.empty()){ + auto pkt = q_pkt_.front(); + q_pkt_.pop_front(); + av_packet_ref(pkt_out, pkt); + av_packet_free(&pkt); + return 0; } - AVPacket &pkt(data->getAVPacket()); + if (gb28181_->getDataType() < 0){ + logIt("======>> readPacket can't recv gb28181 stream"); + return 1; + } + if (!parser_ctx_){ + AVCodecID id = codecMap(gb28181_->getDataType()); + parser_ctx_ = av_parser_init(id); + AVCodec* dec = avcodec_find_decoder(id); + allocCodec(dec, NULL, NULL); + } + if (parser_ctx_ && dec_ctx_){ - return decode(frame, pkt); + int try_run = 0; + AVPacket* pkt = av_packet_alloc(); + bool got_pkt = false; + + while (true) { + int data_size = gb28181_->readData(gb28181_, buffer_, buffer_size_); + // printf("======>> data_size %d pos %d\n", data_size, buffer_pos_); + if (data_size == 0){ + try_run ++; + if (try_run > 12){ + av_packet_free(&pkt); + logIt("gb28181_ readData %d failed, return -1", try_run); + return -1; + } + continue; + } + try_run = 0; + unsigned char* data = buffer_; + while (data_size > 0) { + int ret = av_parser_parse2(parser_ctx_, dec_ctx_, + &pkt->data, &pkt->size, data, data_size, + AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0); + + // logIt("======>> av_parser_parse2 ret %d pkt size %d", ret, pkt->size); + if (ret < 0) { + av_packet_free(&pkt); + logIt("======>> av_parser_parse2 error %d %s", ret, getAVErrorDesc(ret).c_str()); + return ret; + } + + data += ret; + data_size -= ret; + + if (pkt->size){ + if(fps_ == 0 && dec_ctx_->framerate.den > 0 && dec_ctx_->framerate.num > 0){ + fps_ = dec_ctx_->framerate.num/dec_ctx_->framerate.den; + if (fps_ == 0) fps_ = 24; + } + if (parser_ctx_->key_frame == 1){ + pkt->flags |= AV_PKT_FLAG_KEY; + } + got_pkt = true; + AVPacket* tmpkt = av_packet_alloc(); + av_packet_ref(tmpkt, pkt); + q_pkt_.push_back(tmpkt); + } + } + if (got_pkt) { + av_packet_free(&pkt); + auto tmpkt = q_pkt_.front(); + q_pkt_.pop_front(); + av_packet_ref(pkt_out, tmpkt); + av_packet_free(&tmpkt); + return 0; + } + } + } + return -1; } - int FormatIn::readFrame(std::shared_ptr<FrameData> &frame_data){ - - AVFrame *frame(frame_data->getAVFrame()); - - return readFrame(frame); + const bool FormatInGB::IsHEVC()const{ + if (!gb28181_) return false; + return codecMap(gb28181_->getDataType()) == AV_CODEC_ID_HEVC; } + const bool FormatInGB::IsAVC1()const{ + return false; + } + + bool FormatInGB::isVideoPkt(AVPacket *pkt) { + return true; + } + bool FormatInGB::isAudioPkt(AVPacket *pkt) { + return false; + } } -- Gitblit v1.8.0