Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qffmpegencoder.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3#include "qffmpegencoder_p.h"
6#include "private/qmultimediautils_p.h"
7
8#include <qdebug.h>
9#include <qiodevice.h>
10#include <qaudiosource.h>
11#include <qaudiobuffer.h>
12#include "qffmpegaudioinput_p.h"
13#include <private/qplatformcamera_p.h>
14#include <private/qplatformvideosource_p.h>
18
19#include <qloggingcategory.h>
20
21extern "C" {
22#include <libavutil/pixdesc.h>
23#include <libavutil/common.h>
24}
25
27
28static Q_LOGGING_CATEGORY(qLcFFmpegEncoder, "qt.multimedia.ffmpeg.encoder")
29
30namespace QFFmpeg
31{
32
33Encoder::Encoder(const QMediaEncoderSettings &settings, const QUrl &url)
35{
36 const AVOutputFormat *avFormat = QFFmpegMediaFormatInfo::outputFormatForFileFormat(settings.fileFormat());
37
38 formatContext = avformat_alloc_context();
39 formatContext->oformat = const_cast<AVOutputFormat *>(avFormat); // constness varies
40
42 formatContext->url = (char *)av_malloc(encoded.size() + 1);
43 memcpy(formatContext->url, encoded.constData(), encoded.size() + 1);
44 formatContext->pb = nullptr;
45 auto result = avio_open2(&formatContext->pb, formatContext->url, AVIO_FLAG_WRITE, nullptr, nullptr);
46 qCDebug(qLcFFmpegEncoder) << "opened" << result << formatContext->url;
47
48 muxer = new Muxer(this);
49}
50
51Encoder::~Encoder()
52{
53}
54
55void Encoder::addAudioInput(QFFmpegAudioInput *input)
56{
57 audioEncode = new AudioEncoder(this, input, settings);
58 connect(input, &QFFmpegAudioInput::newAudioBuffer, this, &Encoder::newAudioBuffer);
59 input->setRunning(true);
60}
61
62void Encoder::addVideoSource(QPlatformVideoSource * source)
63{
64 auto frameFormat = source->frameFormat();
65
66 if (!frameFormat.isValid()) {
67 qCWarning(qLcFFmpegEncoder) << "Cannot add source; invalid vide frame format";
68 return;
69 }
70
71 std::optional<AVPixelFormat> hwPixelFormat = source->ffmpegHWPixelFormat()
72 ? AVPixelFormat(*source->ffmpegHWPixelFormat())
73 : std::optional<AVPixelFormat>{};
74
75 qCDebug(qLcFFmpegEncoder) << "adding video source" << source->metaObject()->className() << ":"
76 << "pixelFormat=" << frameFormat.pixelFormat()
77 << "frameSize=" << frameFormat.frameSize()
78 << "frameRate=" << frameFormat.frameRate() << "ffmpegHWPixelFormat="
79 << (hwPixelFormat ? *hwPixelFormat : AV_PIX_FMT_NONE);
80
81 auto veUPtr = std::make_unique<VideoEncoder>(this, settings, frameFormat, hwPixelFormat);
82 if (veUPtr->isValid()) {
83 auto ve = veUPtr.release();
85 [=](const QVideoFrame &frame) { ve->addFrame(frame); });
86 videoEncoders.append(ve);
87 connections.append(conn);
88 }
89}
90
91void Encoder::start()
92{
93 qCDebug(qLcFFmpegEncoder) << "Encoder::start!";
94
95 formatContext->metadata = QFFmpegMetaData::toAVMetaData(metaData);
96
97 int res = avformat_write_header(formatContext, nullptr);
98 if (res < 0) {
99 qWarning() << "could not write header, error:" << res << err2str(res);
100 emit error(QMediaRecorder::ResourceError, "Cannot start writing the stream");
101 return;
102 }
103
104 qCDebug(qLcFFmpegEncoder) << "stream header is successfully written";
105
106 muxer->start();
107 if (audioEncode)
108 audioEncode->start();
109 for (auto *videoEncoder : videoEncoders)
110 if (videoEncoder->isValid())
111 videoEncoder->start();
112
113 isRecording = true;
114}
115
116EncodingFinalizer::EncodingFinalizer(Encoder *e) : encoder(e) {
118}
119
120void EncodingFinalizer::run()
121{
122 if (encoder->audioEncode)
123 encoder->audioEncode->kill();
124 for (auto &videoEncoder : encoder->videoEncoders)
125 videoEncoder->kill();
126 encoder->muxer->kill();
127
128 int res = av_write_trailer(encoder->formatContext);
129 if (res < 0)
130 qWarning() << "could not write trailer" << res;
131
132 avformat_free_context(encoder->formatContext);
133 qCDebug(qLcFFmpegEncoder) << " done finalizing.";
134 emit encoder->finalizationDone();
135 delete encoder;
136}
137
138void Encoder::finalize()
139{
140 qCDebug(qLcFFmpegEncoder) << ">>>>>>>>>>>>>>> finalize";
141
142 for (auto &conn : connections)
143 disconnect(conn);
144
145 auto *finalizer = new EncodingFinalizer(this);
146 finalizer->start();
147}
148
149void Encoder::setPaused(bool p)
150{
151 if (audioEncode)
152 audioEncode->setPaused(p);
153 for (auto &videoEncoder : videoEncoders)
154 videoEncoder->setPaused(p);
155}
156
157void Encoder::setMetaData(const QMediaMetaData &metaData)
158{
159 this->metaData = metaData;
160}
161
162void Encoder::newAudioBuffer(const QAudioBuffer &buffer)
163{
164 if (audioEncode && isRecording)
165 audioEncode->addBuffer(buffer);
166}
167
168void Encoder::newTimeStamp(qint64 time)
169{
170 QMutexLocker locker(&timeMutex);
171 if (time > timeRecorded) {
172 timeRecorded = time;
173 emit durationChanged(time);
174 }
175}
176
177Muxer::Muxer(Encoder *encoder)
178 : encoder(encoder)
179{
181}
182
183void Muxer::addPacket(AVPacket *packet)
184{
185// qCDebug(qLcFFmpegEncoder) << "Muxer::addPacket" << packet->pts << packet->stream_index;
186 QMutexLocker locker(&queueMutex);
187 packetQueue.enqueue(packet);
188 wake();
189}
190
191AVPacket *Muxer::takePacket()
192{
193 QMutexLocker locker(&queueMutex);
194 if (packetQueue.isEmpty())
195 return nullptr;
196// qCDebug(qLcFFmpegEncoder) << "Muxer::takePacket" << packetQueue.first()->pts;
197 return packetQueue.dequeue();
198}
199
200void Muxer::init()
201{
202 qCDebug(qLcFFmpegEncoder) << "Muxer::init started thread.";
203}
204
205void Muxer::cleanup()
206{
207}
208
210{
211 QMutexLocker locker(&queueMutex);
212 return packetQueue.isEmpty();
213}
214
215void Muxer::loop()
216{
217 auto *packet = takePacket();
218 // qCDebug(qLcFFmpegEncoder) << "writing packet to file" << packet->pts << packet->duration <<
219 // packet->stream_index;
220 av_interleaved_write_frame(encoder->formatContext, packet);
221}
222
223
224static AVSampleFormat bestMatchingSampleFormat(AVSampleFormat requested, const AVSampleFormat *available)
225{
226 if (!available)
227 return requested;
228
229 const AVSampleFormat *f = available;
230 AVSampleFormat best = *f;
231/*
232 enum {
233 First,
234 Planar,
235 Exact,
236 } score = First;
237*/
238 for (; *f != AV_SAMPLE_FMT_NONE; ++f) {
239 qCDebug(qLcFFmpegEncoder) << "format:" << *f;
240 if (*f == requested) {
241 best = *f;
242// score = Exact;
243 break;
244 }
245
246 if (av_get_planar_sample_fmt(requested) == *f) {
247// score = Planar;
248 best = *f;
249 }
250 }
251 return best;
252}
253
255 : input(input)
257{
258 this->encoder = encoder;
259
260 setObjectName(QLatin1String("AudioEncoder"));
261 qCDebug(qLcFFmpegEncoder) << "AudioEncoder" << settings.audioCodec();
262
263 format = input->device.preferredFormat();
264 auto codecID = QFFmpegMediaFormatInfo::codecIdForAudioCodec(settings.audioCodec());
265 Q_ASSERT(avformat_query_codec(encoder->formatContext->oformat, codecID, FF_COMPLIANCE_NORMAL));
266
267 AVSampleFormat requested = QFFmpegMediaFormatInfo::avSampleFormat(format.sampleFormat());
268
269 avCodec = QFFmpeg::findAVEncoder(codecID, {}, requested);
270
271 if (!avCodec)
272 avCodec = QFFmpeg::findAVEncoder(codecID);
273
274 qCDebug(qLcFFmpegEncoder) << "found audio codec" << avCodec->name;
275
276 Q_ASSERT(avCodec);
277
278 AVSampleFormat bestSampleFormat = bestMatchingSampleFormat(requested, avCodec->sample_fmts);
279
280 stream = avformat_new_stream(encoder->formatContext, nullptr);
281 stream->id = encoder->formatContext->nb_streams - 1;
282 stream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
283 stream->codecpar->codec_id = codecID;
284#if QT_FFMPEG_OLD_CHANNEL_LAYOUT
285 stream->codecpar->channel_layout = av_get_default_channel_layout(format.channelCount());
286 stream->codecpar->channels = format.channelCount();
287#else
288 av_channel_layout_default(&stream->codecpar->ch_layout, format.channelCount());
289#endif
290 stream->codecpar->sample_rate = format.sampleRate();
291 stream->codecpar->frame_size = 1024;
292 stream->codecpar->format = bestSampleFormat;
293 stream->time_base = AVRational{ 1, format.sampleRate() };
294
295 qCDebug(qLcFFmpegEncoder) << "set stream time_base" << stream->time_base.num << "/"
296 << stream->time_base.den;
297}
298
300{
301 AVSampleFormat requested = QFFmpegMediaFormatInfo::avSampleFormat(format.sampleFormat());
302
303 codec = avcodec_alloc_context3(avCodec);
304
305 if (stream->time_base.num != 1 || stream->time_base.den != format.sampleRate()) {
306 qCDebug(qLcFFmpegEncoder) << "Most likely, av_format_write_header changed time base from"
307 << 1 << "/" << format.sampleRate() << "to"
308 << stream->time_base.num << "/" << stream->time_base.den;
309 }
310
311 codec->time_base = stream->time_base;
312
313 avcodec_parameters_to_context(codec, stream->codecpar);
314
315 AVDictionaryHolder opts;
316 applyAudioEncoderOptions(settings, avCodec->name, codec, opts);
317
318 int res = avcodec_open2(codec, avCodec, opts);
319 qCDebug(qLcFFmpegEncoder) << "audio codec opened" << res;
320 qCDebug(qLcFFmpegEncoder) << "audio codec params: fmt=" << codec->sample_fmt << "rate=" << codec->sample_rate;
321
322 if (codec->sample_fmt != requested) {
323#if QT_FFMPEG_OLD_CHANNEL_LAYOUT
324 resampler = swr_alloc_set_opts(nullptr, // we're allocating a new context
325 codec->channel_layout, // out_ch_layout
326 codec->sample_fmt, // out_sample_fmt
327 codec->sample_rate, // out_sample_rate
328 av_get_default_channel_layout(format.channelCount()), // in_ch_layout
329 requested, // in_sample_fmt
330 format.sampleRate(), // in_sample_rate
331 0, // log_offset
332 nullptr);
333#else
334 AVChannelLayout in_ch_layout = {};
335 av_channel_layout_default(&in_ch_layout, format.channelCount());
336 swr_alloc_set_opts2(&resampler, // we're allocating a new context
337 &codec->ch_layout, codec->sample_fmt, codec->sample_rate,
338 &in_ch_layout, requested, format.sampleRate(),
339 0, nullptr);
340#endif
341
342 swr_init(resampler);
343 }
344}
345
347{
348 QMutexLocker locker(&queueMutex);
349 if (!paused.loadRelaxed()) {
350 audioBufferQueue.enqueue(buffer);
351 wake();
352 }
353}
354
355QAudioBuffer AudioEncoder::takeBuffer()
356{
357 QMutexLocker locker(&queueMutex);
358 if (audioBufferQueue.isEmpty())
359 return QAudioBuffer();
360 return audioBufferQueue.dequeue();
361}
362
364{
365 open();
366 if (input) {
367 input->setFrameSize(codec->frame_size);
368 }
369 qCDebug(qLcFFmpegEncoder) << "AudioEncoder::init started audio device thread.";
370}
371
373{
374 while (!audioBufferQueue.isEmpty())
375 loop();
376 while (avcodec_send_frame(codec, nullptr) == AVERROR(EAGAIN))
377 retrievePackets();
378 retrievePackets();
379}
380
381bool AudioEncoder::shouldWait() const
382{
383 QMutexLocker locker(&queueMutex);
384 return audioBufferQueue.isEmpty();
385}
386
387void AudioEncoder::retrievePackets()
388{
389 while (1) {
390 AVPacket *packet = av_packet_alloc();
391 int ret = avcodec_receive_packet(codec, packet);
392 if (ret < 0) {
393 av_packet_unref(packet);
394 if (ret != AVERROR(EOF))
395 break;
396 if (ret != AVERROR(EAGAIN)) {
397 char errStr[1024];
398 av_strerror(ret, errStr, 1024);
399 qCDebug(qLcFFmpegEncoder) << "receive packet" << ret << errStr;
400 }
401 break;
402 }
403
404 // qCDebug(qLcFFmpegEncoder) << "writing audio packet" << packet->size << packet->pts << packet->dts;
405 packet->stream_index = stream->id;
406 encoder->muxer->addPacket(packet);
407 }
408}
409
411{
412 QAudioBuffer buffer = takeBuffer();
413 if (!buffer.isValid() || paused.loadAcquire())
414 return;
415
416// qCDebug(qLcFFmpegEncoder) << "new audio buffer" << buffer.byteCount() << buffer.format() << buffer.frameCount() << codec->frame_size;
417 retrievePackets();
418
419 auto frame = makeAVFrame();
420 frame->format = codec->sample_fmt;
421#if QT_FFMPEG_OLD_CHANNEL_LAYOUT
422 frame->channel_layout = codec->channel_layout;
423 frame->channels = codec->channels;
424#else
425 frame->ch_layout = codec->ch_layout;
426#endif
427 frame->sample_rate = codec->sample_rate;
428 frame->nb_samples = buffer.frameCount();
429 if (frame->nb_samples)
430 av_frame_get_buffer(frame.get(), 0);
431
432 if (resampler) {
433 const uint8_t *data = buffer.constData<uint8_t>();
434 swr_convert(resampler, frame->extended_data, frame->nb_samples, &data, frame->nb_samples);
435 } else {
436 memcpy(frame->buf[0]->data, buffer.constData<uint8_t>(), buffer.byteCount());
437 }
438
439 const auto &timeBase = stream->time_base;
440 const auto pts = timeBase.den && timeBase.num
441 ? timeBase.den * samplesWritten / (codec->sample_rate * timeBase.num)
442 : samplesWritten;
443 setAVFrameTime(*frame, pts, timeBase);
444 samplesWritten += buffer.frameCount();
445
446 qint64 time = format.durationForFrames(samplesWritten);
448
449 // qCDebug(qLcFFmpegEncoder) << "sending audio frame" << buffer.byteCount() << frame->pts <<
450 // ((double)buffer.frameCount()/frame->sample_rate);
451
452 int ret = avcodec_send_frame(codec, frame.get());
453 if (ret < 0) {
454 char errStr[1024];
455 av_strerror(ret, errStr, 1024);
456// qCDebug(qLcFFmpegEncoder) << "error sending frame" << ret << errStr;
457 }
458}
459
461 const QVideoFrameFormat &format, std::optional<AVPixelFormat> hwFormat)
462{
463 this->encoder = encoder;
464
465 setObjectName(QLatin1String("VideoEncoder"));
466
467 AVPixelFormat swFormat = QFFmpegVideoBuffer::toAVPixelFormat(format.pixelFormat());
468 AVPixelFormat ffmpegPixelFormat =
469 hwFormat && *hwFormat != AV_PIX_FMT_NONE ? *hwFormat : swFormat;
470 auto frameRate = format.frameRate();
471 if (frameRate <= 0.) {
472 qWarning() << "Invalid frameRate" << frameRate << "; Using the default instead";
473
474 // set some default frame rate since ffmpeg has UB if it's 0.
475 frameRate = 30.;
476 }
477
478 frameEncoder = new VideoFrameEncoder(settings, format.frameSize(), frameRate, ffmpegPixelFormat,
479 swFormat);
480 frameEncoder->initWithFormatContext(encoder->formatContext);
481}
482
484{
485 delete frameEncoder;
486}
487
489{
490 QMutexLocker locker(&queueMutex);
491
492 // Drop frames if encoder can not keep up with the video source data rate
493 const bool queueFull = videoFrameQueue.size() >= maxQueueSize;
494
495 if (queueFull) {
496 qCDebug(qLcFFmpegEncoder) << "Encoder frame queue full. Frame lost.";
497 } else if (!paused.loadRelaxed()) {
498 videoFrameQueue.enqueue(frame);
499
500 locker.unlock(); // Avoid context switch on wake wake-up
501
502 wake();
503 }
504}
505
506bool VideoEncoder::isValid() const
507{
508 return !frameEncoder->isNull();
509}
510
511QVideoFrame VideoEncoder::takeFrame()
512{
513 QMutexLocker locker(&queueMutex);
514
516 if (!videoFrameQueue.isEmpty())
517 frame = videoFrameQueue.dequeue();
518
519 return frame;
520}
521
522void VideoEncoder::retrievePackets()
523{
524 if (!frameEncoder)
525 return;
526 while (AVPacket *packet = frameEncoder->retrievePacket())
527 encoder->muxer->addPacket(packet);
528}
529
531{
532 qCDebug(qLcFFmpegEncoder) << "VideoEncoder::init started video device thread.";
533 bool ok = frameEncoder->open();
534 if (!ok)
535 emit encoder->error(QMediaRecorder::ResourceError, "Could not initialize encoder");
536}
537
539{
540 while (!videoFrameQueue.isEmpty())
541 loop();
542 if (frameEncoder) {
543 while (frameEncoder->sendFrame(nullptr) == AVERROR(EAGAIN))
544 retrievePackets();
545 retrievePackets();
546 }
547}
548
549bool VideoEncoder::shouldWait() const
550{
551 QMutexLocker locker(&queueMutex);
552 return videoFrameQueue.isEmpty();
553}
554
555struct QVideoFrameHolder
556{
558 QImage i;
559};
560
561static void freeQVideoFrame(void *opaque, uint8_t *)
562{
563 delete reinterpret_cast<QVideoFrameHolder *>(opaque);
564}
565
567{
568 if (paused.loadAcquire())
569 return;
570
571 retrievePackets();
572
573 auto frame = takeFrame();
574 if (!frame.isValid())
575 return;
576
577 if (frameEncoder->isNull())
578 return;
579
580// qCDebug(qLcFFmpegEncoder) << "new video buffer" << frame.startTime();
581
582 AVFrameUPtr avFrame;
583
584 auto *videoBuffer = dynamic_cast<QFFmpegVideoBuffer *>(frame.videoBuffer());
585 if (videoBuffer) {
586 // ffmpeg video buffer, let's use the native AVFrame stored in there
587 auto *hwFrame = videoBuffer->getHWFrame();
588 if (hwFrame && hwFrame->format == frameEncoder->sourceFormat())
589 avFrame.reset(av_frame_clone(hwFrame));
590 }
591
592 if (!avFrame) {
594 auto size = frame.size();
595 avFrame = makeAVFrame();
596 avFrame->format = frameEncoder->sourceFormat();
597 avFrame->width = size.width();
598 avFrame->height = size.height();
599
600 for (int i = 0; i < 4; ++i) {
601 avFrame->data[i] = const_cast<uint8_t *>(frame.bits(i));
602 avFrame->linesize[i] = frame.bytesPerLine(i);
603 }
604
605 QImage img;
606 if (frame.pixelFormat() == QVideoFrameFormat::Format_Jpeg) {
607 // the QImage is cached inside the video frame, so we can take the pointer to the image data here
608 img = frame.toImage();
609 avFrame->data[0] = (uint8_t *)img.bits();
610 avFrame->linesize[0] = img.bytesPerLine();
611 }
612
613 Q_ASSERT(avFrame->data[0]);
614 // ensure the video frame and it's data is alive as long as it's being used in the encoder
615 avFrame->opaque_ref = av_buffer_create(nullptr, 0, freeQVideoFrame, new QVideoFrameHolder{frame, img}, 0);
616 }
617
618 if (baseTime.loadAcquire() == std::numeric_limits<qint64>::min()) {
619 baseTime.storeRelease(frame.startTime() - lastFrameTime);
620 qCDebug(qLcFFmpegEncoder) << ">>>> adjusting base time to" << baseTime.loadAcquire()
621 << frame.startTime() << lastFrameTime;
622 }
623
624 qint64 time = frame.startTime() - baseTime.loadAcquire();
625 lastFrameTime = frame.endTime() - baseTime.loadAcquire();
626
627 setAVFrameTime(*avFrame, frameEncoder->getPts(time), frameEncoder->getTimeBase());
628
630
631 qCDebug(qLcFFmpegEncoder) << ">>> sending frame" << avFrame->pts << time << lastFrameTime;
632 int ret = frameEncoder->sendFrame(std::move(avFrame));
633 if (ret < 0) {
634 qCDebug(qLcFFmpegEncoder) << "error sending frame" << ret << err2str(ret);
636 }
637}
638
639}
640
642
643#include "moc_qffmpegencoder_p.cpp"
\inmodule QtMultimedia
T loadAcquire() const noexcept
void storeRelease(T newValue) noexcept
T loadRelaxed() const noexcept
\inmodule QtCore
Definition qbytearray.h:57
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:474
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:122
void newAudioBuffer(const QAudioBuffer &buffer)
static AVCodecID codecIdForAudioCodec(QMediaFormat::AudioCodec codec)
static const AVOutputFormat * outputFormatForFileFormat(QMediaFormat::FileFormat format)
static AVSampleFormat avSampleFormat(QAudioFormat::SampleFormat format)
static AVDictionary * toAVMetaData(const QMediaMetaData &metaData)
static AVPixelFormat toAVPixelFormat(QVideoFrameFormat::PixelFormat pixelFormat)
AVFrame * getHWFrame() const
void addBuffer(const QAudioBuffer &buffer)
void cleanup() override
bool shouldWait() const override
void loop() override
AudioEncoder(Encoder *encoder, QFFmpegAudioInput *input, const QMediaEncoderSettings &settings)
void init() override
QAtomicInteger< bool > paused
void newTimeStamp(qint64 time)
void error(QMediaRecorder::Error code, const QString &description)
void loop() override
bool shouldWait() const override
void addPacket(AVPacket *)
bool isValid() const
~VideoEncoder() override
void init() override
void loop() override
bool shouldWait() const override
void cleanup() override
void addFrame(const QVideoFrame &frame)
VideoEncoder(Encoder *encoder, const QMediaEncoderSettings &settings, const QVideoFrameFormat &format, std::optional< AVPixelFormat > hwFormat)
void initWithFormatContext(AVFormatContext *formatContext)
const AVRational & getTimeBase() const
qint64 getPts(qint64 ms) const
int sendFrame(AVFrameUPtr frame)
\inmodule QtGui
Definition qimage.h:37
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
\inmodule QtMultimedia
\inmodule QtCore
Definition qmutex.h:317
void unlock() noexcept
Unlocks this mutex locker.
Definition qmutex.h:323
Q_WEAK_OVERLOAD void setObjectName(const QString &name)
Sets the object's name to name.
Definition qobject.h:114
void deleteLater()
\threadsafe
Definition qobject.cpp:2352
void newVideoFrame(const QVideoFrame &)
void enqueue(const T &t)
Adds value t to the tail of the queue.
Definition qqueue.h:18
T dequeue()
Removes the head item in the queue and returns it.
Definition qqueue.h:19
void finished(QPrivateSignal)
\inmodule QtCore
Definition qurl.h:94
QByteArray toEncoded(FormattingOptions options=FullyEncoded) const
Returns the encoded representation of the URL if it's valid; otherwise an empty QByteArray is returne...
Definition qurl.cpp:2964
The QVideoFrameFormat class specifies the stream format of a video presentation surface.
The QVideoFrame class represents a frame of video data.
Definition qvideoframe.h:26
QSize size
the size of the widget excluding any window frame
Definition qwidget.h:113
double e
object setObjectName("A new object name")
AVFrameUPtr makeAVFrame()
Definition qffmpeg_p.h:119
const AVCodec * findAVEncoder(AVCodecID codecId, const std::optional< AVHWDeviceType > &deviceType, const std::optional< PixelOrSampleFormat > &format)
Definition qffmpeg.cpp:276
QString err2str(int errnum)
Definition qffmpeg_p.h:56
void setAVFrameTime(AVFrame &frame, int64_t pts, const AVRational &timeBase)
Definition qffmpeg_p.h:63
void applyAudioEncoderOptions(const QMediaEncoderSettings &settings, const QByteArray &codecName, AVCodecContext *codec, AVDictionary **opts)
std::unique_ptr< AVFrame, AVDeleter< decltype(&av_frame_free), &av_frame_free > > AVFrameUPtr
Definition qffmpeg_p.h:117
Combined button and popup list for selecting options.
DBusConnection const char DBusError * error
EGLStreamKHR stream
#define qWarning
Definition qlogging.h:162
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
return ret
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLfloat GLfloat f
GLenum GLuint buffer
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLsizei GLsizei GLenum format
GLsizei GLsizei GLchar * source
GLuint res
GLint void * img
Definition qopenglext.h:233
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
GLenum GLenum GLenum input
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define emit
long long qint64
Definition qtypes.h:55
QSettings settings("MySoft", "Star Runner")
[0]
QUrl url("example.com")
[constructor-url-reference]
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
myObject disconnect()
[26]
QFrame frame
[0]