From 5dc20e14010d1cf87db73ddd0de2de452049e542 Mon Sep 17 00:00:00 2001 From: zhangmeng <775834166@qq.com> Date: 星期六, 28 九月 2019 16:33:18 +0800 Subject: [PATCH] add rec h265 --- csrc/ffmpeg/format/FormatIn.cpp | 8 +- csrc/wrapper.cpp | 4 csrc/worker/rec.cpp | 4 csrc/ffmpeg/format/FormatOut.cpp | 6 + csrc/buz/recorder.hpp | 13 +++ csrc/buz/recorder.cpp | 199 ++++++++++++++++++++++++++++++++++++++++++++++--- 6 files changed, 210 insertions(+), 24 deletions(-) diff --git a/csrc/buz/recorder.cpp b/csrc/buz/recorder.cpp index c3b4d84..970a68e 100644 --- a/csrc/buz/recorder.cpp +++ b/csrc/buz/recorder.cpp @@ -36,8 +36,12 @@ ,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(){ @@ -58,17 +62,17 @@ { 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_; - } - - if(!in_){ - logIt("init_writer FormatIn not init"); - return -1; } out_ = new FormatOut(in_->getFPS(), "mp4"); @@ -95,7 +99,40 @@ return -1; } - int Recorder::write_correctly(const CPacket &pkt){ + 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; + } + + if (in_->IsHEVC()){ + return init_write_hevc(audio); + }else{ + return init_write_h264(audio); + } + return -2; + } + +//////////////////////// + int Recorder::write_h264(const CPacket &pkt){ //reader failed, break stream if(pkt.id == -1 && !pkt.data){ return -1; @@ -127,15 +164,146 @@ // 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 (remove(hevc_file.c_str()) != 0){ + logIt("mux hevc remove file %s failed", hevc_file.c_str()); + } + + return ret; + } + + static int read_buffer(void *opaque, uint8_t *buf, int buf_size){ + FILE *fp_open = (FILE*)opaque; + 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; + } + + if (in->openWithCustomIO(fp, read_buffer) < 0) { + logIt("mux hevc open custom io error"); + 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(){ + + int ret = -1; + if (in_->IsHEVC()){ + ret = end_write_hevc(); + }else{ + ret = end_write_h264(); + } + if (ret < 0){ + logIt("end write file : %s, h265: %d, failed", file_path_.c_str(), in_->IsHEVC()); + } + + logIt("finished record : %s frames: %d", file_path_.c_str(), cur_frame); { std::lock_guard<std::mutex> l(mutex_pkt_); list_pkt_.clear(); @@ -143,11 +311,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(){ @@ -187,23 +353,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(); diff --git a/csrc/buz/recorder.hpp b/csrc/buz/recorder.hpp index d05ebb8..9c88bbb 100644 --- a/csrc/buz/recorder.hpp +++ b/csrc/buz/recorder.hpp @@ -50,6 +50,15 @@ void end_writer(); void maybe_dump_gop(); + + int init_write_h264(const bool audio); + int write_h264(const CPacket &pkt); + int end_write_h264(); + + int init_write_hevc(const bool audio); + int write_hevc(const CPacket &pkt); + int end_write_hevc(); + int mux_hevc(FILE *fp, const char *outfile); private: ffwrapper::FormatIn *in_; ffwrapper::FormatOut *out_; @@ -59,7 +68,7 @@ int end_frame; int cur_frame; int cur_frame_a; - + std::list<CPacket> list_pkt_; std::atomic_bool stop_recorder_; @@ -79,6 +88,8 @@ bool error_occured_; bool audio_; + + FILE *fp_; }; } } diff --git a/csrc/ffmpeg/format/FormatIn.cpp b/csrc/ffmpeg/format/FormatIn.cpp index 4399822..25d9e3a 100644 --- a/csrc/ffmpeg/format/FormatIn.cpp +++ b/csrc/ffmpeg/format/FormatIn.cpp @@ -155,11 +155,11 @@ vs_idx_ = i; auto in = ctx_->streams[i]; - if(in->avg_frame_rate.num >=1 && in->avg_frame_rate.den >= 1){ - fps_ = av_q2d(in->avg_frame_rate); - }else if(in->r_frame_rate.num >=1 && in->r_frame_rate.den >= 1){ + if(in->r_frame_rate.num >=1 && in->r_frame_rate.den >= 1){ fps_ = av_q2d(in->r_frame_rate); - } + }else if(in->avg_frame_rate.num >=1 && in->avg_frame_rate.den >= 1){ + fps_ = av_q2d(in->avg_frame_rate); + } logIt("in stream video fps %f, time_base: %d : %d", fps_, in->time_base.num, in->time_base.den); } if (type == AVMEDIA_TYPE_AUDIO){ diff --git a/csrc/ffmpeg/format/FormatOut.cpp b/csrc/ffmpeg/format/FormatOut.cpp index 2994153..6bc43df 100644 --- a/csrc/ffmpeg/format/FormatOut.cpp +++ b/csrc/ffmpeg/format/FormatOut.cpp @@ -434,6 +434,12 @@ pkt->pts = pkt->dts = pkt->duration * time_stamp; } + // logIt("BEFORE in stream timebase %d:%d, out timebase %d:%d, + // pts: %lld, dts: %lld, duration: %lld", + // in_stream->time_base.num, in_stream->time_base.den, + // out_stream->time_base.num, out_stream->time_base.den, + // pkt->pts, pkt->dts, pkt->duration); + } bool FormatOut::writeFrame(AVPacket *pkt, const int64_t &frame_cnt, diff --git a/csrc/worker/rec.cpp b/csrc/worker/rec.cpp index d7ce012..01896b0 100644 --- a/csrc/worker/rec.cpp +++ b/csrc/worker/rec.cpp @@ -141,8 +141,8 @@ std::string rid(id); std::string dir(output); - minduration_ = mindur * 25; - maxduration_ = maxdur * 25; + minduration_ = mindur * recRef_->getFPS(); + maxduration_ = maxdur * recRef_->getFPS(); { std::lock_guard<std::mutex> l(mtx_rec_); diff --git a/csrc/wrapper.cpp b/csrc/wrapper.cpp index 26aee19..c03b54f 100644 --- a/csrc/wrapper.cpp +++ b/csrc/wrapper.cpp @@ -151,7 +151,7 @@ void Wrapper::init_worker(ffwrapper::FormatIn *in){ if (rec_->Loaded() && stream_ && decoder_) return; - stream_ = new stream(in, 3 * 25); + stream_ = new stream(in, 3 * in->getFPS()); // stream_->AudioSwitch(audio_); decoder_ = new decoder(in, scale_w_, scale_h_, scale_f_); @@ -192,7 +192,7 @@ int wTime = 1000000.0 / in->getFPS() ; wTime >>= 1; - logIt("INPUT FPS: %d", wTime); + logIt("WAIT TIME PER FRAME: %d", wTime); init_worker(in.get()); -- Gitblit v1.8.0