| | |
| | | void c_ffmpeg_run_gb28181(const cffmpeg h); |
| | | void c_ffmepg_use_cpu(const cffmpeg h); |
| | | /////////passive api |
| | | void c_ffmpeg_build_recorder(const cffmpeg h, const char*id, const char *dir, int mind, int maxd); |
| | | void c_ffmpeg_build_recorder(const cffmpeg h, const char*id, const char *dir, int mind, int maxd, int audio); |
| | | void c_ffmpeg_fire_recorder(const cffmpeg h, const char*sid, const int64_t id); |
| | | void c_ffmpeg_get_info_recorder(const cffmpeg h, int *index, char** recid, int *recidLen, char **fpath, int *pathLen); |
| | | |
| | |
| | | ,func_rec_info_(nullptr) |
| | | ,thrd_(nullptr) |
| | | ,error_occured_(false) |
| | | ,audio_(false) |
| | | { |
| | | // logIt("RECODER ID: %s", id_.c_str()); |
| | | } |
| | |
| | | |
| | | } |
| | | |
| | | int Recorder::init_writer(){ |
| | | int Recorder::init_writer(const bool audio){ |
| | | if (out_) { |
| | | delete out_; |
| | | } |
| | |
| | | return -1; |
| | | } |
| | | |
| | | out_ = new FormatOut(in_->getStream(), "mp4"); |
| | | 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_->getStream(), file_path_.c_str()); |
| | | auto ret = out_->JustWriter(in, file_path_.c_str()); |
| | | if (ret){ |
| | | return 0; |
| | | } |
| | |
| | | end_writer(); |
| | | } |
| | | |
| | | int Recorder::Run(const char* output, const int mind, const int maxd){ |
| | | int Recorder::Run(const char* output, const int mind, const int maxd, const bool audio){ |
| | | |
| | | dir_ = output; |
| | | int ret = init_writer(); |
| | | int ret = init_writer(audio); |
| | | if(ret != 0){ |
| | | logIt("recorder init writer error"); |
| | | return -1; |
| | |
| | | minduration = fps * mind; |
| | | end_frame = minduration; |
| | | } |
| | | |
| | | audio_ = audio; |
| | | |
| | | // logIt("minduration %d maxduration %d curduration %d", minduration, maxduration, end_frame); |
| | | |
| | |
| | | |
| | | 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)){ |
| | |
| | | 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; |
| | |
| | | ~Recorder(); |
| | | |
| | | public: |
| | | int Run(const char* output, const int mind, const int maxd); |
| | | int Run(const char* output, const int mind, const int maxd, const bool audio); |
| | | int PushPacket(const CPacket &pkt); |
| | | int PushPackets(std::list<CPacket> &lst); |
| | | int FireRecorder(const int64_t &id); |
| | |
| | | private: |
| | | void run_thread(); |
| | | |
| | | int init_writer(); |
| | | int init_writer(const bool audio); |
| | | int write_correctly(const CPacket &pkt); |
| | | void end_writer(); |
| | | |
| | |
| | | FUNC_REC_INFO func_rec_info_; |
| | | |
| | | bool error_occured_; |
| | | |
| | | bool audio_; |
| | | }; |
| | | } |
| | | } |
| | |
| | | |
| | | |
| | | //////passive api |
| | | void c_ffmpeg_build_recorder(const cffmpeg h, const char* id, const char *dir, int mind, int maxd){ |
| | | void c_ffmpeg_build_recorder(const cffmpeg h, const char* id, const char *dir, int mind, int maxd, int audio){ |
| | | Wrapper *s = (Wrapper*)h; |
| | | s->BuildRecorder(id, dir, mind, maxd); |
| | | |
| | | bool a = audio == 0 ? false : true; |
| | | s->BuildRecorder(id, dir, mind, maxd, a); |
| | | } |
| | | |
| | | void c_ffmpeg_fire_recorder(const cffmpeg h, const char* sid, const int64_t id){ |
| | |
| | | :ctx_(NULL) |
| | | ,dec_ctx_(NULL) |
| | | ,vs_idx_(-1) |
| | | ,as_idx_(-1) |
| | | ,hw_accl_(hw) |
| | | ,io_ctx_(NULL) |
| | | ,read_io_buff_(NULL) |
| | | ,read_io_buff_size_(32768) |
| | | ,handle_gb28181(NULL) |
| | | ,fps_(25.0) |
| | | {} |
| | | |
| | | FormatIn::~FormatIn() |
| | |
| | | handle_gb28181 = new GB28181API; |
| | | handle_gb28181->addCamera(fn); |
| | | |
| | | int ret = openWithCustomIO((void *)&handle_gb28181, handle_gb28181->readData, options); |
| | | int ret = openWithCustomIO(handle_gb28181, handle_gb28181->readData, options); |
| | | if(ret < 0){ |
| | | logIt("do openWithCustomIO failed:%d",ret); |
| | | } |
| | |
| | | return false; |
| | | } |
| | | |
| | | logIt("there are %d stream", ctx_->nb_streams); |
| | | |
| | | for (int i = 0; i < ctx_->nb_streams; ++i) |
| | | { |
| | | switch(ctx_->streams[i]->codecpar->codec_type){ |
| | | case AVMEDIA_TYPE_VIDEO: |
| | | vs_idx_ = i; |
| | | break; |
| | | auto type = ctx_->streams[i]->codecpar->codec_type; |
| | | if (type == AVMEDIA_TYPE_VIDEO){ |
| | | vs_idx_ = i; |
| | | |
| | | default: |
| | | break; |
| | | auto in = ctx_->streams[i]; |
| | | 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("video stream time base %d : %d", in->time_base.num, in->time_base.den); |
| | | } |
| | | if (type == AVMEDIA_TYPE_AUDIO){ |
| | | as_idx_ = i; |
| | | logIt("audio stream time base %d : %d", ctx_->streams[i]->time_base.num, ctx_->streams[i]->time_base.den); |
| | | } |
| | | } |
| | | return true; |
| | |
| | | return true; |
| | | } |
| | | |
| | | AVStream *FormatIn::getStream(int type){ |
| | | return ctx_->streams[vs_idx_]; |
| | | AVStream *FormatIn::getStream(int type/*=-1*/){ |
| | | if (type == -1){ |
| | | return ctx_->streams[vs_idx_]; |
| | | } |
| | | |
| | | if (type == ctx_->streams[vs_idx_]->codecpar->codec_type) |
| | | return ctx_->streams[vs_idx_]; |
| | | if (type == ctx_->streams[as_idx_]->codecpar->codec_type) |
| | | return ctx_->streams[as_idx_]; |
| | | |
| | | return NULL; |
| | | } |
| | | |
| | | AVCodecContext *FormatIn::getCodecContext(int type){ |
| | | return dec_ctx_; |
| | | } |
| | | |
| | | bool FormatIn::readPacket(AVPacket &pkt_out, int stream_index){ |
| | | |
| | | bool founded = false; |
| | | while (!founded){ |
| | | const int ret = av_read_frame(ctx_, &pkt_out); |
| | | if(ret < 0){ |
| | | // logIt("read frame from %s failed:%s", |
| | | // ctx_->filename,getAVErrorDesc(ret).c_str()); |
| | | |
| | | return false; |
| | | } |
| | | if(pkt_out.stream_index == stream_index){ |
| | | founded = true; |
| | | }else{ |
| | | av_free_packet(&pkt_out); |
| | | av_init_packet(&pkt_out); |
| | | pkt_out.data = NULL; |
| | | pkt_out.size = 0; |
| | | } |
| | | bool FormatIn::isVideoPkt(AVPacket &pkt){ |
| | | if (pkt.stream_index == vs_idx_){ |
| | | return true; |
| | | } |
| | | pkt_out.stream_index = 0; |
| | | return false; |
| | | } |
| | | |
| | | bool FormatIn::isAudioPkt(AVPacket &pkt){ |
| | | if (pkt.stream_index == as_idx_){ |
| | | return true; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | bool FormatIn::readPacket(AVPacket &pkt_out){ |
| | | |
| | | const int ret = av_read_frame(ctx_, &pkt_out); |
| | | if(ret < 0){ |
| | | return false; |
| | | } |
| | | |
| | | return true; |
| | | |
| | | } |
| | | |
| | | bool FormatIn::readPacket(std::shared_ptr<CodedData> &data, int stream_index){ |
| | | bool FormatIn::readPacket(std::shared_ptr<CodedData> &data){ |
| | | |
| | | AVPacket &pkt(data->getAVPacket()); |
| | | return readPacket(pkt, getStream()->index); |
| | | return readPacket(pkt); |
| | | } |
| | | |
| | | int FormatIn::decode(AVFrame* &frame, AVPacket &pkt){ |
| | |
| | | |
| | | bool openCodec(const int type, AVDictionary **options); |
| | | |
| | | bool readPacket(AVPacket &pkt_out, int stream_index = 0); |
| | | bool readPacket(std::shared_ptr<CodedData> &data, int stream_index = 0); |
| | | bool readPacket(AVPacket &pkt_out); |
| | | bool readPacket(std::shared_ptr<CodedData> &data); |
| | | |
| | | int decode(AVFrame* &frame, AVPacket &pkt); |
| | | int decode(std::shared_ptr<FrameData> &frame_data, |
| | |
| | | int readFrame(AVFrame* &frame); |
| | | int readFrame(std::shared_ptr<FrameData> &frame_data); |
| | | |
| | | bool isVideoPkt(AVPacket &pkt); |
| | | bool isAudioPkt(AVPacket &pkt); |
| | | private: |
| | | bool allocCodec(AVCodec *dec, AVStream *s, AVDictionary **options); |
| | | public: |
| | | AVStream *getStream(int type = 0); |
| | | AVStream *getStream(int type = -1); |
| | | AVCodecContext *getCodecContext(int type = 0); |
| | | const double getFPS()const{return fps_;} |
| | | private: |
| | | AVFormatContext *ctx_; |
| | | AVCodecContext *dec_ctx_; |
| | | int vs_idx_; |
| | | int as_idx_; |
| | | |
| | | bool hw_accl_; |
| | | |
| | | double fps_; |
| | | private: |
| | | AVIOContext *io_ctx_; |
| | | uint8_t *read_io_buff_; |
| | |
| | | ,record_(false) |
| | | ,fps_(0.0f) |
| | | ,format_name_("mp4") |
| | | ,streams_(NULL) |
| | | {} |
| | | |
| | | FormatOut::~FormatOut() |
| | |
| | | } |
| | | |
| | | ////////////////////////////////////////////////////////////////////////// |
| | | FormatOut::FormatOut(AVStream *in, const char *format_name) |
| | | FormatOut::FormatOut(const double fps, const char *format_name) |
| | | :FormatOut(){ |
| | | |
| | | format_name_ = format_name; |
| | | |
| | | 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); |
| | | } |
| | | } |
| | | |
| | | |
| | | bool FormatOut::copyCodecFromIn(AVStream *in){ |
| | | |
| | | v_s_ = avformat_new_stream(ctx_, in->codec->codec); |
| | | if(!v_s_){ |
| | | return false; |
| | | } |
| | | |
| | | int ret = avcodec_copy_context(v_s_->codec, in->codec); |
| | | if (ret < 0){ |
| | | logIt("can't copy codec from in error:%s", getAVErrorDesc(ret).c_str()); |
| | | |
| | | return false; |
| | | } |
| | | |
| | | if (ctx_->oformat->flags & AVFMT_GLOBALHEADER) |
| | | { |
| | | v_s_->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; |
| | | } |
| | | return true; |
| | | fps_ = fps; |
| | | } |
| | | |
| | | bool FormatOut::openResource(const char *filename, const int flags){ |
| | | if((ctx_->flags & AVFMT_NOFILE) != AVFMT_NOFILE){ |
| | | if((ctx_->oformat->flags & AVFMT_NOFILE) != AVFMT_NOFILE){ |
| | | |
| | | const int err = avio_open2(&ctx_->pb, filename, flags, NULL, NULL); |
| | | if(err < 0) |
| | |
| | | } |
| | | return true; |
| | | } |
| | | bool FormatOut::JustWriter(AVStream *in, const char *filename){ |
| | | |
| | | bool FormatOut::copyCodecFromIn(std::vector<AVStream*> in){ |
| | | auto count = in.size(); |
| | | |
| | | for(int i = 0; i < count; i++) |
| | | { //根据输入流创建输出流 |
| | | AVStream *in_stream = in[i]; |
| | | AVStream *out_stream = avformat_new_stream(ctx_, in_stream->codec->codec); |
| | | if(!out_stream) |
| | | { |
| | | logIt("Failed allocating output stream.\n"); |
| | | return false; |
| | | } |
| | | |
| | | if (in_stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){ |
| | | v_s_ = out_stream; |
| | | } |
| | | //将输出流的编码信息复制到输入流 |
| | | auto ret = avcodec_copy_context(out_stream->codec, in_stream->codec); |
| | | if(ret<0) |
| | | { |
| | | logIt("Failed to copy context from input to output stream codec context\n"); |
| | | return false; |
| | | } |
| | | out_stream->codec->codec_tag = 0; |
| | | |
| | | if(ctx_->oformat->flags & AVFMT_GLOBALHEADER) |
| | | out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; |
| | | |
| | | } |
| | | |
| | | streams_ = in; |
| | | |
| | | return true; |
| | | } |
| | | |
| | | bool FormatOut::JustWriter(std::vector<AVStream*> in, const char *filename){ |
| | | if(ctx_){ |
| | | clear(); |
| | | } |
| | |
| | | return true; |
| | | } |
| | | |
| | | void FormatOut::adjustPTS(AVPacket &pkt, const int64_t &frame_cnt){ |
| | | void FormatOut::adjustVideoPTS(AVPacket &pkt, const int64_t &frame_cnt){ |
| | | int64_t time_stamp = frame_cnt; |
| | | |
| | | pkt.pos = -1; |
| | |
| | | pkt.dts = pkt.pts; |
| | | pkt.duration = av_rescale_q(calc_duration, time_base_q, time_base); //(double)(calc_duration)*(double)(av_q2d(time_base_q)) / (double)(av_q2d(time_base)); |
| | | |
| | | // logIt("FRAME ID: %lld, PTS : %lld, DTS : %lld", frame_cnt, pkt.pts, pkt.dts); |
| | | // logIt("FRAME ID: %lld, PTS : %lld, DTS : %lld", frame_cnt, pkt.pts, pkt.dts); |
| | | } |
| | | |
| | | void FormatOut::adjustPTS(AVPacket &pkt, const int64_t &frame_cnt){ |
| | | if (streams_.size() == 1){ |
| | | return adjustVideoPTS(pkt, frame_cnt); |
| | | } |
| | | |
| | | if (pkt.stream_index >= streams_.size()){ |
| | | logIt("adjustPTS pkt stream index too much"); |
| | | return; |
| | | } |
| | | |
| | | AVStream *in_stream,*out_stream; |
| | | |
| | | in_stream = streams_[pkt.stream_index]; |
| | | out_stream = ctx_->streams[pkt.stream_index]; |
| | | |
| | | // logIt("stream %d time_base %d : %d", pkt.stream_index, in_stream->time_base.num, in_stream->time_base.den); |
| | | // logIt("out time_base %d : %d", out_stream->time_base.num, out_stream->time_base.den); |
| | | |
| | | std::string type("video"); |
| | | if (in_stream->codecpar->codec_type == 1){ |
| | | type = "audio"; |
| | | } |
| | | |
| | | // logIt("BEFORE stream %d type: %s, pts: %lld, dts: %lld, duration: %lld", |
| | | // pkt.stream_index, type.c_str(), pkt.pts, pkt.pts, pkt.duration); |
| | | //copy packet |
| | | //转换 PTS/DTS 时序 |
| | | pkt.pts = av_rescale_q_rnd(pkt.pts,in_stream->time_base,out_stream->time_base,(enum AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX)); |
| | | pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (enum AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX)); |
| | | //printf("pts %d dts %d base %d\n",pkt.pts,pkt.dts, in_stream->time_base); |
| | | pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base); |
| | | pkt.pos = -1; |
| | | |
| | | // logIt("AFTER stream %d type: %s, pts: %lld, dts: %lld, duration: %lld", |
| | | // pkt.stream_index, type.c_str(), pkt.pts, pkt.pts, pkt.duration); |
| | | |
| | | // //此while循环中并非所有packet都是视频帧,当收到视频帧时记录一下,仅此而已 |
| | | // if(pkt.stream_index==video_index) |
| | | // { |
| | | // printf("Receive %8d video frames from input URL\n",frame_index); |
| | | // frame_index++; |
| | | // } |
| | | |
| | | // //将包数据写入到文件。 |
| | | // ret = av_interleaved_write_frame(ofmt_ctx,&pkt); |
| | | // if(ret < 0) |
| | | // { |
| | | // /** |
| | | // 当网络有问题时,容易出现到达包的先后不一致,pts时序混乱会导致 |
| | | // av_interleaved_write_frame函数报 -22 错误。暂时先丢弃这些迟来的帧吧 |
| | | // 若所大部分包都没有pts时序,那就要看情况自己补上时序(比如较前一帧时序+1)再写入。 |
| | | // */ |
| | | // if(ret==-22){ |
| | | // continue; |
| | | // }else{ |
| | | // printf("Error muxing packet.error code %d\n" , ret); |
| | | // break; |
| | | // } |
| | | |
| | | // } |
| | | |
| | | } |
| | | |
| | | bool FormatOut::writeFrame(AVPacket &pkt, const int64_t &frame_cnt, |
| | |
| | | ret = av_write_frame(ctx_, &pkt); |
| | | } |
| | | |
| | | if(ret < 0){ |
| | | return false; |
| | | if(ret < -22 || ret == 0){ |
| | | return true; |
| | | } |
| | | |
| | | return true; |
| | | return false; |
| | | } |
| | | |
| | | bool FormatOut::writeTrailer(){ |
| | |
| | | #include <stdlib.h> |
| | | #include <memory> |
| | | #include <string> |
| | | #include <vector> |
| | | |
| | | struct AVFormatContext; |
| | | struct AVStream; |
| | |
| | | FormatOut(VideoProp &prop, |
| | | const char *filename, char *format_name = NULL); |
| | | |
| | | FormatOut(AVStream *in, const char *format_name); |
| | | FormatOut(const double fps, const char *format_name); |
| | | |
| | | void clear(); |
| | | public: |
| | |
| | | int encode(std::shared_ptr<CodedData> &data,AVFrame *frame); |
| | | |
| | | public: |
| | | bool copyCodecFromIn(AVStream *in); |
| | | bool copyCodecFromIn(std::vector<AVStream*> in); |
| | | bool openResource(const char *filename, const int flags); |
| | | bool closeResource(); |
| | | |
| | | bool JustWriter(AVStream *in, const char *filename); |
| | | bool JustWriter(std::vector<AVStream*> in, const char *filename); |
| | | bool EncodeWriter(const char *filename); |
| | | bool writeFrame(AVPacket &pkt, const int64_t &frame_cnt, bool interleaved = true); |
| | | void adjustPTS(AVPacket &pkt, const int64_t &frame_cnt); |
| | | void adjustVideoPTS(AVPacket &pkt, const int64_t &frame_cnt); |
| | | bool endWriter(); |
| | | |
| | | bool writeHeader(AVDictionary **options = NULL); |
| | |
| | | double fps_; |
| | | std::string format_name_; |
| | | |
| | | // rec |
| | | std::vector<AVStream*> streams_; |
| | | }; |
| | | } |
| | | #endif |
| | |
| | | |
| | | int decoder::SetFrame(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id){ |
| | | if (!data) return -1; |
| | | if (decRef_->isAudioPkt(data->getAVPacket())) return -2; |
| | | |
| | | if (!conv_){ |
| | | initDecoder(); |
| | |
| | | list_recInfo_.emplace_back(info); |
| | | } |
| | | |
| | | std::unique_ptr<buz::Recorder> rec::startRec(std::string id, std::string dir, const int mind, const int maxd){ |
| | | 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; |
| | |
| | | |
| | | int trycnt = 0; |
| | | while(trycnt < 100){ |
| | | auto ret = rec->Run(dir.c_str(), mind, maxd); |
| | | auto ret = rec->Run(dir.c_str(), mind, maxd, audio); |
| | | if(ret == 0) break; |
| | | usleep(200000); |
| | | } |
| | |
| | | return recRef_ != NULL; |
| | | } |
| | | |
| | | void rec::NewRec(const char* id, const char *output, const int mindur, const int maxdur){ |
| | | 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); |
| | | |
| | |
| | | if (map_rec_.find(rid) != map_rec_.end()){ |
| | | map_rec_.erase(rid); |
| | | } |
| | | map_rec_[rid] = startRec(rid, dir, mindur, maxdur); |
| | | map_rec_[rid] = startRec(rid, dir, mindur, maxdur, audio); |
| | | } |
| | | |
| | | } |
| | |
| | | // 丢弃缓存 |
| | | int shrinkCache(); |
| | | // 创建录像实例开始录像 |
| | | std::unique_ptr<buz::Recorder> startRec(std::string id, std::string dir, const int mind, const int maxd); |
| | | std::unique_ptr<buz::Recorder> startRec(std::string id, std::string dir, const int mind, const int maxd, const bool audio); |
| | | // 清除缓存,断线重连时需要 |
| | | void clear(); |
| | | public: |
| | | void NewRec(const char* id, const char *output, const int mindur, const int maxdur); |
| | | void NewRec(const char* id, const char *output, const int mindur, const int maxdur, const bool audio); |
| | | |
| | | // 准备好录像 |
| | | void Load(ffwrapper::FormatIn *in); |
| | |
| | | #include "stream.hpp" |
| | | |
| | | #include "../ffmpeg/data/CodedData.hpp" |
| | | #include "../ffmpeg/format/FormatIn.hpp" |
| | | |
| | | namespace cffmpeg_wrap{ |
| | | stream::stream(const int maxSize) |
| | | :max_size_(maxSize) |
| | | stream::stream(ffwrapper::FormatIn *in, const int maxSize) |
| | | :streamRef_(in) |
| | | ,max_size_(maxSize) |
| | | ,audio_(false) |
| | | {} |
| | | |
| | | stream::~stream(){ |
| | |
| | | |
| | | int stream::SetPacket(std::shared_ptr<ffwrapper::CodedData> data){ |
| | | if (data){ |
| | | |
| | | auto audio = streamRef_->isAudioPkt(data->getAVPacket()); |
| | | // 如果包是音频包,但是不使用音频,直接返回 |
| | | if (!audio_ && audio){ |
| | | return 0; |
| | | } |
| | | |
| | | std::lock_guard<std::mutex> locker(mutex_avpkt_); |
| | | list_avpkt_.push_back(data); |
| | | |
| | |
| | | #include <memory> |
| | | |
| | | namespace ffwrapper{ |
| | | class FormatIn; |
| | | class CodedData; |
| | | } |
| | | |
| | |
| | | private: |
| | | std::list<std::shared_ptr<ffwrapper::CodedData> > list_avpkt_; |
| | | std::mutex mutex_avpkt_; |
| | | ffwrapper::FormatIn *streamRef_; |
| | | const int max_size_; |
| | | bool audio_; |
| | | public: |
| | | explicit stream(const int maxSize); |
| | | stream(ffwrapper::FormatIn *in, const int maxSize); |
| | | ~stream(); |
| | | |
| | | int SetPacket(std::shared_ptr<ffwrapper::CodedData> data); |
| | | void GetPacket(unsigned char **pktData, int *size, int *key); |
| | | void AudioSwitch(const bool a){audio_ = a;} |
| | | }; |
| | | |
| | | } |
| | |
| | | ,scale_w_(0) |
| | | ,scale_h_(0) |
| | | ,scale_f_(SWS_POINT) |
| | | ,audio_(false) |
| | | ,gb_(0) |
| | | ,cpu_(0) |
| | | ,thread_(nullptr) |
| | |
| | | } |
| | | } |
| | | |
| | | void Wrapper::ScalePicture(const int w, const int h, const int flags){ |
| | | scale_w_ = w; |
| | | scale_f_ = flags; |
| | | scale_h_ = h; |
| | | } |
| | | |
| | | void Wrapper::GB28181(){ |
| | | gb_ = 1; |
| | | } |
| | | |
| | | void Wrapper::CPUDec(){ |
| | | cpu_ = 1; |
| | | } |
| | | |
| | | std::unique_ptr<ffwrapper::FormatIn> Wrapper::init_reader(const char* input){ |
| | | |
| | | VideoProp prop; |
| | |
| | | } |
| | | if(flag == 0){ |
| | | if(!in->findStreamInfo(NULL)){ |
| | | logIt("yolo can't find video stream\n"); |
| | | logIt("can't find video stream\n"); |
| | | return nullptr; |
| | | } |
| | | |
| | |
| | | return 0; |
| | | } |
| | | |
| | | void Wrapper::AudioSwitch(const bool a){ |
| | | audio_ = a; |
| | | if (stream_){ |
| | | stream_->AudioSwitch(a); |
| | | } |
| | | } |
| | | |
| | | void Wrapper::init_worker(ffwrapper::FormatIn *in){ |
| | | if (rec_->Loaded() && stream_ && decoder_) return; |
| | | stream_ = new stream(3 * 25); |
| | | stream_ = new stream(in, 3 * 25); |
| | | stream_->AudioSwitch(audio_); |
| | | |
| | | decoder_ = new decoder(in, scale_w_, scale_h_, scale_f_); |
| | | |
| | | rec_->Load(in); |
| | | if(fn_rec_lazy_) fn_rec_lazy_(in); |
| | | } |
| | | |
| | | void Wrapper::run_worker(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id){ |
| | | void Wrapper::run_worker(ffwrapper::FormatIn *in, std::shared_ptr<ffwrapper::CodedData> data, int64_t &id){ |
| | | |
| | | if (stream_) stream_->SetPacket(data); |
| | | if (decoder_) decoder_->SetFrame(data, id); |
| | | if (rec_->Loaded()) rec_->SetPacket(data, id); |
| | |
| | | break; |
| | | } |
| | | |
| | | run_worker(data, id); |
| | | run_worker(in.get(), data, id); |
| | | id++; |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | void Wrapper::BuildRecorder(const char* id, const char *output, const int mindur, const int maxdur){ |
| | | void Wrapper::BuildRecorder(const char* id, const char *output, const int mindur, const int maxdur, const bool audio){ |
| | | |
| | | if (rec_->Loaded()){ |
| | | rec_->NewRec(id, output, mindur, maxdur); |
| | | rec_->NewRec(id, output, mindur, maxdur, audio); |
| | | }else{ |
| | | std::string rid(id), dir(output); |
| | | fn_rec_lazy_ = |
| | | [=](ffwrapper::FormatIn *in){rec_->NewRec(rid.c_str(), dir.c_str(), mindur, maxdur);}; |
| | | [=](ffwrapper::FormatIn *in){rec_->NewRec(rid.c_str(), dir.c_str(), mindur, maxdur, audio);}; |
| | | } |
| | | } |
| | | |
| | |
| | | std::unique_ptr<ffwrapper::FormatIn> init_reader(const char* input); |
| | | |
| | | void init_worker(ffwrapper::FormatIn *in); |
| | | void run_worker(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id); |
| | | void run_worker(ffwrapper::FormatIn *in, std::shared_ptr<ffwrapper::CodedData> data, int64_t &id); |
| | | void deinit_worker(); |
| | | public: |
| | | int RunStream(const char* input); |
| | | private: |
| | | void run_stream_thread(); |
| | | public: //recorder |
| | | void BuildRecorder(const char* id,const char *dir, const int mind, const int maxd); |
| | | void BuildRecorder(const char* id,const char *dir, const int mind, const int maxd, const bool audio); |
| | | int FireRecorder(const char* sid,const int64_t &id); |
| | | void GetInfoRecorder(std::string &recID, int &index, std::string &path); |
| | | void ScalePicture(const int w, const int h, const int flags); |
| | | void GB28181(); |
| | | void CPUDec(); |
| | | void ScalePicture(const int w, const int h, const int flags){ |
| | | scale_w_ = w; |
| | | scale_h_ = h; |
| | | scale_f_ = flags; |
| | | } |
| | | void GB28181(){gb_ = 1;} |
| | | void CPUDec(){cpu_ = 1;} |
| | | void AudioSwitch(const bool a); |
| | | public: //decoder |
| | | void BuildDecoder(); |
| | | void GetPicDecoder(unsigned char **data, int *w, int *h, int64_t *id); |
| | |
| | | // stream 参数 |
| | | std::string input_url_; |
| | | int scale_w_, scale_h_, scale_f_; |
| | | |
| | | bool audio_; |
| | | int gb_, cpu_; |
| | | // decoder 参数 |
| | | std::unique_ptr<std::thread> thread_; |
| | |
| | | } |
| | | |
| | | // BuildRecorder build recorder |
| | | func (h *GoFFMPEG) BuildRecorder(sid, output string, mind, maxd int) { |
| | | func (h *GoFFMPEG) BuildRecorder(sid, output string, mind, maxd, audio int) { |
| | | out := C.CString(output) |
| | | defer C.free(unsafe.Pointer(out)) |
| | | csid := C.CString(sid) |
| | | defer C.free(unsafe.Pointer(csid)) |
| | | |
| | | C.wrap_fn_recorder(h.ffmpeg, csid, out, C.int(mind), C.int(maxd)) |
| | | C.wrap_fn_recorder(h.ffmpeg, csid, out, C.int(mind), C.int(maxd), C.int(audio)) |
| | | } |
| | | |
| | | // GetInfoRecorder info |
| | |
| | | fn_cpu(h); |
| | | } |
| | | |
| | | void wrap_fn_recorder(const cffmpeg h, const char* id, const char* dir, int mind, int maxd){ |
| | | fn_recorder(h, id, dir, mind, maxd); |
| | | void wrap_fn_recorder(const cffmpeg h, const char* id, const char* dir, int mind, int maxd, int audio){ |
| | | fn_recorder(h, id, dir, mind, maxd, audio); |
| | | } |
| | | |
| | | void wrap_fn_fire_recorder(const cffmpeg h, const char* sid, const int64_t id){ |
| | |
| | | typedef void (*lib_cffmpeg_scale)(const cffmpeg, const int, const int, const int); |
| | | typedef void (*lib_cffmpeg_gb28181)(const cffmpeg); |
| | | typedef void (*lib_cffmpeg_cpu)(const cffmpeg); |
| | | typedef void (*lib_cffmpeg_recorder)(const cffmpeg, const char*, const char*, int, int); |
| | | typedef void (*lib_cffmpeg_recorder)(const cffmpeg, const char*, const char*, int, int, int); |
| | | typedef void (*lib_cffmpeg_fire_recorder)(const cffmpeg, const char*, const int64_t); |
| | | typedef void (*lib_cffmpeg_info_recorder)(const cffmpeg, int*, char**, int*, char**, int*); |
| | | typedef void (*lib_cffmpeg_decoder)(const cffmpeg); |
| | |
| | | void wrap_fn_scale(const cffmpeg h, const int wid, const int hei, const int flags); |
| | | void wrap_fn_run_gb28181(const cffmpeg h); |
| | | void wrap_fn_use_cpu(const cffmpeg h); |
| | | void wrap_fn_recorder(const cffmpeg h, const char* id, const char* dir, int mind, int maxd); |
| | | void wrap_fn_recorder(const cffmpeg h, const char* id, const char* dir, int mind, int maxd, int audio); |
| | | void wrap_fn_fire_recorder(const cffmpeg h, const char *sid, const int64_t id); |
| | | void wrap_fn_info_recorder(const cffmpeg, int* index, char** recid, int* recidLen, char** fpath, int* pathLen); |
| | | void wrap_fn_decoder(const cffmpeg h); |