video analysis2.0拆分,ffmpeg封装go接口库
554325746@qq.com
2020-03-11 62a465253c96a666a8dfbf099a45aeaae6c975bd
csrc/wrapper.cpp
@@ -46,6 +46,8 @@
    ,gb_(0)
    ,cpu_(0)
    ,run_dec_(false)
    ,run_stream_(true)
    ,run_rec_(false)
    ,thread_(nullptr)
    ,stop_stream_(false)
    ,stream_(nullptr)
@@ -53,6 +55,8 @@
    ,rec_(new rec)
    ,logit_(false)
    ,fps_(25)
    ,file_finished_(false)
    ,min_duration_(0)
    {
        makeTheWorld();
    }
@@ -63,12 +67,17 @@
    ,gb_(0)
    ,cpu_(0)
    ,run_dec_(false)
    ,run_stream_(true)
    ,run_rec_(false)
    ,thread_(nullptr)
    ,stop_stream_(false)
    ,stream_(nullptr)
    ,decoder_(nullptr)
    ,rec_(new rec)
    ,logit_(true)
    ,fps_(25)
    ,file_finished_(false)
    ,min_duration_(0)
    {
        makeTheWorld();
        logif::CreateLogger(logfile, true);
@@ -101,16 +110,19 @@
        prop.gpu_acc_ = !cpu_;
       std::unique_ptr<FormatIn> in(new FormatIn(prop.gpuAccl()));
       AVDictionary *avdic = prop.optsFormat();
       int flag = -1;
        if (gb_){
            flag = in->openGb28181(input, NULL);
        }else{
            flag = in->open(input, &avdic);
           AVDictionary *avdic = prop.optsFormat();
            if(avdic){
                flag = in->open(input, &avdic);
              av_dict_free(&avdic);
           }else{
                flag = in->open(input, NULL);
            }
        }
       if(avdic){
          av_dict_free(&avdic);
       }
        if(flag == 0){
            if(!in->findStreamInfo(NULL)){
                logIt("can't find video stream\n");
@@ -150,7 +162,7 @@
        stream_ = new stream(in, 3 * in->getFPS());
        // stream_->AudioSwitch(audio_);
        decoder_ = new decoder(in);
        rec_->Load(in);
@@ -166,9 +178,9 @@
            p.pts = p.dts = AV_NOPTS_VALUE;
        }
        int flag = 0;
        if (stream_) stream_->SetPacket(pkt);
        if (decoder_ && run_dec_) flag = decoder_->SetFrame(pkt);
        if (rec_->Loaded()) rec_->SetPacket(pkt);
        if (run_stream_ && stream_) stream_->SetPacket(pkt);
        if (run_dec_ && decoder_) flag = decoder_->SetFrame(pkt);
        if (run_rec_ && rec_->Loaded()) rec_->SetPacket(pkt);
        return flag;
    }
@@ -181,6 +193,9 @@
    void Wrapper::run_stream_thread(){
        
        int64_t file_rebootime = 0;
        int64_t file_frame = 0;
        while(!stop_stream_.load()){
            auto in = init_reader(input_url_.c_str());
            
@@ -192,9 +207,12 @@
            fps_ = in->getFPS();
            
            int wTime = 1000000.0 / in->getFPS() ;
            if (fps_ < 1 || fps_ > 200){
                fps_ = 25;
            }
            int wTime = 1000000.0 / fps_ ;
            wTime >>= 1;
            logIt("WAIT TIME PER FRAME: %d", wTime);
            init_worker(in.get());
@@ -202,7 +220,13 @@
            int64_t v_id = id;
            int64_t a_id = id;
            bool exist = access(input_url_.c_str(), 0) == 0 ? true : false;
            bool exist = access(input_url_.c_str(), 0) == 0;
            if (exist){
                wTime <<= 1;
                file_rebootime++;
            }
            logIt("WAIT TIME PER FRAME: %d", wTime);
            while(!stop_stream_.load()){
                auto data(std::make_shared<CodedData>());
@@ -214,6 +238,7 @@
                if (in->notVideoAudio(&data->getAVPacket())){
                    continue;
                }
                // 非国标跳过第一帧,测试第一帧有问题
                if (!gb_ && id < 0){
                    id++; v_id++; a_id++;
@@ -236,18 +261,37 @@
                //本地文件太快sleep一下
                if (exist){
                    usleep(wTime);
                    // 记录解码的文件有多少帧
                    file_frame++;
                }
            }
            deinit_worker();
            if (exist) {
                // 三次一帧都没解出来,退出
                if (file_frame == 0 && file_rebootime < 3){
                    continue;
                }
                // 最小需要解出多少帧
                if (file_frame < min_duration_ * fps_){
                    continue;
                }
                logIt("libcffmpeg.so-> local file %s run %lld time, all frames %lld", input_url_.c_str(), file_rebootime, file_frame);
                file_finished_ = true;
                break;
            }
        }
    }
    void Wrapper::SetRecMinCacheTime(const int mind){
        rec_->SetRecMinCacheTime(mind);
    void Wrapper::SetRecMinCacheTime(const int mind, const int maxd){
        min_duration_ = mind;
    }
    void Wrapper::OpenRecorder(){
        run_rec_ = true;
    }
    void Wrapper::BuildRecorder(const char* id, const char *output, const int64_t &fid, const int mindur, const int maxdur, const bool audio){
        bool a = audio;
        if (gb_) a = false;
@@ -260,33 +304,43 @@
            [=]{rec_->NewRec(rid.c_str(), dir.c_str(), fid, mindur, maxdur, a);};
        }
    }
    int Wrapper::FireRecorder(const char* sid,const int64_t &id){
        if (rec_->Loaded()){
            rec_->FireRecSignal(sid, id);
        }
        return 0;
    }
    void Wrapper::GetInfoRecorder(std::string &recID, int &index, std::string &path){
    int Wrapper::GetInfoRecorder(std::string &recID, int &index, std::string &path){
        if (rec_){
            rec_->GetRecInfo(recID, index, path);
        }
        return 0;
    }
    ////////decoder
    void Wrapper::BuildDecoder(){
    void Wrapper::OpenDecoder(){
        run_dec_ = true;
    }
    void Wrapper::GetPicDecoder(unsigned char **data, int *w, int *h, int *format, int *length, int64_t *id){
    int Wrapper::GetPicDecoder(unsigned char **data, int *w, int *h, int *format, int *length, int64_t *id){
        if (file_finished_){
            return -1;
        }
        if (decoder_){
            decoder_->GetFrame(data, w, h, format, length, id);
        }
        return 0;
    }
    
    void Wrapper::GetPacket(unsigned char **pktData, int *size, int *key){
    void Wrapper::CloseStream(){
        run_stream_ = false;
    }
    int Wrapper::GetPacket(unsigned char **pktData, int *size, int *key){
        if (stream_){
            stream_->GetPacket(pktData, size, key);
        }
        return 0;
    }
} // end class wrapper
@@ -298,69 +352,6 @@
// return val: -1 open error; -2, find stream error; -3, converter create
namespace cffmpeg_wrap{ // start test functions
    uint8_t* Decode(const char *file, const int gb, int *w, int *h){
        VideoProp prop;
        prop.url_ = file;
        prop.gpu_acc_ = false;
        std::unique_ptr<FormatIn> in(new FormatIn(prop.gpuAccl()));
        int flag = -1;
        if (gb){
            flag = in->openGb28181(file, NULL);
        }else{
            flag = in->open(file, NULL);
        }
        std::unique_ptr<cvbridge> bridge_(nullptr);
        if(flag == 0){
            if(!in->findStreamInfo(NULL)){
                logIt("yolo can't find video stream\n");
                *w = *h = -2;
                return NULL;
            }
            auto flag = in->openCodec(NULL);
            if(flag){
                auto dec_ctx = in->getCodecContext();
                AVPixelFormat pix_fmt = AV_PIX_FMT_BGR24;
                bridge_.reset(new cvbridge(
                        dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt,
                        dec_ctx->width, dec_ctx->height, pix_fmt, SWS_BICUBIC));
            }else{
                logIt("FormatIn openCodec Failed!");
                *w = *h = -3;
                return NULL;
            }
        }else{
            logIt("open %s error", file);
            *w = *h = -1;
            return NULL;
        }
        uint8_t *pic = NULL;
        *w = *h = 0;
        int tryTime = 0;
        while (tryTime++ < 100){
            auto data(std::make_shared<CodedData>());
            if (in->readPacket(&data->getAVPacket()) == 0){
                auto frame(std::make_shared<FrameData>());
                AVFrame *frm = frame->getAVFrame();
                if(in->decode(frm, &data->getAVPacket()) == 0){
                    *w = frm->width;
                    *h = frm->height;
                    pic = bridge_->convert2Data(frm);
                    break;
                }
            }
        }
        return pic;
    }
/////// for encoder
    typedef struct _PicEncoder{
        FormatOut *enc;
@@ -369,15 +360,13 @@
        int fps;
        int br;
        int gi;
        int pix_fmt;
        int flag;
        int fmt;
        cvbridge *bridge;
    } PicEncoder;
    void *CreateEncoder(const int w, const int h, const int fps, const int br, 
                        const int scale_flag, const int gi, const int fmt, const char *file){
        if (fmt < 0) return NULL;
                        const int pix_fmt, const int scale_flag, const int gi){
        PicEncoder *e = (PicEncoder*)malloc(sizeof(PicEncoder));
        e->enc = NULL;
@@ -386,8 +375,8 @@
        e->fps = fps;
        e->br = br;
        e->gi = gi;
        e->pix_fmt = pix_fmt;
        e->flag = scale_flag;
        e->fmt = fmt;
        e->bridge = NULL;
        VideoProp prop_;
@@ -397,10 +386,7 @@
        prop_.bit_rate_ = br;
        gi < 0 ? prop_.gpu_acc_ = false : prop_.gpu_acc_ = true;
        std::string filename("./88.mp4");
        if (file) filename = file;
      FormatOut *enc = new FormatOut(prop_, filename.c_str());
      FormatOut *enc = new FormatOut(prop_, "./88.mp4");
        e->enc = enc;
        return e;
@@ -425,11 +411,11 @@
        if (e->bridge == NULL){
            e->bridge = new cvbridge(
                    w, h, e->fmt,
                    w, h, e->pix_fmt,
                    e->w, e->h, ctx->pix_fmt, e->flag);
        }
        AVFrame *bgr_frame = cvbridge::fillFrame(in, w, h, e->fmt);
        AVFrame *bgr_frame = cvbridge::fillFrame(in, w, h, e->pix_fmt);
        AVFrame *frame = e->bridge->convert2Frame(bgr_frame);
        av_frame_free(&bgr_frame);
@@ -460,138 +446,25 @@
        return flag;
    }
///////////////////////////////////////////////////////////
    typedef struct _conv
    {
        int srcW;
        int srcH;
        int srcF;
        int dstW;
        int dstH;
        cvbridge *b;
    }Conv;
    void *CreateConvertor(const int srcW, const int srcH, const int srcFormat,
                          const int dstW, const int dstH, const int dstFormat, const int flag){
        auto bridge = new cvbridge(
                srcW, srcH, srcFormat,
                dstW, dstH, dstFormat, flag);
        if (!bridge) return NULL;
    int GetGb28181Pic(const char *rtspUrl, char *retData, int *retDataLen){
        int ret = 0;
        std::string fn = rtspUrl;
        Conv *c = (Conv*)malloc(sizeof(Conv));
        c->b = bridge;
        c->dstW = dstW;
        c->dstH = dstH;
        c->srcW = srcW;
        c->srcH = srcH;
        c->srcF = srcFormat;
        return c;
    }
    uint8_t *Convert(void *h, uint8_t *src){
        Conv *c = (Conv*)h;
        auto b = c->b;
        AVFrame *tmp_frm = cvbridge::fillFrame(src, c->srcW, c->srcH, c->srcF);
        if (!tmp_frm) return NULL;
        unsigned char *picData = b->convert2Data(tmp_frm);
        av_frame_free(&tmp_frm);
        return picData;
    }
    void DestoryConvertor(void *h){
        Conv *c = (Conv*)h;
        delete c->b;
        free(c);
    }
// mjpeg av pix fmt yuv420p
    static int save2PIC(uint8_t *data, const int w, const int h, const char *filename){
        AVPixelFormat src_fmt = AV_PIX_FMT_BGR24;
        AVPixelFormat dst_fmt = AV_PIX_FMT_YUV420P;
        cvbridge *bridge = new cvbridge(w, h, src_fmt, w, h, dst_fmt, 16);
        AVFrame *bgr_frame = cvbridge::fillFrame(data, w, h, src_fmt);
        AVFrame *frame_jpeg = bridge->convert2Frame(bgr_frame);
        av_frame_free(&bgr_frame);
        AVFormatContext *ctx = avformat_alloc_context();
        ctx->oformat = av_guess_format("mjpeg", NULL, NULL);
        if( avio_open(&ctx->pb, filename, AVIO_FLAG_READ_WRITE) < 0) {
            printf("Couldn't open output file.");
            avformat_free_context(ctx);
            delete bridge;
            return -1;
        }
        AVStream* pAVStream = avformat_new_stream(ctx, 0);
        if( pAVStream == NULL ){
            delete bridge;
        auto handle_gb28181 = new GB28181API;
        if(handle_gb28181->addCamera(fn) == -1){
            delete(handle_gb28181);
            logIt("do addCamera Error\n");
            return -1;
        }
        AVCodecContext* pCodecCtx = pAVStream->codec;
        pCodecCtx->codec_id = ctx->oformat->video_codec;
        pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
        pCodecCtx->pix_fmt = dst_fmt;
        pCodecCtx->width = w;
        pCodecCtx->height = h;
        pCodecCtx->time_base.num = 1;
        pCodecCtx->time_base.den = 25;
        AVCodec* pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
        if( !pCodec ) {
            printf("Codec not found.");
            avformat_free_context(ctx);
            delete bridge;
            return -1;
        }
        if( avcodec_open2(pCodecCtx, pCodec, NULL) < 0 ){
            printf("Could not open codec.");
            avformat_free_context(ctx);
            avio_close(ctx->pb);
            delete bridge;
            return -1;
        int retLen = handle_gb28181->capturePic(handle_gb28181, retData, retDataLen);
        if(retLen == 0){
            logIt("do capturePic failed:%d");
            ret = -1;
        }
        avformat_write_header(ctx, NULL);
        int y_size = pCodecCtx->width * pCodecCtx->height;
        AVPacket pkt;
        av_new_packet(&pkt, y_size * 3);
        int got_picture = 0;
        int ret = avcodec_encode_video2(pCodecCtx, &pkt, frame_jpeg, &got_picture);
        av_frame_free(&frame_jpeg);
        delete bridge;
        if( ret < 0 ) {
            printf("Encode Error.\n");
            avformat_free_context(ctx);
            if( pAVStream ) {
                avcodec_close(pAVStream->codec);
            }
            avio_close(ctx->pb);
            return -1;
        }
        if( got_picture == 1 ) {
            pkt.stream_index = pAVStream->index;
            ret = av_write_frame(ctx, &pkt);
            avio_flush(ctx->pb);
        }
        av_free_packet(&pkt);
        //Write Trailer
        av_write_trailer(ctx);
        if( pAVStream ) {
            avcodec_close(pAVStream->codec);
        }
        avio_close(ctx->pb);
        avformat_free_context(ctx);
        return 0;
        handle_gb28181->deleteCamera();
        return ret;
    }
}