#include "rec.hpp" #include #include extern "C"{ #include } #include "../ffmpeg/format/FormatIn.hpp" #include "../ffmpeg/data/CodedData.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() :recRef_(NULL) ,minduration_(250) ,maxduration_(750) {} rec::~rec() { clear(); } 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); } std::unique_ptr rec::startRec(std::string id, std::string dir, const int mind, const int maxd, const bool audio){ 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){ auto ret = rec->Run(dir.c_str(), mind, maxd, audio); if(ret == 0) break; usleep(200000); } if (trycnt < 100){ std::lock_guard locker(mtx_pkt_); rec->PushPackets(list_pkt_); return rec; } return nullptr; } void rec::GetRecInfo(std::string &recID, int &index, std::string &path){ // 获取信息 { std::lock_guard l(mtx_recInfo_); if(!list_recInfo_.empty()){ 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_.empty()){ return; } if (map_rec_.find(recID) != map_rec_.end()){ map_rec_.erase(recID); return; } for (auto iter = map_rec_.begin(); iter != map_rec_.end();){ if (iter->second && iter->second->ErrorOcurred()){ recID = iter->first; index = -1; path = ""; iter == map_rec_.erase(iter); break; }else{ iter++; } } } } void rec::clear(){ { std::lock_guard l(mtx_rec_); map_rec_.clear(); } { std::lock_guard l(mtx_pkt_); list_pkt_.clear(); } } void rec::Load(ffwrapper::FormatIn *in){ recRef_ = in; } void rec::Unload(){ recRef_ = NULL; clear(); } const bool rec::Loaded() const{ return recRef_ != NULL; } void rec::NewRec(const char* id, const char *output, const int mindur, const int maxdur, const bool audio){ std::string rid(id); std::string dir(output); minduration_ = mindur * 25; maxduration_ = maxdur * 25; { std::lock_guard l(mtx_rec_); if (map_rec_.find(rid) != map_rec_.end()){ map_rec_.erase(rid); } map_rec_[rid] = startRec(rid, dir, mindur, maxdur, audio); } } void rec::FireRecSignal(const char* sid, const int64_t &id){ std::lock_guard l(mtx_rec_); auto iter = map_rec_.find(sid); if (iter != map_rec_.end()){ if(iter->second){ iter->second->FireRecorder(id); } } // logIt("recorders count: %d", map_rec_.size()); } void rec::SetPacket(std::shared_ptr data, int64_t &id){ if (!data) return; std::lock_guard l(mtx_rec_); for(auto &i : map_rec_){ if (i.second){ i.second->PushPacket({data, id}); } } 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()) { if (!(data->getAVPacket().flags & AV_PKT_FLAG_KEY)){ return; } } list_pkt_.push_back({data, id}); // 超过缓存最大长度,删除一个gop shrinkCache(); } int rec::shrinkCache(){ //超过最大缓存,丢弃gop //缓存最小长度的,用于记录 int md = minduration_ < 201 ? 200 : minduration_; while (list_pkt_.size() > md/2) { list_pkt_.pop_front(); while(!list_pkt_.empty()){ auto &i = list_pkt_.front(); if (!(i.data->getAVPacket().flags & AV_PKT_FLAG_KEY)){ list_pkt_.pop_front(); }else{ break; } } } } } // namespace cffmpeg_wrap