#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, "listen_timeout", "2", 0);   //设置超时断开连接时间,单位微秒
    av_dict_set(&avdic, "max_delay", "3000", 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.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.";
        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";
}