You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
PayloadAPP/Src/Video/cffmpeg_decode.cpp

165 lines
4.8 KiB
C++

#include "cffmpeg_decode.h"
// Cffmpeg_decode::Cffmpeg_decode() {
Cffmpeg_decode::Cffmpeg_decode(QObject *parent) : QObject(parent) {
fmtCtx = avformat_alloc_context();
pkt = av_packet_alloc();
yuvFrame = av_frame_alloc();
rgbFrame = av_frame_alloc();
}
Cffmpeg_decode::~Cffmpeg_decode() {
if (!pkt)
av_packet_free(&pkt);
if (!yuvFrame)
av_frame_free(&yuvFrame);
if (!rgbFrame)
av_frame_free(&rgbFrame);
if (!videoCodecCtx)
avcodec_free_context(&videoCodecCtx);
if (!videoCodecCtx)
avcodec_close(videoCodecCtx);
if (!fmtCtx)
avformat_close_input(&fmtCtx);
}
void Cffmpeg_decode::setUrl(QString url) { _url = url; }
bool Cffmpeg_decode::open_input_file() {
if (_url.isEmpty())
return 0;
AVDictionary *avdic = NULL;
// 设置缓存大小1080p可将值调大
av_dict_set(&avdic, "buffer_size", "2048000", 0);
// 以udp方式打开如果以tcp方式打开将udp替换为tcp
av_dict_set(&avdic, "rtsp_transport", "udp", 0);
// 设置超时断开连接时间,单位微秒//listen_timeout
av_dict_set(&avdic, "listen_timeout", "200000", 0);
// av_dict_set(&avdic, "stimeout", "200000", 0);
av_dict_set(&avdic, "max_delay", "3", 0); // 设置最大时延
av_dict_set(&avdic, "tune", "zerolatency", 0);
av_dict_set(&avdic, "preset", "ultrafast", 0);
fmtCtx->flags |= AVFMT_FLAG_NONBLOCK;
if (avformat_open_input(&fmtCtx, _url.toUtf8().data(), NULL, &avdic) < 0) {
printf("Cannot open input file.\n");
return 0;
}
if (avformat_find_stream_info(fmtCtx, NULL) < 0) {
printf("Cannot find any stream in file.\n");
return 0;
}
int streamCnt = fmtCtx->nb_streams;
for (int i = 0; i < streamCnt; i++) {
if (fmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStreamIndex = i;
continue;
}
}
if (videoStreamIndex == -1) {
printf("Cannot find video stream in file.\n");
return 0;
}
AVCodecParameters *videoCodecPara =
fmtCtx->streams[videoStreamIndex]->codecpar;
if (!(videoCodec = avcodec_find_decoder(videoCodecPara->codec_id))) {
printf("Cannot find valid decode codec.\n");
return 0;
}
if (!(videoCodecCtx = avcodec_alloc_context3(videoCodec))) {
printf("Cannot find valid decode codec context.\n");
return 0;
}
if (avcodec_parameters_to_context(videoCodecCtx, videoCodecPara) < 0) {
printf("Cannot initialize parameters.\n");
return 0;
}
if (avcodec_open2(videoCodecCtx, videoCodec, NULL) < 0) {
printf("Cannot open codec.\n");
return 0;
}
img_ctx = sws_getContext(videoCodecCtx->width, videoCodecCtx->height,
videoCodecCtx->pix_fmt, videoCodecCtx->width,
videoCodecCtx->height, AV_PIX_FMT_RGB32, SWS_BICUBIC,
NULL, NULL, NULL);
numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB32, videoCodecCtx->width,
videoCodecCtx->height, 1);
out_buffer = (unsigned char *)av_malloc(numBytes * sizeof(unsigned char));
int res = av_image_fill_arrays(rgbFrame->data, rgbFrame->linesize, out_buffer,
AV_PIX_FMT_RGB32, videoCodecCtx->width,
videoCodecCtx->height, 1);
if (res < 0) {
qDebug() << "Fill arrays failed.";
return 0;
}
return true;
}
// 线程里持续执行
void Cffmpeg_decode::run() {
if (!open_input_file()) {
qDebug() << "Please open video file first.";
emit sendConnectFail(1);
IsstopPlay = true;
return;
}
while (av_read_frame(fmtCtx, pkt) >= 0) {
if (pkt->stream_index == videoStreamIndex) {
if (avcodec_send_packet(videoCodecCtx, pkt) >= 0) {
int ret;
while ((ret = avcodec_receive_frame(videoCodecCtx, yuvFrame)) >= 0) {
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
else if (ret < 0) {
fprintf(stderr, "Error during decoding\n");
exit(1);
}
sws_scale(img_ctx, yuvFrame->data, yuvFrame->linesize, 0,
videoCodecCtx->height, rgbFrame->data, rgbFrame->linesize);
QImage img(out_buffer, videoCodecCtx->width, videoCodecCtx->height,
QImage::Format_RGB32);
emit sendQImage(img);
// int m_timeframe= ((double)videoCodecCtx->framerate.den /
// videoCodecCtx->framerate.num)*1000;
QThread::msleep(28);
}
}
av_packet_unref(pkt);
}
if (IsstopPlay) {
break;
}
}
qDebug() << "All video play done";
}
// 退出
void Cffmpeg_decode::stop() {
IsstopPlay = true;
if (!pkt)
av_packet_free(&pkt);
if (!yuvFrame)
av_frame_free(&yuvFrame);
if (!rgbFrame)
av_frame_free(&rgbFrame);
if (!videoCodecCtx)
avcodec_free_context(&videoCodecCtx);
if (!videoCodecCtx)
avcodec_close(videoCodecCtx);
if (!fmtCtx)
avformat_close_input(&fmtCtx);
}