| | |
| | | using namespace ffwrapper; |
| | | using namespace cffmpeg_wrap::buz; |
| | | |
| | | static const int cache_time = 30 * 60; |
| | | |
| | | namespace cffmpeg_wrap |
| | | { |
| | | rec::rec() |
| | | :recRef_(NULL) |
| | | ,min_cache_len_(10 * 60 * 25) // 最小缓存?分钟的视频,因为整个流程会有延迟,暂定?分钟 |
| | | ,min_cache_len_(cache_time * 25) // 最小缓存?分钟的视频,因为整个流程会有延迟,暂定?分钟 |
| | | {} |
| | | |
| | | rec::~rec() |
| | |
| | | list_recInfo_.emplace_back(info); |
| | | } |
| | | |
| | | 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"); |
| | |
| | | } |
| | | |
| | | 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; |
| | | } |
| | | |
| | |
| | | |
| | | void rec::Load(ffwrapper::FormatIn *in){ |
| | | recRef_ = in; |
| | | if (in){ |
| | | min_cache_len_ = in->getFPS() * cache_time; |
| | | } |
| | | } |
| | | |
| | | void rec::Unload(){ |
| | |
| | | // 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(); |
| | |
| | | } |
| | | |
| | | 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; |