#include "cffmpeg_decode.h"
// Cffmpeg_decode::Cffmpeg_decode() {
Cffmpeg_decode::Cffmpeg_decode(QObject *parent) : QObject(parent) {
  inputFormatCtx = avformat_alloc_context();
  outputFormatCtx = avformat_alloc_context();
  inputPacket = av_packet_alloc();
  outputPacket = av_packet_alloc();
  yuvFrame = av_frame_alloc();
  rgbFrame = av_frame_alloc();
  avformat_network_init();
}

Cffmpeg_decode::~Cffmpeg_decode() {
  if (!inputPacket)
    av_packet_free(&inputPacket);
  if (!outputPacket)
    av_packet_free(&outputPacket);
  if (!yuvFrame)
    av_frame_free(&yuvFrame);
  if (!rgbFrame)
    av_frame_free(&rgbFrame);
  if (!encoderCtx)
    avcodec_free_context(&encoderCtx);
  if (!encoderCtx)
    avcodec_close(encoderCtx);
  if (!decoderCtx)
    avcodec_free_context(&decoderCtx);
  if (!decoderCtx)
    avcodec_close(decoderCtx);
  if (!inputFormatCtx)
    avformat_close_input(&inputFormatCtx);
  if (!outputFormatCtx)
    avformat_close_input(&outputFormatCtx);
}

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

  inputFormatCtx->flags |= AVFMT_FLAG_NONBLOCK;

  // 打开输入流
  if (avformat_open_input(&inputFormatCtx, _url.toUtf8().data(), NULL, &avdic) <0) {
    printf("Cannot open input file.\n");
    return 0;
  }
  // 查找流信息
  if (avformat_find_stream_info(inputFormatCtx, NULL) < 0) {
    printf("Cannot find any stream in file.\n");
    return 0;
  }
  // 从输入流中找到第一个视频流
  for (int i = 0; i < inputFormatCtx->nb_streams; i++) {
    if (inputFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
      videoStreamIndex = i;
      continue;
    }
  }
  if (videoStreamIndex == -1) {
    printf("Cannot find video stream in file.\n");
    return 0;
  }

  // 获取视频流的解码器参数
  videoCodecPara = inputFormatCtx->streams[videoStreamIndex]->codecpar;

  decoder = avcodec_find_decoder(videoCodecPara->codec_id);
  if (!decoder) {
    printf("Cannot find valid decode codec.\n");
    return 0;
  }
  // 为解码器上下文分配空间
  decoderCtx = avcodec_alloc_context3(decoder);
  if (!decoderCtx) {
    printf("Cannot find valid decode codec context.\n");
    return 0;
  }
  // 初始化解码器上下文
  if (avcodec_parameters_to_context(decoderCtx, videoCodecPara) < 0) {
    printf("Cannot initialize parameters.\n");
    return 0;
  }
  // 打开解码器
  if (avcodec_open2(decoderCtx, decoder, NULL) < 0) {
    printf("Cannot open codec.\n");
    return 0;
  }

  //===============================编码================================
  //  1、输出文件设置
  if (avformat_alloc_output_context2(&outputFormatCtx, NULL, NULL, "output_video.mp4") < 0) {
    qDebug() << "Could not create output context.\n";
    return 0;
  }

  // 从输入流中找到第一个视频流
  for (int i = 0; i < inputFormatCtx->nb_streams; i++) {
      if (inputFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
          videoStreamIndexOut = i;
          continue;
      }
  }
  if (videoStreamIndexOut == -1) {
      printf("Cannot find video stream in file.\n");
      return 0;
  }
  // 获取视频流的解码器参数
  videoCodecPara2 = inputFormatCtx->streams[videoStreamIndexOut]->codecpar;

  // 3、创建输出视频流
  outStream = avformat_new_stream(outputFormatCtx, NULL);
  if (!outStream) {
    qDebug() << "Failed allocating output stream.\n";
    return 0;
  }
  //4、查找编码器
  encoder = avcodec_find_encoder(videoCodecPara2->codec_id);
  if(!encoder){
      return 0;
  }

  //5、分配解码器上下文
  encoderCtx = avcodec_alloc_context3(encoder);
  if (!encoderCtx) {
    return 0;
  }

  //初始化视频AVCodecContext
  encoderCtx->height = videoCodecPara2->height;
  encoderCtx->width = videoCodecPara2->width;
  videoCodecPara2->framerate = av_guess_frame_rate(inputFormatCtx,inputFormatCtx->streams[videoStreamIndexOut],NULL);

  //视频流的时间基是1 / 帧率
  encoderCtx->time_base = av_inv_q(inputFormatCtx->streams[videoStreamIndexOut]->codecpar->framerate);
  encoderCtx->sample_aspect_ratio = inputFormatCtx->streams[videoStreamIndexOut]->codecpar->sample_aspect_ratio;
  if (encoder->pix_fmts)
  {
      encoderCtx->pix_fmt = encoder->pix_fmts[0];
  }
  encoderCtx->codec_type = AVMEDIA_TYPE_VIDEO;
  encoderCtx->codec_id = AV_CODEC_ID_H264;
  encoderCtx->bit_rate = 2000000;
  encoderCtx->time_base.num = 1;
  encoderCtx->time_base.den = 20;

  //全局头
  if (outputFormatCtx->oformat->flags & AVFMT_GLOBALHEADER)
  {
      encoderCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
  }

  // //设置选项
  // AVDictionary *param = 0;
  // //H.264
  // if(videoCodecPara->codec_id == AV_CODEC_ID_H264) {
  //     av_dict_set(&param, "preset", "slow", 0);
  //     av_dict_set(&param, "tune", "zerolatency", 0);
  //     av_dict_set(&param, "profile", "main", 0);
  // }
  // //H.265
  // if(videoCodecPara->codec_id == AV_CODEC_ID_H265){
  //     av_dict_set(&param, "preset", "ultrafast", 0);
  //     av_dict_set(&param, "tune", "zero-latency", 0);
  // }

  //6、打开编码器
  if (avcodec_open2(encoderCtx, encoder, NULL) < 0) {
      qDebug() << "Error occurred when opening encoder.\n";
    //return 0;
  }

  avcodec_parameters_from_context(outputFormatCtx->streams[0]->codecpar, encoderCtx);
  //avcodec_parameters_to_context(encoderCtx,outStream->codecpar);

  // 打开输出文件
  if (!(outputFormatCtx->oformat->flags & AVFMT_NOFILE)) {
      if (avio_open(&outputFormatCtx->pb,
                    outputFormatCtx->url /* "output_video.mp4"*/,
                    AVIO_FLAG_WRITE) < 0) {
          printf("Could not open output file.\n");
          return 0;
      }
  }

  //写入输出文件的头信息
  if (avformat_write_header(outputFormatCtx, NULL) < 0) {
    qDebug() << "Error occurred when opening output file.\n";
    //return 0;
  }
  //格式化输出输出文件信息
  av_dump_format(outputFormatCtx,0,outputFormatCtx->url,1);



  // 初始化图像转换器
  swsCtx = sws_getContext(decoderCtx->width,   //
                          decoderCtx->height,  //
                          decoderCtx->pix_fmt, //
                          decoderCtx->width,   //
                          decoderCtx->height,  //
                          AV_PIX_FMT_RGB32,    //
                          SWS_BICUBIC, NULL, NULL, NULL);
  numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB32,   //
                                      decoderCtx->width,  //
                                      decoderCtx->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,   //
                                 decoderCtx->width,  //
                                 decoderCtx->height, 1);
  if (res < 0) {
    qDebug() << "Fill arrays failed.\n";
    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(inputFormatCtx, inputPacket) >= 0) {
    if (IsstopPlay) {
      qDebug() << "video play stop";
      break;
    }

    if (inputPacket->stream_index == videoStreamIndex) {
      // 解码数据包
      if (avcodec_send_packet(decoderCtx, inputPacket) >= 0) {
        int ret;
        while ((ret = avcodec_receive_frame(decoderCtx, yuvFrame)) >= 0) {
          if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            return;
          } else if (ret < 0) {
            fprintf(stderr, "Error during decoding\n");
            exit(1);
          }
          sws_scale(swsCtx,             //
                    yuvFrame->data,     //
                    yuvFrame->linesize, //
                    0,                  //
                    decoderCtx->height, //
                    rgbFrame->data,     //
                    rgbFrame->linesize);

          QImage img(out_buffer,         //
                     decoderCtx->width,  //
                     decoderCtx->height, //
                     QImage::Format_RGB32);
          emit sendQImage(img);
          QThread::msleep(28);



          //将解码后的帧写入输出文件
          if (av_write_frame(outputFormatCtx, inputPacket) < 0) {
            //qDebug() << "Error muxing packet.\n";
            break;
          }


        }
      }
      av_packet_unref(inputPacket);
    }
    //花屏
    // if (av_read_frame(inputFormatCtx, inputPacket) < 0) {
    //   break; // 达到文件末尾
    // }
  }
}

// 退出
void Cffmpeg_decode::stop() {

  // 写入输出文件的尾信息
  // av_write_trailer(outputFormatCtx);
  IsstopPlay = true;
  if (!inputPacket)
    av_packet_free(&inputPacket);
  if (!outputPacket)
    av_packet_free(&outputPacket);
  if (!yuvFrame)
    av_frame_free(&yuvFrame);
  if (!rgbFrame)
    av_frame_free(&rgbFrame);
  if (!encoderCtx)
    avcodec_free_context(&encoderCtx);
  if (!encoderCtx)
    avcodec_close(encoderCtx);
  if (!decoderCtx)
    avcodec_free_context(&decoderCtx);
  if (!decoderCtx)
    avcodec_close(decoderCtx);
  if (!inputFormatCtx)
    avformat_close_input(&inputFormatCtx);
  if (!outputFormatCtx)
    avformat_close_input(&outputFormatCtx);
}