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