| | |
| | | |
| | | #include <string.h> |
| | | #include <stdexcept> |
| | | #include <memory> |
| | | |
| | | extern "C"{ |
| | | #include <libavcodec/avcodec.h> |
| | |
| | | double *param/*=NULL*/) |
| | | :scale_(new swscale_wrapper) |
| | | ,pic_(new PicData(dstW, dstH, dstFmt)) |
| | | ,buff_fill_(NULL) |
| | | { |
| | | bool flag = !!scale_ && !!pic_; |
| | | flag = scale_->initContext(srcW, srcH, srcFmt, dstW, dstH, dstFmt, flags) && flag; |
| | |
| | | if(pic_){ |
| | | delete pic_; |
| | | } |
| | | if(buff_fill_){ |
| | | free(buff_fill_); |
| | | } |
| | | } |
| | | |
| | | bool cvbridge::copyPicture(uint8_t *out, AVFrame *in){ |
| | | uint8_t* cvbridge::convert2Data(AVFrame *in){ |
| | | if(!scale_ || !pic_){ |
| | | return false; |
| | | return NULL; |
| | | } |
| | | |
| | | if(!scale_->scaleFrame(in, pic_->getAVFrame())){ |
| | | return false; |
| | | return NULL; |
| | | } |
| | | |
| | | uint8_t *out = (uint8_t*)malloc(pic_->getAVPictureSize()); |
| | | memcpy(out, pic_->getAVPictureData(), |
| | | pic_->getAVPictureSize()); |
| | | |
| | | return true; |
| | | return out; |
| | | } |
| | | bool cvbridge::getAVFrame(uint8_t *in, const int w, const int h, AVFrame * &output){ |
| | | int width = w; |
| | | int height = h; |
| | | |
| | | AVFrame *temp_rgb_frame = av_frame_alloc(); |
| | | temp_rgb_frame->format = (AVPixelFormat)scale_->srcFmt_; |
| | | temp_rgb_frame->width = width; |
| | | temp_rgb_frame->height = height; |
| | | |
| | | //create a AVPicture frame from the opencv Mat input image |
| | | int ret = avpicture_fill((AVPicture *)temp_rgb_frame, |
| | | (uint8_t *)in, |
| | | (AVPixelFormat)scale_->srcFmt_, |
| | | width, |
| | | height); |
| | | if(ret < 0){ |
| | | av_frame_free(&temp_rgb_frame); |
| | | return false; |
| | | } |
| | | // temp_rgb_frame->linesize[0] = frame.step; |
| | | |
| | | |
| | | output->format = (AVPixelFormat)scale_->dstFmt_; |
| | | output->width = width; |
| | | output->height = height; |
| | | |
| | | ret = scale_->scaleFrame(temp_rgb_frame, output); |
| | | |
| | | av_frame_free(&temp_rgb_frame); |
| | | AVFrame* cvbridge::convert2Frame(AVFrame *in){ |
| | | if(!scale_ || !pic_){ |
| | | return NULL; |
| | | } |
| | | |
| | | if(ret) |
| | | return true; |
| | | if(!scale_->scaleFrame(in, pic_->getAVFrame())){ |
| | | return NULL; |
| | | } |
| | | |
| | | return false; |
| | | return av_frame_clone(pic_->getAVFrame()); |
| | | } |
| | | |
| | | AVFrame *cvbridge::getAVFrame(uint8_t *in, const int w, const int h){ |
| | | ///////////////////////////////////////////////////////////////// |
| | | |
| | | AVFrame *cvbridge::fillFrame(uint8_t *in, const int w, const int h, const int f){ |
| | | int width = w; |
| | | int height = h; |
| | | int format = f; |
| | | |
| | | if(!buff_fill_){ |
| | | int size = avpicture_get_size((AVPixelFormat)scale_->dstFmt_, width, height); |
| | | buff_fill_ = (uint8_t *) malloc(size); |
| | | } |
| | | AVFrame * output = av_frame_alloc(); |
| | | const int ret = avpicture_fill((AVPicture*)output, buff_fill_, |
| | | (AVPixelFormat)scale_->dstFmt_, width, height); |
| | | AVFrame *frame = av_frame_alloc(); |
| | | frame->format = format; |
| | | frame->width = width; |
| | | frame->height = height; |
| | | |
| | | // int size = avpicture_get_size((enum AVPixelFormat)frame->format, frame->width, frame->height); |
| | | // if (size <= 0){ |
| | | // return NULL; |
| | | // } |
| | | // printf("size: %d, res: %dx%d, format: %d\n", size, w, h, f); |
| | | // uint8_t *spare = (uint8_t*)malloc(size); |
| | | // memcpy(spare, in, size); |
| | | |
| | | int ret = avpicture_fill((AVPicture *)frame, |
| | | (uint8_t *)in, |
| | | (AVPixelFormat)frame->format, |
| | | frame->width, |
| | | frame->height); |
| | | if(ret < 0){ |
| | | av_frame_free(&output); |
| | | av_frame_free(&frame); |
| | | return NULL; |
| | | } |
| | | return frame; |
| | | } |
| | | |
| | | if(getAVFrame(in, w, h, output)){ |
| | | return output; |
| | | uint8_t* cvbridge::extractFrame(AVFrame *in, int *length){ |
| | | *length = avpicture_get_size((enum AVPixelFormat)in->format, in->width, in->height); |
| | | if (*length <= 0){ |
| | | return NULL; |
| | | } |
| | | av_frame_free(&output); |
| | | return NULL; |
| | | } |
| | | ////////////////////////////////////////////////////////////////////////////////// |
| | | AVFrame *cvbridge::getAVFrame(AVFrame *in){ |
| | | |
| | | int size = avpicture_get_size((enum AVPixelFormat)in->format, in->width, in->height); |
| | | uint8_t *buff = (uint8_t*)malloc(size); |
| | | avpicture_layout((const AVPicture *)in, (enum AVPixelFormat)in->format, |
| | | in->width, in->height, (unsigned char *)buff, size); |
| | | |
| | | AVFrame *output = getAVFrame(buff, in->width, in->height); |
| | | free(buff); |
| | | return output; |
| | | } |
| | | |
| | | bool cvbridge::getAVFrame(AVFrame *in, AVFrame * &output){ |
| | | |
| | | int size = avpicture_get_size((enum AVPixelFormat)in->format, in->width, in->height); |
| | | uint8_t *buff = (uint8_t*)malloc(size); |
| | | avpicture_layout((const AVPicture *)in, (enum AVPixelFormat)in->format, |
| | | in->width, in->height, (unsigned char *)buff, size); |
| | | |
| | | bool flag = getAVFrame(buff, in->width, in->height, output); |
| | | free(buff); |
| | | return flag; |
| | | uint8_t *buff = (uint8_t*)malloc(*length); |
| | | int ret = avpicture_layout((const AVPicture *)in, (enum AVPixelFormat)in->format, |
| | | in->width, in->height, (unsigned char *)buff, *length); |
| | | if (ret < 0){ |
| | | free(buff); |
| | | return NULL; |
| | | } |
| | | return buff; |
| | | } |
| | | |
| | | } |
| | |
| | | ~cvbridge(); |
| | | |
| | | public: |
| | | bool copyPicture(uint8_t *out, AVFrame *in); |
| | | uint8_t* convert2Data(AVFrame *in); |
| | | AVFrame* convert2Frame(AVFrame *in); |
| | | |
| | | bool getAVFrame(uint8_t *in, const int w, const int h, AVFrame * &output); |
| | | AVFrame *getAVFrame(uint8_t *in, const int w, const int h); |
| | | |
| | | AVFrame *getAVFrame(AVFrame *in); |
| | | bool getAVFrame(AVFrame *in, AVFrame * &output); |
| | | static AVFrame *fillFrame(uint8_t *in, const int w, const int h, const int f); |
| | | static uint8_t* extractFrame(AVFrame *in, int *length); |
| | | |
| | | private: |
| | | ffwrapper::swscale_wrapper *scale_; |
| | | ffwrapper::PicData *pic_; |
| | | uint8_t *buff_fill_; |
| | | |
| | | }; |
| | | |
| | |
| | | |
| | | std::lock_guard<std::mutex> l(mutex_frm_); |
| | | for(auto i : list_frm_){ |
| | | av_frame_free(&i.frm); |
| | | free(i.data); |
| | | } |
| | | list_frm_.clear(); |
| | | } |
| | |
| | | } |
| | | |
| | | int decoder::saveFrame(AVFrame *frame, int64_t &id){ |
| | | FRM frm; |
| | | frm.width = frame->width; |
| | | frm.height = frame->height; |
| | | frm.format = frame->format; |
| | | frm.id = id; |
| | | frm.data = cvbridge::extractFrame(frame, &frm.length); |
| | | |
| | | std::lock_guard<std::mutex> l(mutex_frm_); |
| | | while(list_frm_.size() > 50){ |
| | | for(int i = 0; i < 12; i++){ |
| | | auto t = list_frm_.front(); |
| | | av_frame_free(&t.frm); |
| | | free(t.data); |
| | | list_frm_.pop_front(); |
| | | } |
| | | } |
| | | list_frm_.push_back({frame,id}); |
| | | if (!frm.data) return 0; |
| | | list_frm_.push_back(frm); |
| | | return list_frm_.size(); |
| | | } |
| | | |
| | | int decoder::SetFrame(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id){ |
| | | |
| | | if (!data) return -1; |
| | | if (!decRef_->isVideoPkt(&data->getAVPacket())) return -2; |
| | | if (!data) return -10; |
| | | if (!decRef_->isVideoPkt(&data->getAVPacket())) return -20; |
| | | |
| | | if (decRef_->getCodecContext() == NULL){ |
| | | if (initDecoder() != 0) return -3; |
| | | if (initDecoder() != 0) return -30; |
| | | } |
| | | |
| | | AVFrame *frame = av_frame_alloc(); |
| | |
| | | if (ret == 0){ |
| | | saveFrame(frame, id); |
| | | } |
| | | av_frame_free(&frame); |
| | | return ret; |
| | | } |
| | | |
| | | void decoder::GetFrame(unsigned char **data, int *w, int *h, int *format, int *length, int64_t *id){ |
| | | |
| | | AVFrame *frm = NULL; |
| | | { |
| | | std::lock_guard<std::mutex> l(mutex_frm_); |
| | | if(list_frm_.empty()){ |
| | | *data = NULL; |
| | | *w = *h = 0; |
| | | *id = -1; |
| | | return; |
| | | } |
| | | auto p = list_frm_.front(); |
| | | list_frm_.pop_front(); |
| | | frm = p.frm; |
| | | *id = p.id; |
| | | *w = frm->width; |
| | | *h = frm->height; |
| | | *format = frm->format; |
| | | } |
| | | |
| | | *length = avpicture_get_size((enum AVPixelFormat)frm->format, frm->width, frm->height); |
| | | if (*length <= 0){ |
| | | logIt("get raw frame data error"); |
| | | std::lock_guard<std::mutex> l(mutex_frm_); |
| | | if(list_frm_.empty()){ |
| | | *data = NULL; |
| | | *w = *h = 0; |
| | | *id = -1; |
| | | return; |
| | | } |
| | | |
| | | unsigned char *picData = (unsigned char*)malloc(*length); |
| | | auto ret = avpicture_layout((const AVPicture*)frm, (enum AVPixelFormat)frm->format, frm->width, frm->height, picData, *length); |
| | | av_frame_free(&frm); |
| | | |
| | | if (ret < 0){ |
| | | *data = NULL; |
| | | *w = *h = 0; |
| | | *id = -1; |
| | | free(picData); |
| | | return; |
| | | } |
| | | |
| | | *data = picData; |
| | | auto p = list_frm_.front(); |
| | | list_frm_.pop_front(); |
| | | *data = p.data; |
| | | *id = p.id; |
| | | *w = p.width; |
| | | *h = p.height; |
| | | *format = p.format; |
| | | *length = p.length; |
| | | } |
| | | |
| | | } // namespace cffmpeg_wrap |
| | |
| | | namespace cffmpeg_wrap |
| | | { |
| | | typedef struct _frm{ |
| | | AVFrame *frm; |
| | | uint8_t *data; |
| | | int length; |
| | | int width; |
| | | int height; |
| | | int format; |
| | | int64_t id; |
| | | }FRM; |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | void Wrapper::run_worker(ffwrapper::FormatIn *in, std::shared_ptr<ffwrapper::CodedData> data, int64_t &id){ |
| | | int Wrapper::run_worker(ffwrapper::FormatIn *in, std::shared_ptr<ffwrapper::CodedData> data, int64_t &id){ |
| | | if (gb_){ |
| | | AVPacket &pkt = data->getAVPacket(); |
| | | pkt.pts = pkt.dts = AV_NOPTS_VALUE; |
| | | } |
| | | int flag = 0; |
| | | if (stream_) stream_->SetPacket(data, id); |
| | | if (decoder_ && run_dec_) decoder_->SetFrame(data, id); |
| | | if (decoder_ && run_dec_) flag = decoder_->SetFrame(data, id); |
| | | if (rec_->Loaded()) rec_->SetPacket(data, id); |
| | | |
| | | return flag |
| | | } |
| | | |
| | | void Wrapper::deinit_worker(){ |
| | |
| | | id++; |
| | | continue; |
| | | } |
| | | |
| | | run_worker(in.get(), data, id); |
| | | // decode error |
| | | if (run_worker(in.get(), data, id) == -1){ |
| | | break; |
| | | } |
| | | usleep(wTime); |
| | | |
| | | id++; |
| | |
| | | if(in->decode(frm, &data->getAVPacket()) == 0){ |
| | | *w = frm->width; |
| | | *h = frm->height; |
| | | pic = (unsigned char*)malloc(frm->width * frm->height * 3); |
| | | bridge_->copyPicture(pic, frm); |
| | | pic = bridge_->convert2Data(frm); |
| | | break; |
| | | } |
| | | } |
| | |
| | | PicEncoder *e = (PicEncoder*)hdl; |
| | | auto ctx = e->enc->getCodecContext(); |
| | | |
| | | AVPixelFormat pix_fmt = AV_PIX_FMT_BGR24; |
| | | if (e->bridge == NULL){ |
| | | AVPixelFormat pix_fmt = AV_PIX_FMT_BGR24; |
| | | e->bridge = new cvbridge( |
| | | w, h, AV_PIX_FMT_BGR24, |
| | | e->w, e->h, ctx->pix_fmt, e->flag); |
| | | } |
| | | |
| | | AVFrame *frame = e->bridge->getAVFrame(in, w, h); |
| | | AVFrame *frame = cvbridge::fillFrame(in, w, h, pix_fmt); |
| | | AVPacket *pkt = av_packet_alloc(); |
| | | |
| | | auto flag = e->enc->encode(pkt, frame); |
| | |
| | | |
| | | auto b = c->b; |
| | | |
| | | AVFrame *tmp_frm = av_frame_alloc(); |
| | | tmp_frm->format = (AVPixelFormat)c->srcF; |
| | | tmp_frm->width = c->srcW; |
| | | tmp_frm->height = c->srcH; |
| | | |
| | | //create a AVPicture frame from the opencv Mat input image |
| | | int ret = avpicture_fill((AVPicture *)tmp_frm, |
| | | (uint8_t *)src, |
| | | (AVPixelFormat)tmp_frm->format, |
| | | tmp_frm->width, |
| | | tmp_frm->height); |
| | | AVFrame *tmp_frm = cvbridge::fillFrame(src, c->srcW, c->srcH, c->srcF); |
| | | if (!tmp_frm) return NULL; |
| | | |
| | | unsigned char *picData = NULL; |
| | | if (ret > 0){ |
| | | picData = (unsigned char*)malloc(c->dstW * c->dstH * 3); |
| | | b->copyPicture(picData, tmp_frm); |
| | | } |
| | | |
| | | unsigned char *picData = b->convert2Data(tmp_frm); |
| | | |
| | | av_frame_free(&tmp_frm); |
| | | |
| | | |
| | | return picData; |
| | | } |
| | | |
| | |
| | | std::unique_ptr<ffwrapper::FormatIn> init_reader(const char* input); |
| | | |
| | | void init_worker(ffwrapper::FormatIn *in); |
| | | void run_worker(ffwrapper::FormatIn *in, std::shared_ptr<ffwrapper::CodedData> data, int64_t &id); |
| | | int run_worker(ffwrapper::FormatIn *in, std::shared_ptr<ffwrapper::CodedData> data, int64_t &id); |
| | | void deinit_worker(); |
| | | public: |
| | | int RunStream(const char* input); |