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 |  472 +++++++++++++++++++++++++++++++++++------------------------
 1 files changed, 280 insertions(+), 192 deletions(-)

diff --git a/csrc/ffmpeg/format/FormatIn.cpp b/csrc/ffmpeg/format/FormatIn.cpp
index 3f87d59..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,18 +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"
-
 using namespace logif;
 
 namespace ffwrapper{
@@ -30,119 +29,83 @@
 	,dec_ctx_(NULL)
 	,vs_idx_(-1)
 	,as_idx_(-1)
-	,hw_accl_(hw)
+	,prop_(NULL)
 	,io_ctx_(NULL)
 	,read_io_buff_(NULL)
 	,read_io_buff_size_(32768)
-	,handle_gb28181(NULL)
 	,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 (handle_gb28181){
-			delete handle_gb28181;
+
+		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_->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());
+		ctx_ = avformat_alloc_context();
+		if(!ctx_){
+			logIt("open with custom io create format error\n");
 			return -1;
 		}
+
+		ctx_->pb = io_ctx_;
 
 		return 0;
 	}
 
-	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;
-		handle_gb28181->addCamera(fn);
-
-        int ret = openWithCustomIO(handle_gb28181, handle_gb28181->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;
-	}
-
-/////////////////////////////////////////////////////////////////////////
 	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;
+					ctx_->filename,getAVErrorDesc(ret).c_str());
+			return ret;
 		}
-
-		logIt("there are %d stream", ctx_->nb_streams);
 
 		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;
 
@@ -152,105 +115,84 @@
             	}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);
+				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){
-				as_idx_ = i;
-				logIt("audio stream time base %d : %d", ctx_->streams[i]->time_base.num, ctx_->streams[i]->time_base.den);
+				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 true;
+
+		return 0;
 	}
 
-	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); 
+	const bool FormatIn::IsHEVC()const{
+		return ctx_->streams[vs_idx_]->codecpar->codec_id == AV_CODEC_ID_HEVC;
+	}
 
-			return false;
-		}
+	const bool FormatIn::IsAVC1()const{
+		if (IsHEVC()) return false;
 
-		AVStream *s = ctx_->streams[stream_index];
+		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::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;
 
-		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);
@@ -263,13 +205,15 @@
 	}
 
 	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 (type == ctx_->streams[vs_idx_]->codecpar->codec_type)
+		if (vs_idx_ > -1 && type == ctx_->streams[vs_idx_]->codecpar->codec_type)
 			return ctx_->streams[vs_idx_];
-		if (type == ctx_->streams[as_idx_]->codecpar->codec_type)
+		if (as_idx_ > -1 && type == ctx_->streams[as_idx_]->codecpar->codec_type)
 			return ctx_->streams[as_idx_];
 
 		return NULL;
@@ -279,45 +223,40 @@
 		return dec_ctx_;
 	}
 	
-	bool FormatIn::isVideoPkt(AVPacket &pkt){
-		if (pkt.stream_index == vs_idx_){
+	bool FormatIn::isVideoPkt(AVPacket *pkt){
+		if (pkt->stream_index == vs_idx_){
 			return true;
 		}
 		return false;
 	}
 
-	bool FormatIn::isAudioPkt(AVPacket &pkt){
-		if (pkt.stream_index == as_idx_){
+	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::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;
 	}
 
-	bool FormatIn::readPacket(std::shared_ptr<CodedData> &data){
-
-		AVPacket &pkt(data->getAVPacket());
-		return readPacket(pkt);
-	}
-
-	int FormatIn::decode(AVFrame* &frame, AVPacket &pkt){
+	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) {
@@ -328,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