#include "ffmpegapisavevideo.h"
ffmpegApiSaveVideo::ffmpegApiSaveVideo(QObject *parent) : QObject(parent)
{
}
ffmpegApiSaveVideo::~ffmpegApiSaveVideo()
{
}
void ffmpegApiSaveVideo::insertFrame(AVFrame *frame)
{
if(m_FrameVector.length()>MaxFrameNum){
m_FrameVector.pop_front();
}
m_FrameVector.append(frame);
}
void ffmpegApiSaveVideo::init(QString filePath, AVCodecContext *pCodecCtx, ffmpegApiSaveVideo::VideoInfo videoInfo)
{
m_videoInfo = videoInfo;
m_ICodecCtx = pCodecCtx;
initOutput(filePath.toUtf8());
uint8_t *pIBuffer; //开辟存储像素点的存储地址
int pixSize = av_image_get_buffer_size(m_videoInfo.pixFormat,m_ICodecCtx->width, m_ICodecCtx->height,16);
//创建保存空间,底层使用malloc进行内存空间的开辟。
pIBuffer = static_cast<uint8_t *>(av_malloc(static_cast<size_t>(pixSize)));
//创建图像转换之后的帧
m_pIFrameYUV = av_frame_alloc();
av_image_fill_arrays(m_pIFrameYUV->data,
m_pIFrameYUV->linesize,
pIBuffer,
m_videoInfo.pixFormat,
1280,
720,
16);
m_imgYUV_convert_ctx = sws_getContext(m_ICodecCtx->width,
m_ICodecCtx->height,
m_ICodecCtx->pix_fmt,
1280,
720,
m_videoInfo.pixFormat,
SWS_BICUBIC, nullptr, nullptr, nullptr);
issave = true;
}
void ffmpegApiSaveVideo::stopWrite()
{
issave = false;
}
void ffmpegApiSaveVideo::writeVideo()
{
while(issave){
int ret;
int got_packet=0;
AVPacket pkt;
if(m_FrameVector.isEmpty()){
continue;
}
AVFrame *pIFrame = m_FrameVector.front();
int length = m_FrameVector.length();
m_FrameVector.pop_front();
if(pIFrame == nullptr){
continue;
}
sws_scale(m_imgYUV_convert_ctx, static_cast<uint8_t const * const *>(pIFrame->data),
pIFrame->linesize,0, m_ICodecCtx->height, m_pIFrameYUV->data,
m_pIFrameYUV->linesize);
m_pIFrameYUV->pts = m_next_pts++;
av_init_packet(&pkt);
/* 编码图像*/
ret = avcodec_send_frame(m_pCodecCtx, m_pIFrameYUV);
if (ret < 0) {
qDebug()<<"Error sending the frame to the encoder";
return;
}
ret = avcodec_receive_packet(m_pCodecCtx, &pkt);
if (ret < 0) {
qDebug()<<"Error encoding audio frame";
return;
}
ret = write_frame(m_pOFormatCtx, &m_pCodecCtx->time_base, m_pStream, &pkt);
QThread::msleep(10);
av_packet_unref(&pkt);
}
av_write_trailer(m_pOFormatCtx);
avcodec_free_context(&m_pCodecCtx);
/*关闭输出文件*/
if (!(m_pOutFmt->flags & AVFMT_NOFILE))
avio_closep(&m_pOFormatCtx->pb);
/*释放流*/
avformat_free_context(m_pOFormatCtx);
}
void ffmpegApiSaveVideo::initOutput(QByteArray filepath)
{
int ret;
//根据文件路径判断获取编码格式,写入到oc中。向m_pOFormatCtx中写入数据
avformat_alloc_output_context2(&m_pOFormatCtx, nullptr, nullptr, filepath.data());//为输出格式分配一个AVFormatContext。
if(!m_pOFormatCtx)
{
printf("无法从文件扩展名推断出输出格式:使用h264。\n");
avformat_alloc_output_context2(&m_pOFormatCtx, nullptr, m_videoInfo.packageFormat.toUtf8(), filepath.data());
}
//添加流 向m_pOutFmt和m_pCodecCtx m_pCodec写入数据。
addStreamToftc(m_pOFormatCtx);
/*现在所有参数都设置好了,我们可以打开音频和视频编解码器并分配必要的编码缓冲器*/
AVDictionary *opt = nullptr;//AVDictionary是一个健值对存储工具
open_video(m_pCodec,opt);
av_dump_format(m_pOFormatCtx,0,filepath.data(),1);// TODO:
/* 打开输出文件(如果需要) */
if(!(m_pOFormatCtx->flags & AVFMT_NOFILE))
{
//创建并初始化AVIOContext以访问url指示的资源。
ret=avio_open(&m_pOFormatCtx->pb,filepath.data(),AVIO_FLAG_WRITE);
if(ret<0)
{
qDebug()<<QString("打不开'%1': %2").arg(filepath.data()).arg(av_err2str(ret));
}
}
/* 编写流头(如果有)*/
ret=avformat_write_header(m_pOFormatCtx, &opt);
if(ret<0)
{
fprintf(stderr, "打开输出文件时发生错误: %s\n",av_err2str(ret));
}
// 创建 缓存区
}
//*添加输出流。 */
void ffmpegApiSaveVideo::addStreamToftc(AVFormatContext *fct)
{
int i;
/* find the encoder */
m_pOutFmt = m_pOFormatCtx->oformat;
m_pOutFmt->video_codec = m_videoInfo.codecId;//设置编码格式
m_pCodec = avcodec_find_encoder(m_pOutFmt->video_codec);
if (!(m_pCodec))
{
qDebug()<<"Could not find encoder for :" << avcodec_get_name(m_pOutFmt->video_codec);
return;
}
//给媒体文件添加一个流
m_pStream = avformat_new_stream(fct, nullptr);
if (!m_pStream) {
qDebug()<<"Could not allocate stream";
return;
}
m_pStream->id = static_cast<int>(fct->nb_streams-1);
//创建 编码 上下文。
m_pCodecCtx = avcodec_alloc_context3(m_pCodec);
av_opt_set(m_pCodecCtx->priv_data, "tune", "zerolatency", 0);//解决avcodec_receive_packet返回为-11的问题
if (!m_pCodecCtx) {
qDebug()<<"Could not alloc an encoding context";
return;
}
switch((m_pCodec)->type)
{
case AVMEDIA_TYPE_AUDIO:{
m_pCodecCtx->sample_fmt = (m_pCodec)->sample_fmts ?(m_pCodec)->sample_fmts[0] : AV_SAMPLE_FMT_FLTP;
m_pCodecCtx->bit_rate = 64000;
m_pCodecCtx->sample_rate = 44100;
if ((m_pCodec)->supported_samplerates) {
m_pCodecCtx->sample_rate = (m_pCodec)->supported_samplerates[0];
for (i = 0; (m_pCodec)->supported_samplerates[i]; i++) {
if ((m_pCodec)->supported_samplerates[i] == 44100)
m_pCodecCtx->sample_rate = 44100;
}
}
m_pCodecCtx->channels = av_get_channel_layout_nb_channels(m_pCodecCtx->channel_layout);
m_pCodecCtx->channel_layout = AV_CH_LAYOUT_STEREO;
if ((m_pCodec)->channel_layouts) {
m_pCodecCtx->channel_layout = (m_pCodec)->channel_layouts[0];
for (i = 0; (m_pCodec)->channel_layouts[i]; i++) {
if ((m_pCodec)->channel_layouts[i] == AV_CH_LAYOUT_STEREO)
m_pCodecCtx->channel_layout = AV_CH_LAYOUT_STEREO;
}
}
m_pCodecCtx->channels = av_get_channel_layout_nb_channels(m_pCodecCtx->channel_layout);
m_pStream->time_base = (AVRational){ 1, m_pCodecCtx->sample_rate };
break;
}
case AVMEDIA_TYPE_VIDEO:{
m_pCodecCtx->codec_id = m_pOutFmt->video_codec;
m_pCodecCtx->bit_rate = m_videoInfo.kbps; //平均比特率,例子代码默认值是400000
/* 分辨率必须是2的倍数。*/
m_pCodecCtx->width = m_videoInfo.wideth;
m_pCodecCtx->height = m_videoInfo.hight;
/*时基:这是基本的时间单位(以秒为单位)表示其中的帧时间戳。 对于固定fps内容,时基应为1 /framerate,时间戳增量应为等于1。*/
m_pStream->time_base = (AVRational){1,m_videoInfo.fps}; //帧率设置 帧率为25;
m_pCodecCtx->time_base = m_pStr
没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
收起资源包目录
qt切换页面小练习更新2 (400个子文件)
QtSidebar.pro.user.9fd059f.22 22KB
QtSidebar.pro.user.6b0e73a 22KB
libavutil.dll.a 376KB
libavutil.dll.a 338KB
libavcodec.dll.a 175KB
libavfilter.dll.a 160KB
libavcodec.dll.a 152KB
libavformat.dll.a 145KB
libavformat.dll.a 137KB
libavfilter.dll.a 47KB
libswscale.dll.a 22KB
libswscale.dll.a 22KB
libswresample.dll.a 17KB
libswresample.dll.a 15KB
libavdevice.dll.a 13KB
libavdevice.dll.a 13KB
libpostproc.dll.a 7KB
libpostproc.dll.a 7KB
ffmpegapisavevideo.cpp 10KB
ffmpegpushstream.cpp 9KB
videothread.cpp 6KB
ffmpegapi.cpp 5KB
batterywidget.cpp 5KB
ffmpegapiopendevice.cpp 5KB
ffmpegapidisplay.cpp 2KB
displaywindow.cpp 2KB
mainwindow.cpp 2KB
myqtcamera.cpp 2KB
ffmpegcmd.cpp 1KB
main.cpp 556B
permissionwindow.cpp 271B
settingswindow.cpp 257B
statusbar.cpp 222B
avutil-57.def 13KB
avutil-56.def 12KB
avcodec-58.def 6KB
avformat-58.def 4KB
avcodec-59.def 4KB
avformat-59.def 4KB
avfilter-7.def 2KB
avfilter-8.def 2KB
swscale-5.def 756B
swscale-6.def 746B
avdevice-58.def 544B
avdevice-59.def 544B
swresample-4.def 519B
swresample-3.def 473B
postproc-55.def 223B
postproc-56.def 223B
avcodec-59.dll 71.65MB
avcodec-58.dll 55.7MB
avfilter-8.dll 37.07MB
avfilter-7.dll 26.69MB
avformat-59.dll 14.9MB
avformat-58.dll 13.73MB
avdevice-59.dll 3.65MB
avdevice-58.dll 3.5MB
avutil-57.dll 1.11MB
avutil-56.dll 837KB
swscale-6.dll 659KB
swscale-5.dll 539KB
swresample-4.dll 426KB
swresample-3.dll 423KB
postproc-56.dll 132KB
postproc-55.dll 129KB
ffplay.exe 1.7MB
ffplay.exe 1.6MB
ffmpeg.exe 347KB
ffmpeg.exe 342KB
ffprobe.exe 187KB
ffprobe.exe 182KB
1.gif 111KB
avcodec.h 145KB
avformat.h 115KB
avcodec.h 111KB
avformat.h 111KB
avfilter.h 43KB
avfilter.h 41KB
pixfmt.h 36KB
opt.h 36KB
opt.h 36KB
pixfmt.h 34KB
avio.h 32KB
frame.h 32KB
frame.h 31KB
avio.h 31KB
channel_layout.h 31KB
swresample.h 25KB
hwcontext.h 24KB
hwcontext.h 24KB
packet.h 23KB
mem.h 23KB
mem.h 23KB
packet.h 22KB
swresample.h 21KB
intreadwrite.h 18KB
intreadwrite.h 18KB
avdevice.h 18KB
common.h 18KB
avdevice.h 17KB
共 400 条
- 1
- 2
- 3
- 4
资源评论
lmk2015
- 粉丝: 0
- 资源: 16
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- 以下是 VB 入门教程及一个简单的开发案例
- SQL (Structured Query Language) 是用于管理和操作关系型数据库的标准语言
- STM32储能逆变器资料,提供原理图,pcb,源代码 基于STM32F103设计,具有并网充电、放电;并网离网自动切换;485
- Scratch 是一个基于图形化编程的工具,专门设计用于帮助儿童和初学者学习编程概念
- 逆变器光伏逆变器,3.6kw储能逆变器全套资料 STM32储能逆变器 BOOST 全桥 基于STM32F103设计,具有并网充
- 基于python+opencv的手势识别系统,可控制灯的亮度,智能家居,智能小车 基于python+opencv的手势识别系统
- VSC下垂控制策略仿真模型,支持MATLAB2014a及以上版本
- 基于python实现的LSB进行图像隐写的程序
- 考虑分布式光伏储能系统的优化配置方法 完全复现截图文献模型 采用双层模型求解 上层决策储能系统配置容量用遗传 粒子群算法求解 下
- 以下是一个完整的 Ruby 入门教程,帮助你快速了解和上手 Ruby 编程
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功