#include "rec.hpp"
|
|
#include <unistd.h>
|
#include <sys/time.h>
|
|
extern "C"{
|
#include <libavcodec/avcodec.h>
|
}
|
|
#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<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);
|
}
|
|
std::unique_ptr<buz::Recorder> 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<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){
|
auto ret = rec->Run(dir.c_str(), mind, maxd, audio);
|
if(ret == 0) break;
|
usleep(200000);
|
}
|
if (trycnt < 100){
|
std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> l(mtx_rec_);
|
map_rec_.clear();
|
}
|
|
{
|
std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> 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<ffwrapper::CodedData> data, int64_t &id){
|
if (!data) return;
|
|
std::lock_guard<std::mutex> 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<ffwrapper::CodedData> data, int64_t &id){
|
std::lock_guard<std::mutex> 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
|