#include "savestream.h"

SaveStream::SaveStream(QObject *parent) : QObject{parent} {}

bool SaveStream::init(AVFormatContext *formatContext,
                      AVPacketQueueManager *queueManager, int videoIndex) {
    // m_inputCodecContex = codecContex;
    m_inputFormatContext = formatContext;
    // m_saverQueue = queue;
    m_queueManager = queueManager;
    m_videoIndex = videoIndex;
    m_start = openFile();
    if (!m_start) {
        free();
    }
    return m_start;
}

void SaveStream::setSaveFileDirPath(QString fileDirPath) {
    m_outputDirPath = fileDirPath;
}

void SaveStream::close() {
    // QMutexLocker locker(&m_mutex);
    m_start = false;
}

void SaveStream::startSaveStream() {
    qDebug() << "SaveStreamThreadID:" << QThread::currentThreadId();
    if (!m_start) {
        return;
    }
    while (m_start || !m_queueManager->isEmptySaveQueue()) {
        AVPacket *inputPacket = m_queueManager->dequeueSavePacket();
        if (inputPacket) {
            // 由于保存的m_formatContextSave只创建了一个视频流,而读取到的图像的流索引不一定为0,可能会出现错误【Invalid
            // packet stream index: 1】
            // 所以这里需要将stream_index指定为和m_formatContextSave中视频流索引相同,因为就一个流,所以直接设置为0
            inputPacket->stream_index = 0;
            av_write_frame(m_formatContextSave,
                           inputPacket);  // 将数据包写入输出媒体文件
            av_packet_unref(inputPacket);
            inputPacket = nullptr;
        } else {
            QThread::usleep(1000);
        }
    }
    // 写入文件尾
    if (m_formatContextSave && m_writeHeader) {
        av_write_trailer(m_formatContextSave);
        m_writeHeader = false;
    }
    free();
    qDebug() << "视频保存结束!";
    emit sendErrorMessageSignal("视频保存结束!",
                                NotificationType::NOTIFICATION_SUCCESS);
}

bool SaveStream::openFile() {
    // QMutexLocker locker(&m_mutex);
    QDir dir;
    if (!dir.exists(m_outputDirPath)) {
        dir.mkdir(m_outputDirPath);
    }
    QString strName =
        QString("/%1.h264")
            .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH-mm-ss"));
    strName = m_outputDirPath + strName;
    // const AVOutputFormat *ofmt = av_guess_format("mp4", NULL, NULL);
    int ret = avformat_alloc_output_context2(
        &m_formatContextSave, nullptr, nullptr, strName.toStdString().data());
    if (ret < 0) {
        showError(ret);
        qWarning() << "avformat_alloc_output_context2 Error!";
        free();
        return false;
    }
    // m_videoStreamOut->codecpar->codec_tag = 0;
    // if (m_formatContextSave->oformat->flags & AVFMT_GLOBALHEADER) {
    //   m_formatContextSave->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
    //   // m_videoStreamOut->codecpar->extradata = (uint8_t *)av_malloc(1024);
    //   // m_videoStreamOut->codecpar->extradata_size = 0;
    // }
    // 创建并初始化AVIOContext以访问url所指示的资源。
    ret = avio_open(&m_formatContextSave->pb, strName.toStdString().data(),
                    AVIO_FLAG_WRITE);
    if (ret < 0) {
        showError(ret);
        qWarning() << "Open file Error";
        free();
        return false;
    }
    // 向媒体文件添加新流
    m_videoStreamOut = avformat_new_stream(m_formatContextSave, nullptr);
    if (!m_videoStreamOut) {
        free();
        qWarning() << "Create New Stream Error";
        return false;
    }
    // 拷贝一些参数,给codecpar赋值(这里使用编码器上下文进行赋值)
    // ret = avcodec_parameters_from_context(m_videoStreamOut->codecpar,
    //                                       m_inputCodecContex);
    ret = avcodec_parameters_copy(
        m_videoStreamOut->codecpar,
        m_inputFormatContext->streams[m_videoIndex]->codecpar);
    if (ret < 0) {
        showError(ret);
        free();
        qWarning() << "avcodec_parameters_from_context Failed";
        return false;
    }

    // 写入文件头
    ret = avformat_write_header(m_formatContextSave, nullptr);
    if (ret < 0) {
        showError(ret);
        free();
        qWarning() << "avformat_write_header Error";
        return false;
    }

    m_writeHeader = true;
    qDebug() << "保存视频文件初始化成功!";
    return true;
}

void SaveStream::free() {
    // 关闭文件
    if (m_formatContextSave && !(m_formatContextSave->flags & AVFMT_NOFILE)) {
        avio_close(m_formatContextSave->pb);
        // av_freep(m_videoStreamOut);

        // avformat_free_context(m_formatContextSave);
        // m_formatContextSave = nullptr;
    }
    if (m_formatContextSave) {
        avformat_free_context(m_formatContextSave);
        m_formatContextSave = nullptr;
    }
}