#ifndef COMMONFFMPEGFUNC_HPP
|
#define COMMONFFMPEGFUNC_HPP
|
|
#include <basic/debug/Debug.h>
|
|
#ifdef __cplusplus
|
extern "C" {
|
#endif
|
|
#include <libavcodec/avcodec.h>
|
#include <libavdevice/avdevice.h>
|
#include <libavformat/avformat.h>
|
#include <libavfilter/avfilter.h>
|
#include <libavutil/avutil.h>
|
#include <libswscale/swscale.h>
|
|
#include <stdlib.h>
|
#include <stdio.h>
|
#include <string.h>
|
#include <math.h>
|
|
|
#ifdef __cplusplus
|
}
|
#endif
|
|
class CommonFFmpeg
|
{
|
public:
|
CommonFFmpeg():m_pInFmtCtx(nullptr),m_pInVideoStream(nullptr),m_pDict(nullptr){}
|
~CommonFFmpeg(){}
|
|
public:
|
void init()
|
{
|
av_register_all();
|
avformat_network_init();
|
}
|
int rtspInputOpen(const char* rtsp)
|
{
|
av_dict_set(&m_pDict, "rtsp_transport", "tcp", 0);
|
int ret = avformat_open_input(&m_pInFmtCtx, rtsp, NULL, &m_pDict);
|
if (ret!=0)
|
{
|
fprintf(stderr, "could not open input file, ret: %d,info: %x\n",ret,AVERROR(ret));
|
return ret;
|
}
|
ret = avformat_find_stream_info(m_pInFmtCtx, NULL);
|
if (ret<0)
|
{
|
fprintf(stderr, "could not find stream info\n");
|
return ret;
|
}
|
|
/* find first video stream */
|
for (unsigned i=0; i<m_pInFmtCtx->nb_streams; i++)
|
{
|
if (m_pInFmtCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
|
{
|
m_pInVideoStream = m_pInFmtCtx->streams[i];
|
break;
|
}
|
}
|
if (m_pInVideoStream == NULL)
|
{
|
fprintf(stderr, "didn't find any video stream\n");
|
return -1;
|
}
|
return 0;
|
}
|
void rtspInputClose()
|
{
|
if(m_pInFmtCtx!=nullptr)
|
avformat_close_input(&m_pInFmtCtx);
|
if(m_pDict!=nullptr)
|
av_dict_free(&m_pDict);
|
}
|
|
void* rtspCreatePkg()
|
{
|
//g_pkg.lock();
|
mutex().lock();
|
AVPacket* pkt = nullptr;
|
try{pkt=new AVPacket();av_init_packet(pkt);}
|
catch (...){if(pkt!=nullptr){delete pkt;pkt=nullptr;}}
|
//g_pkg.unlock();
|
mutex().unlock();
|
return pkt;
|
}
|
void rtspDestroyPkg(void* packet)
|
{
|
mutex().lock();
|
if(packet!=nullptr)
|
{
|
AVPacket* pkg = static_cast<AVPacket*>(packet);
|
av_free_packet(pkg);
|
delete pkg;
|
pkg = nullptr;
|
}
|
mutex().unlock();
|
}
|
|
int rtspReadPkg(void* packet)
|
{
|
mutex().lock();
|
int ret = -1;
|
if(packet!=nullptr)
|
{
|
AVPacket* pkg = static_cast<AVPacket*>(packet);
|
ret = av_read_frame(m_pInFmtCtx, pkg);
|
}
|
mutex().unlock();
|
return ret;
|
}
|
|
void* getRtspStream()
|
{
|
return (void*)m_pInVideoStream;
|
}
|
|
int fileOutOpen(const char* filename,void* inStream)
|
{
|
AVStream* pInstream = (AVStream*)inStream;
|
if(pInstream==nullptr)
|
{DBG("instream is null");return -1;}
|
int ret = avformat_alloc_output_context2(&m_pOutFmtCtx, NULL, NULL, filename);
|
if(ret<0)
|
{
|
fprintf(stderr, "avformat_alloc_output_context2 failed, errorCode: %d\n",AVERROR(ret));
|
return -1;
|
}
|
/*
|
* since all input files are supposed to be identical (framerate, dimension, color format, ...)
|
* we can safely set output codec values from first input file
|
*/
|
m_pOutVideo_stream = avformat_new_stream(m_pOutFmtCtx, NULL);
|
{
|
AVCodecContext *c;
|
c = m_pOutVideo_stream->codec;
|
c->bit_rate = 400000;
|
c->codec_id = pInstream->codec->codec_id;
|
c->codec_type = pInstream->codec->codec_type;
|
c->time_base.num = pInstream->time_base.num;
|
c->time_base.den = pInstream->time_base.den;
|
fprintf(stderr, "time_base.num = %d time_base.den = %d\n", c->time_base.num, c->time_base.den);
|
c->width = pInstream->codec->width;
|
c->height = pInstream->codec->height;
|
c->pix_fmt = pInstream->codec->pix_fmt;
|
printf("%d %d %d", c->width, c->height, c->pix_fmt);
|
c->flags = pInstream->codec->flags;
|
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
c->me_range = pInstream->codec->me_range;
|
c->max_qdiff = pInstream->codec->max_qdiff;
|
|
c->qmin = pInstream->codec->qmin;
|
c->qmax = pInstream->codec->qmax;
|
|
c->qcompress = pInstream->codec->qcompress;
|
}
|
ret =avio_open(&m_pOutFmtCtx->pb, filename, AVIO_FLAG_WRITE);
|
if(ret<0)
|
{
|
fprintf(stderr, "could not find stream info, errorCode: %d\n",AVERROR(ret));
|
return -1;
|
}
|
|
avformat_write_header(m_pOutFmtCtx, NULL);
|
}
|
|
void fileOutClose()
|
{
|
av_write_trailer(m_pOutFmtCtx);
|
avio_close(m_pOutFmtCtx->pb);
|
avcodec_close(m_pOutFmtCtx->streams[0]->codec);
|
av_freep(&m_pOutFmtCtx->streams[0]->codec);
|
av_freep(&m_pOutFmtCtx->streams[0]);
|
|
av_free(m_pOutFmtCtx);
|
m_pOutFmtCtx = nullptr;
|
}
|
|
int fileWritePkg(void* packet)
|
{
|
mutex().lock();
|
int ret = -1;
|
if(packet!=nullptr)
|
{
|
AVPacket* pkg = static_cast<AVPacket*>(packet);
|
//av_interleaved_write_frame(thisPtr->m_pOutFmtCtx, &i_pkt);
|
ret = av_write_frame(m_pOutFmtCtx, pkg);
|
}
|
mutex().unlock();
|
return ret;
|
}
|
|
bool isKeyFrame(void* packet)
|
{
|
bool ret = false;
|
if(packet!=nullptr)
|
{
|
AVPacket* pkg = static_cast<AVPacket*>(packet);
|
if(pkg->flags&AV_PKT_FLAG_KEY) ret = true;
|
}
|
return ret;
|
}
|
|
long int getPkgDts(void* packet)
|
{
|
long int ret = 0;
|
if(packet!=nullptr)
|
{
|
AVPacket* pkg = static_cast<AVPacket*>(packet);
|
ret = pkg->dts;
|
}
|
return ret;
|
}
|
long int getPkgPts(void* packet)
|
{
|
long int ret = 0;
|
if(packet!=nullptr)
|
{
|
AVPacket* pkg = static_cast<AVPacket*>(packet);
|
ret = pkg->pts;
|
}
|
return ret;
|
}
|
|
void conversion(void* packet,const long int& firstKeyPts,const long int& firstKeyDts,void* inVideoStream)
|
{
|
mutex().lock();
|
if((packet!=nullptr)&&(inVideoStream!=nullptr))
|
{
|
AVStream* inStream = (AVStream*)inVideoStream;
|
AVPacket* pkg = static_cast<AVPacket*>(packet);
|
pkg->pts -= firstKeyPts;
|
pkg->dts -= firstKeyDts;
|
pkg->pts = av_rescale_q_rnd(pkg->pts, inStream->time_base,
|
m_pOutVideo_stream->time_base,
|
(AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
|
pkg->dts = av_rescale_q_rnd(pkg->dts, inStream->time_base,
|
m_pOutVideo_stream->time_base,
|
(AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
|
pkg->duration = av_rescale_q(pkg->duration, inStream->time_base,
|
m_pOutVideo_stream->time_base);
|
pkg->pos = -1;
|
}
|
mutex().unlock();
|
}
|
|
private:
|
AVFormatContext * m_pInFmtCtx;
|
AVStream *m_pInVideoStream;
|
AVDictionary *m_pDict;
|
|
AVFormatContext *m_pOutFmtCtx;
|
AVStream *m_pOutVideo_stream;
|
//static std::mutex g_pkg;
|
inline static int& n() { static int tn = 0; return tn;}
|
|
inline static std::mutex& mutex(){static std::mutex mtx;return mtx;}
|
|
};
|
#endif
|
//std::mutex CommonFFmpeg::g_pkg;
|