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