#include "ScreenVideo.h"
ScreenVideo::ScreenVideo(QWidget *parent)
: QMainWindow(parent)
, m_bPlay(false)
, m_pInputContext(nullptr)
, m_lVideoIndex(-1)
, m_lLastReadTime(0)
, m_pSwsScale(nullptr)
{
ui.setupUi(this);
connect(ui.m_pBtnBegin, SIGNAL(clicked()), this, SLOT(sloBeginVideo()));
connect(ui.m_pBtnStop, SIGNAL(clicked()), this, SLOT(sloStopVideo()));
connect(ui.m_pRBtnRtsp, SIGNAL(clicked(bool)), this, SLOT(sloRtspPath(bool)));
connect(ui.m_pRBtnRtmp, SIGNAL(clicked(bool)), this, SLOT(sloRtmpPath(bool)));
connect(ui.m_pRBtnUdp, SIGNAL(clicked(bool)), this, SLOT(sloUdpPath(bool)));
ui.m_pBtnStop->setEnabled(false);
long l = avformat_version();
//初始化所有复用器,封装器
//av_register_all();
avfilter_register_all();
//初始化所有输入输出设备
avdevice_register_all();
//初始化网络
avformat_network_init();
av_log_set_level(AV_LOG_INFO);
//自适应DPI设置,windows专用
#ifdef Q_OS_WINDOWS
SetProcessDPIAware();
#endif
}
ScreenVideo::~ScreenVideo()
{
m_bPlay = false;
}
static int interrupt(void *p)
{
ScreenVideo *pThis = (ScreenVideo*)p;
int64_t timeOut = 5;
int64_t timeNow = av_gettime() - pThis->m_lLastReadTime;
if (timeNow >= timeOut * 1000 * 1000)
return -1;
return 0;
}
long ScreenVideo::OpenInput(const char *pUrl)
{
m_pInputContext = avformat_alloc_context();
m_lLastReadTime = av_gettime();
m_pInputContext->interrupt_callback.opaque = this;
m_pInputContext->interrupt_callback.callback = interrupt;
AVDictionary *pOptions = NULL;
av_dict_set(&pOptions, "probesize", "4096", 0);
av_dict_set(&pOptions, "max_delay", "100", 0);
av_dict_set_int(&pOptions, "max_analyze_duration", 5 * AV_TIME_BASE, 0);
if (ui.m_pRBtnRtsp->isChecked())
{
av_dict_set(&pOptions, "rtsp_transport", "tcp", 0);
av_dict_set(&pOptions, "buffer_size", "1024000", 0);
}
long ret = avformat_open_input(&m_pInputContext, pUrl, nullptr, &pOptions);
if (ret >= 0)
{
av_log(NULL, AV_LOG_INFO, "Open input success!\n");
}
else {
av_log(NULL, AV_LOG_INFO, "Open input error!(%d)\n", ret);
return ret;
}
//m_pInputContext->flags |= AVFMT_FLAG_NOBUFFER;
ret = avformat_find_stream_info(m_pInputContext, nullptr);
if (ret >= 0)
{
av_log(NULL, AV_LOG_INFO, "Find stream success!\n");
}
else {
av_log(NULL, AV_LOG_INFO, "Find stream error!(%d)\n", ret);
return ret;
}
for (size_t s = 0;s < m_pInputContext->nb_streams; s++)
{
if (m_pInputContext->streams[s]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
m_lVideoIndex = s;
break;
}
}
if (m_lVideoIndex < 0)
return -1;
return 0;
}
void ScreenVideo::CloseInput()
{
if (m_pInputContext != nullptr)
avformat_close_input(&m_pInputContext);
}
long ScreenVideo::InitDecode()
{
AVCodecContext *pCodecContext = m_pInputContext->streams[m_lVideoIndex]->codec;
AVCodec *pCodec= avcodec_find_decoder(pCodecContext->codec_id);
long ret = avcodec_open2(pCodecContext, pCodec, nullptr);
if (ret >= 0)
{
av_log(NULL, AV_LOG_INFO, "decoder open success!\n");
}
else {
av_log(NULL, AV_LOG_ERROR, "decoder open error!(%d)\n", ret);
return ret;
}
return ret;
}
void ScreenVideo::UnInitDecode()
{
if (m_pInputContext != nullptr && m_lVideoIndex >= 0)
avcodec_close(m_pInputContext->streams[m_lVideoIndex]->codec);
}
long ScreenVideo::DecodePacket(AVFrame *pDstFrame, AVPacket *pPktSrc)
{
int got_picture = 0;
AVCodecContext *pCodecContext = m_pInputContext->streams[m_lVideoIndex]->codec;
long ret = avcodec_decode_video2(pCodecContext, pDstFrame, &got_picture, pPktSrc);
if (ret >= 0 && got_picture != 0)
return 0;
return -1;
}
long ScreenVideo::InitSwsScale(long lSrcW, long lSrcH, AVPixelFormat sSrcPix, long lDstW, long lDstH, AVPixelFormat sDstPix)
{
m_pSwsScale = sws_getContext(
lSrcW, lSrcH, sSrcPix,
lDstW, lDstH, sDstPix,
SWS_BICUBIC, NULL, NULL, NULL);
if (m_pSwsScale == nullptr)
return -1;
return 0;
}
std::shared_ptr<AVPacket> ScreenVideo::ReadPacketFromStream()
{
std::shared_ptr<AVPacket> packet(static_cast<AVPacket *>(av_malloc(sizeof(AVPacket))), [&](AVPacket *p) {av_packet_free(&p); av_freep(&p); });
av_init_packet(packet.get());
packet->data = NULL;
packet->size = 0;
m_lLastReadTime = av_gettime();
long ret = av_read_frame(m_pInputContext, packet.get());
if (ret >= 0)
return packet;
av_log(NULL, AV_LOG_ERROR, "read packet error!(%d)", ret);
return nullptr;
}
void ScreenVideo::sloBeginVideo()
{
QString qsPath = ui.m_pEdtUrlPath->text();
long ret = OpenInput(qsPath.toLocal8Bit().data());
if (ret >= 0)
ret = InitDecode();
if (ret >= 0) {
long lW = m_pInputContext->streams[m_lVideoIndex]->codec->width;
long lH = m_pInputContext->streams[m_lVideoIndex]->codec->height;
AVPixelFormat sPix = m_pInputContext->streams[m_lVideoIndex]->codec->pix_fmt;
ret = InitSwsScale(lW, lH, sPix, lW, lH, AV_PIX_FMT_RGB32);
}
if (ret >= 0)
{
AVFrame *pFrame = av_frame_alloc();
AVFrame *pRGBFrame = av_frame_alloc();
long lW = m_pInputContext->streams[m_lVideoIndex]->codec->width;
long lH = m_pInputContext->streams[m_lVideoIndex]->codec->height;
long lSize = av_image_get_buffer_size(AV_PIX_FMT_RGB32, lW, lH, 1);
uint8_t *pBuff = static_cast<uint8_t *>(av_malloc(sizeof(uint8_t) * lSize));
av_image_fill_arrays(pRGBFrame->data, pRGBFrame->linesize, pBuff, AV_PIX_FMT_RGB32, lW, lH, 1);
m_bPlay = true;
ui.m_pBtnBegin->setEnabled(false);
ui.m_pBtnStop->setEnabled(true);
long lTemp = AV_PICTURE_TYPE_I;
long lCount = 0;
bool bReConnect = false;
while (m_bPlay)
{
QApplication::processEvents();
std::shared_ptr<AVPacket> pktRead = ReadPacketFromStream();
if (pktRead == nullptr)
{
bReConnect = true;
break;
}
if (pktRead->stream_index == m_lVideoIndex)
{
int64_t lBeginTime = av_gettime();
long dec = DecodePacket(pFrame, pktRead.get());
if (lTemp != pFrame->pict_type)
{
av_log(NULL, AV_LOG_INFO, "Frame is %d pic!(%d)\n", lTemp, lCount);
lTemp = pFrame->pict_type;
lCount = 0;
}
lCount++;
int64_t lDecodeTime = av_gettime() - lBeginTime;
if (dec >= 0)
{
sws_scale(m_pSwsScale, (const UCHAR * const *)pFrame->data, pFrame->linesize, 0, lH, pRGBFrame->data, pRGBFrame->linesize);
QImage img((uchar *)pRGBFrame->data[0], lW, lH, QImage::Format_RGB32);
QPixmap pixmap = QPixmap::fromImage(img);
QPixmap fitpixmap = pixmap.scaled(ui.m_pLblVideo->width(), ui.m_pLblVideo->height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); // 饱满填充
ui.m_pLblVideo->setPixmap(fitpixmap);
}
int64_t lEndTime = av_gettime() - lDecodeTime;
}
}
av_free(pBuff);
av_frame_free(&pRGBFrame);
av_frame_free(&pFrame);
UnInitDecode();
CloseInput();
if (bReConnect)
{
sloBeginVideo();
}
}
return;
/*
//long lScreenW = ui.m_pEdtWidth->text().toLong();
//long lScreenH = ui.m_pEdtHeight->text().toLong();
//QString qsVideoSize = QString("%1x%2").arg(lScreenW).arg(lScreenH);
////解码用来显示
//AVFormatContext *pdeFormatCtx = NULL;
//pdeFormatCtx = avformat_alloc_context();
//AVInputFormat *ifmt = av_find_input_format("gdigrab");
//AVDictionary* options = NULL;
//av_dict_set(&options, "framerate", "30", 0);//帧率调整
//av_dict_set(&options, "video_size", qsVideoSize.toLocal8Bit().data(), 0);
//if (avformat_open_input(&pdeFormatCtx,"desktop", ifmt, &options))
//{
// QMessageBox::information(NULL, "说明", "打开输入设备错误!avformat_open_input");
// avformat_close_input(&pdeFormatCtx);
// return ;
//}
//if (avformat_find_stream_info(pdeFormatCtx,NULL) < 0)
//{
// QMessageBox::information(NULL, "说明", "无法找到流!avformat_find_stream_info");
// return;
//}
//AVPacket *pPacketEx = (AVPacket *)av_malloc(sizeof(AVPacket));
//av_read_frame(pdeFormat