video analysis2.0拆分,ffmpeg封装go接口库
zhangmeng
2019-09-16 927a49bc04984400cb9b968e41d299cc977e4988
update so file
6个文件已添加
8个文件已修改
1075 ■■■■■ 已修改文件
cffmpeg.h 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/buz/recorder.cpp 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/cffmpeg.cpp 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/decoder.cpp 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/decoder.hpp 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/rec.cpp 189 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/rec.hpp 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/stream.cpp 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/stream.hpp 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/wrapper.cpp 369 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/wrapper.hpp 99 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
goffmpeg.go 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libcffmpeg.c 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libcffmpeg.h 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cffmpeg.h
@@ -19,15 +19,14 @@
/////////passive api
void c_ffmpeg_build_recorder(const cffmpeg h, const char*id, const char *dir, int mind, int maxd);
void c_ffmpeg_fire_recorder(const cffmpeg h, const char*sid, const int64_t id);
char* c_ffmpeg_get_info_recorder(const cffmpeg h, int *index, int *length);
char* c_ffmpeg_get_rec_id(const cffmpeg h, const char* p, int *length);
void c_ffmpeg_get_info_recorder(const cffmpeg h, int *index, char** recid, int *recidLen, char **fpath, int *pathLen);
void c_ffmpeg_build_decoder(const cffmpeg h);
void* c_ffmpeg_get_pic_decoder(const cffmpeg h, int *wid, int *hei, int64_t *id);
void* c_ffmpeg_get_avpacket(const cffmpeg h, int *size, int *key);
//////test
void* c_ffmpeg_decode_jpeg(const cffmpeg h, const char *file, int *wid, int *hei);
void* c_ffmpeg_decode_jpeg(const char *file, int *wid, int *hei);
// pic encoder
void *c_ffmpeg_create_encoder(const int w, const int h, const int fps, const int br, const int scale_flag, const int gi);
csrc/buz/recorder.cpp
@@ -124,7 +124,7 @@
            //callback to frame index and path
            if(func_rec_info_){
                func_rec_info_(id_,file_frame_index_, file_path_);
                func_rec_info_(id_, file_frame_index_, file_path_);
            }
        }
csrc/cffmpeg.cpp
@@ -58,31 +58,27 @@
    s->FireRecorder(sid, id);
}
char* c_ffmpeg_get_info_recorder(const cffmpeg h, int *index, int *length){
void c_ffmpeg_get_info_recorder(const cffmpeg h, int *index, char** recid, int *recidLen, char **fpath, int *pathLen){
    Wrapper *s = (Wrapper*)h;
    int i;
    std::string p;
    s->GetInfoRecorder(i, p);
    std::string p(""), id("");
    s->GetInfoRecorder(id, i, p);
    // printf("cffmpeg get info : index : %d, file : %s\n", i, p.c_str());
    *index = i;
    *length = p.length();
    char *path = (char*)malloc(*length + 1);
    memcpy(path, p.c_str(), *length);
    path[*length] = '\0';
    
    return path;
}
    *pathLen = p.length();
    char *path = (char*)malloc(*pathLen + 1);
    memcpy(path, p.c_str(), *pathLen);
    path[*pathLen] = '\0';
    *fpath = path;
char* c_ffmpeg_get_rec_id(const cffmpeg h, const char* p, int *length){
    Wrapper *s = (Wrapper*)h;
    std::string id = s->GetRecorderID(p);
    *length = id.length();
    char *i = (char*)malloc(*length+1);
    memcpy(i, id.c_str(), *length);
    i[*length] = '\0';
    return i;
    *recidLen = id.length();
    char *rid = (char*)malloc(*recidLen + 1);
    memcpy(rid, id.c_str(), *recidLen);
    rid[*recidLen] = '\0';
    *recid = rid;
}
void c_ffmpeg_build_decoder(const cffmpeg h){
@@ -105,9 +101,8 @@
}
/////////////////////test
void* c_ffmpeg_decode_jpeg(const cffmpeg h, const char *file, int *wid, int *hei){
    Wrapper *s = (Wrapper*)h;
    uint8_t *p = s->decodeJPEG(file, wid, hei);
void* c_ffmpeg_decode_jpeg(const char *file, int *wid, int *hei){
    uint8_t *p = DecodeJPEG(file, wid, hei);
    if(!p){
        *wid = *hei = 0;
    }
csrc/decoder.cpp
New file
@@ -0,0 +1,114 @@
#include "decoder.hpp"
#include "ffmpeg/bridge/cvbridge.hpp"
#include "ffmpeg/format/FormatIn.hpp"
#include "ffmpeg/data/CodedData.hpp"
#include "ffmpeg/data/FrameData.hpp"
#include "ffmpeg/log/log.hpp"
extern "C"{
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <libswscale/swscale.h>
}
using namespace ffwrapper;
using namespace logif;
namespace cffmpeg_wrap
{
    decoder::decoder(ffwrapper::FormatIn *dec, const int w, const int h, const int f)
    :conv_(NULL)
    ,conv_w_(w)
    ,conv_h_(h)
    ,conv_flag_(f)
    ,decRef_(dec)
    {}
    decoder::~decoder(){
        if (conv_){
            delete conv_;
        }
        std::lock_guard<std::mutex> l(mutex_pic_);
        for(auto &i : list_pic_){
            free(i.data);
        }
        list_pic_.clear();
    }
    int decoder::initDecoder(){
        if (!decRef_) return -1;
        if(decRef_->getCodecContext() == NULL){
            bool flag = true;
            flag = decRef_->openCodec(AVMEDIA_TYPE_VIDEO, NULL);
            auto dec_ctx = decRef_->getCodecContext();
            if(conv_){
                delete conv_;
                conv_ = NULL;
            }
            conv_w_ = conv_w_ == 0 || conv_w_ > dec_ctx->width ? dec_ctx->width : conv_w_;
            conv_h_ = conv_h_ == 0 || conv_h_ > dec_ctx->height ? dec_ctx->height : conv_h_;
            AVPixelFormat pix_fmt = AV_PIX_FMT_BGR24;
            conv_ = new cvbridge(
                    dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt,
                    conv_w_, conv_h_, pix_fmt, conv_flag_);
            if (!flag){
                logIt("FormatIn openCodec Failed!");
                return -1;
            }
        }
        return 0;
    }
    int decoder::SetFrame(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id){
        if (!data) return -1;
        if (!conv_){
            initDecoder();
        }
        auto frame(std::make_shared<FrameData>());
        auto ret = decRef_->decode(frame, data);
        if(ret == 1){
            //缓存数据
            BGR24 pic;
            AVFrame *frm = frame->getAVFrame();
            pic.w = conv_w_;
            pic.h = conv_h_;
            unsigned char *picData = (unsigned char*)malloc(pic.w * pic.h * 3);
            conv_->copyPicture(picData, frm);
            pic.data = picData;
            pic.id = id;
            std::lock_guard<std::mutex> l(mutex_pic_);
            while(list_pic_.size() > 10){
                for(int i = 0; i < 5; i++){
                    auto t = list_pic_.front();
                    free(t.data);
                    list_pic_.pop_front();
                }
            }
            list_pic_.emplace_back(pic);
        }
        return list_pic_.size();
    }
    void decoder::GetFrame(unsigned char **data, int *w, int *h, int64_t *id){
        std::lock_guard<std::mutex> l(mutex_pic_);
        if(list_pic_.empty()){
            *data = NULL;
            *w = 0;
            *h = 0;
            return;
        }
        auto p = list_pic_.front();
        *data = p.data; *w = p.w; *h = p.h;
        *id = p.id;
        list_pic_.pop_front();
    }
} // namespace cffmpeg_wrap
csrc/decoder.hpp
New file
@@ -0,0 +1,50 @@
#ifndef _cffmpeg_decoder_hpp_
#define _cffmpeg_decoder_hpp_
#include <stdint.h>
#include <memory>
#include <list>
#include <mutex>
namespace ffwrapper
{
    class FormatIn;
    class cvbridge;
    class CodedData;
} // namespace ffwrapper
namespace cffmpeg_wrap
{
    typedef struct _pic_bgr24{
        unsigned char *data;
        int w;
        int h;
        int64_t id;
    }BGR24;
    class decoder
    {
    private:
        ffwrapper::cvbridge *conv_;
        int conv_w_, conv_h_, conv_flag_;
        ffwrapper::FormatIn *decRef_;
        std::list<BGR24> list_pic_;
        std::mutex mutex_pic_;
    private:
        int initDecoder();
    public:
        int SetFrame(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id);
        void GetFrame(unsigned char **data, int *w, int *h, int64_t *id);
    public:
        decoder(ffwrapper::FormatIn *dec, const int w, const int h, const int f);
        ~decoder();
    };
} // namespace cffmpeg_wrap
#endif
csrc/rec.cpp
New file
@@ -0,0 +1,189 @@
#include "rec.hpp"
#include <unistd.h>
#include "ffmpeg/format/FormatIn.hpp"
#include "ffmpeg/data/CodedData.hpp"
#include "buz/recorder.hpp"
#include "ffmpeg/log/log.hpp"
#include "common/callback.hpp"
using namespace logif;
using namespace ffwrapper;
using namespace cffmpeg_wrap::buz;
namespace cffmpeg_wrap
{
    rec::rec(ffwrapper::FormatIn *in)
    :recRef_(in)
    ,minduration_(250)
    ,maxduration_(750)
    {}
    rec::~rec()
    {
        {
            std::lock_guard<std::mutex> l(mtx_rec_);
            map_rec_.clear();
        }
        {
            std::lock_guard<std::mutex> l(mtx_pkt_);
            list_pkt_.clear();
        }
    }
    std::unique_ptr<Recorder> rec::newRec(std::string id, std::string dir, const int mind, const int maxd){
        if(!recRef_){
            logIt("Init wrapper first");
            return nullptr;
        }
        std::unique_ptr<Recorder> rec(new Recorder(recRef_, id.c_str()));
        rec->SetCallback([&](std::string &id, int &index, std::string &path){
            setRecInfo(id, index, path);
        });
        int trycnt = 0;
        while(trycnt < 100){
            const int ret = rec->Run(dir.c_str(), mind, maxd);
            if(ret == 0) break;
            usleep(200000);
        }
        if (trycnt < 100){
            return rec;
        }
        return nullptr;
    }
    void rec::setRecInfo(std::string &id, int &index, std::string &path){
        std::lock_guard<std::mutex> l(mtx_recInfo_);
        while(list_recInfo_.size() > 100){
            for(int i = 0; i < 25; i++){
                list_recInfo_.pop_front();
            }
        }
        struct record_file_info info;
        info.frmIdx = index;
        info.fPath = path;
        info.recID = id;
        list_recInfo_.emplace_back(info);
        logIt("LIST REC FILES COUNT : %d", list_recInfo_.size());
    }
    void rec::GetRecInfo(std::string &recID, int &index, std::string &path){
        // 获取信息
        {
            std::lock_guard<std::mutex> l(mtx_recInfo_);
            if(list_recInfo_.empty()){
                index = -1;
                path = "";
                return;
            }
            auto info = list_recInfo_.front();
            recID = info.recID;
            index = info.frmIdx;
            path = info.fPath;
            list_recInfo_.pop_front();
        }
        // 删除rec实例
        {
            std::lock_guard<std::mutex> l(mtx_rec_);
            if (map_rec_.find(recID) != map_rec_.end())
                map_rec_.erase(recID);
            for (auto iter = map_rec_.begin(); iter != map_rec_.end();){
                if (iter->second.rec && iter->second.rec->ErrorOcurred()){
                    iter == map_rec_.erase(iter);
                }else{
                    iter++;
                }
            }
        }
    }
    void rec::NewRec(const char* id, const char *output, const int mindur, const int maxdur){
        std::string rid(id);
        std::string dir(output);
        {
            std::lock_guard<std::mutex> l(mtx_rec_);
            if (map_rec_.find(rid) != map_rec_.end()){
                map_rec_.erase(rid);
            }
            map_rec_[rid] = {rid, dir, mindur, maxdur, nullptr};
        }
        minduration_ = mindur * 25;
        maxduration_ = maxdur * 25;
    }
    void rec::FireRecSignal(const char* sid,const int64_t &id){
        auto iter = map_rec_.find(sid);
        if (iter != map_rec_.end()){
            if(iter->second.rec){
                iter->second.rec->FireRecorder(id);
            }
        }
    }
    void rec::SetPacket(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id){
        if (!data) return;
        cachePacket(data, id);
        std::lock_guard<std::mutex> l(mtx_rec_);
        for(auto &i : map_rec_){
            if (!i.second.rec){
                i.second.rec = newRec(i.second.rid, i.second.dir, i.second.min, i.second.max);
                if (i.second.rec){
                    //此函数还未退出,不需要这个锁
                    // std::lock_guard<std::mutex> locker(mtx_pkt_);
                    for(auto &k : list_pkt_){
                        i.second.rec->CachePacket({k.data, k.id});
                    }
                    // 新的数据缓存
                    i.second.rec->CachePacket({data, id});
                    logIt("START REC %d FRAMES", list_pkt_.size());
                }
            }else if (i.second.rec){
                i.second.rec->CachePacket({data, id});
            }
        }
    }
    void rec::cachePacket(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id){
        std::lock_guard<std::mutex> l(mtx_pkt_);
        //wait I
        if (list_pkt_.empty()) {
            AVPacket &avpkt = data->getAVPacket();
            if (!(avpkt.flags & AV_PKT_FLAG_KEY)){
                return;
            }
        }
        list_pkt_.push_back({data, id});
        // 超过缓存最大长度,删除一个gop
        shrinkCache();
    }
    int rec::shrinkCache(){
        //超过最大缓存,丢弃gop
        while (list_pkt_.size() > minduration_) {
            list_pkt_.pop_front();
            while(!list_pkt_.empty()){
                auto &cache = list_pkt_.front();
                AVPacket &avpkt = cache.data->getAVPacket();
                if (!(avpkt.flags & AV_PKT_FLAG_KEY)){
                    list_pkt_.pop_front();
                }else{
                    break;
                }
            }
        }
    }
} // namespace cffmpeg_wrap
csrc/rec.hpp
New file
@@ -0,0 +1,89 @@
#ifndef _cffmpeg_rec_hpp_
#define _cffmpeg_rec_hpp_
#include <string>
#include <memory>
#include <unordered_map>
#include <list>
#include <mutex>
namespace ffwrapper
{
    class FormatIn;
    class CodedData;
} // namespace ffwrapper
namespace cffmpeg_wrap
{
    namespace buz{
        class Recorder;
        struct avpacket;
    }
    class rec
    {
    private:
        ffwrapper::FormatIn *recRef_;
        int     maxduration_;
        int     minduration_;
        // 录像的实例,对应任务
        typedef struct _fn_rec{
            std::string rid;        //id对应任务id
            std::string dir;
            int min;
            int max;
            std::unique_ptr<buz::Recorder> rec;
        }FnRec;
        std::unordered_map<std::string, FnRec> map_rec_;
        // 多线程添加任务实例,在读流线程使用录像,但是添加在另一个线程
        std::mutex mtx_rec_;
        // recoder将录像文件的信息放到此处
        typedef struct record_file_info{
            int frmIdx;
            std::string fPath;
            std::string recID;
        }RecInfo;
        std::list<RecInfo>  list_recInfo_;
        // 多线程录像,加锁获取录像后的信息
        std::mutex mtx_recInfo_;
        // 缓存的视频帧,等待firerecsignal触发开始录像
        typedef struct _cache_pkt{
            std::shared_ptr<ffwrapper::CodedData> data;
            int64_t id;
        }CPacket;
        std::list<CPacket> list_pkt_;
        // 多线程,生产者线程reader push pkt,消费者,录像线程pop
        std::mutex mtx_pkt_;
    private:
        // 创建录像实例
        std::unique_ptr<buz::Recorder> newRec(std::string id, std::string dir, const int mind, const int maxd);
        // 录像实例的回调函数,录像完成后设置录像文件路径,id和帧id
        void setRecInfo(std::string &id, int &index, std::string &path);
        // 缓存视频包
        void cachePacket(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id);
        // 丢弃缓存
        int shrinkCache();
    public:
        void NewRec(const char* id, const char *output, const int mindur, const int maxdur);
        // 缓存录像的视频包,等待触发录像,或直接放到录像缓存
        void SetPacket(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id);
        // 触发录像
        void FireRecSignal(const char* sid,const int64_t &id);
        // 获取录像文件路径和帧id
        void GetRecInfo(std::string &recID, int &index, std::string &path);
    public:
        explicit rec(ffwrapper::FormatIn *in);
        ~rec();
    };
} // namespace cffmpeg_wrap
#endif
csrc/stream.cpp
New file
@@ -0,0 +1,36 @@
#include "stream.hpp"
#include "ffmpeg/data/CodedData.hpp"
namespace cffmpeg_wrap{
    stream::stream(){
    }
    stream::~stream(){
    }
    int stream::SetPacket(std::shared_ptr<ffwrapper::CodedData> data){
        if (data){
            std::lock_guard<std::mutex> locker(mutex_avpkt_);
            list_avpkt_.push_back(data);
            return list_avpkt_.size();
        }
        return 0;
    }
    void stream::GetPacket(unsigned char **pktData, int *size, int *key){
        std::lock_guard<std::mutex> l(mutex_avpkt_);
        if(list_avpkt_.empty()){
            return;
        }
        auto data = list_avpkt_.front();
        auto pkt = data->getAVPacket();
        *key = pkt.flags & AV_PKT_FLAG_KEY;
        *size = pkt.size;
        *pktData = (unsigned char *)malloc(*size);
        memcpy(*pktData, pkt.data, pkt.size);
        list_avpkt_.pop_front();
    }
}
csrc/stream.hpp
New file
@@ -0,0 +1,29 @@
#ifndef _cffmpeg_stream_hpp_
#define _cffmpeg_stream_hpp_
#include <list>
#include <mutex>
#include <memory>
namespace ffwrapper{
    class CodedData;
}
namespace cffmpeg_wrap{
    class stream
    {
    private:
        std::list<std::shared_ptr<ffwrapper::CodedData> > list_avpkt_;
        std::mutex mutex_avpkt_;
    public:
        stream(/* args */);
        ~stream();
        int SetPacket(std::shared_ptr<ffwrapper::CodedData> data);
        void GetPacket(unsigned char **pktData, int *size, int *key);
    };
}
#endif
csrc/wrapper.cpp
@@ -21,8 +21,11 @@
#include "buz/recorder.hpp"
using namespace logif;
#include "stream.hpp"
#include "decoder.hpp"
#include "rec.hpp"
using namespace logif;
using namespace ffwrapper;
namespace cffmpeg_wrap{
@@ -30,17 +33,17 @@
    Wrapper::Wrapper()
    :input_url_("")
    ,thread_(nullptr)
    ,stop_stream_(false)
    ,bridge_(NULL)
    ,scale_w_(0)
    ,scale_h_(0)
    ,scale_f_(SWS_POINT)
    ,gb_(0)
    ,cpu_(0)
    ,use_decoder_(false)
    ,minduration(250)
    ,maxduration(750)
    ,thread_(nullptr)
    ,stop_stream_(false)
    ,stream_(nullptr)
    ,decoder_(nullptr)
    ,rec_(nullptr)
    {
        makeTheWorld();
    }
@@ -54,23 +57,11 @@
                stop_stream_.store(true);
                thread_->join();
            }
            if(bridge_){
                delete bridge_; bridge_ = NULL;
            }
            map_rec_.clear();
            list_rec_pkt_.clear();
            for(auto &i : list_pic_){
                free(i.data);
            }
        }
        catch(const std::exception& e)
        {
            logIt("WRAPPER EXCEPTION: ", e.what());
        }
    }
    void Wrapper::ScalePicture(const int w, const int h, const int flags){
@@ -132,344 +123,94 @@
        return 0;
    }
    void Wrapper::init_stream(){
        if (stream_) delete stream_;
        stream_ = new stream;
    }
    void Wrapper::init_decoder(ffwrapper::FormatIn *in){
        if (decoder_) delete decoder_;
        decoder_ = new decoder(in, scale_w_, scale_h_,scale_f_);
    }
    void Wrapper::init_rec(ffwrapper::FormatIn *in){
        if (rec_) delete rec_;
        rec_ = new rec(in);
    }
    void Wrapper::run_stream_thread(){
        
        while(!stop_stream_.load()){
            auto in = init_reader(input_url_.c_str());
            if (!in) {
                logIt("ERROR: init_reader! url: %s\n", input_url_.c_str());
                usleep(200000);
                continue;
            }
            init_stream();
            if (use_decoder_){
                init_decoder(in.get());
            }
            init_rec(in.get());
            int64_t id = 0;
            avpacket pkt;
            while(!stop_stream_.load()){
                auto data(std::make_shared<CodedData>());
                if(!in->readPacket(data)){
                    logIt("read packet error");
                    data.reset();
                    data = nullptr;
                    pkt.id = -1;
                    id = 0;
                }else{
                    pkt.id = id++;
                }
                pkt.data = data;
                if(data != nullptr) {
                    cacheAVPacket(data->getAVPacket());
                }
                run_worker(in.get(), pkt);
                if(!data){
                    {
                        std::lock_guard<std::mutex> l(mutex_rec_);
                        map_rec_.clear();
                    }
                    std::lock_guard<std::mutex> locker(mtx_rec_pkt_);
                    list_rec_pkt_.clear();
                    break;
                }
                //test
                // if(recorder_)
                //     if(id % 250 == 0)
                //         recorder_->FireRecorder(id);
                }
                if (stream_) stream_->SetPacket(data);
                if (use_decoder_ && decoder_) decoder_->SetFrame(data, id);
                if (rec_) rec_->SetPacket(data, id);
                id++;
            }
        }
    }
    void Wrapper::run_worker(ffwrapper::FormatIn *in, avpacket &pkt){
        if(!pkt.data) return;
        if (use_decoder_) {
            if(in->getCodecContext() == NULL){
                bool flag = true;
                flag = in->openCodec(AVMEDIA_TYPE_VIDEO, NULL);
                auto dec_ctx = in->getCodecContext();
                if(bridge_)delete bridge_;
                scale_w_ = scale_w_ == 0 || scale_w_ > dec_ctx->width ? dec_ctx->width : scale_w_;
                scale_h_ = scale_h_ == 0 || scale_h_ > dec_ctx->height ? dec_ctx->height : scale_h_;
                AVPixelFormat pix_fmt = AV_PIX_FMT_BGR24;
                bridge_ = new cvbridge(
                        dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt,
                        scale_w_, scale_h_, pix_fmt, scale_f_);
                if (!flag){
                    logIt("FormatIn openCodec Failed!");
                }
            }
            auto frame(std::make_shared<FrameData>());
            auto ret = in->decode(frame, pkt.data);
            if(ret == 1){
                //吐出数据
                cache_pic(frame, pkt.id);
            }
        }
        cache_rec_pkt(pkt);
        {
            std::lock_guard<std::mutex> l(mutex_rec_);
            for(auto &i : map_rec_){
                if (!i.second.rec){
                    i.second.rec = std::move(init_recorder(in, i.second.rid, i.second.dir, i.second.min, i.second.max));
                    if (i.second.rec){
                        std::lock_guard<std::mutex> locker(mtx_rec_pkt_);
                        for(auto &k : list_rec_pkt_){
                            avpacket p = {k.data, k.id};
                            i.second.rec->CachePacket(p);
                        }
                        logIt("START REC %d FRAMES", list_rec_pkt_.size());
                    }
                }else if (i.second.rec){
                    i.second.rec->CachePacket(pkt);
                }
            }
        }
    }
    int Wrapper::cache_rec_pkt(const avpacket &pkt){
        std::lock_guard<std::mutex> locker(mtx_rec_pkt_);
        //wait I
        if (list_rec_pkt_.empty()) {
            AVPacket &avpkt = pkt.data->getAVPacket();
            if (!(avpkt.flags & AV_PKT_FLAG_KEY)){
                return -1;
            }
        }
        maybe_dump_rec_pkt();
        recpkt k = {pkt.data, pkt.id};
        list_rec_pkt_.push_back(k);
        return 0;
    }
    void Wrapper::maybe_dump_rec_pkt(){
        //超过min/2,丢弃gop
        while (list_rec_pkt_.size() > minduration) {
            list_rec_pkt_.pop_front();
            while(!list_rec_pkt_.empty()){
                auto &cache = list_rec_pkt_.front();
                AVPacket &avpkt = cache.data->getAVPacket();
                if (!(avpkt.flags & AV_PKT_FLAG_KEY)){
                    list_rec_pkt_.pop_front();
                }else{
                    break;
                }
            }
        }
    }
    //////////////recorder
    std::unique_ptr<Recorder> Wrapper::init_recorder(FormatIn *in, std::string id, std::string dir, const int mind, const int maxd){
        if(!in){
            logIt("Init wrapper first");
            return nullptr;
        }
        std::unique_ptr<Recorder> rec(new Recorder(in, id.c_str()));
        rec->SetCallback([&](std::string &id, int &index, std::string &path){
            cache_rec_info(id, index, path);
        });
        int trycnt = 0;
        while(trycnt < 100){
            const int ret = rec->Run(dir.c_str(), mind, maxd);
            if(ret == 0) break;
            usleep(200000);
        }
        if (trycnt < 100){
            return rec;
        }
        return nullptr;
    }
    void Wrapper::BuildRecorder(const char* id, const char *output, const int mindur, const int maxdur){
        std::string rid(id);
        std::string dir(output);
        
        std::lock_guard<std::mutex> l(mutex_rec_);
        // auto fn = [=](FormatIn *in){
        //     return init_recorder(in, rid, dir, mindur, maxdur);
        // };
        // FnRec r = FnRec{fn, nullptr};
        if (map_rec_.find(rid) != map_rec_.end()){
            map_rec_.erase(rid);
        if (rec_){
            rec_->NewRec(id, output, mindur, maxdur);
        }
        // for (auto iter = map_rec_.begin(); iter != map_rec_.end();){
        //     if (iter->second.rec && iter->second.rec->ErrorOcurred()){
        //         iter == map_rec_.erase(iter);
        //     }else{
        //         iter++;
        //     }
        // }
        FnRec fr;
        fr.rid = rid;
        fr.dir = dir;
        fr.min = mindur;
        fr.max = maxdur;
        map_rec_[rid] = std::move(fr);
        minduration = mindur * 25;
        maxduration = maxdur * 25;
    }
    int Wrapper::FireRecorder(const char* sid,const int64_t &id){
        std::lock_guard<std::mutex> l(mutex_rec_);
        auto iter = map_rec_.find(sid);
        if (iter != map_rec_.end()){
            if(iter->second.rec){
                iter->second.rec->FireRecorder(id);
            }
        if (rec_){
            rec_->FireRecSignal(sid, id);
        }
        // for (auto iter = map_rec_.begin(); iter != map_rec_.end();){
        //     if (iter->second.rec && iter->second.rec->ErrorOcurred()){
        //         iter == map_rec_.erase(iter);
        //     }else{
        //         iter++;
        //     }
        // }
    }
    void Wrapper::cache_rec_info(std::string &id, int &index, std::string &path){
        std::lock_guard<std::mutex> l(mutex_rec_);
        while(list_rec_.size() > 100){
            for(int i = 0; i < 25; i++){
                list_rec_.pop_front();
            }
    void Wrapper::GetInfoRecorder(std::string &recID, int &index, std::string &path){
        if (rec_){
            rec_->GetRecInfo(recID, index, path);
        }
        struct record_file_info info;
        info.file_frame_index = index;
        info.file_path = path;
        info.rec_id = id;
        list_rec_.emplace_back(info);
        list_rec_map_[path] = id;
        logIt("LIST REC FILES COUNT : %d", list_rec_.size());
    }
    void Wrapper::GetInfoRecorder(int &index, std::string &path){
        std::lock_guard<std::mutex> l(mutex_rec_);
        if(list_rec_.empty()){
            index = -1;
            path = "";
            return;
        }
        auto info = list_rec_.front();
        index = info.file_frame_index;
        path = info.file_path;
        list_rec_.pop_front();
        if (map_rec_.find(info.rec_id) != map_rec_.end())
            map_rec_.erase(info.rec_id);
        for (auto iter = map_rec_.begin(); iter != map_rec_.end();){
            if (iter->second.rec && iter->second.rec->ErrorOcurred()){
                iter == map_rec_.erase(iter);
            }else{
                iter++;
            }
        }
        // logIt("go get info index: %d, file: %s\n", index, path.c_str());
    }
    std::string Wrapper::GetRecorderID(const std::string &path){
        std::lock_guard<std::mutex> l(mutex_rec_);
        std::string ret("");
        auto iter = list_rec_map_.find(path);
        if (iter != list_rec_map_.end()){
            ret = iter->second;
            list_rec_map_.erase(iter);
        }
        return ret;
    }
    ////////decoder
    void Wrapper::BuildDecoder(){
        use_decoder_ = true;
    }
    void Wrapper::cache_pic(std::shared_ptr<ffwrapper::FrameData> &frame, int64_t &id){
        pic_bgr24 pic;
        if(bridge_){
            AVFrame *frm = frame->getAVFrame();
            pic.w = scale_w_;
            pic.h = scale_h_;
            unsigned char *data = (unsigned char*)malloc(pic.w * pic.h * 3);
            bridge_->copyPicture(data, frm);
            pic.data = data;
            pic.id = id;
        }
        {
            std::lock_guard<std::mutex> l(mutex_pic_);
            while(list_pic_.size() > 10){
                for(int i = 0; i < 5; i++){
                    auto t = list_pic_.front();
                    free(t.data);
                    list_pic_.pop_front();
                }
            }
            list_pic_.emplace_back(pic);
        }
    }
    void Wrapper::GetPicDecoder(unsigned char **data, int *w, int *h, int64_t *id){
        std::lock_guard<std::mutex> l(mutex_pic_);
        if(list_pic_.empty()){
            *data = NULL;
            *w = 0;
            *h = 0;
            return;
        if (decoder_){
            decoder_->GetFrame(data, w, h, id);
        }
        auto p = list_pic_.front();
        *data = p.data; *w = p.w; *h = p.h;
        *id = p.id;
        list_pic_.pop_front();
    }
    void Wrapper::GetPacket(unsigned char **pktData, int *size, int *key){
        std::lock_guard<std::mutex> l(mutex_avpkt_);
        if(list_avpkt_.empty()){
            return;
        if (stream_){
            stream_->GetPacket(pktData, size, key);
        }
        auto pkt = list_avpkt_.front();
        *key = pkt.flags & AV_PKT_FLAG_KEY;
        *size = pkt.size;
        *pktData = (unsigned char *)malloc(*size);
        memcpy(*pktData, pkt.data, pkt.size);
        list_avpkt_.pop_front();
    }
    void Wrapper::cacheAVPacket(const AVPacket &pkt){
        std::lock_guard<std::mutex> l(mutex_avpkt_);
        while(list_avpkt_.size() > 10){
//            printf("cacheAVPacket drop packets!!!!!!!!!!\n");
            for(int i = 0; i < 5; i++){
                list_avpkt_.pop_front();
            }
        }
        list_avpkt_.emplace_back(pkt);
    }
    ////// test
    uint8_t *Wrapper::decodeJPEG(const char *file, int *w, int *h){
} // end class wrapper
///////////////////////////////////////////////////////////
///single decode or encoder
    ////// decoder
namespace cffmpeg_wrap{ // start test functions
    uint8_t* DecodeJPEG(const char *file, int *w, int *h){
        VideoProp prop;
        prop.url_ = file;
        prop.gpu_acc_ = false;
@@ -498,7 +239,7 @@
                return NULL;
            }
        }else{
            logIt("open %s error", input_url_.c_str());
            logIt("open %s error", file);
            return NULL;
        }
        
@@ -519,8 +260,6 @@
        }
        return NULL;
    }
/////// for encoder
    typedef struct _PicEncoder{
        FormatOut *enc;
csrc/wrapper.hpp
@@ -19,40 +19,16 @@
namespace ffwrapper{
    class FormatIn;
    class FormatOut;
    
    class VideoProp;
    class CodedData;
    class FrameData;
    class cvbridge;
}
namespace cffmpeg_wrap{
    typedef struct _pic_bgr24{
        unsigned char *data;
        int w;
        int h;
        int64_t id;
    }pic_bgr24;
    namespace buz{
        class Recorder;
        struct avpacket;
    }
    // typedef std::function<std::shared_ptr<buz::Recorder>(ffwrapper::FormatIn*)> FN_REC;
    typedef struct _fn_rec{
        std::string rid;
        std::string dir;
        int min;
        int max;
        std::unique_ptr<buz::Recorder> rec;
    }FnRec;
    class stream;
    class decoder;
    class rec;
    class Wrapper{
        public:
@@ -61,14 +37,10 @@
        private: 
            std::unique_ptr<ffwrapper::FormatIn> init_reader(const char* input);
            // ffwrapper::FormatIn* init_reader_gb28181(const char* input);
            void run_worker(ffwrapper::FormatIn *in, buz::avpacket &pkt);
            std::unique_ptr<buz::Recorder> init_recorder(ffwrapper::FormatIn *in, std::string id,std::string dir, const int mind, const int maxd);
            void cache_rec_info(std::string &id, int &index, std::string &path);
            void cache_pic(std::shared_ptr<ffwrapper::FrameData> &frame, int64_t &id);
            void cacheAVPacket(const AVPacket &pkt);
            void init_stream();
            void init_decoder(ffwrapper::FormatIn *in);
            void init_rec(ffwrapper::FormatIn *in);
        public: 
            int RunStream(const char* input);
        private: 
@@ -77,8 +49,7 @@
        public: //recorder
            void BuildRecorder(const char* id,const char *dir, const int mind, const int maxd);
            int FireRecorder(const char* sid,const int64_t &id);
            void GetInfoRecorder(int &index, std::string &path);
            std::string GetRecorderID(const std::string &path);
            void GetInfoRecorder(std::string &recID, int &index, std::string &path);
            void ScalePicture(const int w, const int h, const int flags);
            void UseGB28181();
@@ -87,57 +58,29 @@
            void BuildDecoder();
            void GetPicDecoder(unsigned char **data, int *w, int *h, int64_t *id);
            void GetPacket(unsigned char **pktData, int *size, int *key);
            //active api
        private:
            // stream 参数
            std::string input_url_;
            int scale_w_, scale_h_, scale_f_;
            int gb_, cpu_;
            bool use_decoder_;
            // decoder 参数
            std::unique_ptr<std::thread> thread_;
            std::atomic_bool    stop_stream_;
            ffwrapper::cvbridge *bridge_;
            bool use_decoder_;
            std::unordered_map<std::string, FnRec> map_rec_;
            //passive api
            struct record_file_info{
                int file_frame_index;
                std::string file_path;
                std::string rec_id;
            };
            std::list<struct record_file_info>  list_rec_;
            std::unordered_map<std::string, std::string> list_rec_map_;
            std::mutex mutex_rec_;
            std::list<pic_bgr24> list_pic_;
            std::mutex mutex_pic_;
            std::list<AVPacket> list_avpkt_;
            std::mutex mutex_avpkt_;
            int scale_w_, scale_h_, scale_f_;
            int gb_, cpu_;
            typedef struct recpkt{
                std::shared_ptr<ffwrapper::CodedData> data;
                int64_t id;
            }recpkt;
            std::list<recpkt> list_rec_pkt_;
            std::mutex mtx_rec_pkt_;
            int cache_rec_pkt(const buz::avpacket &pkt);
            void maybe_dump_rec_pkt();
            int     maxduration;
            int     minduration;
        //////////////////test frame to bgr24
        public:
            uint8_t *decodeJPEG(const char *file, int *w, int *h);
            // 业务类
            // 推流类
            stream* stream_;
            // 解码类
            decoder* decoder_;
            // 录像类
            rec* rec_;
    };
    uint8_t *DecodeJPEG(const char *file, int *w, int *h);
    void *CreateEncoder(const int w, const int h, const int fps, const int br, const int scale_flag, const int gi);
    void DestroyEncoder(void *h);
    int Encode(void *hdl, uint8_t *in, const int w, const int h, uint8_t **out, int *size, int *key);
goffmpeg.go
@@ -108,13 +108,13 @@
}
// DecodeJPEG decode jpeg file
func (h *GoFFMPEG) DecodeJPEG(input string) ([]byte, int, int) {
func DecodeJPEG(input string) ([]byte, int, int) {
    in := C.CString(input)
    defer C.free(unsafe.Pointer(in))
    var width C.int
    var height C.int
    p := C.wrap_fn_decode_jpeg(h.ffmpeg, in, &width, &height)
    p := C.wrap_fn_decode_jpeg(in, &width, &height)
    defer C.free(p)
    if width > 0 && height > 0 {
@@ -144,34 +144,27 @@
}
// GetInfoRecorder info
func (h *GoFFMPEG) GetInfoRecorder() (int, string) {
func (h *GoFFMPEG) GetInfoRecorder() (string, int, string) {
    var i C.int = -1
    var l C.int
    p := C.wrap_fn_info_recorder(h.ffmpeg, &i, &l)
    var id *C.char
    var idl C.int
    var p *C.char
    var pl C.int
    C.wrap_fn_info_recorder(h.ffmpeg, &i, &id, &idl, &p, &pl)
    // if p == nil {
    //     return -1, ""
    // }
    gID := C.GoString(id)
    C.free(unsafe.Pointer(id))
    path := C.GoString(p)
    C.free(unsafe.Pointer(p))
    // fmt.Println("Go get info : ", path, " len: ", l)
    return int(i), path
}
// GetRecID get rec id
func (h *GoFFMPEG) GetRecID(p string) string {
    pt := C.CString(p)
    defer C.free(unsafe.Pointer(pt))
    var i C.int
    cid := C.wrap_fn_rec_id(h.ffmpeg, pt, &i)
    id := C.GoString(cid)
    C.free(unsafe.Pointer(cid))
    return id
    return gID, int(i), path
}
// BuildDecoder build decoder
libcffmpeg.c
@@ -35,8 +35,6 @@
        release_if_err(fn_fire_recorder, lib);
        fn_info_recorder = (lib_cffmpeg_info_recorder)dlsym(lib, "c_ffmpeg_get_info_recorder");
        release_if_err(fn_info_recorder, lib);
        fn_rec_id = (lib_cffmpeg_rec_id)dlsym(lib, "c_ffmpeg_get_rec_id");
        release_if_err(fn_rec_id, lib);
        fn_decoder = (lib_cffmpeg_decoder)dlsym(lib, "c_ffmpeg_build_decoder");
        release_if_err(fn_decoder, lib);
        fn_decoder_pic = (lib_cffmpeg_pic)dlsym(lib, "c_ffmpeg_get_pic_decoder");
@@ -97,12 +95,8 @@
    fn_fire_recorder(h, sid, id);
}
char* wrap_fn_info_recorder(const cffmpeg h, int* index, int* length){
    return fn_info_recorder(h, index, length);
}
char* wrap_fn_rec_id(const cffmpeg h, const char* path, int*length){
    return fn_rec_id(h, path, length);
void wrap_fn_info_recorder(const cffmpeg h, int* index, char** recid, int* recidLen, char** fpath, int* pathLen){
    return fn_info_recorder(h, index, recid, recidLen, fpath, pathLen);
}
void wrap_fn_decoder(const cffmpeg h){
@@ -117,8 +111,8 @@
    return fn_get_avpacket(h, size, key);
}
void* wrap_fn_decode_jpeg(const cffmpeg h, const char* file, int* wid, int* hei){
    return fn_dec_jpeg(h, file, wid, hei);
void* wrap_fn_decode_jpeg(const char* file, int* wid, int* hei){
    return fn_dec_jpeg(file, wid, hei);
}
// for encoder
libcffmpeg.h
@@ -18,12 +18,11 @@
typedef void (*lib_cffmpeg_cpu)(const cffmpeg);
typedef void (*lib_cffmpeg_recorder)(const cffmpeg, const char*, const char*, int, int);
typedef void (*lib_cffmpeg_fire_recorder)(const cffmpeg, const char*, const int64_t);
typedef char*(*lib_cffmpeg_info_recorder)(const cffmpeg, int*, int*);
typedef char*(*lib_cffmpeg_rec_id)(const cffmpeg, const char*, int*);
typedef void (*lib_cffmpeg_info_recorder)(const cffmpeg, int*, char**, int*, char**, int*);
typedef void (*lib_cffmpeg_decoder)(const cffmpeg);
typedef void*(*lib_cffmpeg_pic)(const cffmpeg, int*, int*, int64_t*);
typedef void*(*lib_cffmpeg_avpacket)(const cffmpeg, int*, int*);
typedef void*(*lib_cffmpeg_decode_jpeg)(const cffmpeg, const char*, int*, int*);
typedef void*(*lib_cffmpeg_decode_jpeg)(const char*, int*, int*);
static lib_cffmpeg_create              fn_create = NULL;
static lib_cffmpeg_destroy             fn_destroy = NULL;
@@ -34,7 +33,6 @@
static lib_cffmpeg_recorder            fn_recorder = NULL;
static lib_cffmpeg_fire_recorder       fn_fire_recorder = NULL;
static lib_cffmpeg_info_recorder       fn_info_recorder = NULL;
static lib_cffmpeg_rec_id              fn_rec_id = NULL;
static lib_cffmpeg_decoder             fn_decoder = NULL;
static lib_cffmpeg_pic                 fn_decoder_pic = NULL;
static lib_cffmpeg_avpacket            fn_get_avpacket = NULL;
@@ -52,12 +50,11 @@
void wrap_fn_use_cpu(const cffmpeg h);
void wrap_fn_recorder(const cffmpeg h, const char* id, const char* dir, int mind, int maxd);
void wrap_fn_fire_recorder(const cffmpeg h, const char *sid, const int64_t id);
char* wrap_fn_info_recorder(const cffmpeg, int* index, int* length);
char* wrap_fn_rec_id(const cffmpeg h, const char* path, int*length);
void wrap_fn_info_recorder(const cffmpeg, int* index, char** recid, int* recidLen, char** fpath, int* pathLen);
void wrap_fn_decoder(const cffmpeg h);
void* wrap_fn_decoder_pic(const cffmpeg h, int* wid, int* hei, int64_t *id);
void* wrap_fn_get_avpacket(const cffmpeg h, int* size, int* key);
void* wrap_fn_decode_jpeg(const cffmpeg h, const char* file, int* wid, int* hei);
void* wrap_fn_decode_jpeg(const char* file, int* wid, int* hei);
// for encoder