#include "videocodec.h"
#include <QDebug>
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/avutil.h"
#include "libswscale/swscale.h"
#include "libavutil/imgutils.h"
#include "libavdevice/avdevice.h"
}
// 异常信息数组长度
#define ERROR_LEN 1024
#define PRINT_LOG 1
VideoCodec::VideoCodec()
{
}
VideoCodec::~VideoCodec()
{
close();
}
//初始化并打开视频编解码器,通过分配输出上下文、打开输出文件、查询编码器、设置编码器参数、打开编码器、向媒体文件添加新流、写入文件头等操作完成
bool VideoCodec::open(AVCodecContext *codecContext, QPoint point, const QString &fileName)
{
//检查输入参数codecContext和fileName是否为空
if(!codecContext || fileName.isEmpty())
{
return false;
}
// 通过输出文件名为输出格式分配AVFormatContext
//参数3编码器设置为空,由参数4文件名后缀推测合适的编码器
int ret = avformat_alloc_output_context2(&m_formatContext, nullptr, nullptr, fileName.toStdString().data());
if(ret < 0)
{
close();
showError(ret);
return false;
}
// 创建并初始化AVIOContext以访问url所指示的资源。将打开的结果保存在m_formatContext->pb中
ret = avio_open(&m_formatContext->pb, fileName.toStdString().data(), AVIO_FLAG_WRITE);
if(ret < 0)
{
close();
showError(ret);
return false;
}
// 查询编码器
const AVCodec* codec = avcodec_find_encoder(m_formatContext->oformat->video_codec);
//检查codec是否为空
if(!codec)
{
close();
showError(AVERROR(ENOMEM));
return false;
}
qDebug() << codec->id <<" " << codec->name;
// 分配AVCodecContext并将其字段设置为默认值。
m_codecContext = avcodec_alloc_context3(codec);
if(!m_codecContext)
{
close();
showError(AVERROR(ENOMEM));
return false;
}
// 设置编码器上下文参数
m_codecContext->width = codecContext->width; // 图片宽度/高度
m_codecContext->height = codecContext->height;
m_codecContext->pix_fmt = codec->pix_fmts[0]; // 像素格式(这里通过编码器赋值,不需要自己指定)
m_codecContext->time_base = {point.y(), point.x()}; //设置时间基,20为分母,1为分子,表示以1/20秒时间间隔播放一帧图像
m_codecContext->framerate = {point.x(), point.y()};
m_codecContext->bit_rate = bitrate; // 目标的码率,即采样的码率;显然,采样码率越大,视频大小越大,画质越高
m_codecContext->gop_size = 12; // I帧间隔(值越大,视频文件越小,编解码延时越长)
m_codecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; //将AV_CODEC_FLAG_GLOBAL_HEADER标志设置到m_codecContext的flags字段中
// 打开编码器
ret = avcodec_open2(m_codecContext, nullptr, nullptr);
if(ret < 0)
{
close();
showError(ret);
return false;
}
// 向媒体文件添加新流
m_videoStream = avformat_new_stream(m_formatContext, nullptr);
if(!m_videoStream)
{
close();
showError(AVERROR(ENOMEM));
return false;
}
//拷贝一些参数,给codecpar赋值
ret = avcodec_parameters_from_context(m_videoStream->codecpar,m_codecContext);
if(ret < 0)
{
close();
showError(ret);
return false;
}
//将m_codecContext中的参数拷贝给m_videoStream->codecpar,写入文件头
ret = avformat_write_header(m_formatContext, nullptr);
if(ret < 0)
{
close();
showError(ret);
return false;
}
m_writeHeader = true;
// 分配一个AVPacket
m_packet = av_packet_alloc();
if(!m_packet)
{
close();
showError(AVERROR(ENOMEM));
return false;
}
m_frame = av_frame_alloc();
if(!m_frame)
{
close();
showError(AVERROR(ENOMEM));
return false;
}
//设置m_frame的像素格式
m_frame->format = codec->pix_fmts[0];
qDebug() << "开始录制视频!";
return true;
}
//将视频帧进行编码并写入视频文件。如果需要,它会转换帧的格式,并将帧发送给编码器。然后,它循环接收和写入所有已编码的数据包到文件中
void VideoCodec::write(AVFrame *frame)
{
//获取互斥锁,以保证线程安全
QMutexLocker locker(&m_mutex);
if(!m_packet)
{
return;
}
// 由于解码的图像格式和编码需要的图像格式不一定相同,所以需要转换一下格式
if(!swsFormat(frame))
{
return;
}
//如果不为空,设置m_frame的pts为m_index(用于指定当前帧的时间戳),然后自增m_index
if(m_frame)
{
// pts从0开始增加,保存的视频才会时间从0开始增加
m_frame->pts = m_index;
m_index++;
}
// 将图像传入编码器
avcodec_send_frame(m_codecContext, m_frame);
// 循环读取所有编码完的帧
while (true)
{
// 从编码器中读取图像帧
int ret = avcodec_receive_packet(m_codecContext, m_packet);
if(ret < 0)
{
break;
}
// 将数据包中的有效时间字段(时间戳/持续时间)从一个时基转换为 输出流的时间
av_packet_rescale_ts(m_packet, m_codecContext->time_base, m_videoStream->time_base);
av_write_frame(m_formatContext, m_packet); // 将数据包写入输出媒体文件
av_packet_unref(m_packet);
}
}
//关闭视频编解码器,包括写入文件尾部、关闭AVIO上下文、释放分配的资源
void VideoCodec::close()
{
//传入空帧,读取所有编码数据
write(nullptr);
// 如果不加锁可能在点击关闭时,write函数正在写入数据,导致崩溃
QMutexLocker locker(&m_mutex);
//是否成功初始化了输出媒体文件上下文
if(m_formatContext)
{
// 写入文件尾
if(m_writeHeader)
{
//避免重复写入文件尾部
m_writeHeader = false;
int ret = av_write_trailer(m_formatContext);
if(ret < 0)
{
showError(ret);
return;
}
}
//关闭输出IO流
int ret = avio_close(m_formatContext->pb);
if(ret < 0)
{
showError(ret);
return;
}
//释放输出媒体文件上下文的资源
avformat_free_context(m_formatContext);
m_formatContext = nullptr;
m_videoStream = nullptr;
}
// 释放编解码器上下文并置空
if(m_codecContext)
{
avcodec_free_context(&m_codecContext);
}
if(m_packet)
{
av_packet_free(&m_packet);
}
// 释放上下文swsContext。
if(m_swsContext)
{
sws_freeContext(m_swsContext);
m_swsContext = nullptr; // sws_freeContext不会把上下文置NULL
}
if(m_frame)
{
//释放帧占用的内存
av_frame_free(&m_frame);
}
m_index = 0;
}
//在函数执行过程中,记录和显示任何错误消息
void VideoCodec::showError(int err)
{
#if PRINT_LOG
static char m_error[ERROR_LEN]; // 保存异常信息
memset(m_error, 0, ERROR_LEN); // 将数组置零
av_strerror(err, m_error, ERROR_LEN); //将错误码err转换为对�
没有合适的资源?快使用搜索试试~ 我知道了~
基于QT以及FFmpeg开发的录屏软件以及视频播放器代码
共344个文件
h:219个
cpp:26个
dll:25个
需积分: 0 14 下载量 59 浏览量
2023-07-21
08:24:20
上传
评论 1
收藏 77.61MB ZIP 举报
温馨提示
基于QT以及FFmpeg开发的录屏软件以及视频播放器代码
资源推荐
资源详情
资源评论
收起资源包目录
基于QT以及FFmpeg开发的录屏软件以及视频播放器代码 (344个子文件)
libSDL2.a 20.75MB
libavcodec.dll.a 866KB
libavcodec.dll.a 847KB
libSDL2_test.a 629KB
libSDL2.dll.a 539KB
libavdevice.dll.a 445KB
libavdevice.dll.a 434KB
libavutil.dll.a 341KB
libavutil.dll.a 333KB
libavformat.dll.a 138KB
libavformat.dll.a 134KB
libavfilter.dll.a 47KB
libavfilter.dll.a 46KB
libswscale.dll.a 22KB
libswscale.dll.a 22KB
libswresample.dll.a 15KB
libswresample.dll.a 15KB
libSDL2main.a 9KB
libpostproc.dll.a 7KB
libpostproc.dll.a 7KB
sdl2-config.cmake 8KB
sdl2-config-version.cmake 344B
videocodec.cpp 11KB
videodecode.cpp 11KB
XDemux.cpp 8KB
XVideoWidget.cpp 8KB
screenshot.cpp 6KB
XDemuxThread.cpp 5KB
XAudioThread.cpp 5KB
XAudioPlay.cpp 5KB
capturevideo.cpp 5KB
XDecode.cpp 4KB
captureaudio.cpp 4KB
readthread.cpp 4KB
XPlay2.cpp 4KB
XVideoThread.cpp 3KB
subthread.cpp 3KB
XResample.cpp 3KB
XDecodeThread.cpp 3KB
audioplay_thread.cpp 3KB
videocut.cpp 2KB
audioplaywidget.cpp 2KB
audiosubthread.cpp 1KB
mainwindow.cpp 1KB
capture.cpp 910B
play.cpp 838B
XSlider.cpp 396B
main.cpp 194B
avutil-56.def 12KB
avutil-56.def 12KB
avcodec-58.def 6KB
avcodec-58.def 6KB
avformat-58.def 4KB
avformat-58.def 4KB
avfilter-7.def 2KB
avfilter-7.def 2KB
swscale-5.def 756B
swscale-5.def 756B
avdevice-58.def 544B
avdevice-58.def 544B
swresample-3.def 473B
swresample-3.def 473B
postproc-55.def 223B
postproc-55.def 223B
avcodec-58.dll 44.81MB
avcodec-58.dll 44.81MB
avcodec-58.dll 32.66MB
avformat-58.dll 9.84MB
avformat-58.dll 9.84MB
avformat-58.dll 9.45MB
avfilter-7.dll 7.47MB
avfilter-7.dll 7.47MB
avfilter-7.dll 7.02MB
avdevice-58.dll 2.51MB
avdevice-58.dll 2.51MB
SDL2.dll 2.38MB
avdevice-58.dll 1.37MB
avutil-56.dll 775KB
avutil-56.dll 775KB
avutil-56.dll 763KB
swscale-5.dll 532KB
swscale-5.dll 532KB
swscale-5.dll 507KB
swresample-3.dll 419KB
swresample-3.dll 419KB
swresample-3.dll 310KB
postproc-55.dll 132KB
postproc-55.dll 132KB
postproc-55.dll 122KB
ffmpeg.exe 289KB
ffmpeg.exe 287KB
ffprobe.exe 170KB
ffprobe.exe 163KB
ffplay.exe 150KB
ffplay.exe 145KB
TestFFMpeg.exe 69KB
TestFFMpeg.exe 52KB
SDL_opengl_glext.h 844KB
SDL_opengles2_gl2ext.h 236KB
avcodec.h 209KB
共 344 条
- 1
- 2
- 3
- 4
资源评论
m0_73698771
- 粉丝: 0
- 资源: 1
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功