22 const QVideoFrameFormat &format, std::optional<AVPixelFormat> hwFormat)
23 : EncoderThread(recordingEngine), m_settings(settings)
25 setObjectName(QLatin1String(
"VideoEncoder"));
27 const AVPixelFormat swFormat = QFFmpegVideoBuffer::toAVPixelFormat(format.pixelFormat());
28 qreal frameRate = format.streamFrameRate();
29 if (frameRate <= 0.) {
30 qWarning() <<
"Invalid frameRate" << frameRate <<
"; Using the default instead";
36 m_sourceParams.size = format.frameSize();
37 m_sourceParams.format = hwFormat && *hwFormat != AV_PIX_FMT_NONE ? *hwFormat : swFormat;
40 m_sourceParams.swFormat =
41 isSwPixelFormat(m_sourceParams.format) ? m_sourceParams.format : swFormat;
42 m_sourceParams.transform = qNormalizedSurfaceTransformation(format);
43 m_sourceParams.frameRate = frameRate;
44 m_sourceParams.colorTransfer = QFFmpeg::toAvColorTransfer(format.colorTransfer());
45 m_sourceParams.colorSpace = QFFmpeg::toAvColorSpace(format.colorSpace());
46 m_sourceParams.colorRange = QFFmpeg::toAvColorRange(format.colorRange());
48 if (!m_settings.videoResolution().isValid())
49 m_settings.setVideoResolution(m_sourceParams.size);
51 if (m_settings.videoFrameRate() <= 0.)
52 m_settings.setVideoFrameRate(m_sourceParams.frameRate);
59 if (!frame.isValid()) {
60 setEndOfSourceStream();
65 auto guard = lockLoopData();
67 resetEndOfSourceStream();
70 m_shouldAdjustTimeBaseForNextFrame =
true;
76 const bool queueFull = m_videoFrameQueue.size() >= m_maxQueueSize;
79 qCDebug(qLcFFmpegVideoEncoder) <<
"RecordingEngine frame queue full. Frame lost.";
83 m_videoFrameQueue.push({ frame, m_shouldAdjustTimeBaseForNextFrame });
84 m_shouldAdjustTimeBaseForNextFrame =
false;
105 m_frameEncoder = VideoFrameEncoder::create(m_settings, m_sourceParams,
106 m_recordingEngine.avFormatContext());
108 qCDebug(qLcFFmpegVideoEncoder) <<
"VideoEncoder::init started video device thread.";
109 if (!m_frameEncoder) {
110 emit m_recordingEngine.sessionError(QMediaRecorder::ResourceError,
111 u"Could not initialize encoder"_s);
115 return EncoderThread::init();
148 Q_ASSERT(m_frameEncoder);
152 FrameInfo frameInfo = takeFrame();
153 QVideoFrame &frame = frameInfo.frame;
154 Q_ASSERT(frame.isValid());
160 auto *videoBuffer =
dynamic_cast<QFFmpegVideoBuffer *>(QVideoFramePrivate::hwBuffer(frame));
163 auto *hwFrame = videoBuffer->getHWFrame();
164 if (hwFrame && hwFrame->format == m_frameEncoder->sourceFormat())
165 avFrame.reset(av_frame_clone(hwFrame));
169 frame.map(QVideoFrame::ReadOnly);
170 auto size = frame.size();
171 avFrame = makeAVFrame();
172 avFrame->format = m_frameEncoder->sourceFormat();
173 avFrame->width = size.width();
174 avFrame->height = size.height();
176 for (
int i = 0; i < 4; ++i) {
177 avFrame->data[i] =
const_cast<uint8_t *>(frame.bits(i));
178 avFrame->linesize[i] = frame.bytesPerLine(i);
191 if (frame.pixelFormat() == QVideoFrameFormat::Format_Jpeg) {
194 img = frame.toImage();
195 avFrame->data[0] = (uint8_t *)img.bits();
196 avFrame->linesize[0] = img.bytesPerLine();
199 Q_ASSERT(avFrame->data[0]);
205 const auto [startTime, endTime] = frameTimeStamps(frame);
207 if (frameInfo.shouldAdjustTimeBase) {
208 m_baseTime += startTime - m_lastFrameTime;
209 qCDebug(qLcFFmpegVideoEncoder)
210 <<
">>>> adjusting base time to" << m_baseTime << startTime << m_lastFrameTime;
213 const qint64 time = startTime - m_baseTime;
214 m_lastFrameTime = endTime;
216 setAVFrameTime(*avFrame, m_frameEncoder->getPts(time), m_frameEncoder->getTimeBase());
218 m_recordingEngine.newTimeStamp(time / 1000);
220 qCDebug(qLcFFmpegVideoEncoder)
221 <<
">>> sending frame" << avFrame->pts << time << m_lastFrameTime;
222 int ret = m_frameEncoder->sendFrame(std::move(avFrame));
224 qCDebug(qLcFFmpegVideoEncoder) <<
"error sending frame" << ret << AVError(ret);
225 emit m_recordingEngine.sessionError(QMediaRecorder::ResourceError, err2str(ret));