* @brief Sets up the QMediaRecorder pipeline for a new per-group .mp4. */
| 177 | * @brief Sets up the QMediaRecorder pipeline for a new per-group .mp4. |
| 178 | */ |
| 179 | bool Widgets::VideoExportWorker::ensureSession(int groupId, |
| 180 | const QString& projectTitle, |
| 181 | const QString& groupTitle, |
| 182 | const QImage& firstFrame) |
| 183 | { |
| 184 | const auto dt = QDateTime::currentDateTime(); |
| 185 | const auto stamp = dt.toString(QStringLiteral("yyyy-MM-dd_HH-mm-ss-zzz")); |
| 186 | const auto base = Misc::WorkspaceManager::instance().path(QStringLiteral("Video Recordings")); |
| 187 | const QString path = QStringLiteral("%1/%2/%3").arg(base, projectTitle, groupTitle); |
| 188 | |
| 189 | QDir dir(path); |
| 190 | if (!dir.exists() && !dir.mkpath(QStringLiteral("."))) { |
| 191 | qWarning() << "ImageExport: failed to create directory:" << path; |
| 192 | return false; |
| 193 | } |
| 194 | |
| 195 | const QString file = dir.filePath(stamp + QStringLiteral(".mp4")); |
| 196 | |
| 197 | VideoSession session; |
| 198 | session.outputPath = file; |
| 199 | session.frameSize = firstFrame.size(); |
| 200 | session.startTime = std::chrono::steady_clock::now(); |
| 201 | session.captureSession = std::make_unique<QMediaCaptureSession>(); |
| 202 | session.recorder = std::make_unique<QMediaRecorder>(); |
| 203 | session.frameInput = std::make_unique<QVideoFrameInput>(); |
| 204 | |
| 205 | session.captureSession->setVideoFrameInput(session.frameInput.get()); |
| 206 | session.captureSession->setRecorder(session.recorder.get()); |
| 207 | |
| 208 | QMediaFormat format; |
| 209 | format.setFileFormat(QMediaFormat::FileFormat::MPEG4); |
| 210 | format.setVideoCodec(QMediaFormat::VideoCodec::H264); |
| 211 | session.recorder->setMediaFormat(format); |
| 212 | session.recorder->setQuality(QMediaRecorder::HighQuality); |
| 213 | session.recorder->setOutputLocation(QUrl::fromLocalFile(file)); |
| 214 | |
| 215 | session.recorder->record(); |
| 216 | |
| 217 | QEventLoop loop; |
| 218 | QTimer timeoutTimer; |
| 219 | timeoutTimer.setSingleShot(true); |
| 220 | timeoutTimer.setInterval(1500); |
| 221 | QObject::connect(session.recorder.get(), |
| 222 | &QMediaRecorder::recorderStateChanged, |
| 223 | &loop, |
| 224 | [&loop](QMediaRecorder::RecorderState state) { |
| 225 | if (state == QMediaRecorder::RecordingState) |
| 226 | loop.quit(); |
| 227 | }); |
| 228 | QObject::connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); |
| 229 | if (session.recorder->recorderState() != QMediaRecorder::RecordingState) { |
| 230 | timeoutTimer.start(); |
| 231 | loop.exec(); |
| 232 | } |
| 233 | |
| 234 | if (session.recorder->recorderState() != QMediaRecorder::RecordingState) { |
| 235 | qWarning() << "ImageExport: recorder failed to start for" << file << "--" |
| 236 | << session.recorder->errorString(); |