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