#include "rec.hpp" #include #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 l(mtx_rec_); map_rec_.clear(); } { std::lock_guard l(mtx_pkt_); list_pkt_.clear(); } } std::unique_ptr 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 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 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 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 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 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 data, int64_t &id){ if (!data) return; cachePacket(data, id); std::lock_guard 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 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 data, int64_t &id){ std::lock_guard 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