video analysis2.0拆分,ffmpeg封装go接口库
chenshijun
2019-10-29 4587f8d5507300782e329f9527f35f905f3bb697
Merge branch 'master' of ssh://192.168.5.5:29418/valib/goffmpeg
26个文件已修改
900 ■■■■■ 已修改文件
cffmpeg.h 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/buz/recorder.cpp 246 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/buz/recorder.hpp 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/cffmpeg.cpp 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/common.hpp 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/ffmpeg/configure/conf.cpp 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/ffmpeg/format/FormatIn.cpp 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/ffmpeg/format/FormatOut.cpp 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/thirdparty/gb28181/include/PsToEs.hpp 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/worker/decoder.cpp 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/worker/decoder.hpp 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/worker/rec.cpp 106 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/worker/rec.hpp 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/worker/stream.cpp 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/worker/stream.hpp 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/wrapper.cpp 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
csrc/wrapper.hpp 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
goconv.go 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
godec.go 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
godecjpeg.go 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
goenc.go 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
goffmpeg.go 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
gorec.go 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
gostream.go 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
libcffmpeg.c 184 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libcffmpeg.h 48 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cffmpeg.h
@@ -15,11 +15,12 @@
void c_ffmpeg_destroy(const cffmpeg h);
void c_ffmpeg_run(const cffmpeg h, const char *input);
int c_ffmpeg_get_fps(const cffmpeg h);
void c_ffmpeg_run_gb28181(const cffmpeg h);
void c_ffmepg_use_cpu(const cffmpeg h);
/////////passive api
void c_ffmpeg_set_record_duration(const cffmpeg h, const int min, const int max);
void c_ffmpeg_build_recorder(const cffmpeg h, const char*id, const char *dir, int mind, int maxd, int audio);
void c_ffmpeg_build_recorder(const cffmpeg h, const char*id, const char *dir, const int64_t fid, int mind, int maxd, int audio);
void c_ffmpeg_fire_recorder(const cffmpeg h, const char*sid, const int64_t id);
void c_ffmpeg_get_info_recorder(const cffmpeg h, int *index, char** recid, int *recidLen, char **fpath, int *pathLen);
@@ -40,9 +41,6 @@
                          const int dstW, const int dstH, const int dstFormat, const int flag);
void c_ffmpeg_destroy_conv(void *h);
void *c_ffmpeg_conv(void *h, uint8_t *in);
// gpu conv
void* c_gpu_conv(uint8_t *in, const int w, const int h, const int dst_w, const int dst_h, int *length);
#ifdef __cplusplus
}
csrc/buz/recorder.cpp
@@ -5,6 +5,8 @@
#include <unistd.h>
#include <chrono>
#include <sys/stat.h>
extern "C"{
#include <libavcodec/avcodec.h>
}
@@ -24,19 +26,20 @@
        ,out_(NULL)
        ,maxduration(30 * 25)
        ,minduration(10 * 25)
        ,end_frame(minduration)
        ,cur_frame(0)
        ,fp_(NULL)
        ,stop_recorder_(false)
        ,id_(id)
        ,id_frame_(-1)
        ,id_frame_in_file_(-1)
        ,id_frame_(0)
        ,id_frame_in_file_(0)
        ,file_path_("")
        ,func_rec_info_(nullptr)
        ,thrd_(nullptr)
        ,error_occured_(false)
        ,audio_(false)
        ,cur_frame_a(0)
        ,fp_(NULL)
        ,end_frame_(0)
        ,v_cur_frame_(0)
        ,a_cur_frame_(0)
        ,error_occured_(false)
        ,last_rec_id_(-1)
        {
            if (in){
                maxduration = 30 * in->getFPS();
@@ -81,6 +84,12 @@
            std::string filename(sole::uuid4().base62() + "-" + std::to_string(pid) + ".mp4");
            file_path_ = dir_ + "/" + filename;
            std::string backup_dir("./video");
            size_t pos = dir_.rfind("/");
            if (pos != std::string::npos){
                backup_dir = dir_.substr(0, pos);
            }
            auto v = in_->getStream(AVMEDIA_TYPE_VIDEO);
            if (!v){
                return -2;
@@ -91,14 +100,16 @@
            }
            bool ret = out_->JustWriter(v, a, file_path_.c_str());
            if (ret){
                logIt("start record file: %s", file_path_.c_str());
                logIt("start record h264 file: %s", file_path_.c_str());
                return 0;
            }else{
                file_path_ = "./" + filename;
                ret = out_->JustWriter(v, a, file_path_.c_str());
                mkdir(backup_dir.c_str(), 0777);
                file_path_ = backup_dir + "/" + filename;
                logIt("failed in dir %s, try file %s to start record file", dir_.c_str(), file_path_.c_str());                
                ret = out_->JustWriter(v, a, file_path_.c_str());
                if (ret){
                    logIt("start record file: %s", file_path_.c_str());
                    logIt("start record h264 file: %s", file_path_.c_str());
                    return 0;
                }
            }
@@ -114,12 +125,20 @@
            }
            int pid = getpid();
            std::string filename(sole::uuid4().base62() + "-" + std::to_string(pid) + ".mp4");
            std::string filename(sole::uuid4().base62() + "-" + std::to_string(pid) + ".hevc");
            file_path_ = dir_ + "/" + filename;
            std::string backup_dir("./video");
            size_t pos = dir_.rfind("/");
            if (pos != std::string::npos){
                backup_dir = dir_.substr(0, pos);
            }
            fp_ = fopen(file_path_.c_str(), "wb");
            if (!fp_){
                file_path_ = "./" + filename;
                mkdir(backup_dir.c_str(), 0777);
                file_path_ = backup_dir + "/" + filename;
                logIt("failed in dir %s, try file %s to start record hevc file", dir_.c_str(), file_path_.c_str());                
                fp_ = fopen(file_path_.c_str(), "wb");
                if (!fp_){
@@ -127,7 +146,7 @@
                    return -1;
                }
            }
            logIt("start record file: %s", file_path_.c_str());
            logIt("start record hevc file: %s", file_path_.c_str());
            return 0;
        }
@@ -149,27 +168,33 @@
////////////////////////
        int Recorder::write_h264(const CPacket &pkt){
            //reader failed, break stream
            if(pkt.id == -1 && !pkt.data){
            if(!pkt.data){
                return -1;
            }
            if (cur_frame == end_frame){
            if (v_cur_frame_ == end_frame_){
                return 1;
            }
            AVPacket &op = pkt.data->getAVPacket();
            if (!audio_ && in_->isAudioPkt(&op)) {
                return 0;
            }
            AVPacket np(op);
            av_copy_packet(&np, &op);
            
            int64_t cur = cur_frame;
            int64_t cur = v_cur_frame_;
            if (in_->isVideoPkt(&np)){
                if(pkt.id == id_frame_){
                    id_frame_in_file_ = cur_frame;
                if(pkt.v_id == id_frame_){
                    id_frame_in_file_ = v_cur_frame_;
                }
                cur_frame++;
                v_cur_frame_++;
            }else if (in_->isAudioPkt(&np)) {
                cur = cur_frame_a++;
                cur = a_cur_frame_++;
            }
            
            auto ret = out_->writeFrame(&np, cur);
@@ -187,21 +212,29 @@
                logIt("write hevc packet error, file not open");
                return -1;
            }
            if (cur_frame == end_frame){
            if (v_cur_frame_ == end_frame_){
                return 1;
            }
            
            AVPacket &op = pkt.data->getAVPacket();
            int64_t cur = cur_frame;
            if (in_->isVideoPkt(&op)){
                if(pkt.id == id_frame_){
                    id_frame_in_file_ = cur_frame;
                }
                cur_frame++;
            if (in_->isAudioPkt(&op)) {
                return 0;
            }
            if (op.data == NULL){
                logIt("hevc avpacket data null");
                return 0;
            }
            if (in_->isVideoPkt(&op)){
                if(pkt.v_id == id_frame_){
                    id_frame_in_file_ = v_cur_frame_;
                }
                v_cur_frame_++;
            }
            fwrite(op.data, op.size, 1, fp_); 
            return 0;
        }
@@ -265,22 +298,27 @@
        }
        int Recorder::mux_hevc(FILE *fp, const char *outfile){
            std::unique_ptr<FormatIn> in(new FormatIn(false));
            if (!fp) {
                logIt("mux hevc file handle is null");
                return -1;
            }
            std::unique_ptr<FormatIn> in(nullptr);
            int tryTime = 0;
            while (in->openWithCustomIO(fp, read_buffer) < 0) {
                usleep(10000);
                if (tryTime++ < 100){
                    logIt("mux hevc mux: %d failed open custom io %s, try again", tryTime, outfile);
                    continue;
            while(true){
                std::unique_ptr<FormatIn> tmp(new FormatIn(false));
                auto ret = tmp->openWithCustomIO(fp, read_buffer);
                if (ret == 0){
                    in = std::move(tmp);
                    break;
                }
                logIt("mux hevc try %d time to open custom io, failed", tryTime);
                return -2;
                usleep(10000);
                if (tryTime++ > 100){
                    logIt("mux hevc try %d time to open custom io %s, failed", tryTime, outfile);
                    return -2;
                }
            }
            if (in->open(NULL, NULL) < 0){
                logIt("mux hevc open stream error");
@@ -298,7 +336,7 @@
                return -5;
            }
            if (out->JustWriter(v, NULL, outfile)){
                logIt("mux hevc  start record file: %s", outfile);
                logIt("mux hevc start record file: %s", outfile);
            }
            int64_t id = 0;
@@ -327,13 +365,12 @@
                end_write_h264();
            }
            logIt("finished record : %s frames: %d", file_path_.c_str(), cur_frame);
            logIt("finished record : %s frames: %d, frame in file id: %d",
                    file_path_.c_str(), end_frame_, id_frame_in_file_);
            {
                std::lock_guard<std::mutex> l(mutex_pkt_);
                list_pkt_.clear();
            }
            // logIt("INDEX %d, REAL-FRAME-ID %d, FILE %s, CURFrame %d, ENDFrame %d\n",
            //      id_frame_in_file_, id_frame_, file_path_.c_str(), cur_frame, end_frame);
            if(func_rec_info_){
                func_rec_info_(id_,id_frame_in_file_, file_path_);
@@ -347,14 +384,17 @@
                std::list<CPacket> pkts;
                {
                    std::unique_lock<std::mutex> locker(mutex_pkt_);
                    auto status = cv_.wait_for(locker, std::chrono::seconds(3), [&]{
                    int sec = minduration/50;
                    if (in_) sec = minduration/in_->getFPS()/2;
                    auto status = cv_.wait_for(locker, std::chrono::seconds(sec), [&]{
                        return !list_pkt_.empty() || stop_recorder_.load();
                    });
                    if (!status || stop_recorder_.load()){
                        error_occured_ = !status;
                        break;
                    }
                    list_pkt_.swap(pkts);
                }
                
@@ -373,6 +413,7 @@
            stop_recorder_.store(true);
            end_writer();
            list_pkt_.clear();
        }
        int Recorder::Run(const char* output, const int mind, const int maxd, const bool audio){
@@ -391,12 +432,12 @@
            if(fps > 1.0){
                maxduration = fps * maxd;
                minduration = fps * mind;
                end_frame = minduration;
                end_frame_ = minduration;
            }
            audio_ = a;
            logIt("minduration %d maxduration %d curduration %d", minduration, maxduration, end_frame);
            logIt("minduration %d maxduration %d", minduration, maxduration);
            thrd_.reset(new std::thread([&]{
                run_thread();
@@ -409,76 +450,111 @@
        int Recorder::FireRecorder(const int64_t &id){
            if (stop_recorder_.load()) return -1;
            if(id_frame_ == -1){
            if(id_frame_ == 0){
                id_frame_ = id;
                std::lock_guard<std::mutex> locker(mutex_pkt_);
                if (list_pkt_.size() > end_frame){
                    end_frame = list_pkt_.size() + minduration/2;
                    if (end_frame > maxduration)
                        end_frame = maxduration;
                if (list_pkt_.size() > end_frame_){
                    end_frame_ = list_pkt_.size() + minduration/2;
                    if (end_frame_ > maxduration)
                        end_frame_ = maxduration;
                }
            }else if(v_cur_frame_ > minduration/2 && end_frame_ < maxduration){
                logIt("cur frame: %d, end frame: %d, duration: [%d-%d]",
                        v_cur_frame_, end_frame_, minduration, maxduration);
                // logIt("FIRST FIRE RECORD ID: %lld, cur_frame: %d, end_frame: %d", id, cur_frame, end_frame);
            }else if(cur_frame > minduration/2 && end_frame < maxduration){
                end_frame = end_frame + minduration / 2;
                if(end_frame > maxduration){
                    end_frame = maxduration;
                end_frame_ = end_frame_ + minduration / 2;
                if(end_frame_ > maxduration){
                    end_frame_ = maxduration;
                }
                // logIt("PROLONG REC, cur_frame: %d, end_frame: %d", cur_frame, end_frame);
            }
            // logIt("FIRE REC FRAME ID: %lld", id);
            return 0;
        }
        int Recorder::PushPacket(const CPacket &pkt){
        int Recorder::PushPacket(std::list<CPacket> &lst){
            if (stop_recorder_.load()) return 0;
            std::lock_guard<std::mutex> locker(mutex_pkt_);
            if(id_frame_ == -1){
                //wait I
                if (!audio_ && in_->isAudioPkt(&pkt.data->getAVPacket())){
                    return 0;
            // 没有开始录制
            if (last_rec_id_ < 0){
                logIt("last rec id is 0 cache size: %ld", lst.size());
                for (auto &i : lst){
                    // 从第一个非音频关键帧开始
                    if (last_rec_id_ < 0){
                        if (!in_->isVideoPkt(&i.data->getAVPacket())){
                            continue;
                        }
                        if (!(i.data->getAVPacket().flags & AV_PKT_FLAG_KEY)){
                            continue;
                        }
                    }
                    last_rec_id_ = i.id;
                    list_pkt_.push_back(i);
                }
                maybe_dump_gop();
                list_pkt_.push_back(pkt);
                // cv_.notify_one();
            }else{
                list_pkt_.push_back(pkt);
                cv_.notify_one();
                for(auto &i : lst){
                    if (i.id > last_rec_id_){
                        list_pkt_.push_back(i);
                        last_rec_id_++;
                    }
                }
            }
            cv_.notify_one();
            return list_pkt_.size();
        }
        int Recorder::PushPackets(std::list<CPacket> &lst){
        int Recorder::StartWritePacket(std::list<CPacket> &lst, const int64_t &id, const int start, const int end){
            if (stop_recorder_.load()) return 0;
            // 第一次录像,设置触发帧id
            id_frame_ = id;
            if (start < 0) {
                logIt("start write packet [%d-%d] in pkt size: %d, frame id: %lld, "
                    "cur frame: %d, end frame: %d, duration: [%d-%d], last rec id: %lld",
                    start, end, lst.size(), id_frame_,
                    v_cur_frame_, end_frame_, minduration, maxduration, last_rec_id_);
                return -1;
            }
            std::lock_guard<std::mutex> locker(mutex_pkt_);
            bool i = false;
            // 将传入的所有packets保存如缓存
            int index = -1;
            for (auto &p : lst){
                if (!audio_ && in_->isAudioPkt(&p.data->getAVPacket())){
                    continue;
                }
                index++;
                if (index < start) continue;
                
                list_pkt_.push_back(p);
                if (index == end){
                    last_rec_id_ = p.id;
                    break;
                }
            }
            maybe_dump_gop();
            logIt("start write packet [%d-%d] in pkt size: %d, frame id: %lld, "
                "cur frame: %d, end frame: %d, duration: [%d-%d], last rec id: %lld",
                start, end, lst.size(), id_frame_,
                v_cur_frame_, end_frame_, minduration, maxduration, last_rec_id_);
            // maybe_dump_gop();
            cv_.notify_one();
            // logIt("CACHE PACKET : %d", list_pkt_.size());
            return list_pkt_.size();
        }
        void Recorder::maybe_dump_gop(){
            //超过min/2,丢弃gop
            while (list_pkt_.size() > minduration) {
            while (list_pkt_.size() > maxduration) {
                list_pkt_.pop_front();
                while(!list_pkt_.empty()){
                    auto &i = list_pkt_.front();
@@ -490,5 +566,5 @@
                }
            }
        }
    }
}
    }// end clase
}// end namespace
csrc/buz/recorder.hpp
@@ -32,8 +32,8 @@
            public: 
                int Run(const char* output, const int mind, const int maxd, const bool audio);
                int PushPacket(const CPacket &pkt);
                int PushPackets(std::list<CPacket> &lst);
                int PushPacket(std::list<CPacket> &lst);
                int StartWritePacket(std::list<CPacket> &lst, const int64_t &id, const int start, const int end);
                int FireRecorder(const int64_t &id);
                void SetCallback(FUNC_REC_INFO cb){
@@ -63,33 +63,33 @@
                ffwrapper::FormatIn     *in_;
                ffwrapper::FormatOut    *out_;
                int     maxduration;
                int     minduration;
                int     end_frame;
                int     cur_frame;
                int     cur_frame_a;
                std::list<CPacket>     list_pkt_;
                std::list<CPacket>      list_pkt_;
                std::atomic_bool        stop_recorder_;
                std::mutex              mutex_pkt_;
                 std::condition_variable cv_;
                std::unique_ptr<std::thread> thrd_;
                std::string             dir_;
                std::string             id_;
                int64_t                 id_frame_;
                int                     id_frame_in_file_;
                std::string             file_path_;
                FUNC_REC_INFO           func_rec_info_;
                bool                    error_occured_;
                FILE                    *fp_;
                bool                    audio_;
                FILE                    *fp_;
                std::unique_ptr<std::thread> thrd_;
                int     end_frame_;
                int     v_cur_frame_;
                int     a_cur_frame_;
                int64_t last_rec_id_;
                int     maxduration;
                int     minduration;
                bool                    error_occured_;
        };
    }
}
csrc/cffmpeg.cpp
@@ -33,6 +33,11 @@
    s->RunStream(input);
}
int c_ffmpeg_get_fps(const cffmpeg h){
    Wrapper *s = (Wrapper*)h;
    return s->GetFPS();
}
void c_ffmpeg_run_gb28181(const cffmpeg h){
    Wrapper *s = (Wrapper*)h;
    s->GB28181();
@@ -50,11 +55,11 @@
    s->SetRecMinCacheTime(min);
}
void c_ffmpeg_build_recorder(const cffmpeg h, const char* id, const char *dir, int mind, int maxd, int audio){
void c_ffmpeg_build_recorder(const cffmpeg h, const char* id, const char *dir, const int64_t fid, int mind, int maxd, int audio){
    Wrapper *s = (Wrapper*)h;
    bool a = audio == 0 ? false : true;
    s->BuildRecorder(id, dir, mind, maxd, a);
    s->BuildRecorder(id, dir, fid, mind, maxd, a);
}
void c_ffmpeg_fire_recorder(const cffmpeg h, const char* sid, const int64_t id){
@@ -134,7 +139,3 @@
void c_ffmpeg_destroy_conv(void *h){
    DestoryConvertor(h);
}
void* c_gpu_conv(uint8_t *in, const int w, const int h, const int dst_w, const int dst_h, int *length){
    return ConvertYUV2BGR(in, w, h, dst_w, dst_h, length);
}
csrc/common.hpp
@@ -8,9 +8,12 @@
    class CodedData;
}
// 缓存的视频帧
typedef struct _cache_pkt{
class CPacket{
public:
    std::shared_ptr<ffwrapper::CodedData> data;
    int64_t v_id;
    int64_t a_id;
    int64_t id;
}CPacket;
};
#endif
csrc/ffmpeg/configure/conf.cpp
@@ -13,7 +13,7 @@
        av_register_all();
        avfilter_register_all();
        avformat_network_init();
        av_log_set_level(AV_LOG_VERBOSE);
        av_log_set_level(AV_LOG_ERROR);
    }
    std::string getAVErrorDesc(const int code){
csrc/ffmpeg/format/FormatIn.cpp
@@ -38,20 +38,13 @@
    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;
        }
        if(ctx_){
            if (!ctx_->oformat){
                avformat_free_context(ctx_);
            }else{
            if (!(ctx_->flags & AVFMT_FLAG_CUSTOM_IO)){
                avformat_close_input(&ctx_);
            }else{
                avformat_free_context(ctx_);
            }
            ctx_ = NULL;
            if(dec_ctx_){
                avcodec_close(dec_ctx_);
@@ -59,18 +52,23 @@
            }
            
        }
        if (handle_gb28181){
            delete handle_gb28181;
        }
        if(read_io_buff_){
            av_free(read_io_buff_);
            read_io_buff_ = NULL;
        }
        if(io_ctx_){
            avio_context_free(&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\n");
            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\n");
@@ -82,9 +80,16 @@
            logIt("open with custom io create custom avio error\n");
            return -1;
        }
        ctx_ = avformat_alloc_context();
        if(!ctx_){
            logIt("open with custom io create format error\n");
            return -1;
        }
        ctx_->pb = io_ctx_;
        auto err = av_probe_input_buffer(ctx_->pb, &ctx_->iformat, NULL, NULL, 0, read_io_buff_size_);
        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;
csrc/ffmpeg/format/FormatOut.cpp
@@ -399,7 +399,7 @@
        int out_idx = -1;
        std::vector<AVStream*> in_streams{in_v_stream_, in_a_stream_};
        for (auto i : in_streams){
            if (i->index == pkt->stream_index){
            if (i && (i->index == pkt->stream_index)){
                if (i->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){
                    out_idx = v_idx_;
                    in_stream = i;
csrc/thirdparty/gb28181/include/PsToEs.hpp
@@ -75,6 +75,16 @@
        while (!q.empty()) q.pop_front();
        pthread_mutex_unlock(&mtx);
    }
    void clearAll(std::function<void(T)> fn){
        pthread_mutex_lock(&mtx);
        while (!q.empty()){
            T value = q.front();
            fn(value);
            q.pop_front();
        }
        pthread_mutex_unlock(&mtx);
    }
private:
    deque<T> q;
    pthread_mutex_t mtx;
@@ -96,7 +106,11 @@
    ~GB28181API(){
        printf("GB28181API end!\n");
        m_rtpQueue.clearAll();
        // m_rtpQueue.clearAll();
        m_rtpQueue.clearAll([](frameBuffInfo *info){
            delete[] info->buff;
            delete info;
        });
        deleteCamera();
    }
csrc/worker/decoder.cpp
@@ -4,6 +4,7 @@
#include "../ffmpeg/format/FormatIn.hpp"
#include "../ffmpeg/data/CodedData.hpp"
#include "../ffmpeg/log/log.hpp"
#include "../common.hpp"
extern "C"{
#include <libavformat/avformat.h>
@@ -46,7 +47,7 @@
        return 0;
    }
    int decoder::saveFrame(AVFrame *frame, int64_t &id){
    int decoder::saveFrame(AVFrame *frame, const int64_t &id){
        FRM frm;
        frm.width = frame->width;
        frm.height = frame->height;
@@ -67,7 +68,8 @@
        return list_frm_.size();   
    }
    int decoder::SetFrame(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id){
    int decoder::SetFrame(const CPacket &pkt){
        auto data = pkt.data;
        if (!data) return -10;
        if (!decRef_->isVideoPkt(&data->getAVPacket())) return -20;
@@ -83,7 +85,7 @@
        av_packet_unref(&np);
        
        if (ret == 0){
            saveFrame(frame, id);
            saveFrame(frame, pkt.v_id);
        }
        av_frame_free(&frame);
        return ret;
csrc/worker/decoder.hpp
@@ -12,6 +12,8 @@
struct AVFrame;
struct AVCodecContext;
class CPacket;
namespace ffwrapper
{
    class FormatIn;
@@ -40,10 +42,10 @@
        
    private:
        int initDecoder();
        int saveFrame(AVFrame *frame, int64_t &id);
        int saveFrame(AVFrame *frame, const int64_t &id);
    public: 
        void Start();
        int SetFrame(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id);
        int SetFrame(const CPacket &pkt);
        void GetFrame(unsigned char **data, int *w, int *h, int *format, int *length, int64_t *id);
    
    public:
csrc/worker/rec.cpp
@@ -16,12 +16,13 @@
using namespace ffwrapper;
using namespace cffmpeg_wrap::buz;
static const int cache_time = 6 * 60;
namespace cffmpeg_wrap
{
    rec::rec()
    :recRef_(NULL)
    ,min_cache_len_(125)
    ,time_offset_(5)
    ,min_cache_len_(cache_time * 25) // 最小缓存?分钟的视频,因为整个流程会有延迟,暂定?分钟
    {}
    rec::~rec()
@@ -44,7 +45,49 @@
        list_recInfo_.emplace_back(info);
    }
    std::unique_ptr<buz::Recorder> rec::startRec(std::string id, std::string dir, const int mind, const int maxd, const bool audio){
    void rec::findRecFramesIndex(const int64_t &fired_id, const int duration, int &start, int &end){
        start = end = -1;
        if (list_pkt_.empty()){
            return;
        }
        // 录像开始id在触发id之前1/2时长,保证在中间
        int64_t start_id = fired_id - duration/2;
        // 寻找关键帧作为录像开始id
        int offset = recRef_ ? recRef_->getFPS() : 25;
        int64_t index = -1;
        for(auto &i : list_pkt_){
            index++;
            // 跳过音频
            if(!recRef_->isVideoPkt(&i.data->getAVPacket())){
                continue;
            }
            // 寻找关键帧作为起始
            if (start < 0){
                if (i.data->getAVPacket().flags & AV_PKT_FLAG_KEY){
                    // 当前帧id > 开始id或开始id在offset内,作为起始录像帧
                    if (i.v_id >= start_id || start_id - i.v_id < offset){
                        start = index;
                        start_id = i.v_id;
                    }
                }
            }else if (recRef_->isVideoPkt(&i.data->getAVPacket())){
                // 视频帧,看是否缓存中有所有的duration数据
                if (i.v_id - start_id == duration){
                    end = index;
                }
            }
        }
        if (end < 0) end = index;
    }
    std::unique_ptr<buz::Recorder> rec::startRec(std::string id, std::string dir, const int64_t &frameID, const int mind, const int maxd, const bool audio){
        if(!recRef_){
            logIt("Init wrapper first");
            return nullptr;
@@ -62,9 +105,17 @@
            if(ret == 0) break;
            usleep(200000);
        }
        if (trycnt < 100){
            int duration = mind * recRef_->getFPS();
            int start=0, end=0;
            std::lock_guard<std::mutex> locker(mtx_pkt_);
            rec->PushPackets(list_pkt_);
            logIt("cache size: %ld", list_pkt_.size());
            // 首次获取录像信息,先存一个最短时长
            findRecFramesIndex(frameID, duration, start, end);
            rec->StartWritePacket(list_pkt_, frameID, start, end);
            return rec;
        }
@@ -126,6 +177,9 @@
    void rec::Load(ffwrapper::FormatIn *in){
        recRef_ = in;
        if (in){
            min_cache_len_ = in->getFPS() * cache_time;
        }
    }
    void rec::Unload(){
@@ -137,7 +191,7 @@
        return recRef_ != NULL;
    }
    
    void rec::NewRec(const char* id, const char *output, const int mindur, const int maxdur, const bool audio){
    void rec::NewRec(const char* id, const char *output, const int64_t &frameID, const int mindur, const int maxdur, const bool audio){
        std::string rid(id);
        std::string dir(output);
        
@@ -146,7 +200,7 @@
            if (map_rec_.find(rid) != map_rec_.end()){
                map_rec_.erase(rid);
            }
            map_rec_[rid] = startRec(rid, dir, mindur, maxdur, audio);
            map_rec_[rid] = startRec(rid, dir, frameID, mindur, maxdur, audio);
        }
        
    }
@@ -165,30 +219,35 @@
        // logIt("recorders count: %d", map_rec_.size());
    }
    void rec::SetPacket(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id){
        if (!data) return;
    void rec::SetPacket(const CPacket &pkt){
        if (!pkt.data) return;
        cachePacket(pkt);
        std::lock_guard<std::mutex> l(mtx_rec_);
        for(auto &i : map_rec_){
            if (i.second){
                i.second->PushPacket({data, id});
                std::lock_guard<std::mutex> pl(mtx_pkt_);
                i.second->PushPacket(list_pkt_);
            }
        }
        cachePacket(data, id);
    }
    void rec::cachePacket(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id){
    void rec::cachePacket(const CPacket &pkt){
        std::lock_guard<std::mutex> l(mtx_pkt_);
        //wait I 
        if (list_pkt_.empty()) {
            if (!recRef_->isVideoPkt(&pkt.data->getAVPacket())){
                return;
            }
            if (!(data->getAVPacket().flags & AV_PKT_FLAG_KEY)){
            if (!(pkt.data->getAVPacket().flags & AV_PKT_FLAG_KEY)){
                return;
            }
        }
        
        list_pkt_.push_back({data, id});
        list_pkt_.push_back(pkt);
        // 超过缓存最大长度,删除一个gop
        shrinkCache();
@@ -200,24 +259,21 @@
        if (recRef_){
            fps = recRef_->getFPS();
        }
        min_cache_len_ = (min + time_offset_) * fps;
        min_cache_len_ += min * fps;
    }
    int rec::shrinkCache(){
        //超过最大缓存,丢弃gop
        //缓存最小长度的,用于记录
        int fps = 25;
        if (recRef_){
            fps = recRef_->getFPS();
        }
        // 最小5秒长度
        int mincache = fps * 5;
        int md = min_cache_len_ < mincache ? mincache : min_cache_len_;
        while (list_pkt_.size() > md) {
        //超过最大缓存,丢弃gop
        while (list_pkt_.size() > min_cache_len_) {
            list_pkt_.pop_front();
            while(!list_pkt_.empty()){
                auto &i = list_pkt_.front();
                if (!(i.data->getAVPacket().flags & AV_PKT_FLAG_KEY)){
                // 音频丢弃
                if (!recRef_->isVideoPkt(&i.data->getAVPacket())){
                    list_pkt_.pop_front();
                }else if (!(i.data->getAVPacket().flags & AV_PKT_FLAG_KEY)){
                    // 非关键帧丢弃
                    list_pkt_.pop_front();
                }else{
                    break;
csrc/worker/rec.hpp
@@ -9,6 +9,7 @@
#include "../buz/recorder.hpp"
struct AVPacket;
class CPacket;
namespace ffwrapper
{
@@ -24,8 +25,6 @@
    private:
        ffwrapper::FormatIn *recRef_;
        int min_cache_len_;
        // 整个流程耗时补偿录制时间,2s默认
        const int time_offset_;
        // 录像的实例,对应任务
        std::unordered_map<std::string, std::unique_ptr<buz::Recorder> > map_rec_;
        // 多线程添加任务实例,在读流线程使用录像,但是添加在另一个线程
@@ -47,25 +46,28 @@
        std::mutex mtx_pkt_;
    private: 
        // 查找缓存中的录制帧
        void findRecFramesIndex(const int64_t &fired_id, const int duration, int &start, int &end);
        // 录像实例的回调函数,录像完成后设置录像文件路径,id和帧id
        void setRecInfo(std::string &id, int &index, std::string &path);
        // 缓存视频包
        void cachePacket(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id);
        void cachePacket(const CPacket &pkt);
        // 丢弃缓存
        int shrinkCache();
        // 创建录像实例开始录像
        std::unique_ptr<buz::Recorder> startRec(std::string id, std::string dir, const int mind, const int maxd, const bool audio);
        std::unique_ptr<buz::Recorder> startRec(std::string id, std::string dir, const int64_t &frameID, const int mind, const int maxd, const bool audio);
        // 清除缓存,断线重连时需要
        void clear();
    public:
        void NewRec(const char* id, const char *output, const int mindur, const int maxdur, const bool audio);
        void NewRec(const char* id, const char *output, const int64_t &frameID, const int mindur, const int maxdur, const bool audio);
        // 准备好录像
        void Load(ffwrapper::FormatIn *in);
        void Unload();
        const bool Loaded() const;
        // 缓存录像的视频包,等待触发录像,或直接放到录像缓存
        void SetPacket(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id);
        void SetPacket(const CPacket &pkt);
        // 触发录像
        void FireRecSignal(const char* sid,const int64_t &id);
        // 获取录像文件路径和帧id
csrc/worker/stream.cpp
@@ -6,6 +6,8 @@
#include "../ffmpeg/format/FormatIn.hpp"
#include "../ffmpeg/data/CodedData.hpp"
#include "../ffmpeg/log/log.hpp"
using namespace logif;
namespace cffmpeg_wrap{
    stream::stream(ffwrapper::FormatIn *in, const int maxSize)
@@ -19,16 +21,15 @@
        list_pkt_.clear();
    }
    int stream::SetPacket(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id){
        if (data){
    int stream::SetPacket(const CPacket &pkt){
        if (pkt.data){
            // 如果包是音频包,但是不使用音频,直接返回
            if (!audio_ && streamRef_->isAudioPkt(&data->getAVPacket())){
            if (!audio_ && streamRef_->isAudioPkt(&pkt.data->getAVPacket())){
                return 0;
            }
            
            std::lock_guard<std::mutex> locker(mutex_avpkt_);
            list_pkt_.push_back({data, id});
            list_pkt_.push_back(pkt);
            
            while(list_pkt_.size() > max_size_/2*3){
                list_pkt_.pop_front();
csrc/worker/stream.hpp
@@ -24,7 +24,7 @@
        stream(ffwrapper::FormatIn *in, const int maxSize);
        ~stream();
        int SetPacket(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id);
        int SetPacket(const CPacket &pkt);
        void GetPacket(unsigned char **pktData, int *size, int *key);
        void AudioSwitch(const bool a){audio_ = a;}
    };
csrc/wrapper.cpp
@@ -24,8 +24,7 @@
#include "worker/stream.hpp"
#include "worker/decoder.hpp"
#include "worker/rec.hpp"
#include "CUDALERP.h"
#include "common.hpp"
using namespace logif;
using namespace ffwrapper;
@@ -53,6 +52,7 @@
    ,decoder_(nullptr)
    ,rec_(new rec)
    ,logit_(false)
    ,fps_(25)
    {
        makeTheWorld();
    }
@@ -160,15 +160,15 @@
        }
    }
    
    int Wrapper::run_worker(ffwrapper::FormatIn *in, std::shared_ptr<ffwrapper::CodedData> data, int64_t &id){
    int Wrapper::run_worker(ffwrapper::FormatIn *in, const CPacket &pkt){
        if (gb_){
            AVPacket &pkt = data->getAVPacket();
            pkt.pts = pkt.dts = AV_NOPTS_VALUE;
            AVPacket &p = pkt.data->getAVPacket();
            p.pts = p.dts = AV_NOPTS_VALUE;
        }
        int flag = 0;
        if (stream_) stream_->SetPacket(data, id);
        if (decoder_ && run_dec_) flag = decoder_->SetFrame(data, id);
        if (rec_->Loaded()) rec_->SetPacket(data, id);
        if (stream_) stream_->SetPacket(pkt);
        if (decoder_ && run_dec_) flag = decoder_->SetFrame(pkt);
        if (rec_->Loaded()) rec_->SetPacket(pkt);
        return flag;
    }
@@ -190,6 +190,8 @@
                continue;
            }
            fps_ = in->getFPS();
            int wTime = 1000000.0 / in->getFPS() ;
            wTime >>= 1;
            logIt("WAIT TIME PER FRAME: %d", wTime);
@@ -197,7 +199,9 @@
            init_worker(in.get());
            int64_t id = gb_ ? 0 : -1;
            int64_t v_id = id;
            int64_t a_id = id;
            bool exist = access(input_url_.c_str(), 0) == 0 ? true : false;
            while(!stop_stream_.load()){
@@ -206,25 +210,34 @@
                    logIt("read packet error, id: %lld", id);
                    break;
                }
                // 非音视频
                if (in->notVideoAudio(&data->getAVPacket())){
                    continue;
                }
                // 非国标跳过第一帧,测试第一帧有问题
                if (!gb_ && id < 0){
                    id++;
                    id++; v_id++; a_id++;
                    continue;
                }
                CPacket pkt{data, v_id, a_id, id};
                // decode error
                if (run_worker(in.get(), data, id) == -1){
                if (run_worker(in.get(), pkt) == -1){
                    break;
                }
                if (in->isVideoPkt(&data->getAVPacket())){
                    v_id++;
                }else{
                    a_id++;
                }
                id++;
                //本地文件太快sleep一下
                if (exist){
                    usleep(wTime);
                }
                id++;
            }
            deinit_worker();
@@ -235,16 +248,16 @@
        rec_->SetRecMinCacheTime(mind);
    }
    void Wrapper::BuildRecorder(const char* id, const char *output, const int mindur, const int maxdur, const bool audio){
    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;
        if (rec_->Loaded()){
            rec_->NewRec(id, output, mindur, maxdur, a);
            rec_->NewRec(id, output, fid, mindur, maxdur, a);
        }else{
            std::string rid(id), dir(output);
            fn_rec_lazy_ = 
            [=]{rec_->NewRec(rid.c_str(), dir.c_str(), mindur, maxdur, a);};
            [=]{rec_->NewRec(rid.c_str(), dir.c_str(), fid, mindur, maxdur, a);};
        }
    }
@@ -488,45 +501,5 @@
        free(c);
    }
    uint8_t* ConvertYUV2BGR(uint8_t *src, const int w, const int h, const int dst_w, const int dst_h, int *length){
        return NULL;
        // int oldw = w, oldh = h, neww = dst_w, newh = dst_h;
        //     // setting cache and shared modes
        // cudaDeviceSetCacheConfig(cudaFuncCachePreferL1);
        // cudaDeviceSetSharedMemConfig(cudaSharedMemBankSizeFourByte);
        // // allocating and transferring image and binding to texture object
        // cudaChannelFormatDesc chandesc_img = cudaCreateChannelDesc(8, 0, 0, 0, cudaChannelFormatKindUnsigned);
        // cudaArray* d_img_arr;
        // cudaMallocArray(&d_img_arr, &chandesc_img, oldw, oldh, cudaArrayTextureGather);
        // cudaMemcpyToArray(d_img_arr, 0, 0, image, oldh * oldw, cudaMemcpyHostToDevice);
        // struct cudaResourceDesc resdesc_img;
        // memset(&resdesc_img, 0, sizeof(resdesc_img));
        // resdesc_img.resType = cudaResourceTypeArray;
        // resdesc_img.res.array.array = d_img_arr;
        // struct cudaTextureDesc texdesc_img;
        // memset(&texdesc_img, 0, sizeof(texdesc_img));
        // texdesc_img.addressMode[0] = cudaAddressModeClamp;
        // texdesc_img.addressMode[1] = cudaAddressModeClamp;
        // texdesc_img.readMode = cudaReadModeNormalizedFloat;
        // texdesc_img.filterMode = cudaFilterModePoint;
        // texdesc_img.normalizedCoords = 0;
        // cudaTextureObject_t d_img_tex = 0;
        // cudaCreateTextureObject(&d_img_tex, &resdesc_img, &texdesc_img, nullptr);
        // uint8_t* d_out = nullptr;
        // cudaMalloc(&d_out, total);
        // for (int i = 0; i < warmups; ++i) CUDALERP(d_img_tex, oldw, oldh, d_out, neww, newh);
        // auto start = high_resolution_clock::now();
        // for (int i = 0; i < runs; ++i) CUDALERP(d_img_tex, oldw, oldh, d_out, neww, newh);
        // auto end = high_resolution_clock::now();
        // auto sum = (end - start) / runs;
        // auto h_out = new uint8_t[neww * newh];
        // cudaMemcpy(h_out, d_out, total, cudaMemcpyDeviceToHost);
    }
}
csrc/wrapper.hpp
@@ -11,7 +11,7 @@
#include <memory>
#include "common/callback.hpp"
class CPacket;
namespace ffwrapper{
    class FormatIn;
@@ -34,14 +34,14 @@
        std::unique_ptr<ffwrapper::FormatIn> init_reader(const char* input);
        void init_worker(ffwrapper::FormatIn *in);
        int run_worker(ffwrapper::FormatIn *in, std::shared_ptr<ffwrapper::CodedData> data, int64_t &id);
        int run_worker(ffwrapper::FormatIn *in, const CPacket &pkt);
        void deinit_worker();
    public: 
        int RunStream(const char* input);
    private: 
        void run_stream_thread();
    public: //recorder
        void BuildRecorder(const char* id,const char *dir, const int mind, const int maxd, const bool audio);
        void BuildRecorder(const char* id, const char *dir, const int64_t &fid, const int mind, const int maxd, const bool audio);
        int FireRecorder(const char* sid,const int64_t &id);
        void GetInfoRecorder(std::string &recID, int &index, std::string &path);
    
@@ -50,6 +50,8 @@
        void CPUDec(){cpu_ = 1;}
        void AudioSwitch(const bool a);
        void SetRecMinCacheTime(const int mind);
        int GetFPS(){return fps_;}
    public: //decoder
        void BuildDecoder();
        void GetPicDecoder(unsigned char **data, int *w, int *h, int *format, int *length, int64_t *id);
@@ -74,6 +76,7 @@
        // 录像请求缓存,等待runstream后添加
        std::function<void()> fn_rec_lazy_;
        bool logit_;
        int fps_;
    };
    uint8_t* Decode(const char *file, const int gb, int *w, int *h);
@@ -86,8 +89,6 @@
                          const int dstW, const int dstH, const int dstFormat, const int flag);
    uint8_t *Convert(void *h, uint8_t *src);
    void DestoryConvertor(void *h);
    uint8_t* ConvertYUV2BGR(uint8_t *src, const int w, const int h, const int dst_w, const int dst_h, int *length);
}
#endif
goconv.go
@@ -52,7 +52,7 @@
// NewConv new conv
func NewConv(srcW, srcH, dstW, dstH, scaleFlag int) *GoConv {
    c := C.wrap_fn_create_conv(C.int(srcW), C.int(srcH), C.int(SrcFormat),
    c := C.wrap_fn_create_conv(unsafe.Pointer(libcffmpeg), C.int(srcW), C.int(srcH), C.int(SrcFormat),
        C.int(dstW), C.int(dstH), C.int(DstFormat), C.int(scaleFlag))
    if c == nil {
@@ -70,7 +70,7 @@
// NewResizer resize
func NewResizer(srcW, srcH, format, dstW, dstH, scaleFlag int) *GoConv {
    c := C.wrap_fn_create_conv(C.int(srcW), C.int(srcH), C.int(format),
    c := C.wrap_fn_create_conv(unsafe.Pointer(libcffmpeg), C.int(srcW), C.int(srcH), C.int(format),
        C.int(dstW), C.int(dstH), C.int(format), C.int(scaleFlag))
    if c == nil {
@@ -89,7 +89,7 @@
// Free free
func (c *GoConv) Free() {
    if c.conv != nil {
        C.wrap_fn_destroy_conv(c.conv)
        C.wrap_fn_destroy_conv(unsafe.Pointer(libcffmpeg), c.conv)
    }
}
@@ -102,7 +102,7 @@
    cin := C.CBytes(src)
    defer C.free(cin)
    bgr := C.wrap_fn_conv(c.conv, (*C.uchar)(cin))
    bgr := C.wrap_fn_conv(unsafe.Pointer(libcffmpeg), c.conv, (*C.uchar)(cin))
    defer C.free(unsafe.Pointer(bgr))
    if bgr != nil {
godec.go
@@ -9,7 +9,7 @@
// BuildDecoder build decoder
func (h *GoFFMPEG) BuildDecoder() {
    C.wrap_fn_decoder(h.ffmpeg)
    C.wrap_fn_decoder(unsafe.Pointer(libcffmpeg), h.ffmpeg)
}
// GetYUV get yuv data
@@ -18,7 +18,7 @@
    var length C.int
    var srcW, srcH, srcF C.int
    p := C.wrap_fn_decoder_pic(h.ffmpeg, &srcW, &srcH, &srcF, &length, &fid)
    p := C.wrap_fn_decoder_pic(unsafe.Pointer(libcffmpeg), h.ffmpeg, &srcW, &srcH, &srcF, &length, &fid)
    if srcW == 0 || srcH == 0 {
        return nil, 0, 0, 0
    }
godecjpeg.go
@@ -23,7 +23,7 @@
    var width C.int
    var height C.int
    p := C.wrap_fn_decode(in, C.int(withGB), &width, &height)
    p := C.wrap_fn_decode(unsafe.Pointer(libcffmpeg), in, C.int(withGB), &width, &height)
    defer C.free(p)
    if width > 0 && height > 0 {
goenc.go
@@ -5,6 +5,7 @@
#include "libcffmpeg.h"
*/
import "C"
import "unsafe"
///////////////for encoder
@@ -20,14 +21,14 @@
    }
    return &GoEncoder{
        enc: C.wrap_fn_create_encoder(C.int(w), C.int(h), C.int(fps), C.int(br), C.int(sFlag), C.int(gi)),
        enc: C.wrap_fn_create_encoder(unsafe.Pointer(libcffmpeg), C.int(w), C.int(h), C.int(fps), C.int(br), C.int(sFlag), C.int(gi)),
    }
}
// Free free
func (e *GoEncoder) Free() {
    if e.enc != nil {
        C.wrap_fn_destroy_encoder(e.enc)
        C.wrap_fn_destroy_encoder(unsafe.Pointer(libcffmpeg), e.enc)
    }
}
@@ -39,7 +40,7 @@
    cin := C.CBytes(in)
    defer C.free(cin)
    p := C.wrap_fn_encode(e.enc, cin, C.int(w), C.int(h), &size, &key)
    p := C.wrap_fn_encode(unsafe.Pointer(libcffmpeg), e.enc, cin, C.int(w), C.int(h), &size, &key)
    defer C.free(p)
    if p != nil && size > 0 {
        b := C.GoBytes(p, size)
goffmpeg.go
@@ -42,16 +42,16 @@
// New 2nd new
func New(GB, CPU bool) *GoFFMPEG {
    f := C.wrap_fn_create()
    f := C.wrap_fn_create(unsafe.Pointer(libcffmpeg))
    if f == nil {
        return nil
    }
    if GB {
        C.wrap_fn_run_gb28181(f)
        C.wrap_fn_run_gb28181(unsafe.Pointer(libcffmpeg), f)
    }
    if CPU {
        C.wrap_fn_use_cpu(f)
        C.wrap_fn_use_cpu(unsafe.Pointer(libcffmpeg), f)
    }
    return &GoFFMPEG{
@@ -64,15 +64,15 @@
    lf := C.CString(ffmpegLog)
    defer C.free(unsafe.Pointer(lf))
    f := C.wrap_fn_create2(lf)
    f := C.wrap_fn_create2(unsafe.Pointer(libcffmpeg), lf)
    if f == nil {
        return nil
    }
    if GB {
        C.wrap_fn_run_gb28181(f)
        C.wrap_fn_run_gb28181(unsafe.Pointer(libcffmpeg), f)
    }
    if CPU {
        C.wrap_fn_use_cpu(f)
        C.wrap_fn_use_cpu(unsafe.Pointer(libcffmpeg), f)
    }
    return &GoFFMPEG{
@@ -83,7 +83,7 @@
// Free free handle
func (h *GoFFMPEG) Free() {
    if h.ffmpeg != nil {
        C.wrap_fn_destroy(h.ffmpeg)
        C.wrap_fn_destroy(unsafe.Pointer(libcffmpeg), h.ffmpeg)
    }
}
@@ -92,5 +92,10 @@
    in := C.CString(input)
    defer C.free(unsafe.Pointer(in))
    C.wrap_fn_run(h.ffmpeg, in)
    C.wrap_fn_run(unsafe.Pointer(libcffmpeg), h.ffmpeg, in)
}
// FPS fps
func (h *GoFFMPEG) FPS() int {
    return int(C.wrap_fn_fps(unsafe.Pointer(libcffmpeg), h.ffmpeg))
}
gorec.go
@@ -12,11 +12,11 @@
func (h *GoFFMPEG) FireRecorder(sid string, id int64) {
    csid := C.CString(sid)
    defer C.free(unsafe.Pointer(csid))
    C.wrap_fn_fire_recorder(h.ffmpeg, csid, C.long(id))
    C.wrap_fn_fire_recorder(unsafe.Pointer(libcffmpeg), h.ffmpeg, csid, C.long(id))
}
// BuildRecorder build recorder
func (h *GoFFMPEG) BuildRecorder(sid, output string, mind, maxd int, audio bool) {
func (h *GoFFMPEG) BuildRecorder(sid, output string, id int64, mind, maxd int, audio bool) {
    out := C.CString(output)
    defer C.free(unsafe.Pointer(out))
    csid := C.CString(sid)
@@ -26,7 +26,7 @@
    if audio {
        a = 1
    }
    C.wrap_fn_recorder(h.ffmpeg, csid, out, C.int(mind), C.int(maxd), C.int(a))
    C.wrap_fn_recorder(unsafe.Pointer(libcffmpeg), h.ffmpeg, csid, out, C.long(id), C.int(mind), C.int(maxd), C.int(a))
}
// GetInfoRecorder info
@@ -39,7 +39,7 @@
    var p *C.char
    var pl C.int
    C.wrap_fn_info_recorder(h.ffmpeg, &i, &id, &idl, &p, &pl)
    C.wrap_fn_info_recorder(unsafe.Pointer(libcffmpeg), h.ffmpeg, &i, &id, &idl, &p, &pl)
    // if p == nil {
    //     return -1, ""
    // }
@@ -55,5 +55,5 @@
// SetRecDurationForCache cache
func (h *GoFFMPEG) SetRecDurationForCache(min, max int) {
    C.wrap_fn_rec_duration(h.ffmpeg, C.int(min), C.int(max))
    C.wrap_fn_rec_duration(unsafe.Pointer(libcffmpeg), h.ffmpeg, C.int(min), C.int(max))
}
gostream.go
@@ -13,7 +13,7 @@
    var key C.int
    var size C.int
    p := C.wrap_fn_get_avpacket(h.ffmpeg, &size, &key)
    p := C.wrap_fn_get_avpacket(unsafe.Pointer(libcffmpeg), h.ffmpeg, &size, &key)
    if size <= 0 {
        return nil, 0, -1
    }
libcffmpeg.c
@@ -17,58 +17,9 @@
libcffmpeg init_libcffmpeg(const char *so_file){
    libcffmpeg lib = dlopen(so_file, RTLD_LAZY);
    if(lib){
        fn_create = (lib_cffmpeg_create)dlsym(lib, "c_ffmpeg_create");
        release_if_err(fn_create, lib);
        fn_create2 = (lib_cffmpeg_create)dlsym(lib, "c_ffmpeg_create2");
        release_if_err(fn_create2, lib);
        fn_destroy = (lib_cffmpeg_destroy)dlsym(lib, "c_ffmpeg_destroy");
        release_if_err(fn_destroy, lib);
        fn_run = (lib_cffmpeg_run)dlsym(lib, "c_ffmpeg_run");
        release_if_err(fn_run, lib);
        fn_gb28181 = (lib_cffmpeg_gb28181)dlsym(lib, "c_ffmpeg_run_gb28181");
        release_if_err(fn_gb28181, lib);
        fn_cpu = (lib_cffmpeg_cpu)dlsym(lib, "c_ffmepg_use_cpu");
        release_if_err(fn_cpu, lib);
        fn_rec_duration = (lib_cffmpeg_rec_duration)dlsym(lib, "c_ffmpeg_set_record_duration");
        release_if_err(fn_rec_duration, lib);
        fn_recorder = (lib_cffmpeg_recorder)dlsym(lib, "c_ffmpeg_build_recorder");
        release_if_err(fn_recorder, lib);
        fn_fire_recorder = (lib_cffmpeg_fire_recorder)dlsym(lib, "c_ffmpeg_fire_recorder");
        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_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");
        release_if_err(fn_decoder_pic, lib);
        fn_get_avpacket = (lib_cffmpeg_avpacket)dlsym(lib, "c_ffmpeg_get_avpacket");
        release_if_err(fn_get_avpacket, lib);
        fn_decode = (lib_cffmpeg_decode)dlsym(lib, "c_ffmpeg_decode");
        release_if_err(fn_decode, lib);
        fn_create_encoder = (lib_cffmpeg_create_encoder)dlsym(lib, "c_ffmpeg_create_encoder");
        release_if_err(fn_create_encoder, lib);
        fn_destroy_encoder = (lib_cffmpeg_destroy_encoder)dlsym(lib, "c_ffmpeg_destroy_encoder");
        release_if_err(fn_destroy_encoder, lib);
        fn_encode = (lib_cffmpeg_encode)dlsym(lib, "c_ffmpeg_encode");
        release_if_err(fn_encode, lib);
        fn_create_conv = (lib_cffmpeg_create_conv)dlsym(lib, "c_ffmpeg_create_conv");
        release_if_err(fn_create_conv, lib);
        fn_destroy_conv = (lib_cffmpeg_destroy_conv)dlsym(lib, "c_ffmpeg_destroy_conv");
        release_if_err(fn_destroy_conv, lib);
        fn_conv = (lib_cffmpeg_conv)dlsym(lib, "c_ffmpeg_conv");
        release_if_err(fn_conv, lib);
        fn_gpu_conv = (lib_gpu_conv)dlsym(lib, "c_gpu_conv");
        release_if_err(fn_gpu_conv, lib);
    }else{
        printf("dlopen - %s\n", dlerror());  
@@ -82,77 +33,148 @@
    }
}
cffmpeg wrap_fn_create(){
cffmpeg wrap_fn_create(void *lib){
    if (!fn_create){
        fn_create = (lib_cffmpeg_create)dlsym(lib, "c_ffmpeg_create");
        release_if_err(fn_create, lib);
    }
    return fn_create();
}
cffmpeg wrap_fn_create2(const char *logfile){
cffmpeg wrap_fn_create2(void *lib, const char *logfile){
    if (!fn_create2){
        fn_create2 = (lib_cffmpeg_create)dlsym(lib, "c_ffmpeg_create2");
        release_if_err(fn_create2, lib);
    }
    return fn_create2(logfile);
}
void wrap_fn_destroy(const cffmpeg h){
void wrap_fn_destroy(void *lib, const cffmpeg h){
    fn_destroy(h);
}
void wrap_fn_run(const cffmpeg h, const char* input){
void wrap_fn_run(void *lib, const cffmpeg h, const char* input){
    if (!fn_run){
        fn_run = (lib_cffmpeg_run)dlsym(lib, "c_ffmpeg_run");
        if (!fn_run) return;
    }
    fn_run(h, input);
}
void wrap_fn_run_gb28181(const cffmpeg h){
int wrap_fn_fps(void *lib, const cffmpeg h){
    if(!fn_fps){
        fn_fps = (lib_cffmpeg_fps)dlsym(lib, "c_ffmpeg_get_fps");
        if (!fn_fps) return 25;
    }
    return fn_fps(h);
}
void wrap_fn_run_gb28181(void *lib, const cffmpeg h){
    if (!fn_gb28181){
        fn_gb28181 = (lib_cffmpeg_gb28181)dlsym(lib, "c_ffmpeg_run_gb28181");
        if (!fn_gb28181) return;
    }
    fn_gb28181(h);
}
void wrap_fn_use_cpu(const cffmpeg h){
void wrap_fn_use_cpu(void *lib, const cffmpeg h){
    if (!fn_cpu){
        fn_cpu = (lib_cffmpeg_cpu)dlsym(lib, "c_ffmepg_use_cpu");
        if (!fn_cpu) return;
    }
    fn_cpu(h);
}
void wrap_fn_recorder(const cffmpeg h, const char* id, const char* dir, int mind, int maxd, int audio){
    fn_recorder(h, id, dir, mind, maxd, audio);
void wrap_fn_recorder(void *lib, const cffmpeg h, const char* id, const char* dir, const int64_t fid, int mind, int maxd, int audio){
    if (!fn_recorder){
        fn_recorder = (lib_cffmpeg_recorder)dlsym(lib, "c_ffmpeg_build_recorder");
        if (!fn_recorder) return;
    }
    fn_recorder(h, id, dir, fid, mind, maxd, audio);
}
void wrap_fn_rec_duration(const cffmpeg h, const int min, const int max){
void wrap_fn_rec_duration(void *lib, const cffmpeg h, const int min, const int max){
    if (!fn_rec_duration){
        fn_rec_duration = (lib_cffmpeg_rec_duration)dlsym(lib, "c_ffmpeg_set_record_duration");
        if (!fn_rec_duration) return;
    }
    fn_rec_duration(h, min, max);
}
void wrap_fn_fire_recorder(const cffmpeg h, const char* sid, const int64_t id){
void wrap_fn_fire_recorder(void *lib, const cffmpeg h, const char* sid, const int64_t id){
    if (!fn_fire_recorder){
        fn_fire_recorder = (lib_cffmpeg_fire_recorder)dlsym(lib, "c_ffmpeg_fire_recorder");
        if (!fn_fire_recorder) return;
    }
    fn_fire_recorder(h, sid, id);
}
void wrap_fn_info_recorder(const cffmpeg h, int* index, char** recid, int* recidLen, char** fpath, int* pathLen){
void wrap_fn_info_recorder(void *lib, const cffmpeg h, int* index, char** recid, int* recidLen, char** fpath, int* pathLen){
    if (!fn_info_recorder){
        fn_info_recorder = (lib_cffmpeg_info_recorder)dlsym(lib, "c_ffmpeg_get_info_recorder");
        if (!fn_info_recorder) return;
    }
    return fn_info_recorder(h, index, recid, recidLen, fpath, pathLen);
}
void wrap_fn_decoder(const cffmpeg h){
void wrap_fn_decoder(void *lib, const cffmpeg h){
    if (!fn_decoder){
        fn_decoder = (lib_cffmpeg_decoder)dlsym(lib, "c_ffmpeg_build_decoder");
        if (!fn_decoder) return;
    }
    fn_decoder(h);
}
void* wrap_fn_decoder_pic(const cffmpeg h, int *wid, int *hei, int *format, int *length, int64_t *id){
void* wrap_fn_decoder_pic(void *lib, const cffmpeg h, int *wid, int *hei, int *format, int *length, int64_t *id){
    if (!fn_decoder_pic){
        fn_decoder_pic = (lib_cffmpeg_pic)dlsym(lib, "c_ffmpeg_get_pic_decoder");
        release_if_err(fn_decoder_pic, lib);
    }
    return fn_decoder_pic(h, wid, hei, format, length, id);
}
void* wrap_fn_get_avpacket(const cffmpeg h, int* size, int* key){
void* wrap_fn_get_avpacket(void *lib, const cffmpeg h, int* size, int* key){
    if(!fn_get_avpacket){
        fn_get_avpacket = (lib_cffmpeg_avpacket)dlsym(lib, "c_ffmpeg_get_avpacket");
        release_if_err(fn_get_avpacket, lib);
    }
    return fn_get_avpacket(h, size, key);
}
// return val: -1 open error; -2, find stream error; -3, converter create error
void* wrap_fn_decode(const char* file, const int gb, int* wid, int* hei){
void* wrap_fn_decode(void *lib, const char* file, const int gb, int* wid, int* hei){
    if (!fn_decode){
        fn_decode = (lib_cffmpeg_decode)dlsym(lib, "c_ffmpeg_decode");
        release_if_err(fn_decode, lib);
    }
    return fn_decode(file, gb, wid, hei);
}
void* wran_fn_gpu_conv(void *in, const int w, const int h, const int dst_w, const int dst_h, int *length){
    return fn_gpu_conv(in, w, h, dst_w, dst_h, length);
}
// for encoder
cencoder wrap_fn_create_encoder(const int w, const int h, const int fps, const int br, const int scale_flag, const int gi){
cencoder wrap_fn_create_encoder(void *lib, const int w, const int h, const int fps, const int br, const int scale_flag, const int gi){
    if (!fn_create_encoder){
        fn_create_encoder = (lib_cffmpeg_create_encoder)dlsym(lib, "c_ffmpeg_create_encoder");
        release_if_err(fn_create_encoder, lib);
    }
    return fn_create_encoder(w, h, fps, br, scale_flag, gi);
}
void wrap_fn_destroy_encoder(const cencoder h){
void wrap_fn_destroy_encoder(void *lib, const cencoder h){
    if (!fn_destroy_encoder){
        fn_destroy_encoder = (lib_cffmpeg_destroy_encoder)dlsym(lib, "c_ffmpeg_destroy_encoder");
        if(!fn_destroy_encoder) return;
    }
    fn_destroy_encoder(h);
}
void* wrap_fn_encode(cencoder hdl, void *in, const int w, const int h, int *out_size, int *key){
void* wrap_fn_encode(void *lib, cencoder hdl, void *in, const int w, const int h, int *out_size, int *key){
    if (!fn_encode){
        fn_encode = (lib_cffmpeg_encode)dlsym(lib, "c_ffmpeg_encode");
        release_if_err(fn_encode, lib);
    }
    uint8_t *out = NULL;
    const int flag = fn_encode(hdl, (uint8_t*)in, w, h, &out, out_size, key);
    if (flag > 0 && out != NULL) {
@@ -164,14 +186,28 @@
}
// for conv
cconv wrap_fn_create_conv(const int srcW, const int srcH, const int srcFormat,
cconv wrap_fn_create_conv(void *lib, const int srcW, const int srcH, const int srcFormat,
                          const int dstW, const int dstH, const int dstFormat, const int flag){
    if (!fn_create_conv){
        fn_create_conv = (lib_cffmpeg_create_conv)dlsym(lib, "c_ffmpeg_create_conv");
        release_if_err(fn_create_conv, lib);
    }
    return fn_create_conv(srcW, srcH, srcFormat, dstW, dstH, dstFormat, flag);
}
void wrap_fn_destroy_conv(const cconv h){
void wrap_fn_destroy_conv(void *lib, const cconv h){
    if (!fn_destroy_conv){
        fn_destroy_conv = (lib_cffmpeg_destroy_conv)dlsym(lib, "c_ffmpeg_destroy_conv");
        if(!fn_destroy_conv) return;
    }
    fn_destroy_conv(h);
}
void* wrap_fn_conv(const cconv h, uint8_t *in){
void* wrap_fn_conv(void *lib, const cconv h, uint8_t *in){
    if (!fn_conv){
        fn_conv = (lib_cffmpeg_conv)dlsym(lib, "c_ffmpeg_conv");
        release_if_err(fn_conv, lib);
    }
    return fn_conv(h, in);
}
libcffmpeg.h
@@ -14,22 +14,23 @@
typedef cffmpeg(*lib_cffmpeg_create2)(const char*);
typedef void (*lib_cffmpeg_destroy)(const cffmpeg);
typedef void (*lib_cffmpeg_run)(const cffmpeg, const char*);
typedef int (*lib_cffmpeg_fps)(const cffmpeg);
typedef void (*lib_cffmpeg_gb28181)(const cffmpeg);
typedef void (*lib_cffmpeg_cpu)(const cffmpeg);
typedef void (*lib_cffmpeg_rec_duration)(const cffmpeg, const int, const int);
typedef void (*lib_cffmpeg_recorder)(const cffmpeg, const char*, const char*, int, int, int);
typedef void (*lib_cffmpeg_recorder)(const cffmpeg, const char*, const char*, const int64_t, int, int, int);
typedef void (*lib_cffmpeg_fire_recorder)(const cffmpeg, const char*, const int64_t);
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*, int*, int*, int64_t*);
typedef void*(*lib_cffmpeg_avpacket)(const cffmpeg, int*, int*);
typedef void*(*lib_cffmpeg_decode)(const char*, const int, int*, int*);
typedef void*(*lib_gpu_conv)(void*, const int, const int, const int, const int, int *);
static lib_cffmpeg_create              fn_create = NULL;
static lib_cffmpeg_create2             fn_create2 = NULL;
static lib_cffmpeg_destroy             fn_destroy = NULL;
static lib_cffmpeg_run                 fn_run = NULL;
static lib_cffmpeg_fps                 fn_fps = NULL;
static lib_cffmpeg_gb28181             fn_gb28181 = NULL;
static lib_cffmpeg_cpu                 fn_cpu = NULL;
static lib_cffmpeg_rec_duration        fn_rec_duration = NULL;
@@ -40,27 +41,26 @@
static lib_cffmpeg_pic                 fn_decoder_pic = NULL;
static lib_cffmpeg_avpacket            fn_get_avpacket = NULL;
static lib_cffmpeg_decode              fn_decode = NULL;
static lib_gpu_conv                    fn_gpu_conv = NULL;
typedef void* libcffmpeg;
libcffmpeg init_libcffmpeg(const char *so_file);
void release_libcffmpeg(libcffmpeg lib);
cffmpeg wrap_fn_create();
cffmpeg wrap_fn_create2(const char *logfile);
void wrap_fn_destroy(const cffmpeg h);
void wrap_fn_run(const cffmpeg h, const char* input);
void wrap_fn_run_gb28181(const cffmpeg h);
void wrap_fn_use_cpu(const cffmpeg h);
void wrap_fn_rec_duration(const cffmpeg h, const int min, const int max);
void wrap_fn_recorder(const cffmpeg h, const char* id, const char* dir, int mind, int maxd, int audio);
void wrap_fn_fire_recorder(const cffmpeg h, const char *sid, const int64_t id);
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, int *format, int *length, int64_t *id);
void* wrap_fn_get_avpacket(const cffmpeg h, int* size, int* key);
void* wrap_fn_decode(const char* file, const int gb, int* wid, int* hei);
void* wran_fn_gpu_conv(void *in, const int w, const int h, const int dst_w, const int dst_h, int *length);
cffmpeg wrap_fn_create(void *lib);
cffmpeg wrap_fn_create2(void *lib, const char *logfile);
void wrap_fn_destroy(void *lib, const cffmpeg h);
void wrap_fn_run(void *lib, const cffmpeg h, const char* input);
int wrap_fn_fps(void *lib, const cffmpeg h);
void wrap_fn_run_gb28181(void *lib, const cffmpeg h);
void wrap_fn_use_cpu(void *lib, const cffmpeg h);
void wrap_fn_rec_duration(void *lib, const cffmpeg h, const int min, const int max);
void wrap_fn_recorder(void *lib, const cffmpeg h, const char* id, const char* dir, const int64_t fid, int mind, int maxd, int audio);
void wrap_fn_fire_recorder(void *lib, const cffmpeg h, const char *sid, const int64_t id);
void wrap_fn_info_recorder(void *lib, const cffmpeg, int* index, char** recid, int* recidLen, char** fpath, int* pathLen);
void wrap_fn_decoder(void *lib, const cffmpeg h);
void* wrap_fn_decoder_pic(void *lib, const cffmpeg h, int *wid, int *hei, int *format, int *length, int64_t *id);
void* wrap_fn_get_avpacket(void *lib, const cffmpeg h, int* size, int* key);
void* wrap_fn_decode(void *lib, const char* file, const int gb, int* wid, int* hei);
// for encoder
typedef void* cencoder;
typedef cencoder (*lib_cffmpeg_create_encoder)(const int w, const int h, const int fps, const int br, const int scale_flag, const int gi);
@@ -71,9 +71,9 @@
static lib_cffmpeg_destroy_encoder fn_destroy_encoder = NULL;
static lib_cffmpeg_encode fn_encode = NULL;
cencoder wrap_fn_create_encoder(const int w, const int h, const int fps, const int br, const int scale_flag, const int gi);
void wrap_fn_destroy_encoder(const cencoder h);
void* wrap_fn_encode(cencoder hdl, void *in, const int w, const int h, int *out_size, int *key);
cencoder wrap_fn_create_encoder(void *lib, const int w, const int h, const int fps, const int br, const int scale_flag, const int gi);
void wrap_fn_destroy_encoder(void *lib, const cencoder h);
void* wrap_fn_encode(void *lib, cencoder hdl, void *in, const int w, const int h, int *out_size, int *key);
// for conv
@@ -86,10 +86,10 @@
static lib_cffmpeg_destroy_conv fn_destroy_conv = NULL;
static lib_cffmpeg_conv fn_conv = NULL;
cconv wrap_fn_create_conv(const int srcW, const int srcH, const int srcFormat,
cconv wrap_fn_create_conv(void *lib, const int srcW, const int srcH, const int srcFormat,
                          const int dstW, const int dstH, const int dstFormat, const int flag);
void wrap_fn_destroy_conv(const cconv h);
void* wrap_fn_conv(const cconv h, uint8_t *in);
void wrap_fn_destroy_conv(void *lib, const cconv h);
void* wrap_fn_conv(void *lib, const cconv h, uint8_t *in);
#ifdef __cplusplus
}