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 | 408 +++++++++++++++++++++++++++++++++++++--------------------
1 files changed, 262 insertions(+), 146 deletions(-)
diff --git a/csrc/ffmpeg/format/FormatIn.cpp b/csrc/ffmpeg/format/FormatIn.cpp
index 59f3f23..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,7 +12,7 @@
#include <libavutil/opt.h>
#include <libavutil/avassert.h>
#include <libavutil/imgutils.h>
-#include <libswscale/swscale.h>
+#include <libswscale/swscale.h>
}
#include "../log/log.hpp"
@@ -19,7 +21,6 @@
#include "../property/VideoProp.hpp"
#include "../../common/gpu/info.h"
-
using namespace logif;
namespace ffwrapper{
@@ -28,46 +29,43 @@
,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()
+ FormatIn::FormatIn(const VideoProp &prop, bool hw/*=true*/)
+ :FormatIn(hw)
{
- if(ctx_){
- if (!(ctx_->flags & AVFMT_FLAG_CUSTOM_IO)){
- avformat_close_input(&ctx_);
- }else{
- avformat_free_context(ctx_);
- }
-
- ctx_ = NULL;
- if(dec_ctx_){
- avcodec_close(dec_ctx_);
- dec_ctx_ = NULL;
- }
-
- }
-
- if (handle_gb28181){
- delete handle_gb28181;
- }
- if(read_io_buff_){
- av_free(read_io_buff_);
- read_io_buff_ = NULL;
- }
- if(io_ctx_){
- avio_context_free(&io_ctx_);
- io_ctx_ = NULL;
- }
-
+ prop_ = new VideoProp;
+ *prop_ = prop;
}
-////////////////////////////////////////////////////////////////////////
+ FormatIn::~FormatIn()
+ {
+ 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_);
+ 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*/){
read_io_buff_ = (uint8_t*)av_malloc(read_io_buff_size_);
if(!read_io_buff_){
@@ -80,7 +78,7 @@
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");
@@ -89,66 +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;
}
- 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;
- }
-
-/////////////////////////////////////////////////////////////////////////
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)
{
@@ -163,12 +114,12 @@
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", fps_, 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){
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
@@ -176,89 +127,72 @@
}
}
- return true;
+ return 0;
}
const bool FormatIn::IsHEVC()const{
return ctx_->streams[vs_idx_]->codecpar->codec_id == AV_CODEC_ID_HEVC;
}
+ const bool FormatIn::IsAVC1()const{
+ if (IsHEVC()) return false;
+
+ 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);
- }
- }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);
@@ -271,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_];
}
@@ -306,20 +242,21 @@
}
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("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) {
@@ -335,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