#include "ctffmpeg.h"
#include <QImage>
#include "ctaudioplayer.h"
#include <QPixmap>
#include <QDate>
#include <QTime>
#include <QThread>
#pragma execution_character_set("utf-8")
ctFFmpeg::ctFFmpeg()
{
}
ctFFmpeg::~ctFFmpeg()
{
}
int ctFFmpeg::Init(QString sUrl, QString sWinName)
{
MY_DEBUG << "ctFFmpeg::Init sUrl:" << sUrl << " start.";
const AVCodec *pvAVCodec = nullptr; //ffmpeg 5.1
m_bQuit = false;
if(sUrl.contains("rtsp://") > 0 || sUrl.contains("http://") > 0) //实时流
m_nPlayWay = MEDIA_PLAY_STREAM;
else
m_nPlayWay = MEDIA_PLAY_FILE;
avformat_network_init();//初始化网络流
//参数设置
AVDictionary* pOptDict = NULL;
MY_DEBUG << "UDP";
av_dict_set(&pOptDict, "rtsp_transport", "udp", 0);
av_dict_set(&pOptDict, "stimeout", "5000000", 0);
av_dict_set(&pOptDict, "buffer_size", "8192000", 0);
av_dict_set(&pOptDict, "recv_buffer_size", "4096000", 0); // 防止花屏, max 4M.
av_dict_set(&pOptDict, "tune", "stillimage,fastdecode,zerolatency", 0);//快速解码和低延时
if(nullptr == m_pAVFmtCxt)
m_pAVFmtCxt = avformat_alloc_context();
if(nullptr == m_pYuvFrame)
m_pYuvFrame = av_frame_alloc();
if(nullptr == m_pDstVideoFrame)
m_pDstVideoFrame = av_frame_alloc();
if(nullptr == m_pPcmFrame)
m_pPcmFrame = av_frame_alloc();
//加入中断处理
m_nLastReadPacktTime = av_gettime();
m_pAVFmtCxt->interrupt_callback.opaque = this;
m_pAVFmtCxt->interrupt_callback.callback = [](void* ctx)
{
ctFFmpeg* pThis = (ctFFmpeg*)ctx;
int nTimeout = 3;
if (av_gettime() - pThis->m_nLastReadPacktTime > nTimeout * 1000 * 1000)
{
return -1;
}
return 0;
};
//打开码流
MY_DEBUG << "Open Stream.";
int nRet;
if(m_nPlayWay == MEDIA_PLAY_FILE)
{
nRet = avformat_open_input(&m_pAVFmtCxt, sUrl.toStdString().c_str(), nullptr, nullptr);
if(m_pAVFmtCxt)
{
m_FileTotalTimes = m_pAVFmtCxt->duration/1000000.0;//获取总时长,转化为秒
MY_DEBUG << "m_FileTimes:" << m_FileTotalTimes;
}
}
else
nRet = avformat_open_input(&m_pAVFmtCxt, sUrl.toStdString().c_str(), nullptr, &pOptDict);
if(nRet < 0)
{
MY_DEBUG << "avformat_open_input failed nRet:" << nRet;
av_dict_free(&pOptDict);
return nRet;
}
av_dict_free(&pOptDict);
//设置探测时间,获取码流信息
MY_DEBUG << "Get Stream Info.";
m_pAVFmtCxt->probesize = MAX_PROBE_SIZE;
m_pAVFmtCxt->max_analyze_duration = MAX_ANALYZE_DURATION;
nRet = avformat_find_stream_info(m_pAVFmtCxt, nullptr);
if(nRet < 0)
{
MY_DEBUG << "avformat_find_stream_info failed nRet:" << nRet;
return nRet;
}
//打印码流信息
av_dump_format(m_pAVFmtCxt, 0, sUrl.toStdString().c_str(), 0);
//查找码流
MY_DEBUG << "av_find_best_stream.";
m_nVideoIndex = av_find_best_stream(m_pAVFmtCxt, AVMEDIA_TYPE_VIDEO, -1, -1, &pvAVCodec, 0);
m_nAudioIndex = av_find_best_stream(m_pAVFmtCxt, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
if(nullptr == pvAVCodec)
{
MY_DEBUG << "nullptr == pvAVCodec error.";
return -1;
}
//初始化视频
MY_DEBUG << "Init Video.";
if(InitVideo() < 0)
{
MY_DEBUG << "InitVideo() error";
return -1;
}
//初始化音频
if(m_nAudioIndex > 0)
{
if(InitAudio() < 0)
{
MY_DEBUG << "InitAudio() error";
m_bSupportAudioPlay = false;
}
else
m_bSupportAudioPlay = true;
}
m_sWinName = sWinName;
#if OPENCV_NAME_WINDOW_SHOW
cv::namedWindow(m_sWinName.toStdString(), cv::WINDOW_NORMAL);
#endif
MY_DEBUG << "ctFFmpeg::Init sUrl:" << sUrl << " success.";
return 0;
}
void ctFFmpeg::DeInit()
{
MY_DEBUG << "DeInit 000";
m_mutex.lock();
m_bQuit = true;
destroyWindow(m_sWinName.toStdString());
MY_DEBUG << "DeInit 222";
if (nullptr != m_pVideoSwsContext)
{
sws_freeContext(m_pVideoSwsContext);
}
MY_DEBUG << "DeInit 444";
if (nullptr != m_pAudioSwrContext)
{
swr_free(&m_pAudioSwrContext);
m_pAudioSwrContext = nullptr;
}
MY_DEBUG << "DeInit 555";
if (m_pDstVideoFrame)
av_frame_free(&m_pDstVideoFrame);
MY_DEBUG << "DeInit 666";
if(nullptr != m_pYuvFrame)
av_free(m_pYuvFrame);
MY_DEBUG << "DeInit 777";
if(nullptr != m_pPcmFrame)
av_free(m_pPcmFrame);
MY_DEBUG << "DeInit 999";
if(nullptr != m_pFrameRGB)
av_free(m_pFrameRGB);
MY_DEBUG << "DeInit aaa";
if(nullptr != m_pOutBuffer)
{
av_free(m_pOutBuffer);
}
MY_DEBUG << "DeInit bbb";
if(nullptr != m_pVideoCodecCxt)
{
avcodec_close(m_pVideoCodecCxt);
m_pVideoCodecCxt = nullptr;
}
MY_DEBUG << "DeInit ccc";
if (nullptr != m_pAudioCodecCxt)
{
avcodec_close(m_pAudioCodecCxt);
//avcodec_free_context(&m_pAudioCodecCxt);
m_pAudioCodecCxt = nullptr;
}
MY_DEBUG << "DeInit ddd";
if(nullptr != m_pAVFmtCxt)
{
avformat_close_input(&m_pAVFmtCxt);
MY_DEBUG << "DeInit eee";
avformat_free_context(m_pAVFmtCxt);
m_pAVFmtCxt = nullptr;
}
MY_DEBUG << "DeInit end";
m_mutex.unlock();
}
AVPacket ctFFmpeg::getPacket()
{
AVPacket pkt;
memset(&pkt, 0, sizeof(AVPacket));
if(!m_pAVFmtCxt)
{
return pkt;
}
m_nLastReadPacktTime = av_gettime();
int nErr = av_read_frame(m_pAVFmtCxt, &pkt);
if(nErr < 0)
{
//错误信息
char errorbuff[1024];
av_strerror(nErr, errorbuff, sizeof(errorbuff));
}
m_nCurPktSize = pkt.size;
return pkt;
}
bool ctFFmpeg::Decode(const AVPacket *pkt)
{
m_mutex.lock();
if(!m_pAVFmtCxt)
{
m_mutex.unlock();
return false;
}
if (m_bSupportAudioPlay && pkt->stream_index == m_nAudioIndex)
{
m_pFrame = m_pPcmFrame;
m_pCodecCxt = m_pAudioCodecCxt;
}
else if(pkt->stream_index == m_nVideoIndex)
{
m_pFrame = m_pYuvFrame;
m_pCodecCxt = m_pVideoCodecCxt;
}
else
{
m_mutex.unlock();
return false;
}
//发送编码数据包
int nRet = avcodec_send_packet(m_pCodecCxt, pkt);
if (nRet != 0)
{
m_mutex.unlock();
MY_DEBUG << "avcodec_send_packet error---" << nRet;
return false;
}
if((m_pFrame->width != 0 && m_pFrame->height != 0) && (m_pFrame->width != m_nVideoW || m_pFrame->height != m_nVideoH))
{
MY_DEBUG << "Resolution Change, need to reconnect...";
m_mutex.unlock();
return false;
}
//获取解码的输出数据
nRet = avcodec_receive_frame(m_pCodecCxt, m_pFrame);
if(nRet == 0)
{
//获取当前时长
if(m_nPlayWay == MEDIA_PLAY_FILE && pkt->stream_index == m_nVideoIndex)
{
m_nFilePlayCurTime = static_cast<int>(m_pFrame->best_effort_timestamp * av_q2d(m_pAVFmtCxt->streams[m_nVideoIndex]->time_base));
//MY_DEBUG << "m_nFilePlayCurTime:" << m_nFilePlayCurTime;
}
m_mutex.unlock();
return true;
}
else
{
m_mutex.unlock();
MY_DEBUG << "avcodec_receive_frame error---" << nRet;
return false;
}
}
bool ctFFmpeg::RecvDecodedFrame()
{
if(m_pCodecCxt && m_pFrame)
{
int nRet = avcodec_receive_frame(m_pCodecCxt, m_pFrame);
if(nRet == 0)
{
没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
本篇文档的demo包含了 1.使用OpenCV对图像进行处理,对图像进行置灰,旋转,抠图,高斯模糊,中值滤波,部分区域清除置黑,背景移除,边缘检测等操作;2.单纯使用opencv播放显示视频;3.使用opencv和openGL播放显示视频;4.在ffmpeg解码后,使用opencv显示视频,并支持对视频的旋转翻转、裁剪、添加文字、添加logo、亮度调节、置灰、录像截图,音频开关等功能。视频播放器同时支持本地文件与网络码流地址的播放。本篇博客的最后有提供工程代码的下载。免费可执行程序下载和详细内容可以看我的博客。
资源推荐
资源详情
资源评论











格式:exe 资源大小:6.0MB


















收起资源包目录





































































































共 1305 条
- 1
- 2
- 3
- 4
- 5
- 6
- 14

浅笑一斤
- 粉丝: 2w+
上传资源 快速赚钱
我的内容管理 展开
我的资源 快来上传第一个资源
我的收益
登录查看自己的收益我的积分 登录查看自己的积分
我的C币 登录后查看C币余额
我的收藏
我的下载
下载帮助


最新资源
- 本库是个基于python的工具集,用于记录数据到文件。 使用方便,代码简洁, 是一个可靠、省心且实用的工具。 支持多线程同时写入。.zip
- 本科毕业设计,基于python的图像复制粘贴篡改识别软件。.zip
- 本项目是基于计算机视觉的端到端交通路口智能监控系统.采用的设计架构由SRS
- 碧蓝航线ios平台自动脚本,基于python+opencv+facebook_wda实现.zip
- 毕业设计中基于给定微博数据的反作弊识别,用python开发。.zip
- 毕业设计项目,基于深度学习的实时语义分割算法研究,python实现。.zip
- 对基于python的微博爬虫进行重写,重写语言:java.zip
- 此框架是基于Python+Pytest+Requests+Allure+Yaml+Json实现全链路接口自动化测试
- 程序语言课程作业在线评测平台(实现Java、C、Python的选择、填空、代码题在线评测),基于SpringBoot+Layui+MySQL实现.zip
- 非官方的科大讯飞语音合成(用于朗读,配音场景)python API (基于官方demo增加了:超过2000字上限自动分割再合并音频的功能).zip
- 非官方的简易中国铁路列车运行图系统,基于Python + PyQt5
- 超市POS销售与后台管理系统_商品录入收银业务会员管理进货销售库存人员权限断网收银断电保护_实现超市前台POS销售商品扫描条形码输入收银计算找零打印清单会员折扣累计消费以及后台管理.zip
- 俄罗斯方块闯关版,基于Python实现.zip
- 该项目是基于Python和数据库实现的学生信息管理系统.zip
- 该仓库为agv系统调度软件的前后端实现。项目基于fastapi(python后端框架)和vue2实现了RESTful风格的前后端分离.zip
- 该项目是基于Scrapy框架的Python新闻爬虫,能够爬取网易,搜狐,凤凰和澎湃网站上的新闻,将标题,内容,评论,时间等内容整理并保存到本地.zip
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈



安全验证
文档复制为VIP权益,开通VIP直接复制

- 1
- 2
- 3
前往页