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 | 373 ++++++++++++++++------------ csrc/wrapper.cpp | 75 +++-- csrc/worker/stream.cpp | 5 csrc/worker/decoder.cpp | 43 +- csrc/wrapper.hpp | 1 csrc/ffmpeg/format/FormatOut.cpp | 11 csrc/worker/stream.hpp | 4 csrc/buz/recorder.cpp | 5 csrc/thirdparty/gb28181/include/PsToEs.hpp | 191 ++++++++------ csrc/ffmpeg/format/FormatIn.hpp | 68 +++-- 10 files changed, 445 insertions(+), 331 deletions(-) diff --git a/csrc/buz/recorder.cpp b/csrc/buz/recorder.cpp index beda224..8f32088 100644 --- a/csrc/buz/recorder.cpp +++ b/csrc/buz/recorder.cpp @@ -70,7 +70,6 @@ fclose(fp_); fp_ = NULL; } - } int Recorder::init_write_h264(const bool audio){ @@ -323,10 +322,6 @@ if (in->open(NULL, NULL) < 0){ logIt("mux hevc open stream error"); return -3; - } - if (!in->findStreamInfo(NULL)) { - logIt("mux hevc can't find streams"); - return -4; } std::unique_ptr<FormatOut> out(new FormatOut(in_->getFPS(), "mp4")); diff --git a/csrc/ffmpeg/format/FormatIn.cpp b/csrc/ffmpeg/format/FormatIn.cpp index b827eb6..120e2c7 100644 --- a/csrc/ffmpeg/format/FormatIn.cpp +++ b/csrc/ffmpeg/format/FormatIn.cpp @@ -21,7 +21,6 @@ #include "../property/VideoProp.hpp" #include "../../common/gpu/info.h" - using namespace logif; namespace ffwrapper{ @@ -31,30 +30,14 @@ ,vs_idx_(-1) ,as_idx_(-1) ,prop_(NULL) - ,hw_accl_(hw) ,io_ctx_(NULL) ,read_io_buff_(NULL) ,read_io_buff_size_(32768) -#ifdef GB28181 - ,handle_gb28181(NULL) -#endif ,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) -#ifdef GB28181 - ,handle_gb28181(NULL) -#endif - ,fps_(25.0) + :FormatIn(hw) { prop_ = new VideoProp; *prop_ = prop; @@ -76,21 +59,13 @@ ctx_ = NULL; } -#ifdef GB28181 - if (handle_gb28181){ - delete handle_gb28181; - } -#endif - 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*/){ read_io_buff_ = (uint8_t*)av_malloc(read_io_buff_size_); if(!read_io_buff_){ @@ -112,67 +87,19 @@ ctx_->pb = io_ctx_; - // 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; } -#ifdef GB28181 - 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; - } -#endif -///////////////////////////////////////////////////////////////////////// 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; + return ret; } - - // logIt("there are %d stream", ctx_->nb_streams); for (int i = 0; i < ctx_->nb_streams; ++i) { @@ -188,13 +115,11 @@ }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); - - + 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); + 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 @@ -202,7 +127,7 @@ } } - return true; + return 0; } const bool FormatIn::IsHEVC()const{ @@ -220,81 +145,29 @@ } 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; - srand((unsigned)time(NULL)); + AVCodec *dec = avcodec_find_decoder(codec_id); -constexpr int need = 350; // M -constexpr int reserved = 512; // M - - for (int i = 0; i < 2; ++i) - { - if(hw_accl_){ - - // 璁剧疆gpu index - if (prop_->gpu_index_ > -1){ - if (!gpu::satisfy(prop_->gpu_index_, need, reserved)){ - hw_accl_ = false; - continue; - } - idle_gpu = prop_->gpu_index_; - }else{ - idle_gpu = gpu::getGPUPrior(need, reserved, 0); - // idle_gpu = gpu::getGPU(300); - usleep(2000000 + rand()%3000000); - if (!gpu::satisfy(idle_gpu, need, reserved)){ - hw_accl_ = false; - continue; - } - } - - if(idle_gpu < 0){ - logIt("NO GPU RESOURCE TO DECODE"); - hw_accl_ = false; - continue; - } - - 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); - } - }else{ - dec = avcodec_find_decoder(codecpar->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; @@ -302,21 +175,24 @@ 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); @@ -329,6 +205,8 @@ } 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_]; } @@ -364,16 +242,18 @@ } 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; } int FormatIn::decode(AVFrame* frame, AVPacket *pkt){ AVStream *in = getStream(); - - av_packet_rescale_ts(pkt, in->time_base, in->codec->time_base); + 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("pkt size %d avcodec_send_packet error : %s", pkt->size, getAVErrorDesc(ret).c_str()); @@ -392,4 +272,183 @@ } 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 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; + } + + 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_){ + + 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; + } + + 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; + } + } diff --git a/csrc/ffmpeg/format/FormatIn.hpp b/csrc/ffmpeg/format/FormatIn.hpp index 2bdafd1..c558aa6 100644 --- a/csrc/ffmpeg/format/FormatIn.hpp +++ b/csrc/ffmpeg/format/FormatIn.hpp @@ -3,9 +3,8 @@ #include <stdint.h> #include <memory> -#ifdef GB28181 +#include <deque> #include "PsToEs.hpp" -#endif struct AVFormatContext; struct AVDictionary; @@ -15,6 +14,7 @@ struct AVFrame; struct AVCodec; struct AVIOContext; +struct AVCodecParserContext; typedef int(* read_packet)(void *opaque,uint8_t *buf, int buf_size); @@ -27,52 +27,64 @@ public: explicit FormatIn(bool hw=true); explicit FormatIn(const VideoProp &prop, bool hw=true); - ~FormatIn(); + virtual ~FormatIn(); public: - int openWithCustomIO(void *opaque, read_packet fn, AVDictionary **options=NULL); -#ifdef GB28181 - int openGb28181(const char *filename, AVDictionary **options); -#endif - int open(const char *filename, AVDictionary **options); - bool findStreamInfo(AVDictionary **options); - - bool openCodec(AVDictionary **options); - - int readPacket(AVPacket *pkt_out); - - int decode(AVFrame* frame, AVPacket *pkt); - - bool isVideoPkt(AVPacket *pkt); - bool isAudioPkt(AVPacket *pkt); + virtual int open(const char *filename, AVDictionary **options); + virtual const bool IsHEVC()const; + virtual const bool IsAVC1()const; + virtual int readPacket(AVPacket *pkt_out); + virtual bool isVideoPkt(AVPacket *pkt); + virtual bool isAudioPkt(AVPacket *pkt); bool notVideoAudio(AVPacket *pkt); - private: + + int openWithCustomIO(void *opaque, read_packet fn, AVDictionary **options=NULL); + bool openCodec(AVDictionary **options); + int decode(AVFrame* frame, AVPacket *pkt); + + protected: bool allocCodec(AVCodec *dec, AVStream *s, AVDictionary **options); public: AVStream *getStream(int type = -1); AVCodecContext *getCodecContext(int type = 0); AVFormatContext *getFromatContext(){return ctx_;} const double getFPS()const{return fps_;} - const bool IsHEVC()const; - const bool IsAVC1()const; - private: + protected: AVFormatContext *ctx_; AVCodecContext *dec_ctx_; int vs_idx_; int as_idx_; - VideoProp *prop_; - bool hw_accl_; - double fps_; + int fps_; private: AVIOContext *io_ctx_; uint8_t *read_io_buff_; const int read_io_buff_size_; -#ifdef GB28181 - GB28181API *handle_gb28181; -#endif + }; + + class FormatInGB : public FormatIn{ + public: + FormatInGB(); + explicit FormatInGB(const VideoProp &prop); + ~FormatInGB(); + + virtual int open(const char *filename, AVDictionary **options) override; + virtual const bool IsHEVC()const override; + virtual const bool IsAVC1()const override; + virtual int readPacket(AVPacket *pkt_out) override; + + virtual bool isVideoPkt(AVPacket *pkt) override; + virtual bool isAudioPkt(AVPacket *pkt) override; + + private: + GB28181API* gb28181_; + AVCodecParserContext* parser_ctx_; + unsigned char* buffer_; + int buffer_size_; + + std::deque<AVPacket*> q_pkt_; }; } diff --git a/csrc/ffmpeg/format/FormatOut.cpp b/csrc/ffmpeg/format/FormatOut.cpp index 6c91db6..5d51aaf 100644 --- a/csrc/ffmpeg/format/FormatOut.cpp +++ b/csrc/ffmpeg/format/FormatOut.cpp @@ -107,8 +107,8 @@ enc_ctx_->codec_id = AV_CODEC_ID_H264; enc_ctx_->codec_type = AVMEDIA_TYPE_VIDEO; - enc_ctx_->height = (prop.height_ & 0x01) ? prop.height_-1 : prop.height_; - enc_ctx_->width = (prop.width_ & 0x01) ? prop.width_ - 1 : prop.width_; + enc_ctx_->height = prop.height_ & ~0x01; + enc_ctx_->width = prop.width_ & ~0x01; enc_ctx_->sample_aspect_ratio = prop.sample_aspect_ratio_; @@ -182,7 +182,7 @@ av_opt_set(enc_ctx_->priv_data, "tune", "zerolatency", 0); av_opt_set(enc_ctx_->priv_data, "profile", "baseline", 0); - int err =avcodec_open2(enc_ctx_, codec, NULL); + int err = avcodec_open2(enc_ctx_, codec, NULL); if( err< 0) { logIt("can't open output codec: %s", getAVErrorDesc(err).c_str()); @@ -194,14 +194,11 @@ return false; } ofmt->video_codec = codec_id; - if(ofmt->flags & AVFMT_GLOBALHEADER) - { + if(ofmt->flags & AVFMT_GLOBALHEADER){ enc_ctx_->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; } - return true; - } AVStream *FormatOut::getStream(){ diff --git a/csrc/thirdparty/gb28181/include/PsToEs.hpp b/csrc/thirdparty/gb28181/include/PsToEs.hpp index d73d93c..54dc25f 100644 --- a/csrc/thirdparty/gb28181/include/PsToEs.hpp +++ b/csrc/thirdparty/gb28181/include/PsToEs.hpp @@ -43,16 +43,22 @@ } T pop() { - struct timespec now, end; - clock_gettime(CLOCK_MONOTONIC, &now); - static uint64_t waitS = 12; // wait - end.tv_sec = now.tv_sec + waitS; - end.tv_nsec = now.tv_nsec; + struct timespec to; + clock_gettime(CLOCK_MONOTONIC, &to); + static uint64_t waitMS = 620; // wait + uint64_t sec = waitMS / 1000; + uint64_t nsec = (waitMS % 1000) * 1e6; + to.tv_sec = to.tv_sec + sec; + nsec += to.tv_nsec; + sec = nsec / 1000000000; + nsec = nsec % 1000000000; + to.tv_sec += sec; + to.tv_nsec = nsec; // printf("======>>wait stream data\n"); pthread_mutex_lock(&mtx); while(q.empty()){ - if(pthread_cond_timedwait(&cond, &mtx, &end) == ETIMEDOUT){ + if(pthread_cond_timedwait(&cond, &mtx, &to) == ETIMEDOUT){ printf("======>>timeout quit\n"); break; } @@ -109,8 +115,90 @@ int buffLen; } frameBuffInfo; +typedef enum +{ + E_VIDEO_STREAM_NONE = -1, + E_VIDEO_STREAM_H264 = 0, + E_VIDEO_STREAM_MPEG2 = 1, // MPEG4 + E_VIDEO_STREAM_MPEG4 = 2, // MPEG4 + E_VIDEO_STREAM_SVAC = 3, // SVAC + E_VIDEO_STREAM_3GP = 4, // 3GP + E_VIDEO_STREAM_H265 = 5, //H265 +}VideoStreamType_E; + class GB28181API{ public: + + static int capturePic(void *opaque, char *buf, int *bufsize, const int tt) { + + GB28181API *_this = (GB28181API *) opaque; + int len = 0; + *bufsize = 0; + + int ttt = 0; + do { + if (ttt > tt) return 0; + ttt++; + + //浠庣紦瀛樹腑鑾峰彇buffinfo + if (_this->m_rtpQueue.count_queue() == 0) { +// printf(" count_queue == 0 \n"); + usleep(200000); + continue; + } + + frameBuffInfo *buffinfo = _this->m_rtpQueue.pop(); + if (buffinfo == nullptr) { + printf(" buffinfo == nullptr \n"); + return 0; + } +//////////////////////////////////////////////////////// + FILE* fpJpg = NULL; + char fileJpgName[32] = "./tmpCaptureJpg.jpg"; + char fileIFrameName[32] = "./tmpCaptureX264IFrame"; + char cmd[512] = {0}; + + for(int i = 0; i < 10 * 25; i++){ + if (!buffinfo){ + buffinfo = _this->m_rtpQueue.pop(); + } + if (!buffinfo) continue; + + auto fpIframe = fopen(fileIFrameName, "wb+"); + fwrite(buffinfo->buff, buffinfo->buffLen, 1, fpIframe); + fflush(fpIframe); + fclose(fpIframe); + + memset(cmd, 0, 512); + sprintf(cmd, "ffmpeg -i %s -y -f image2 -ss 00:00:00 -vframes 1 %s >/dev/null", fileIFrameName, + fileJpgName); + int rr = system(cmd); + + delete[] buffinfo->buff; + delete buffinfo; + buffinfo = nullptr; + + fpJpg = fopen(fileJpgName, "rb"); + if (fpJpg) { + break; + } + } +/////////////////////////////////////////////////////////// + + fseek(fpJpg, 0, SEEK_END); + len = ftell(fpJpg); + fseek(fpJpg, 0, SEEK_SET); + *bufsize = fread(buf, sizeof(char), len, fpJpg); + fclose(fpJpg); + + memset(cmd, 0, 128); + sprintf(cmd, "rm %s %s >/dev/null", fileIFrameName, fileJpgName); + system(cmd); + } while (*bufsize == 0); + + return *bufsize; + } + GB28181API(/*string rtspUrl*/){ // handle = addCamera(rtspUrl); } @@ -127,9 +215,10 @@ deleteCamera(); } + static const int keep_queue_count = 126; bool pushInfo(unsigned char *data, int datalen) { - while(m_rtpQueue.count_queue() > 120){ + while(m_rtpQueue.count_queue() > keep_queue_count){ auto p = m_rtpQueue.popNotWait(); if (p){ delete[] p->buff; @@ -160,7 +249,7 @@ frameBuffInfo *buffinfo = _this->m_rtpQueue.pop(); // printf(" m_rtpQueue.pop after \n"); if(buffinfo != nullptr){ - diff = len - buffinfo->buffLen; + diff = len - buffinfo->buffLen; }else{ return 0; } @@ -175,7 +264,7 @@ info->buff = new unsigned char[buffinfo->buffLen - len]{}; memcpy(info->buff, buffinfo->buff + len, buffinfo->buffLen - len); - while(_this->m_rtpQueue.count_queue() > 120){ + while(_this->m_rtpQueue.count_queue() > keep_queue_count){ auto p = _this->m_rtpQueue.popNotWait(); if (p){ delete[] p->buff; @@ -204,76 +293,6 @@ return bufsize; } - static int capturePic(void *opaque, char *buf, int *bufsize, const int tt) { - - GB28181API *_this = (GB28181API *) opaque; - int len = 0; - *bufsize = 0; - - int ttt = 0; - do { - if (ttt > tt) return 0; - ttt++; - - //浠庣紦瀛樹腑鑾峰彇buffinfo - if (_this->m_rtpQueue.count_queue() == 0) { -// printf(" count_queue == 0 \n"); - usleep(200000); - continue; - } - - frameBuffInfo *buffinfo = _this->m_rtpQueue.pop(); - if (buffinfo == nullptr) { - printf(" buffinfo == nullptr \n"); - return 0; - } -//////////////////////////////////////////////////////// - FILE* fpJpg = NULL; - char fileJpgName[32] = "./tmpCaptureJpg.jpg"; - char fileIFrameName[32] = "./tmpCaptureX264IFrame"; - char cmd[512] = {0}; - - for(int i = 0; i < 10 * 25; i++){ - if (!buffinfo){ - buffinfo = _this->m_rtpQueue.pop(); - } - if (!buffinfo) continue; - - auto fpIframe = fopen(fileIFrameName, "wb+"); - fwrite(buffinfo->buff, buffinfo->buffLen, 1, fpIframe); - fflush(fpIframe); - fclose(fpIframe); - - memset(cmd, 0, 512); - sprintf(cmd, "ffmpeg -i %s -y -f image2 -ss 00:00:00 -vframes 1 %s >/dev/null", fileIFrameName, - fileJpgName); - int rr = system(cmd); - - delete[] buffinfo->buff; - delete buffinfo; - buffinfo = nullptr; - - fpJpg = fopen(fileJpgName, "rb"); - if (fpJpg) { - break; - } - } -/////////////////////////////////////////////////////////// - - fseek(fpJpg, 0, SEEK_END); - len = ftell(fpJpg); - fseek(fpJpg, 0, SEEK_SET); - *bufsize = fread(buf, sizeof(char), len, fpJpg); - fclose(fpJpg); - - memset(cmd, 0, 128); - sprintf(cmd, "rm %s %s >/dev/null", fileIFrameName, fileJpgName); - system(cmd); - } while (*bufsize == 0); - - return *bufsize; - } - static void streamCallBack(int datatype, int frametype, unsigned char *data, unsigned int datalen, long userdata) { GB28181API *_this = (GB28181API *)userdata; @@ -282,17 +301,23 @@ if(frametype == GB_VIDEO_FRAME_I){ startFlag = true; } + + // printf("streamCallBack recv data len %d frametype %d\n", datalen, startFlag); + if (_this->datatype_ < 0) + _this->datatype_ = datatype; + if((data != NULL) && (startFlag == true)){ - _this->pushInfo(data, datalen); + _this->pushInfo(data, datalen); } } long addCamera(string &rtsp){ int count = 0; - while (handle == -1 && count <= 3) { + while (handle < 0 && count <= 3) { count ++; handle = RTSPSTREAM_Open(rtsp.c_str(), streamCallBack, (long) this); printf("RTSPSTREAM_Open, handle:%ld \n", handle); + usleep(20000); } return handle; } @@ -304,8 +329,10 @@ } handle = -1; - } + } + const int getDataType(){return datatype_;} private: + int datatype_ = -1; MyQueue<frameBuffInfo *> m_rtpQueue; long handle = -1; }; diff --git a/csrc/worker/decoder.cpp b/csrc/worker/decoder.cpp index 5e8a7c9..4d5a3b7 100644 --- a/csrc/worker/decoder.cpp +++ b/csrc/worker/decoder.cpp @@ -95,6 +95,8 @@ next_idx_ = i.id + 1; if (frame) {av_frame_free(&frame); frame = NULL;} frame = frm; + }else { + av_frame_free(&frm); } } } @@ -103,30 +105,33 @@ int pix_fmt = frame->format; int width = frame->width; int height = frame->height; - int len = 0; - uint8_t *origin = cvbridge::extractFrame(frame, &len); - av_frame_free(&frame); - if (!origin) return; - - uint8_t *finale = NULL; if (pix_fmt != AV_PIX_FMT_NV12){ - finale = (uint8_t*)malloc(len); - unsigned char* SrcU = origin + width * height; - unsigned char* SrcV = SrcU + width * height / 4 ; - unsigned char* DstU = finale + width * height; - memcpy(finale, origin, width * height); - int i = 0; - for( i = 0 ; i < width * height / 4 ; i++ ){ - *(DstU++) = *(SrcU++); - *(DstU++) = *(SrcV++); - } - free(origin); - }else{ - finale = origin; + cvbridge* bridge = new cvbridge(width, height, pix_fmt, + width, height, AV_PIX_FMT_NV12); + AVFrame* nv12 = bridge->convert2Frame(frame); + av_frame_free(&frame); + frame = nv12; + delete bridge; + + // finale = (uint8_t*)malloc(len); + // unsigned char* SrcU = origin + width * height; + // unsigned char* SrcV = SrcU + width * height / 4 ; + // unsigned char* DstU = finale + width * height; + // memcpy(finale, origin, width * height); + // int i = 0; + // for( i = 0 ; i < width * height / 4 ; i++ ){ + // *(DstU++) = *(SrcU++); + // *(DstU++) = *(SrcV++); + // } + // free(origin); } + int len = 0; + uint8_t* finale = cvbridge::extractFrame(frame, &len); + av_frame_free(&frame); + *data = finale; *w = width; *h = height; diff --git a/csrc/worker/stream.cpp b/csrc/worker/stream.cpp index 94e5ac3..92bc032 100644 --- a/csrc/worker/stream.cpp +++ b/csrc/worker/stream.cpp @@ -30,8 +30,11 @@ std::lock_guard<std::mutex> locker(mutex_avpkt_); list_pkt_.push_back(pkt); - while(list_pkt_.size() > max_size_/2*3){ + CPacket &tmpkt = list_pkt_.front(); + if (tmpkt.data->getAVPacket().flags & AV_PKT_FLAG_KEY){ + break; + } list_pkt_.pop_front(); } diff --git a/csrc/worker/stream.hpp b/csrc/worker/stream.hpp index 8a0feec..43b24b0 100644 --- a/csrc/worker/stream.hpp +++ b/csrc/worker/stream.hpp @@ -1,7 +1,7 @@ #ifndef _cffmpeg_stream_hpp_ #define _cffmpeg_stream_hpp_ -#include <list> +#include <deque> #include <mutex> #include <memory> @@ -15,7 +15,7 @@ class stream { private: - std::list<CPacket> list_pkt_; + std::deque<CPacket> list_pkt_; std::mutex mutex_avpkt_; ffwrapper::FormatIn *streamRef_; const int max_size_; diff --git a/csrc/wrapper.cpp b/csrc/wrapper.cpp index e4540b3..a84fd19 100644 --- a/csrc/wrapper.cpp +++ b/csrc/wrapper.cpp @@ -50,6 +50,7 @@ ,run_dec_(false) ,run_stream_(true) ,run_rec_(false) + ,work_start(false) ,thread_(nullptr) ,stop_stream_(false) ,stream_(nullptr) @@ -72,6 +73,7 @@ ,run_dec_(false) ,run_stream_(true) ,run_rec_(false) + ,work_start(false) ,thread_(nullptr) ,stop_stream_(false) ,stream_(nullptr) @@ -103,6 +105,8 @@ } if (logit_) logif::DestroyLogger(); + + printf("wrapper release\n"); } std::unique_ptr<ffwrapper::FormatIn> Wrapper::init_reader(const char* input){ @@ -113,32 +117,23 @@ prop.gpu_acc_ = false; prop.gpu_index_ = devid_; - std::unique_ptr<FormatIn> in(new FormatIn(prop, prop.gpuAccl())); + std::unique_ptr<FormatIn> in(nullptr); int flag = -1; -#ifdef GB28181 + AVDictionary* avdic = NULL; if (gb_){ - flag = in->openGb28181(input, NULL); + in.reset(new FormatInGB(prop)); }else{ -#endif - AVDictionary *avdic = prop.optsFormat(); - if(avdic){ - flag = in->open(input, &avdic); - av_dict_free(&avdic); - }else{ - flag = in->open(input, NULL); - } -#ifdef GB28181 + in.reset(new FormatIn(prop, prop.gpuAccl())); + avdic = prop.optsFormat(); } -#endif - - if(flag == 0){ - if(!in->findStreamInfo(NULL)){ - logIt("can't find video stream\n"); - return nullptr; - } - - return in; + + if(avdic){ + flag = in->open(input, &avdic); + av_dict_free(&avdic); + }else{ + flag = in->open(input, NULL); } + if(flag == 0) return in; return nullptr; } @@ -183,7 +178,7 @@ int Wrapper::run_worker(ffwrapper::FormatIn *in, const CPacket &pkt){ if (gb_){ AVPacket &p = pkt.data->getAVPacket(); - p.pts = p.dts = AV_NOPTS_VALUE; + // p.pts = p.dts = AV_NOPTS_VALUE; } int flag = 0; if (run_stream_ && stream_) stream_->SetPacket(pkt); @@ -205,22 +200,32 @@ int64_t file_frame = 0; using namespace std; - const string gb_suffix[] = {"/StreamType=2", "/StreamType=3", ""}; + // const string gb_suffix[] = {"/StreamType=2", "/StreamType=3", ""}; + // const string gb_suffix[] = {"/StreamType=2", ""}; + const string gb_suffix[] = {""}; const size_t gb_size = sizeof(gb_suffix) / sizeof(string); int gs_idx = 0; - string url = input_url_; + string url; + url.reserve(input_url_.size()*2); + url = input_url_; + work_start = false; while(!stop_stream_.load()){ if (gb_){ if (input_url_.find("/StreamType=") == string::npos) url = input_url_ + gb_suffix[gs_idx]; - logIt("======>>input real url %s\n", url.c_str()); + gs_idx = (gs_idx + 1) % gb_size; } auto in = init_reader(url.c_str()); if (!in) { + work_start = false; logIt("ERROR: init_reader! url: %s\n", url.c_str()); - sleep(2); + usleep(126000); + // for(int i = 0; i < 10; i++){ + // if (stop_stream_.load()) break; + if(gb_) usleep(2617000); + // } continue; } @@ -234,6 +239,7 @@ wTime >>= 1; init_worker(in.get()); + work_start = true; int64_t id = gb_ ? 0 : -1; int64_t v_id = id; @@ -249,7 +255,13 @@ while(!stop_stream_.load()){ auto data(std::make_shared<CodedData>()); - if (in->readPacket(&data->getAVPacket()) != 0){ + auto ret = in->readPacket(&data->getAVPacket()); + if (ret > 0){ + sleep(2); + continue; + } + + if (ret < 0){ logIt("read packet error, id: %lld", id); break; } @@ -283,7 +295,6 @@ file_frame++; usleep(wTime); } - } deinit_worker(); @@ -335,7 +346,7 @@ } int Wrapper::GetInfoRecorder(std::string &recID, int &index, std::string &path){ - if (rec_){ + if (work_start && rec_){ rec_->GetRecInfo(recID, index, path); } return 0; @@ -351,6 +362,10 @@ } if (decoder_){ decoder_->GetFrame(data, w, h, format, length, id); + }else { + if (work_start){ + for(int i = 0; i < 6; i++)this_thread::sleep_for(chrono::seconds{1}); + } } return 0; } @@ -360,7 +375,7 @@ } int Wrapper::GetPacket(unsigned char **pktData, int *size, int *key){ - if (stream_){ + if (work_start && stream_){ stream_->GetPacket(pktData, size, key); } return 0; diff --git a/csrc/wrapper.hpp b/csrc/wrapper.hpp index b0df07a..42f0c91 100644 --- a/csrc/wrapper.hpp +++ b/csrc/wrapper.hpp @@ -73,6 +73,7 @@ bool run_dec_; bool run_stream_; bool run_rec_; + bool work_start; // decoder 鍙傛暟 std::unique_ptr<std::thread> thread_; std::atomic_bool stop_stream_; -- Gitblit v1.8.0