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 |  373 ++++++++++++++++++++++++++++++----------------------
 1 files changed, 216 insertions(+), 157 deletions(-)

diff --git a/csrc/ffmpeg/format/FormatIn.cpp b/csrc/ffmpeg/format/FormatIn.cpp
index b827eb6..120e2c7 100644
--- a/csrc/ffmpeg/format/FormatIn.cpp
+++ b/csrc/ffmpeg/format/FormatIn.cpp
@@ -21,7 +21,6 @@
 #include "../property/VideoProp.hpp"
 
 #include "../../common/gpu/info.h"
-
 using namespace logif;
 
 namespace ffwrapper{
@@ -31,30 +30,14 @@
 	,vs_idx_(-1)
 	,as_idx_(-1)
 	,prop_(NULL)
-	,hw_accl_(hw)
 	,io_ctx_(NULL)
 	,read_io_buff_(NULL)
 	,read_io_buff_size_(32768)
-#ifdef GB28181
-	,handle_gb28181(NULL)
-#endif
 	,fps_(25.0)
 	{}
 
 	FormatIn::FormatIn(const VideoProp &prop, bool hw/*=true*/)
-	:ctx_(NULL)
-	,dec_ctx_(NULL)
-	,vs_idx_(-1)
-	,as_idx_(-1)
-	,prop_(NULL)
-	,hw_accl_(hw)
-	,io_ctx_(NULL)
-	,read_io_buff_(NULL)
-	,read_io_buff_size_(32768)
-#ifdef GB28181
-	,handle_gb28181(NULL)
-#endif
-	,fps_(25.0)
+	:FormatIn(hw)
 	{
 		prop_ = new VideoProp;
 		*prop_ = prop;
@@ -76,21 +59,13 @@
 			ctx_ = NULL;
 		}
 
-#ifdef GB28181
-		if (handle_gb28181){
-			delete handle_gb28181;
-		}
-#endif
-
 		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*/){
 		read_io_buff_ = (uint8_t*)av_malloc(read_io_buff_size_);
 		if(!read_io_buff_){
@@ -112,67 +87,19 @@
 
 		ctx_->pb = io_ctx_;
 
-		// auto err = av_probe_input_buffer(ctx_->pb, &ctx_->iformat, NULL, NULL, 0, 0);
-		// if(err != 0){
-		// 	logIt("open with custom io prob input buffer error:%d err: %s\n", err, getAVErrorDesc(err).c_str());
-		// 	return -1;
-		// }
-
 		return 0;
 	}
 
-#ifdef GB28181
-	int FormatIn::openGb28181(const char *filename, AVDictionary **options){
-
-	    std::string fn = filename;
-		//GB28181API gb28181(fn);
-		if (handle_gb28181){
-			delete handle_gb28181;
-		}
-		handle_gb28181 = new GB28181API;
-		if(handle_gb28181->addCamera(fn) == -1){
-			logIt("do addCamera Error\n");
-			return -1;
-		}
-
-        int ret = openWithCustomIO(handle_gb28181, handle_gb28181->readData, options);
-        if(ret < 0){
-            logIt("do openWithCustomIO failed:%d",ret);
-        }else{
-        	ret = avformat_open_input(&ctx_, "", NULL, options);
-		}
-
-        // if(ret < 0){
-            // logIt("open %s failed:%s",filename,
-            //       getAVErrorDesc(ret).c_str());
-        // }
-
-		return ret;
-	}
-#endif
-/////////////////////////////////////////////////////////////////////////
 	int FormatIn::open(const char *filename, AVDictionary **options){
 
-		const int ret = avformat_open_input(&ctx_, filename, NULL, options);
-		// if(ret < 0){
-		// 	logIt("open %s failed:%s",filename,
-		// 			getAVErrorDesc(ret).c_str());
-		// }
+		int ret = avformat_open_input(&ctx_, filename, NULL, options);
 
-		return ret;
-	}
-
-	bool FormatIn::findStreamInfo(AVDictionary **options){
-
-		const int ret = avformat_find_stream_info(ctx_, 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 false;
+			return ret;
 		}
-
-		// logIt("there are %d stream", ctx_->nb_streams);
 
 		for (int i = 0; i < ctx_->nb_streams; ++i)
 		{
@@ -188,13 +115,11 @@
             	}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);
-
-
+				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);
+				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
@@ -202,7 +127,7 @@
 			}
 		}
 
-		return true;
+		return 0;
 	}
 
 	const bool FormatIn::IsHEVC()const{
@@ -220,81 +145,29 @@
 	}
 
 	bool FormatIn::openCodec(AVDictionary **options){
+		if (dec_ctx_) return true;
 		if (vs_idx_ == -1) return false;
 
 		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;
 
-		srand((unsigned)time(NULL));
+        AVCodec *dec = avcodec_find_decoder(codec_id);
 
-constexpr int need = 350; // M
-constexpr int reserved = 512; // M
-
-		for (int i = 0; i < 2; ++i)
-		{
-			if(hw_accl_){
-
-				// 璁剧疆gpu index
-            	if (prop_->gpu_index_ > -1){
-            		if (!gpu::satisfy(prop_->gpu_index_, need, reserved)){
-            			hw_accl_ = false;
-            			continue;
-            		}
-            	    idle_gpu = prop_->gpu_index_;
-            	}else{
-                	idle_gpu = gpu::getGPUPrior(need, reserved, 0);
-                	// idle_gpu = gpu::getGPU(300);
-					usleep(2000000 + rand()%3000000);
-					if (!gpu::satisfy(idle_gpu, need, reserved)){
-            			hw_accl_ = false;
-            			continue;
-            		}
-            	}
-
-                if(idle_gpu < 0){
-                    logIt("NO GPU RESOURCE TO DECODE");
-                    hw_accl_ = false;
-                    continue;
-                }
-
-				std::string codec_name(avcodec_get_name(codecpar->codec_id));
-				codec_name += "_cuvid";
-				dec = avcodec_find_decoder_by_name(codec_name.c_str());
-
-            	if(!dec){
-            		hw_accl_ = false;
-            		continue;
-            	}else{
-            		av_dict_set(&avdic, "gpu", std::to_string(idle_gpu).c_str(), 0);
-            	}
-			}else{
-            	dec = avcodec_find_decoder(codecpar->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;
@@ -302,21 +175,24 @@
 
 	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);
@@ -329,6 +205,8 @@
 	}
 
 	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_];
 		}
@@ -364,16 +242,18 @@
 	}
 	
 	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);
+		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("pkt size %d avcodec_send_packet error : %s", pkt->size, getAVErrorDesc(ret).c_str());
@@ -392,4 +272,183 @@
         }
 		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 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;
+		}
+
+		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_){
+
+			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;
+	}
+
+	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