#include "ffmpeg_EncodeThread.h"
//关闭流
void ffmpeg_EncodeThread::ffmpeg_close_stream(OutputStream *ost)
{
avcodec_free_context(&ost->enc);
av_frame_free(&ost->frame);
av_frame_free(&ost->tmp_frame);
sws_freeContext(ost->sws_ctx);
swr_free(&ost->swr_ctx);
}
//添加输出流
void ffmpeg_EncodeThread::ffmpeg_add_stream(OutputStream *ost, AVFormatContext *oc,AVCodec **codec,enum AVCodecID codec_id)
{
AVCodecContext *c;
*codec = avcodec_find_encoder(codec_id);
ost->st = avformat_new_stream(oc,nullptr);
ost->st->id = oc->nb_streams-1;
c=avcodec_alloc_context3(*codec);
ost->enc = c;
switch ((*codec)->type)
{
case AVMEDIA_TYPE_AUDIO:
//设置数据格式
c->sample_fmt = FFMPEG_AudioFormat;
c->bit_rate = AUDIO_BIT_RATE_SET; //设置码率
c->sample_rate = AUDIO_RATE_SET; //音频采样率
//设置采样通道
c->channels= av_get_channel_layout_nb_channels(c->channel_layout);
c->channel_layout = AUDIO_CHANNEL_SET; //AV_CH_LAYOUT_MONO 单声道 AV_CH_LAYOUT_STEREO 立体声
c->channels=av_get_channel_layout_nb_channels(c->channel_layout); //通道数
ost->st->time_base={1,c->sample_rate};
//c->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; //允许使用实验性AAC编码器-增加的
break;
case AVMEDIA_TYPE_VIDEO:
c->codec_id = codec_id;
//码率:影响体积,与体积成正比:码率越大,体积越大;码率越小,体积越小。
c->bit_rate = m_RecordConfig->video_bit_rate; //设置码率400000 400kps 500000
/*分辨率必须是2的倍数。 */
c->width = m_RecordConfig->ImageWidth;
c->height = m_RecordConfig->ImageHeight;
/*时基:这是基本的时间单位,以秒为单位*/
ost->st->time_base={1,m_RecordConfig->video_frame}; //按帧率计算时间基准
c->framerate = {m_RecordConfig->video_frame,1}; //设置帧率
c->time_base = ost->st->time_base;
c->gop_size = 10; // 关键帧间隔 /* 最多每十二帧发射一帧内帧 */
c->pix_fmt = AV_PIX_FMT_YUV420P; //固定设置为420P
c->max_b_frames = 0; // 不使用b帧
if(c->codec_id == AV_CODEC_ID_MPEG1VIDEO)
{
c->mb_decision = 2;
}
// 预设:快速
av_opt_set(c->priv_data,"preset", "superfast", 0);
break;
default:
break;
}
/* 某些格式希望流头分开*/
if(oc->oformat->flags & AVFMT_GLOBALHEADER)c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
AVFrame *ffmpeg_EncodeThread::ffmpeg_alloc_picture(enum AVPixelFormat pix_fmt, int width, int height)
{
AVFrame *picture;
picture=av_frame_alloc();
picture->format = pix_fmt;
picture->width = width;
picture->height = height;
/*为帧数据分配缓冲区*/
av_frame_get_buffer(picture,32);
return picture;
}
void ffmpeg_EncodeThread::ffmpeg_open_video(AVCodec *codec, OutputStream *ost, AVDictionary *opt_arg)
{
AVCodecContext *c = ost->enc;
AVDictionary *opt = nullptr;
av_dict_copy(&opt, opt_arg, 0);
//H264编码器的一些参数设置
c->qmin = 10;
c->qmax = 51;
//Optional Param
c->max_b_frames = 0;
#if 1
//下面设置两个参数影响编码延时,如果不设置,编码器默认会缓冲很多帧
// Set H264 preset and tune
// av_dict_set(&opt, "preset", "fast", 0);
// av_dict_set(&opt, "tune", "zerolatency", 0);
#else
/**
* ultrafast,superfast, veryfast, faster, fast, medium
* slow, slower, veryslow, placebo.
注意:这是x264编码速度的选项, 设置该参数可以降低编码延时
*/
av_opt_set(c->priv_data,"preset","superfast",0);
#endif
avcodec_open2(c, codec, &opt);
av_dict_free(&opt);
ost->frame = ffmpeg_alloc_picture(c->pix_fmt, c->width,c->height);
ost->tmp_frame = nullptr;
/* 将流参数复制到多路复用器 */
avcodec_parameters_from_context(ost->st->codecpar,c);
}
/*
准备图像数据
YUV422占用内存空间 = w * h * 2
YUV420占用内存空间 = width*height*3/2
*/
void ffmpeg_EncodeThread::fill_yuv_image(AVFrame *pict, int frame_index,int width, int height)
{
unsigned int y_size=width*height;
m_RecordConfig->video_encode_mutex.lock();
m_RecordConfig->video_WaitConditon.wait(&m_RecordConfig->video_encode_mutex);
memcpy(m_RecordConfig->video_yuv420p_buff_temp,
m_RecordConfig->video_yuv420p_buff,
m_RecordConfig->yuv420p_size);
m_RecordConfig->video_encode_mutex.unlock();
//将YUV数据拷贝到缓冲区 y_size=wXh
memcpy(pict->data[0],m_RecordConfig->video_yuv420p_buff_temp,y_size);
memcpy(pict->data[1],m_RecordConfig->video_yuv420p_buff_temp+y_size,y_size/4);
memcpy(pict->data[2],m_RecordConfig->video_yuv420p_buff_temp+y_size+y_size/4,y_size/4);
}
//获取一帧视频
AVFrame *ffmpeg_EncodeThread::get_video_frame(OutputStream *ost)
{
AVCodecContext *c = ost->enc;
/* 检查我们是否要生成更多帧---判断是否结束录制 */
// if(av_compare_ts(ost->next_pts, c->time_base,STREAM_DURATION, (AVRational){ 1, 1 }) >= 0)
// return nullptr;
/*当我们将帧传递给编码器时,它可能会保留对它的引用
*内部; 确保我们在这里不覆盖它*/
if (av_frame_make_writable(ost->frame) < 0) return nullptr;
//获取图像
//DTS(解码时间戳)和PTS(显示时间戳)
fill_yuv_image(ost->frame, ost->next_pts, c->width, c->height);
ost->frame->pts = ost->next_pts++;
//视频帧添加水印
return ost->frame;
}
int ffmpeg_EncodeThread::ffmpeg_write_frame(AVFormatContext *fmt_ctx, const AVRational *time_base, AVStream *st, AVPacket *pkt)
{
/*将输出数据包时间戳值从编解码器重新调整为流时基 */
av_packet_rescale_ts(pkt, *time_base, st->time_base);
pkt->stream_index = st->index;
/*将压缩的帧写入媒体文件*/
return av_interleaved_write_frame(fmt_ctx, pkt);
}
/*
*编码一个视频帧并将其发送到多路复用器
*/
int ffmpeg_EncodeThread::ffmpeg_write_video_frame(AVFormatContext *oc, OutputStream *ost)
{
int ret;
AVCodecContext *c;
AVFrame *frame;
int got_packet = 0;
AVPacket pkt;
c=ost->enc;
//获取一帧数据
frame = get_video_frame(ost);
if(frame==nullptr)
{
emit LogSend(-1,"视频帧制作失败...\n");
return -1;
}
av_init_packet(&pkt);
//编码图像
ret=avcodec_encode_video2(c, &pkt, frame, &got_packet);
if(ret < 0)
{
emit LogSend(-1,"视频帧编码出错...\n");
return ret;
}
if(got_packet)
{
ret=ffmpeg_write_frame(oc, &c->time_base, ost->st, &pkt);
}
else
{
ret = 0;
}
if(ret < 0)
{
emit LogSend(-1,"写入视频帧时出错...\n");
return ret;
}
return 0;
}
/*获取一帧音频数据 */
AVFrame *ffmpeg_EncodeThread::get_audio_frame(OutputStream *ost)
{
AVFrame *frame = ost->tmp_frame;
int16_t *q = (int16_t*)frame->data[0];
/* 检查我们是否要生成更多帧----用于判断是否结束*/
// if(av_compare_ts(ost->next_pts, ost->enc->time_base,
// STREAM_DURATION, (AVRational){ 1, 1 }) >= 0)
// {
// // if(videoaudioencode.audio_data_queue.isEmpty())
// return nullptr;
// }
// qDebug("frame->nb_samples=%d\n",frame->nb_samples); //2048
// qDebug("ost->enc->channels=%d\n",ost->enc->channels); //1
//判断缓冲区的数据是
DS小龙哥
- 粉丝: 5w+
- 资源: 904
最新资源
- 基于重复控制的单相桥式逆变系统设计仿真研究:Simulink仿真应用与性能分析,#Simulink仿真#基于重复控制的单相桥式逆变系统设计仿真 ,核心关键词:Simulink仿真; 重复控制; 单相桥
- 飞常准航班统计国际航线按机场内地机场总计划航班量20190101-20250101日度数据.xlsx
- 飞常准航班统计国际航线按机场内地机场总执行航班量20190101-20250101日度数据.xlsx
- 飞常准航班统计国际航线按机场内地机场总取消航班量20190101-20250101日度数据.xlsx
- 飞常准航班统计国际航线按机场内地机场总取消率20190101-20250101日度数据.xlsx
- 基于28035芯片的同步机无传感滑膜观测器模型与代码实现:典型smo+pll方案,实际应用级可比性,含simulink模型,一个同步机无传感滑膜观测器模型加代码,该模型基于28035芯片,采用了典型的
- 基于电子病历的疾病风险预测.pdf
- 电力系统故障分析与短路类型解析:从短路电流波形到中性点小电流接地故障定位模拟研究,电力系统故障点分析,短路类型分析,中性点小电流接地 不接地故障分析,故障点定位,可模拟三相变压器三相短路、单相短路、两
- 西门子SMART LINE触摸屏实现与ABB 510变频器直接通讯的程序设计与应用,西门子SMART LINE触摸屏485直接通讯ABB 510程序 实例采用V3触摸屏,485通讯方式,可以控制ABB
- STm32锅炉控制项目:从C原程序到实际应用的全方位教程,涵盖多路AD、Modbus、CRC等关键技术,STm32真实项目程序 c原程序,有电路图,PcB (AD工程),适合没有参加工作或初学STm
- 三菱FX3U精准控制配料系统:配方多样化、智能监控与数据传输功能一体化,三菱FX3U,用ST语言与梯形图,混合编写的16仓位的配方程序,程序大小约12984步,可以配1到16种不同的产品,16种配方可
- 基于Matlab的卡尔曼滤波语音去噪程序:对含有人为噪声的语音信号进行滤波处理,matlab,基于卡尔曼滤波的语音处理程序,针对现有语音信号,人为添加噪声,使用卡尔曼滤波器对其噪声进行滤波,达到语音去
- 基于形态学的权重自适应图像去噪算法与MATLAB数字图像处理实践:代码工程目录及运行效果展示,基于形态学的权重自适应图像去噪 MATLAB数字图像处理 基于形态学的权重自适应图像去噪 代码工程目录及运
- 电动汽车Simulink仿真模型:整车动力性能仿真与NEDC能耗测试综合平台,电动汽车 simulink仿真模型, 可进行整车动力性仿真测试(最高车速,最大爬坡,加入时间)和NEDC工况能耗测试(电耗
- 经过验证的Verilog串口收发程序,高低温环境下稳定传输数据,遵循特定的帧格式 ,Verilog编写的串口收发程序,工作稳定 代码经过实际应用验证,经过高低温等环境实验验证 有需要的可以联系了
- 西门子锂电池项目:PLC程序块集成与对接机器人系统、视觉、MES通信模块 使用STL与LAD编写 ,西门子锂电池项目,1500安全型PLC程序 包含对接雅马哈机器人,视觉,库卡机器人,MES通信程序
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
- 1
- 2
- 3
- 4
前往页