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++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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);
}