记录 FFmpeg开发常用功能封装

发布时间 2023-08-15 14:36:44作者: DoubleLi

说明

记录下个人在开发中使用到的FFmpeg常用功能,避免相同功能代码的重复编写,使用时直接复制提升效率。由于音视频处理的场景众多,无法编写完全通用的方法接口,可能需根据实际场景进行一定的修改,本文章中的代码也将持续更新优化

代码

这里提供ffmpegheader.h,ffmpegheader.cpp。配置好基本的FFmpeg库环境后,直接导入上述两个文件,即可直接使用对应功能。

更新记录

2023.05.29  优化编码时间戳为 固定累加+实时矫正

2023.06.13  优化编码类;新增时间戳处理类

1、头文件

 
 
#ifndef FFMPEGHEADER_H
 
#define FFMPEGHEADER_H
 
 
 
/**
 
* 封装常用的ffmpeg方法以及类 只需要引入文件即可直接使用 避免重复轮子
 
* By ZXT
 
*/
 
 
 
extern "C"
 
{
 
#include "./libavcodec/avcodec.h"
 
#include "./libavformat/avformat.h"
 
#include "./libavformat/avio.h"
 
#include "./libavutil/opt.h"
 
#include "./libavutil/time.h"
 
#include "./libavutil/imgutils.h"
 
#include "./libswscale/swscale.h"
 
#include "./libswresample/swresample.h"
 
#include "./libavutil/avutil.h"
 
#include "./libavutil/ffversion.h"
 
#include "./libavutil/frame.h"
 
#include "./libavutil/pixdesc.h"
 
#include "./libavutil/imgutils.h"
 
#include "./libavfilter/avfilter.h"
 
#include "./libavfilter/buffersink.h"
 
#include "./libavfilter/buffersrc.h"
 
#include "./libavdevice/avdevice.h"
 
}
 
 
 
#include <QDebug>
 
 
 
/************************************* 常用函数封装 ************************************/
 
//获取ffmpeg报错信息
 
char *getAVError(int errNum);
 
 
 
//根据pts计算实际时间us
 
int64_t getRealTimeByPTS(int64_t pts, AVRational timebase);
 
//pts转换为us差时进行延时
 
void calcAndDelay(int64_t startTime, int64_t pts, AVRational timebase);
 
 
 
//十六进制字节数组转十进制
 
int32_t hexArrayToDec(char *array, int len);
 
 
 
 
 
/************************************* 常用类封装 *************************************/
 
//视频图像转换类
 
class VideoSwser
 
{
 
public:
 
VideoSwser();
 
~VideoSwser();
 
 
 
//初始化转换器
 
bool initSwsCtx(int srcWidth, int srcHeight, AVPixelFormat srcFmt, int dstWidth, int dstHeight, AVPixelFormat dstFmt);
 
void release();
 
 
 
//返回转换格式后的AVFrame
 
AVFrame *getSwsFrame(AVFrame *srcFrame);
 
 
 
private:
 
bool hasInit;
 
bool needSws;
 
 
 
int dstWidth;
 
int dstHeight;
 
AVPixelFormat dstFmt;
 
 
 
//格式转换
 
SwsContext *videoSwsCtx;
 
};
 
 
 
//视频编码器类
 
class VideoEncoder
 
{
 
public:
 
VideoEncoder();
 
~VideoEncoder();
 
 
 
//初始化编码器
 
bool initEncoder(int width, int height, AVPixelFormat fmt, int fps);
 
void release();
 
 
 
//返回编码后AVpacket
 
AVPacket *getEncodePacket(AVFrame *srcFrame);
 
AVPacket *flushEncoder();
 
 
 
//返回编码器上下文
 
AVCodecContext *getCodecContent();
 
 
 
private:
 
bool hasInit;
 
 
 
//编码器
 
AVCodecContext *videoEnCodecCtx;
 
};
 
 
 
 
 
//音频重采样类
 
class AudioSwrer
 
{
 
public:
 
AudioSwrer();
 
~AudioSwrer();
 
 
 
//初始化转换器
 
bool initSwrCtx(int inChannels, int inSampleRate, AVSampleFormat inFmt, int outChannels, int outSampleRate, AVSampleFormat outFmt);
 
void release();
 
 
 
//返回转换格式后的AVFrame
 
AVFrame *getSwrFrame(AVFrame *srcFrame);
 
//返回转换格式后的AVFrame srcdata为一帧源格式的数据
 
AVFrame *getSwrFrame(uint8_t *srcData);
 
 
 
private:
 
bool hasInit;
 
bool needSwr;
 
 
 
int outChannels;
 
int outSampleRate;
 
AVSampleFormat outFmt;
 
 
 
//格式转换
 
SwrContext *audioSwrCtx;
 
};
 
 
 
//音频编码器类
 
class AudioEncoder
 
{
 
public:
 
AudioEncoder();
 
~AudioEncoder();
 
 
 
//初始化编码器
 
bool initEncoder(int channels, int sampleRate, AVSampleFormat sampleFmt);
 
void release();
 
 
 
//返回编码后AVpacket
 
AVPacket *getEncodePacket(AVFrame *srcFrame);
 
AVPacket *flushEncoder();
 
 
 
//返回编码器上下文
 
AVCodecContext *getCodecContent();
 
 
 
private:
 
bool hasInit;
 
 
 
//编码器
 
AVCodecContext *audioEnCodecCtx;
 
};
 
 
 
//实时采集场景时间戳处理类
 
class AVTimeStamp
 
{
 
public:
 
//累加帧间隔 优点:时间戳稳定均匀 缺点:实际采集帧率可能不稳定,固定累加或忽略小数会累加误差造成不同步
 
//实时时间戳 优点:时间戳保持实时及正确 缺点:存在帧间隔不均匀,极端情况不能正常播放
 
//累加+实时矫正 优点:时间戳实时且较为均匀 缺点:纠正时间戳的某一时刻可能画面或声音卡顿
 
enum PTSMode
 
{
 
PTS_RECTIFY = 0, //默认矫正类型 保持帧间隔尽量均匀
 
PTS_REALTIME //实时pts
 
};
 
 
 
public:
 
AVTimeStamp();
 
~AVTimeStamp();
 
 
 
//初始化时间戳参数
 
void initAudioTimeStampParm(int sampleRate, PTSMode mode = PTS_RECTIFY);
 
void initVideoTimeStampParm(int fps, PTSMode mode = PTS_RECTIFY);
 
 
 
//开始时间戳记录
 
void startTimeStamp();
 
 
 
//返回pts
 
int64_t getAudioPts();
 
int64_t getVideoPts();
 
 
 
private:
 
//当前模式
 
PTSMode aMode;
 
PTSMode vMode;
 
 
 
//时间戳相关记录 均us单位
 
int64_t startTime;
 
int64_t audioTimeStamp;
 
int64_t videoTimeStamp;
 
double audioDuration;
 
double videoDuration;
 
};
 
 
 
#endif // FFMPEGHEADER_H
 
 
 
 

2、实现文件

 
 
#include "ffmpegheader.h"
 
 
 
char *getAVError(int errNum)
 
{
 
static char msg[32] = {0};
 
av_strerror(errNum, msg, 32);
 
return msg;
 
}
 
 
 
int64_t getRealTimeByPTS(int64_t pts, AVRational timebase)
 
{
 
//pts转换为对应us值
 
AVRational timebase_q = {1, AV_TIME_BASE};
 
int64_t ptsTime = av_rescale_q(pts, timebase, timebase_q);
 
return ptsTime;
 
}
 
 
 
void calcAndDelay(int64_t startTime, int64_t pts, AVRational timebase)
 
{
 
int64_t ptsTime = getRealTimeByPTS(pts, timebase);
 
 
 
//计算startTime到此刻的时间差值
 
int64_t nowTime = av_gettime() - startTime;
 
int64_t offset = ptsTime - nowTime;
 
 
 
//大于2秒一般时间戳存在问题 延时无法挽救
 
if(offset > 1000 && offset < 2*1000*1000)
 
av_usleep(offset);
 
}
 
 
 
int32_t hexArrayToDec(char *array, int len)
 
{
 
//目前限制四字节长度 超过则注意返回类型 防止溢出
 
if(array == nullptr || len > 4)
 
return -1;
 
 
 
int32_t result = 0;
 
for(int i=0; i<len; i++)
 
result = result * 256 + (unsigned char)array[i];
 
 
 
return result;
 
}
 
 
 
 
 
VideoSwser::VideoSwser()
 
{
 
videoSwsCtx = nullptr;
 
hasInit = false;
 
needSws = false;
 
}
 
 
 
VideoSwser::~VideoSwser()
 
{
 
release();
 
}
 
 
 
bool VideoSwser::initSwsCtx(int srcWidth, int srcHeight, AVPixelFormat srcFmt, int dstWidth, int dstHeight, AVPixelFormat dstFmt)
 
{
 
release();
 
 
 
if(srcWidth == dstWidth && srcHeight == dstHeight && srcFmt == dstFmt)
 
{
 
needSws = false;
 
}
 
else
 
{
 
//设置转换上下文 srcFmt 到 dstFmt(一般为AV_PIX_FMT_YUV420P)的转换
 
videoSwsCtx = sws_getContext(srcWidth, srcHeight, srcFmt, dstWidth, dstHeight, dstFmt, SWS_BILINEAR, NULL, NULL, NULL);
 
if (videoSwsCtx == NULL)
 
{
 
qDebug() << "sws_getContext error";
 
return false;
 
}
 
 
 
this->dstFmt = dstFmt;
 
this->dstWidth = dstWidth;
 
this->dstHeight = dstHeight;
 
 
 
needSws = true;
 
}
 
 
 
hasInit = true;
 
return true;
 
}
 
 
 
void VideoSwser::release()
 
{
 
if(videoSwsCtx)
 
{
 
sws_freeContext(videoSwsCtx);
 
videoSwsCtx = nullptr;
 
}
 
 
 
hasInit = false;
 
needSws = false;
 
}
 
 
 
AVFrame *VideoSwser::getSwsFrame(AVFrame *srcFrame)
 
{
 
if(!hasInit)
 
{
 
qDebug() << "Swser未初始化";
 
return nullptr;
 
}
 
 
 
if(!srcFrame)
 
return nullptr;
 
 
 
if(!needSws)
 
return srcFrame;
 
 
 
AVFrame *frame = av_frame_alloc();
 
frame->format = dstFmt;
 
frame->width = dstWidth;
 
frame->height = dstHeight;
 
 
 
int ret = av_frame_get_buffer(frame, 0);
 
if (ret != 0)
 
{
 
qDebug() << "av_frame_get_buffer swsFrame error";
 
return nullptr;
 
}
 
 
 
ret = av_frame_make_writable(frame);
 
if (ret != 0)
 
{
 
qDebug() << "av_frame_make_writable swsFrame error";
 
return nullptr;
 
}
 
 
 
sws_scale(videoSwsCtx, (const uint8_t *const *)srcFrame->data, srcFrame->linesize, 0, dstHeight, frame->data, frame->linesize);
 
return frame;
 
}
 
 
 
 
 
VideoEncoder::VideoEncoder()
 
{
 
videoEnCodecCtx = nullptr;
 
hasInit = false;
 
}
 
 
 
VideoEncoder::~VideoEncoder()
 
{
 
release();
 
}
 
 
 
bool VideoEncoder::initEncoder(int width, int height, AVPixelFormat fmt, int fps)
 
{
 
//重置编码信息
 
release();
 
 
 
//设置编码器参数 默认AV_CODEC_ID_H264
 
AVCodec *videoEnCoder = avcodec_find_encoder(AV_CODEC_ID_H264);
 
if(!videoEnCoder)
 
{
 
qDebug() << "avcodec_find_encoder AV_CODEC_ID_H264 error";
 
return false;
 
}
 
 
 
videoEnCodecCtx = avcodec_alloc_context3(videoEnCoder);
 
if(!videoEnCodecCtx)
 
{
 
qDebug() << "avcodec_alloc_context3 AV_CODEC_ID_H264 error";
 
return false;
 
}
 
 
 
//重要!编码参数设置 应根据实际场景修改以下参数
 
videoEnCodecCtx->bit_rate = 2*1024*1024; //1080P:4Mbps 720P:2Mbps 480P:1Mbps 默认中等码率可适当增大
 
videoEnCodecCtx->width = width;
 
videoEnCodecCtx->height = height;
 
videoEnCodecCtx->framerate = {fps, 1};
 
videoEnCodecCtx->time_base = {1, AV_TIME_BASE};
 
videoEnCodecCtx->gop_size = fps;
 
videoEnCodecCtx->max_b_frames = 0;
 
videoEnCodecCtx->pix_fmt = fmt;
 
videoEnCodecCtx->thread_count = 2;
 
videoEnCodecCtx->thread_type = FF_THREAD_FRAME;
 
 
 
//设置QP最大和最小量化系数,取值范围为0~51 越大编码质量越差
 
videoEnCodecCtx->qmin = 10;
 
videoEnCodecCtx->qmax = 30;
 
 
 
//若设置此项 则sps、pps将保存在extradata;否则放置于每个I帧前
 
videoEnCodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
 
 
 
//预设参数 编码速度与压缩率的平衡 如编码快选择的算法就偏简单 压缩率低
 
//由慢到快veryslow slower slow medium fast faster veryfast superfast ultrafast 默认medium
 
int ret = av_opt_set(videoEnCodecCtx->priv_data, "preset", "ultrafast", 0);
 
if(ret != 0)
 
qDebug() << "av_opt_set preset error";
 
 
 
//偏好设置 进行视觉优化
 
//film电影 animation动画片 grain颗粒物 stillimage静止图片 psnr ssim图像评价指标 fastdecode快速解码 zerolatency零延迟
 
ret = av_opt_set(videoEnCodecCtx->priv_data, "tune", "zerolatency", 0);
 
if(ret != 0)
 
qDebug() << "av_opt_set preset error";
 
 
 
//画质设置 可能自动改变 如编码很快很难保证高画质会自动降级
 
//baseline实时通信 extended使用较少 main流媒体 high广电、存储
 
ret = av_opt_set(videoEnCodecCtx->priv_data, "profile", "main", 0);
 
if(ret != 0)
 
qDebug() << "av_opt_set preset error";
 
 
 
ret = avcodec_open2(videoEnCodecCtx, videoEnCoder, NULL);
 
if(ret != 0)
 
{
 
qDebug() << "avcodec_open2 video error";
 
return false;
 
}
 
 
 
hasInit = true;
 
return true;
 
}
 
 
 
void VideoEncoder::release()
 
{
 
if(videoEnCodecCtx)
 
{
 
avcodec_free_context(&videoEnCodecCtx);
 
videoEnCodecCtx = nullptr;
 
}
 
 
 
hasInit = false;
 
}
 
 
 
AVPacket *VideoEncoder::getEncodePacket(AVFrame *srcFrame)
 
{
 
if(!hasInit)
 
{
 
qDebug() << "VideoEncoder no init";
 
return nullptr;
 
}
 
 
 
if(!srcFrame)
 
return nullptr;
 
 
 
if(srcFrame->width != videoEnCodecCtx->width
 
|| srcFrame->height != videoEnCodecCtx->height
 
|| srcFrame->format != videoEnCodecCtx->pix_fmt)
 
{
 
qDebug() << "srcFrame不符合视频编码器设置格式";
 
return nullptr;
 
}
 
 
 
//应保证srcFrame pts为us单位
 
srcFrame->pts = av_rescale_q(srcFrame->pts, AVRational{1, AV_TIME_BASE}, videoEnCodecCtx->time_base);
 
int ret = avcodec_send_frame(videoEnCodecCtx, srcFrame);
 
if (ret != 0)
 
return nullptr;
 
 
 
//接收者负责释放packet
 
AVPacket *packet = av_packet_alloc();
 
ret = avcodec_receive_packet(videoEnCodecCtx, packet);
 
if (ret != 0)
 
{
 
av_packet_free(&packet);
 
return nullptr;
 
}
 
 
 
return packet;
 
}
 
 
 
AVPacket *VideoEncoder::flushEncoder()
 
{
 
if(!hasInit)
 
{
 
qDebug() << "VideoEncoder no init";
 
return nullptr;
 
}
 
 
 
int ret = avcodec_send_frame(videoEnCodecCtx, NULL);
 
if (ret != 0)
 
return nullptr;
 
 
 
//接收者负责释放packet
 
AVPacket *packet = av_packet_alloc();
 
ret = avcodec_receive_packet(videoEnCodecCtx, packet);
 
if (ret != 0)
 
{
 
av_packet_free(&packet);
 
return nullptr;
 
}
 
 
 
return packet;
 
}
 
 
 
AVCodecContext *VideoEncoder::getCodecContent()
 
{
 
return videoEnCodecCtx;
 
}
 
 
 
 
 
AudioSwrer::AudioSwrer()
 
{
 
audioSwrCtx = nullptr;
 
hasInit = false;
 
needSwr = false;
 
}
 
 
 
AudioSwrer::~AudioSwrer()
 
{
 
release();
 
}
 
 
 
bool AudioSwrer::initSwrCtx(int inChannels, int inSampleRate, AVSampleFormat inFmt, int outChannels, int outSampleRate, AVSampleFormat outFmt)
 
{
 
release();
 
 
 
if(inChannels == outChannels && inSampleRate == outSampleRate && inFmt == outFmt)
 
{
 
needSwr = false;
 
}
 
else
 
{
 
audioSwrCtx = swr_alloc_set_opts(NULL, av_get_default_channel_layout(outChannels), outFmt, outSampleRate,
 
av_get_default_channel_layout(inChannels), inFmt, inSampleRate, 0, NULL);
 
if (!audioSwrCtx)
 
{
 
qDebug() << "swr_alloc_set_opts failed!";
 
return false;
 
}
 
 
 
int ret = swr_init(audioSwrCtx);
 
if (ret != 0)
 
{
 
qDebug() << "swr_init error";
 
swr_free(&audioSwrCtx);
 
return false;
 
}
 
 
 
this->outFmt = outFmt;
 
this->outChannels = outChannels;
 
this->outSampleRate = outSampleRate;
 
 
 
needSwr = true;
 
}
 
 
 
hasInit = true;
 
return true;
 
}
 
 
 
void AudioSwrer::release()
 
{
 
if(audioSwrCtx)
 
{
 
swr_free(&audioSwrCtx);
 
audioSwrCtx = nullptr;
 
}
 
 
 
hasInit = false;
 
needSwr = false;
 
}
 
 
 
AVFrame *AudioSwrer::getSwrFrame(AVFrame *srcFrame)
 
{
 
if(!hasInit)
 
{
 
qDebug() << "Swrer未初始化";
 
return nullptr;
 
}
 
 
 
if(!srcFrame)
 
return nullptr;
 
 
 
if(!needSwr)
 
return srcFrame;
 
 
 
AVFrame *frame = av_frame_alloc();
 
frame->format = outFmt;
 
frame->channels = outChannels;
 
frame->channel_layout = av_get_default_channel_layout(outChannels);
 
frame->nb_samples = 1024; //默认aac
 
 
 
int ret = av_frame_get_buffer(frame, 0);
 
if (ret != 0)
 
{
 
qDebug() << "av_frame_get_buffer audio error";
 
return nullptr;
 
}
 
 
 
ret = av_frame_make_writable(frame);
 
if (ret != 0)
 
{
 
qDebug() << "av_frame_make_writable swrFrame error";
 
return nullptr;
 
}
 
 
 
const uint8_t **inData = (const uint8_t **)srcFrame->data;
 
swr_convert(audioSwrCtx, frame->data, frame->nb_samples, inData, frame->nb_samples);
 
return frame;
 
}
 
 
 
AVFrame *AudioSwrer::getSwrFrame(uint8_t *srcData)
 
{
 
if(!hasInit)
 
{
 
qDebug() << "Swrer未初始化";
 
return nullptr;
 
}
 
 
 
if(!srcData)
 
return nullptr;
 
 
 
if(!needSwr)
 
return nullptr;
 
 
 
AVFrame *frame = av_frame_alloc();
 
frame->format = outFmt;
 
frame->channels = outChannels;
 
frame->sample_rate = outSampleRate;
 
frame->channel_layout = av_get_default_channel_layout(outChannels);
 
frame->nb_samples = 1024; //默认aac
 
 
 
int ret = av_frame_get_buffer(frame, 0);
 
if (ret != 0)
 
{
 
qDebug() << "av_frame_get_buffer audio error";
 
return nullptr;
 
}
 
 
 
ret = av_frame_make_writable(frame);
 
if (ret != 0)
 
{
 
qDebug() << "av_frame_make_writable swrFrame error";
 
return nullptr;
 
}
 
 
 
const uint8_t *indata[AV_NUM_DATA_POINTERS] = {0};
 
indata[0] = srcData;
 
swr_convert(audioSwrCtx, frame->data, frame->nb_samples, indata, frame->nb_samples);
 
return frame;
 
}
 
 
 
AudioEncoder::AudioEncoder()
 
{
 
audioEnCodecCtx = nullptr;
 
hasInit = false;
 
}
 
 
 
AudioEncoder::~AudioEncoder()
 
{
 
release();
 
}
 
 
 
bool AudioEncoder::initEncoder(int channels, int sampleRate, AVSampleFormat sampleFmt)
 
{
 
release();
 
 
 
//初始化音频编码器相关 默认AAC
 
AVCodec *audioEnCoder = avcodec_find_encoder(AV_CODEC_ID_AAC);
 
if (!audioEnCoder)
 
{
 
qDebug() << "avcodec_find_encoder AV_CODEC_ID_AAC failed!";
 
return false;
 
}
 
 
 
audioEnCodecCtx = avcodec_alloc_context3(audioEnCoder);
 
if (!audioEnCodecCtx)
 
{
 
qDebug() << "avcodec_alloc_context3 AV_CODEC_ID_AAC failed!";
 
return false;
 
}
 
 
 
//ffmpeg -h encoder=aac 自带编码器仅支持AV_SAMPLE_FMT_FLTP 大多数AAC编码器都采用平面布局格式 提高数据访问效率和缓存命中率 加快编码效率
 
//音频数据量偏小 设置较为简单
 
audioEnCodecCtx->bit_rate = 64*1024;
 
audioEnCodecCtx->time_base = AVRational{1, sampleRate};
 
audioEnCodecCtx->sample_rate = sampleRate;
 
audioEnCodecCtx->sample_fmt = sampleFmt;
 
audioEnCodecCtx->channels = channels;
 
audioEnCodecCtx->channel_layout = av_get_default_channel_layout(channels);
 
audioEnCodecCtx->frame_size = 1024;
 
 
 
//打开音频编码器
 
int ret = avcodec_open2(audioEnCodecCtx, audioEnCoder, NULL);
 
if (ret != 0)
 
{
 
qDebug() << "avcodec_open2 audio error" << getAVError(ret);
 
return false;
 
}
 
 
 
hasInit = true;
 
return true;
 
}
 
 
 
void AudioEncoder::release()
 
{
 
if(audioEnCodecCtx)
 
{
 
avcodec_free_context(&audioEnCodecCtx);
 
audioEnCodecCtx = nullptr;
 
}
 
 
 
hasInit = false;
 
}
 
 
 
AVPacket *AudioEncoder::getEncodePacket(AVFrame *srcFrame)
 
{
 
if(!hasInit)
 
{
 
qDebug() << "AudioEncoder no init";
 
return nullptr;
 
}
 
 
 
if(!srcFrame)
 
return nullptr;
 
 
 
if(srcFrame->channels != audioEnCodecCtx->channels
 
|| srcFrame->sample_rate != audioEnCodecCtx->sample_rate
 
|| srcFrame->format != audioEnCodecCtx->sample_fmt)
 
{
 
qDebug() << "srcFrame不符合音频编码器设置格式";
 
return nullptr;
 
}
 
 
 
//应保证srcFrame pts为us单位
 
srcFrame->pts = av_rescale_q(srcFrame->pts, AVRational{1, AV_TIME_BASE}, audioEnCodecCtx->time_base);
 
 
 
//进行音频编码得到编码数据AVPacket
 
int ret = avcodec_send_frame(audioEnCodecCtx, srcFrame);
 
if (ret != 0)
 
return nullptr;
 
 
 
//接收者负责释放packet
 
AVPacket *packet = av_packet_alloc();
 
ret = avcodec_receive_packet(audioEnCodecCtx, packet);
 
if (ret != 0)
 
{
 
av_packet_free(&packet);
 
return nullptr;
 
}
 
 
 
return packet;
 
}
 
 
 
AVPacket *AudioEncoder::flushEncoder()
 
{
 
if(!hasInit)
 
{
 
qDebug() << "AudioEncoder no init";
 
return nullptr;
 
}
 
 
 
int ret = avcodec_send_frame(audioEnCodecCtx, NULL);
 
if (ret != 0)
 
return nullptr;
 
 
 
//接收者负责释放packet
 
AVPacket *packet = av_packet_alloc();
 
ret = avcodec_receive_packet(audioEnCodecCtx, packet);
 
if (ret != 0)
 
{
 
av_packet_free(&packet);
 
return nullptr;
 
}
 
 
 
return packet;
 
}
 
 
 
AVCodecContext *AudioEncoder::getCodecContent()
 
{
 
return audioEnCodecCtx;
 
}
 
 
 
AVTimeStamp::AVTimeStamp()
 
{
 
aMode = PTS_RECTIFY;
 
vMode = PTS_RECTIFY;
 
startTime = 0;
 
audioTimeStamp = 0;
 
videoTimeStamp = 0;
 
 
 
//默认视频264编码 25帧
 
videoDuration = 1000000 / 25;
 
//默认音频aac编码 44100采样率
 
audioDuration = 1000000 / (44100 / 1024);
 
}
 
 
 
AVTimeStamp::~AVTimeStamp()
 
{
 
 
 
}
 
 
 
void AVTimeStamp::initAudioTimeStampParm(int sampleRate, AVTimeStamp::PTSMode mode)
 
{
 
aMode = mode;
 
audioDuration = 1000000 / (sampleRate / 1024);
 
}
 
 
 
void AVTimeStamp::initVideoTimeStampParm(int fps, AVTimeStamp::PTSMode mode)
 
{
 
vMode = mode;
 
videoDuration = 1000000 / fps;
 
}
 
 
 
void AVTimeStamp::startTimeStamp()
 
{
 
audioTimeStamp = 0;
 
videoTimeStamp = 0;
 
startTime = av_gettime();
 
}
 
 
 
int64_t AVTimeStamp::getAudioPts()
 
{
 
if(aMode == PTS_RECTIFY)
 
{
 
int64_t elapsed = av_gettime() - startTime;
 
uint32_t offset = qAbs(elapsed - (audioTimeStamp + audioDuration));
 
if(offset < (audioDuration * 0.5))
 
audioTimeStamp += audioDuration;
 
else
 
audioTimeStamp = elapsed;
 
}
 
else
 
{
 
audioTimeStamp = av_gettime() - startTime;
 
}
 
 
 
return audioTimeStamp;
 
}
 
 
 
int64_t AVTimeStamp::getVideoPts()
 
{
 
if(vMode == PTS_RECTIFY)
 
{
 
int64_t elapsed = av_gettime() - startTime;
 
uint32_t offset = qAbs(elapsed - (videoTimeStamp + videoDuration));
 
if(offset < (videoDuration * 0.5))
 
videoTimeStamp += videoDuration;
 
else
 
videoTimeStamp = elapsed;
 
}
 
else
 
{
 
videoTimeStamp = av_gettime() - startTime;
 
}
 
 
 
return videoTimeStamp;
 
}