From 18a05d269516a5e33d8460291c2f93e73d95adce Mon Sep 17 00:00:00 2001
From: zhangmeng <775834166@qq.com>
Date: 星期二, 26 十二月 2023 10:45:31 +0800
Subject: [PATCH] GetYUV format is NV12
---
csrc/ffmpeg/format/FormatIn.cpp | 527 +++++++++++++++++++++++++++++++++++----------------------
1 files changed, 321 insertions(+), 206 deletions(-)
diff --git a/csrc/ffmpeg/format/FormatIn.cpp b/csrc/ffmpeg/format/FormatIn.cpp
index d61fbc7..120e2c7 100644
--- a/csrc/ffmpeg/format/FormatIn.cpp
+++ b/csrc/ffmpeg/format/FormatIn.cpp
@@ -2,6 +2,8 @@
#include <stdexcept>
#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
extern "C"{
#include <libavformat/avformat.h>
@@ -10,19 +12,15 @@
#include <libavutil/opt.h>
#include <libavutil/avassert.h>
#include <libavutil/imgutils.h>
-#include <libswscale/swscale.h>
+#include <libswscale/swscale.h>
}
#include "../log/log.hpp"
#include "../configure/conf.hpp"
#include "../property/VideoProp.hpp"
-#include "../data/CodedData.hpp"
-#include "../data/FrameData.hpp"
#include "../../common/gpu/info.h"
-#include "PsToEs.hpp"
-
using namespace logif;
namespace ffwrapper{
@@ -30,209 +28,171 @@
:ctx_(NULL)
,dec_ctx_(NULL)
,vs_idx_(-1)
- ,hw_accl_(hw)
+ ,as_idx_(-1)
+ ,prop_(NULL)
,io_ctx_(NULL)
,read_io_buff_(NULL)
,read_io_buff_size_(32768)
+ ,fps_(25.0)
{}
+
+ FormatIn::FormatIn(const VideoProp &prop, bool hw/*=true*/)
+ :FormatIn(hw)
+ {
+ prop_ = new VideoProp;
+ *prop_ = prop;
+ }
FormatIn::~FormatIn()
{
- if(io_ctx_){
- if(read_io_buff_){
- // av_free(read_io_buff_);
- read_io_buff_ = NULL;
- }
- avio_context_free(&io_ctx_);
- io_ctx_ = NULL;
+ logIt("free format in");
+ if (prop_) delete prop_;
+
+ if(dec_ctx_){
+ avcodec_close(dec_ctx_);
+ avcodec_free_context(&dec_ctx_);
+ dec_ctx_ = NULL;
}
+
if(ctx_){
avformat_close_input(&ctx_);
- avformat_free_context(ctx_);
ctx_ = NULL;
- if(dec_ctx_){
- avcodec_close(dec_ctx_);
- dec_ctx_ = NULL;
- }
+ }
+
+ if(io_ctx_){
+ av_freep(&io_ctx_->buffer);
+ av_freep(&io_ctx_);
+ io_ctx_ = NULL;
}
}
-////////////////////////////////////////////////////////////////////////
int FormatIn::openWithCustomIO(void *opaque, read_packet fn, AVDictionary **options/*=NULL*/){
- ctx_ = avformat_alloc_context();
- if(!ctx_){
- logIt("open with custom io create format error");
- return -1;
- }
read_io_buff_ = (uint8_t*)av_malloc(read_io_buff_size_);
if(!read_io_buff_){
- logIt("open with custom io alloc read io buff error");
+ logIt("open with custom io alloc read io buff error\n");
return -1;
}
io_ctx_ = avio_alloc_context(read_io_buff_, read_io_buff_size_, 0, opaque, fn, NULL, NULL);//opaque
if(!io_ctx_){
- logIt("open with custom io create custom avio error");
+ logIt("open with custom io create custom avio error\n");
return -1;
}
+
+ ctx_ = avformat_alloc_context();
+ if(!ctx_){
+ logIt("open with custom io create format error\n");
+ return -1;
+ }
+
ctx_->pb = io_ctx_;
- auto err = av_probe_input_buffer(ctx_->pb, &ctx_->iformat, NULL, NULL, 0, read_io_buff_size_);
- if(err != 0){
- logIt("open with custom io prob input buffer error:%d", err);
- logIt("failed:%s", getAVErrorDesc(err).c_str());
- return -1;
+ return 0;
+ }
+
+ int FormatIn::open(const char *filename, AVDictionary **options){
+
+ int ret = avformat_open_input(&ctx_, filename, NULL, options);
+
+ ret = avformat_find_stream_info(ctx_, options);
+ if(ret < 0){
+ logIt("find %s stream info failed:%s",
+ ctx_->filename,getAVErrorDesc(ret).c_str());
+ return ret;
+ }
+
+ for (int i = 0; i < ctx_->nb_streams; ++i)
+ {
+ auto type = ctx_->streams[i]->codecpar->codec_type;
+ logIt("there are %d stream, stream %d, type %d", ctx_->nb_streams, i, type);
+
+ if (type == AVMEDIA_TYPE_VIDEO){
+ vs_idx_ = i;
+
+ 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("in stream video fps %f, time_base: %d:%d, size: %dx%d", fps_, in->time_base.num, in->time_base.den, in->codecpar->width, in->codecpar->height);
+ }
+ if (type == AVMEDIA_TYPE_AUDIO){
+ auto in = ctx_->streams[i];
+ logIt("in stream audio %d time_base: %d:%d", in->codecpar->codec_id, in->time_base.num, in->time_base.den);
+ if (in->codecpar->codec_id == AV_CODEC_ID_AAC)
+ as_idx_ = i;
+ else
+ logIt("record not support audio codec: %d", in->codecpar->codec_id);
+ }
}
return 0;
}
- int FormatIn::openGb28181(const char *filename, AVDictionary **options){
-
- std::string fn = filename;
- addCamera(fn);
-
- int ret = openWithCustomIO(NULL, readData, options);
- if(ret < 0){
- logIt("do openWithCustomIO failed:%d",ret);
- }
-
- ret = avformat_open_input(&ctx_, "", NULL, options);
- if(ret < 0){
- logIt("open %s failed:%s",filename,
- getAVErrorDesc(ret).c_str());
-
- }
-
- return ret;
+ const bool FormatIn::IsHEVC()const{
+ return ctx_->streams[vs_idx_]->codecpar->codec_id == AV_CODEC_ID_HEVC;
}
-/////////////////////////////////////////////////////////////////////////
- int FormatIn::open(const char *filename, AVDictionary **options){
+ const bool FormatIn::IsAVC1()const{
+ if (IsHEVC()) return false;
- const int ret = avformat_open_input(&ctx_, filename, NULL, options);
- if(ret < 0){
- logIt("open %s failed:%s",filename,
- getAVErrorDesc(ret).c_str());
-
- }
-
- return ret;
+ char p[100] = {0};
+ char *sub = av_fourcc_make_string(p, ctx_->streams[vs_idx_]->codecpar->codec_tag);
+ const int ret = strcmp(sub, "avc1");
+ if (ret == 0) return true;
+ return false;
}
- bool FormatIn::findStreamInfo(AVDictionary **options){
+ bool FormatIn::openCodec(AVDictionary **options){
+ if (dec_ctx_) return true;
+ if (vs_idx_ == -1) return false;
- const int ret = avformat_find_stream_info(ctx_, options);
- if(ret < 0){
- logIt("find %s stream info failed:%s",
- ctx_->filename,getAVErrorDesc(ret).c_str());
-
- return false;
- }
-
- for (int i = 0; i < ctx_->nb_streams; ++i)
- {
- switch(ctx_->streams[i]->codecpar->codec_type){
- case AVMEDIA_TYPE_VIDEO:
- vs_idx_ = i;
- break;
-
- default:
- break;
- }
- }
- return true;
- }
-
- bool FormatIn::openCodec(const int type, AVDictionary **options){
- int stream_index = -1;
- switch(type){
- case AVMEDIA_TYPE_VIDEO:
- stream_index = vs_idx_;
- break;
- default:
- break;
- }
- if(stream_index < 0){
- logIt("open input %s codec need correct stream",ctx_->filename);
-
- return false;
- }
-
- AVStream *s = ctx_->streams[stream_index];
-
+ AVStream *s = ctx_->streams[vs_idx_];
AVCodecParameters *codecpar = s->codecpar;
- AVCodec *dec = NULL;
bool flag = false;
- AVDictionary *avdic = NULL;
- int idle_gpu = -1;
+ AVCodecID codec_id = codecpar->codec_id;
- for (int i = 0; i < 2; ++i)
- {
- if(hw_accl_){
- idle_gpu = gpu::getGPU(100);
- if(idle_gpu < 0){
- logIt("NO GPU RESOURCE TO DECODE");
- hw_accl_ = false;
- continue;
- }
- if(codecpar->codec_id == AV_CODEC_ID_H264){
- dec = avcodec_find_decoder_by_name("h264_cuvid");
- }else if(codecpar->codec_id == AV_CODEC_ID_H265){
- dec = avcodec_find_decoder_by_name("hevc_cuvid");
- }
- if(!dec){
- hw_accl_ = false;
- continue;
- }else{
- av_dict_set(&avdic, "gpu", std::to_string(idle_gpu).c_str(), 0);
- // av_dict_set(&avdic, "gpu", std::to_string(2).c_str(), 0);
- }
- }else{
- dec = avcodec_find_decoder(codecpar->codec_id);
+ AVCodec *dec = avcodec_find_decoder(codec_id);
+
+ if(dec){
+ flag = allocCodec(dec, s, options);
+ if(*options){
+ av_dict_free(options);
}
- if(dec){
- if(avdic){
- options = &avdic;
- logIt("DECODE USE GPU %d", idle_gpu);
- }
- flag = allocCodec(dec, s, options);
- if(avdic){
- av_dict_free(&avdic);
- }
- if(flag){
- logIt("use decoder %s\n", dec->name);
- break;
- }else{
- av_free(dec_ctx_);
- dec_ctx_ = NULL;
- hw_accl_ = false;
- }
+ if(!flag){
+ av_free(dec_ctx_);
+ dec_ctx_ = NULL;
}
+
+ logIt("use decoder %s\n", dec->name);
}
-
+
return flag;
}
bool FormatIn::allocCodec(AVCodec *dec, AVStream *s, AVDictionary **options){
- AVCodecParameters *codecpar = s->codecpar;
+ AVCodecParameters *codecpar = NULL;
+ if(s) codecpar = s->codecpar;
dec_ctx_ = avcodec_alloc_context3(dec);
if (!dec_ctx_){
logIt("avcodec_alloc_context3 error");
return false;
}
- int ret = avcodec_parameters_to_context(dec_ctx_, codecpar);
- if(ret < 0){
- logIt("avcodec_parameters_to_context error : %s", getAVErrorDesc(ret).c_str());
- return false;
+ int ret = 0;
+ if(s && codecpar) {
+ ret = avcodec_parameters_to_context(dec_ctx_, codecpar);
+ if(ret < 0) {
+ logIt("avcodec_parameters_to_context error : %s", getAVErrorDesc(ret).c_str());
+ return false;
+ }
+ av_codec_set_pkt_timebase(dec_ctx_, s->time_base);
+ dec_ctx_->framerate = av_guess_frame_rate(ctx_, s, NULL);
}
- av_codec_set_pkt_timebase(dec_ctx_, s->time_base);
-
- dec_ctx_->framerate = av_guess_frame_rate(ctx_, s, NULL);
dec_ctx_->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
ret = avcodec_open2(dec_ctx_,dec, options);
@@ -244,53 +204,59 @@
return true;
}
- AVStream *FormatIn::getStream(int type){
- return ctx_->streams[vs_idx_];
+ AVStream *FormatIn::getStream(int type/*=-1*/){
+ if (vs_idx_ < 0 || !ctx_ || ctx_->nb_streams == 0 || !ctx_->streams) return NULL;
+
+ if (type == -1){
+ return ctx_->streams[vs_idx_];
+ }
+
+ if (vs_idx_ > -1 && type == ctx_->streams[vs_idx_]->codecpar->codec_type)
+ return ctx_->streams[vs_idx_];
+ if (as_idx_ > -1 && 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 true;
-
+ return false;
}
- bool FormatIn::readPacket(std::shared_ptr<CodedData> &data, int stream_index){
-
- AVPacket &pkt(data->getAVPacket());
- return readPacket(pkt, getStream()->index);
+ bool FormatIn::isAudioPkt(AVPacket *pkt){
+ if (pkt->stream_index == as_idx_){
+ return true;
+ }
+ return false;
}
- int FormatIn::decode(AVFrame* &frame, AVPacket &pkt){
+ bool FormatIn::notVideoAudio(AVPacket *pkt){
+ return !isVideoPkt(pkt) && !isAudioPkt(pkt);
+ }
+
+ int FormatIn::readPacket(AVPacket *pkt_out){
+ auto flag = av_read_frame(ctx_, pkt_out);
+ if (flag < 0)
+ logIt("======>> av_read_frame error %s", getAVErrorDesc(flag).c_str());
+ return flag;
+ }
+
+ int FormatIn::decode(AVFrame* frame, AVPacket *pkt){
AVStream *in = getStream();
-
- av_packet_rescale_ts(&pkt, in->time_base, in->codec->time_base);
- int ret = avcodec_send_packet(dec_ctx_, &pkt);
+ if (in){
+ av_packet_rescale_ts(pkt, in->time_base, in->codec->time_base);
+ }
+ int ret = avcodec_send_packet(dec_ctx_, pkt);
if(ret < 0){
- logIt("avcodec_send_packet error : %s", getAVErrorDesc(ret).c_str());
+ logIt("pkt size %d avcodec_send_packet error : %s", pkt->size, getAVErrorDesc(ret).c_str());
return -1;
}
while (ret >= 0) {
@@ -301,39 +267,188 @@
logIt("decode frame failed : %s", getAVErrorDesc(ret).c_str());
return -1;
}else{
- return 1;
+ return 0;
}
}
+ return -2;
+ }
+
+//////////////////////////////////////////////////////////////////////
+ constexpr int bs = 8192;
+ FormatInGB::FormatInGB()
+ :FormatIn()
+ ,gb28181_(NULL)
+ ,parser_ctx_(NULL)
+ ,buffer_(NULL)
+ ,buffer_size_(bs)
+ {
+ buffer_ = (unsigned char*)malloc(buffer_size_);
+ }
+
+ FormatInGB::FormatInGB(const VideoProp &prop)
+ :FormatInGB()
+ {
+ prop_ = new VideoProp;
+ *prop_ = prop;
+ }
+
+ FormatInGB::~FormatInGB(){
+ if (parser_ctx_){
+ av_parser_close(parser_ctx_);
+ }
+ if (gb28181_)delete gb28181_;
+ if (buffer_) free(buffer_);
+
+ for(auto &pkt : q_pkt_){
+ av_packet_free(&pkt);
+ }
+ q_pkt_.clear();
+ }
+
+ static enum AVCodecID codecMap(const int c){
+ switch (c) {
+ case E_VIDEO_STREAM_H264:// = 0,
+ return AV_CODEC_ID_H264;
+ case E_VIDEO_STREAM_MPEG2:// = 1, // MPEG4
+ // return AV_CODEC_ID_MPEG2VIDEO;
+ case E_VIDEO_STREAM_MPEG4:// = 2, // MPEG4
+ return AV_CODEC_ID_MPEG4;
+ case E_VIDEO_STREAM_SVAC:// = 3, // SVAC
+ return AV_CODEC_ID_NONE;
+ case E_VIDEO_STREAM_3GP:// = 4, // 3GP
+ return AV_CODEC_ID_NONE; // audio
+ case E_VIDEO_STREAM_H265:// = 5, //H265
+ return AV_CODEC_ID_HEVC;
+ default:
+ break;
+ }
+ return AV_CODEC_ID_NONE;
+ }
+
+ int FormatInGB::open(const char *filename, AVDictionary **options){
+ if (gb28181_){
+ delete gb28181_;
+ }
+
+ gb28181_ = new GB28181API;
+ std::string fn = filename;
+
+ if(gb28181_->addCamera(fn) < 0){
+ delete gb28181_;
+ gb28181_ = NULL;
+ logIt("do addCamera Error\n");
+ return -1;
+ }
+ for(int i = 0; i < 6; i++){
+ if (gb28181_->getDataType() >= 0){
+ AVCodecID id = codecMap(gb28181_->getDataType());
+ logIt("======>>codec name %s\n", avcodec_get_name(id));
+ parser_ctx_ = av_parser_init(id);
+ if (parser_ctx_) parser_ctx_->flags |= PARSER_FLAG_USE_CODEC_TS;
+ AVCodec* dec = avcodec_find_decoder(id);
+ allocCodec(dec, NULL, NULL);
+ break;
+ }
+ usleep(1000000);
+ }
return 0;
}
- int FormatIn::decode(std::shared_ptr<FrameData> &frame_data,
- std::shared_ptr<CodedData> &data){
-
- AVFrame *frame = frame_data->getAVFrame();
- AVPacket &pkt(data->getAVPacket());
-
- return decode(frame, pkt);
- }
-
- int FormatIn::readFrame(AVFrame* &frame){
-
- auto data(std::make_shared<CodedData>());
- if(!readPacket(data)){
- return -1;
+ int FormatInGB::readPacket(AVPacket *pkt_out){
+ if (!q_pkt_.empty()){
+ auto pkt = q_pkt_.front();
+ q_pkt_.pop_front();
+ av_packet_ref(pkt_out, pkt);
+ av_packet_free(&pkt);
+ return 0;
}
- AVPacket &pkt(data->getAVPacket());
+ if (gb28181_->getDataType() < 0){
+ logIt("======>> readPacket can't recv gb28181 stream");
+ return 1;
+ }
+ if (!parser_ctx_){
+ AVCodecID id = codecMap(gb28181_->getDataType());
+ parser_ctx_ = av_parser_init(id);
+ AVCodec* dec = avcodec_find_decoder(id);
+ allocCodec(dec, NULL, NULL);
+ }
+ if (parser_ctx_ && dec_ctx_){
- return decode(frame, pkt);
+ int try_run = 0;
+ AVPacket* pkt = av_packet_alloc();
+ bool got_pkt = false;
+
+ while (true) {
+ int data_size = gb28181_->readData(gb28181_, buffer_, buffer_size_);
+ // printf("======>> data_size %d pos %d\n", data_size, buffer_pos_);
+ if (data_size == 0){
+ try_run ++;
+ if (try_run > 12){
+ av_packet_free(&pkt);
+ logIt("gb28181_ readData %d failed, return -1", try_run);
+ return -1;
+ }
+ continue;
+ }
+ try_run = 0;
+ unsigned char* data = buffer_;
+ while (data_size > 0) {
+ int ret = av_parser_parse2(parser_ctx_, dec_ctx_,
+ &pkt->data, &pkt->size, data, data_size,
+ AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
+
+ // logIt("======>> av_parser_parse2 ret %d pkt size %d", ret, pkt->size);
+ if (ret < 0) {
+ av_packet_free(&pkt);
+ logIt("======>> av_parser_parse2 error %d %s", ret, getAVErrorDesc(ret).c_str());
+ return ret;
+ }
+
+ data += ret;
+ data_size -= ret;
+
+ if (pkt->size){
+ if(fps_ == 0 && dec_ctx_->framerate.den > 0 && dec_ctx_->framerate.num > 0){
+ fps_ = dec_ctx_->framerate.num/dec_ctx_->framerate.den;
+ if (fps_ == 0) fps_ = 24;
+ }
+ if (parser_ctx_->key_frame == 1){
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ }
+ got_pkt = true;
+ AVPacket* tmpkt = av_packet_alloc();
+ av_packet_ref(tmpkt, pkt);
+ q_pkt_.push_back(tmpkt);
+ }
+ }
+ if (got_pkt) {
+ av_packet_free(&pkt);
+ auto tmpkt = q_pkt_.front();
+ q_pkt_.pop_front();
+ av_packet_ref(pkt_out, tmpkt);
+ av_packet_free(&tmpkt);
+ return 0;
+ }
+ }
+ }
+ return -1;
}
- int FormatIn::readFrame(std::shared_ptr<FrameData> &frame_data){
-
- AVFrame *frame(frame_data->getAVFrame());
-
- return readFrame(frame);
+ const bool FormatInGB::IsHEVC()const{
+ if (!gb28181_) return false;
+ return codecMap(gb28181_->getDataType()) == AV_CODEC_ID_HEVC;
}
+ const bool FormatInGB::IsAVC1()const{
+ return false;
+ }
+
+ bool FormatInGB::isVideoPkt(AVPacket *pkt) {
+ return true;
+ }
+ bool FormatInGB::isAudioPkt(AVPacket *pkt) {
+ return false;
+ }
}
--
Gitblit v1.8.0