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/cffmpeg_decode.cpp

151 lines
4.6 KiB
C++

#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;
av_dict_set(&avdic, "buffer_size", "2048000", 0); //设置缓存大小1080p可将值调大
av_dict_set(&avdic, "rtsp_transport", "udp", 0); //以udp方式打开如果以tcp方式打开将udp替换为tcp
av_dict_set(&avdic, "stimeout", "2000000", 0); //设置超时断开连接时间,单位微秒
av_dict_set(&avdic, "max_delay", "3000", 0); //设置最大时延
av_dict_set(&avdic, "tune", "zerolatency", 0);
av_dict_set(&avdic, "preset", "ultrafast", 0);
if(avformat_open_input(&fmtCtx,_url.toLocal8Bit().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.";
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";
}