|
|
#include "cffmpeg_decode.h"
|
|
|
Cffmpeg_decode::Cffmpeg_decode() {
|
|
|
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", "tcp", 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);
|
|
|
}
|