| | |
| | | ,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(){ |
| | |
| | | { |
| | | 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"); |
| | |
| | | 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; |
| | |
| | | |
| | | // 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(); |
| | |
| | | // 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(){ |
| | |
| | | |
| | | 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(); |