| | |
| | | #include "../ffmpeg/format/FormatIn.hpp" |
| | | #include "../ffmpeg/data/CodedData.hpp" |
| | | #include "../ffmpeg/log/log.hpp" |
| | | #include "../common.hpp" |
| | | |
| | | extern "C"{ |
| | | #include <libavformat/avformat.h> |
| | |
| | | { |
| | | decoder::decoder(ffwrapper::FormatIn *dec) |
| | | :decRef_(dec) |
| | | ,next_idx_(-1) |
| | | {} |
| | | |
| | | decoder::~decoder(){ |
| | | |
| | | std::lock_guard<std::mutex> l(mutex_frm_); |
| | | for(auto i : list_frm_){ |
| | | av_frame_free(&i.frm); |
| | | } |
| | | list_frm_.clear(); |
| | | |
| | | std::lock_guard<std::mutex> l(mutex_pkt_); |
| | | list_pkt_.clear(); |
| | | } |
| | | |
| | | int decoder::initDecoder(){ |
| | |
| | | return 0; |
| | | } |
| | | |
| | | int decoder::saveFrame(AVFrame *frame, int64_t &id){ |
| | | while(list_frm_.size() > 50){ |
| | | for(int i = 0; i < 12; i++){ |
| | | auto t = list_frm_.front(); |
| | | av_frame_free(&t.frm); |
| | | list_frm_.pop_front(); |
| | | } |
| | | } |
| | | list_frm_.push_back({frame,id}); |
| | | return list_frm_.size(); |
| | | } |
| | | int decoder::SetFrame(const CPacket &pkt){ |
| | | auto data = pkt.data; |
| | | |
| | | 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(); |
| | | AVPacket np(data->getAVPacket()); |
| | | av_copy_packet(&np, &data->getAVPacket()); |
| | | auto ret = decRef_->decode(frame, &np); |
| | | av_packet_unref(&np); |
| | | |
| | | if (ret == 0){ |
| | | saveFrame(frame, id); |
| | | std::lock_guard<std::mutex> l(mutex_pkt_); |
| | | if (data->getAVPacket().flags & AV_PKT_FLAG_KEY){ |
| | | list_pkt_.clear(); |
| | | } |
| | | list_pkt_.push_back(pkt); |
| | | |
| | | return list_pkt_.size(); |
| | | } |
| | | |
| | | void decoder::GetFrame(unsigned char **data, int *w, int *h, int *format, int *length, int64_t *id){ |
| | | *data = NULL; |
| | | *length = 0; |
| | | |
| | | AVFrame *frm = NULL; |
| | | AVFrame *frame = NULL; |
| | | |
| | | { |
| | | std::lock_guard<std::mutex> l(mutex_frm_); |
| | | if(list_frm_.empty()){ |
| | | *data = NULL; |
| | | *w = *h = 0; |
| | | *id = -1; |
| | | return; |
| | | std::lock_guard<std::mutex> l(mutex_pkt_); |
| | | if (list_pkt_.empty()) return; |
| | | auto check = list_pkt_.front(); |
| | | if (check.id > next_idx_){ |
| | | next_idx_ = -1; |
| | | } |
| | | auto p = list_frm_.front(); |
| | | list_frm_.pop_front(); |
| | | frm = p.frm; |
| | | *id = p.id; |
| | | *w = frm->width; |
| | | *h = frm->height; |
| | | *format = frm->format; |
| | | |
| | | for (auto &i : list_pkt_){ |
| | | if (i.id < next_idx_){ |
| | | continue; |
| | | } |
| | | |
| | | *id = i.v_id; |
| | | auto data = i.data; |
| | | |
| | | AVFrame *frm = av_frame_alloc(); |
| | | AVPacket np(data->getAVPacket()); |
| | | av_copy_packet(&np, &data->getAVPacket()); |
| | | auto ret = decRef_->decode(frm, &np); |
| | | av_packet_unref(&np); |
| | | if (ret == 0){ |
| | | next_idx_ = i.id + 1; |
| | | if (frame) {av_frame_free(&frame); frame = NULL;} |
| | | frame = frm; |
| | | } |
| | | } |
| | | } |
| | | if (!frame) return; |
| | | |
| | | int pix_fmt = frame->format; |
| | | int width = frame->width; |
| | | int height = frame->height; |
| | | int len = 0; |
| | | |
| | | uint8_t *origin = cvbridge::extractFrame(frame, &len); |
| | | av_frame_free(&frame); |
| | | if (!origin) return; |
| | | |
| | | uint8_t *finale = NULL; |
| | | if (pix_fmt != AV_PIX_FMT_NV12){ |
| | | finale = (uint8_t*)malloc(len); |
| | | |
| | | unsigned char* SrcU = origin + width * height; |
| | | unsigned char* SrcV = SrcU + width * height / 4 ; |
| | | unsigned char* DstU = finale + width * height; |
| | | memcpy(finale, origin, width * height); |
| | | int i = 0; |
| | | for( i = 0 ; i < width * height / 4 ; i++ ){ |
| | | *(DstU++) = *(SrcU++); |
| | | *(DstU++) = *(SrcV++); |
| | | } |
| | | free(origin); |
| | | }else{ |
| | | finale = origin; |
| | | } |
| | | |
| | | *length = avpicture_get_size((enum AVPixelFormat)frm->format, frm->width, frm->height); |
| | | if (*length <= 0){ |
| | | logIt("get raw frame data error"); |
| | | *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; |
| | | *data = finale; |
| | | *w = width; |
| | | *h = height; |
| | | *format = pix_fmt; |
| | | *length = len; |
| | | } |
| | | |
| | | } // namespace cffmpeg_wrap |