From e878e92811a2dbfb6b4d3f7b2c357435f56e28db Mon Sep 17 00:00:00 2001
From: zhangmeng <775834166@qq.com>
Date: 星期日, 29 九月 2019 10:27:21 +0800
Subject: [PATCH] add trytime

---
 csrc/buz/recorder.cpp |  283 ++++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 230 insertions(+), 53 deletions(-)

diff --git a/csrc/buz/recorder.cpp b/csrc/buz/recorder.cpp
index 86afe89..00611c2 100644
--- a/csrc/buz/recorder.cpp
+++ b/csrc/buz/recorder.cpp
@@ -35,8 +35,13 @@
         ,thrd_(nullptr)
         ,error_occured_(false)
         ,audio_(false)
+        ,cur_frame_a(0)
+        ,fp_(NULL)
         {
-            // logIt("RECODER ID: %s", id_.c_str());
+            if (in){
+                maxduration = 30 * in->getFPS();
+                minduration = 10 * in->getFPS();
+            }
         }
 
         Recorder::~Recorder(){
@@ -57,39 +62,77 @@
             {
                 logIt("RECODER DESTRUCTOR EXCEPTION: ", e.what());
             }
+
+            if (fp_) {
+                fclose(fp_);
+                fp_ = NULL;
+            }
             
         }
 
-        int Recorder::init_writer(const bool audio){
+        int Recorder::init_write_h264(const bool audio){
             if (out_) {
                 delete out_;
             }
 
+            out_ = new FormatOut(in_->getFPS(), "mp4");
+            
+            int pid = getpid();
+            file_path_ = dir_ + "/" + sole::uuid4().base62() + "-" + std::to_string(pid) + ".mp4";
+
+            auto v = in_->getStream(AVMEDIA_TYPE_VIDEO);
+            if (!v){
+                return -2;
+            }
+            AVStream *a = in_->getStream(AVMEDIA_TYPE_AUDIO);
+            if (!audio){
+                a = NULL;
+            }
+            auto ret = out_->JustWriter(v, a, file_path_.c_str());
+            if (ret){
+                logIt("start record file: %s", file_path_.c_str());
+                return 0;
+            }
+
+            logIt("failed to start record: %s", file_path_.c_str());
+
+            return -1;
+        }
+
+        int Recorder::init_write_hevc(const bool audio){
+            if (fp_){
+                fclose(fp_);
+            }
+
+            int pid = getpid();
+            file_path_ = dir_ + "/" + sole::uuid4().base62() + "-" + std::to_string(pid) + ".hevc";
+
+            fp_ = fopen(file_path_.c_str(), "wb");
+            if (!fp_){
+                logIt("write hevc open file error: %s", file_path_.c_str());
+                return -1;
+            }
+            logIt("start record file: %s", file_path_.c_str());
+
+            return 0;
+        }
+
+        int Recorder::init_writer(const bool audio){
             if(!in_){
                 logIt("init_writer FormatIn not init");
                 return -1;
             }
 
-            out_ = new FormatOut(in_->getFPS(), "mp4");
-            AVStream *vs = in_->getStream(0);
-            AVStream *as = in_->getStream(1);
-            if (!vs) return -1;
-            if (audio && !as) logIt("there is no audio");
-            
-            std::vector<AVStream*> in;
-            in.push_back(vs);
-            if (audio && as) in.push_back(as);
-
-            file_path_ = dir_ + "/" + sole::uuid4().base62() + ".mp4";
-            auto ret = out_->JustWriter(in, file_path_.c_str());
-            if (ret){
-                return 0;
+            if (in_->IsHEVC()){
+                return init_write_hevc(audio);
+            }else{
+                return init_write_h264(audio);
             }
-
-            return -1;
+            return -2;
         }
 
-        int Recorder::write_correctly(const CPacket &pkt){
+////////////////////////
+        int Recorder::write_h264(const CPacket &pkt){
             //reader failed, break stream
             if(pkt.id == -1 && !pkt.data){
                 return -1;
@@ -99,29 +142,177 @@
                 return 1;
             }
 
-            int64_t cur = cur_frame++;
             AVPacket &op = pkt.data->getAVPacket();
             AVPacket np(op);
             av_copy_packet(&np, &op);
-            auto ret = out_->writeFrame(np, cur);
-            av_packet_unref(&np);
-            if (!ret) return -1;
             
-            if(pkt.id == id_frame_){
-                id_frame_in_file_ = cur_frame-1;
+            int64_t cur = cur_frame;
+            if (in_->isVideoPkt(&np)){
+
+                if(pkt.id == id_frame_){
+                    id_frame_in_file_ = cur_frame;
+                }
+                cur_frame++;
+            }else if (in_->isAudioPkt(&np)) {
+                cur = cur_frame_a++;
             }
+            
+            auto ret = out_->writeFrame(&np, cur);
+            av_packet_unref(&np);
+            
+            if (!ret) return -1;
             
             // logIt("WRITE FRAME ID: %d, RECORD ID: %d", pkt.id, id_frame_);
             return 0;
+            
         }
 
-        void Recorder::end_writer(){
+        int Recorder::write_hevc(const CPacket &pkt){
+            if (!fp_){
+                logIt("write hevc packet error, file not open");
+                return -1;
+            }
+            if (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++;
+            }
+
+            fwrite(op.data, op.size, 1, fp_); 
+            return 0;
+        }
+
+        int Recorder::write_correctly(const CPacket &pkt){
+            if (in_->IsHEVC()){
+                return write_hevc(pkt);
+            }
+            return write_h264(pkt);
+        }
+
+        int Recorder::end_write_h264(){
+            if (!out_) return -1;
             out_->endWriter();
             if (out_){
                 delete out_;
                 out_ = NULL;
             }
+            return 0;
+        }
+
+        int Recorder::end_write_hevc(){
+            if (fp_){
+                fclose(fp_);
+                fp_ = NULL;
+            }
+
+            std::string hevc_file(file_path_);
+            auto pos = file_path_.rfind(".hevc");
+            if (pos != std::string::npos){
+                file_path_ = file_path_.substr(0, pos) + ".mp4";
+                logIt("mux hevc real file : %s", file_path_.c_str());
+            }
+
+            FILE *fp = fopen(hevc_file.c_str(), "rb");
+            if (!fp) return 0;
+
+            int ret = mux_hevc(fp, file_path_.c_str());
+            fclose(fp);
+            if (ret == 0){
+                if (remove(hevc_file.c_str()) != 0){
+                    logIt("mux hevc remove file %s failed", hevc_file.c_str());
+                }
+            }else{
+                logIt("mux hevc to mp4 error, use raw hevc");
+                file_path_ = hevc_file;
+            }
+
+            return 0;
+        }
+
+        static int read_buffer(void *opaque, uint8_t *buf, int buf_size){
+            FILE *fp_open = (FILE*)opaque;
+            if (!fp_open) logIt("mux hevc open file error");
+
+        	if(!feof(fp_open)){
+        		int true_size=fread(buf,1,buf_size,fp_open);
+        		return true_size;
+        	}else{
+        		return -1;
+        	}
+        }
+
+        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;
+            }
+
+            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;
+                }
+                logIt("mux hevc try %d time to open custom io, failed", tryTime);
+                return -2;
+            }
+            if (in->open(NULL, NULL) < 0){
+                logIt("mux hevc open stream error");
+                return -3;
+            }
+            if (!in->findStreamInfo(NULL)) {
+                logIt("mux hevc can't find streams");
+                return -4;
+            }
+            
+            std::unique_ptr<FormatOut> out(new FormatOut(in_->getFPS(), "mp4"));
+            auto v = in->getStream(AVMEDIA_TYPE_VIDEO);
+            if (!v){
+                logIt("mux hevc file can't find video stream");
+                return -5;
+            }
+            if (out->JustWriter(v, NULL, outfile)){
+                logIt("mux hevc  start record file: %s", outfile);
+            }
+
+            int64_t id = 0;
+            while(true){
+                AVPacket pkt;
+                if (in->readPacket(&pkt) != 0){
+                    logIt("mux hevc read packet error, id: %lld", id);
+                    break;
+                }
+                out->writeFrame(&pkt, id);
+                // logIt("read frame: %d", id);
+                
+                av_packet_unref(&pkt);
+                id++;
+            }
+            out->endWriter();
+
+            return 0;
+        }
+
+        void Recorder::end_writer(){
+
+            if (in_->IsHEVC()){
+                end_write_hevc();
+            }else{
+                end_write_h264();
+            }
+
+            logIt("finished record : %s frames: %d", file_path_.c_str(), cur_frame);
             {
                 std::lock_guard<std::mutex> l(mutex_pkt_);
                 list_pkt_.clear();
@@ -129,11 +320,9 @@
             // 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);
 
-            //callback to frame index and path
             if(func_rec_info_){
                 func_rec_info_(id_,id_frame_in_file_, file_path_);
             }
-
         }
 
         void Recorder::run_thread(){
@@ -173,23 +362,26 @@
 
         int Recorder::Run(const char* output, const int mind, const int maxd, const bool audio){
 
+            bool a = audio;
+            if (in_->IsHEVC()) a = false;
+
             dir_ = output;
-            int ret = init_writer(audio);
+            int ret = init_writer(a);
             if(ret != 0){
                 logIt("recorder init writer error");
                 return -1;
             }
 
-            double fps = out_->getFPS();    
+            double fps = in_->getFPS();    
             if(fps > 1.0){
                 maxduration = fps * maxd;
                 minduration = fps * mind;
                 end_frame = minduration;
             }
 
-            audio_ = audio;
+            audio_ = a;
 
-            // logIt("minduration %d maxduration %d curduration %d", minduration, maxduration, end_frame);    
+            logIt("minduration %d maxduration %d curduration %d", minduration, maxduration, end_frame);    
 
             thrd_.reset(new std::thread([&]{
                 run_thread();
@@ -232,15 +424,8 @@
 
             if(id_frame_ == -1){
                 //wait I 
-                if (!audio_ && in_->isAudioPkt(pkt.data->getAVPacket())){
-                        return 0;
-                }
-
-                if (list_pkt_.empty()) {
-                    AVPacket &avpkt = pkt.data->getAVPacket();
-                    if (!(avpkt.flags & AV_PKT_FLAG_KEY)){
-                        return -1;
-                    }
+                if (!audio_ && in_->isAudioPkt(&pkt.data->getAVPacket())){
+                    return 0;
                 }
 
                 maybe_dump_gop();
@@ -263,15 +448,8 @@
             std::lock_guard<std::mutex> locker(mutex_pkt_);
             bool i = false;
             for (auto &p : lst){
-                if (!i){
-                    if (!audio_ && in_->isAudioPkt(p.data->getAVPacket())){
-                        continue;
-                    }
-                    AVPacket &avpkt = p.data->getAVPacket();
-                    if (!(avpkt.flags & AV_PKT_FLAG_KEY)){
-                        continue;
-                    }
-                    i = true;
+                if (!audio_ && in_->isAudioPkt(&p.data->getAVPacket())){
+                    continue;
                 }
                 
                 list_pkt_.push_back(p);
@@ -288,9 +466,8 @@
             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)){
+                    auto &i = list_pkt_.front();
+                    if (!(i.data->getAVPacket().flags & AV_PKT_FLAG_KEY)){
                         list_pkt_.pop_front();
                     }else{
                         break;

--
Gitblit v1.8.0