11#include <QtMultimedia/private/qmediastoragelocation_p.h>
12#include <QtMultimedia/private/qplatformcamera_p.h>
13#include <QtMultimedia/qaudiodevice.h>
15#include <QtCore/qdebug.h>
16#include <QtCore/qeventloop.h>
17#include <QtCore/qstandardpaths.h>
18#include <QtCore/qmimetype.h>
19#include <QtCore/qloggingcategory.h>
21#include <gst/gsttagsetter.h>
22#include <gst/gstversion.h>
23#include <gst/video/video.h>
24#include <gst/pbutils/encoding-profile.h>
32 audioPauseControl(*
this),
33 videoPauseControl(*
this)
35 signalDurationChangedTimer.setInterval(100);
36 signalDurationChangedTimer.callOnTimeout(&signalDurationChangedTimer, [
this]() {
37 durationChanged(duration());
43 if (!capturePipeline.
isNull()) {
63 constexpr bool traceStateChange =
false;
64 constexpr bool traceAllEvents =
false;
66 if constexpr (traceAllEvents)
67 qCDebug(qLcMediaEncoderGst) <<
"received event:" << msg;
70 case GST_MESSAGE_ELEMENT: {
72 if (
s.name() ==
"GstBinForwarded")
76 <<
"received element message from" << msg.
source().
name() <<
s.name();
80 case GST_MESSAGE_EOS: {
86 case GST_MESSAGE_ERROR: {
100 case GST_MESSAGE_STATE_CHANGED: {
101 if constexpr (traceStateChange)
115 return std::max(audioPauseControl.duration, videoPauseControl.duration);
123 auto caps = formatInfo->formatCaps(
settings.fileFormat());
125 GstEncodingContainerProfile *profile =
126 (GstEncodingContainerProfile *)gst_encoding_container_profile_new(
127 "container_profile", (gchar *)
"custom container profile",
128 const_cast<GstCaps *
>(caps.caps()),
145 GstEncodingVideoProfile *profile =
146 gst_encoding_video_profile_new(
const_cast<GstCaps *
>(caps.
caps()),
nullptr,
150 gst_encoding_video_profile_set_pass(profile, 0);
151 gst_encoding_video_profile_set_variableframerate(profile, TRUE);
153 return (GstEncodingProfile *)profile;
160 auto caps = formatInfo->audioCaps(
settings.mediaFormat());
164 GstEncodingProfile *profile =
165 (GstEncodingProfile *)gst_encoding_audio_profile_new(
const_cast<GstCaps *
>(caps.caps()),
177 if (!containerProfile) {
178 qWarning() <<
"QGstreamerMediaEncoder: failed to create container profile!";
183 GstEncodingProfile *videoProfile =
nullptr;
191 if (!gst_encoding_container_profile_add_profile(containerProfile, videoProfile)) {
192 qWarning() <<
"QGstreamerMediaEncoder: failed to add video profile!";
193 gst_encoding_profile_unref(videoProfile);
197 if (!gst_encoding_container_profile_add_profile(containerProfile, audioProfile)) {
198 qWarning() <<
"QGstreamerMediaEncoder: failed to add audio profile!";
199 gst_encoding_profile_unref(audioProfile);
203 return containerProfile;
206void QGstreamerMediaEncoder::PauseControl::reset()
209 pauseStartPts.reset();
211 firstBufferPts.reset();
214void QGstreamerMediaEncoder::PauseControl::installOn(
QGstPad pad)
216 pad.
addProbe<&QGstreamerMediaEncoder::PauseControl::processBuffer>(
this, GST_PAD_PROBE_TYPE_BUFFER);
219GstPadProbeReturn QGstreamerMediaEncoder::PauseControl::processBuffer(
QGstPad, GstPadProbeInfo *
info)
221 auto buffer = GST_PAD_PROBE_INFO_BUFFER(
info);
223 return GST_PAD_PROBE_OK;
228 return GST_PAD_PROBE_OK;
232 if (!GST_BUFFER_PTS_IS_VALID(
buffer))
233 return GST_PAD_PROBE_OK;
236 firstBufferPts = GST_BUFFER_PTS(
buffer);
240 pauseStartPts = GST_BUFFER_PTS(
buffer);
242 return GST_PAD_PROBE_DROP;
246 pauseOffsetPts += GST_BUFFER_PTS(
buffer) - *pauseStartPts;
247 pauseStartPts.reset();
249 GST_BUFFER_PTS(
buffer) -= pauseOffsetPts;
251 duration = (GST_BUFFER_PTS(
buffer) - *firstBufferPts) / GST_MSECOND;
253 return GST_PAD_PROBE_OK;
262 const auto hasAudio = m_session->
audioInput() !=
nullptr;
264 if (!hasVideo && !hasAudio) {
272 auto container =
settings.mimeType().preferredSuffix();
276 qCDebug(qLcMediaEncoderGst) <<
"recording new video to" << actualSink;
283 g_object_set (gstEncoder.
object(),
"profile", encodingProfile,
nullptr);
284 gst_encoding_profile_unref(encodingProfile);
289 gstFileSink.
set(
"async",
false);
294 audioPauseControl.reset();
295 videoPauseControl.reset();
300 qWarning() <<
"Unsupported audio codec";
302 audioPauseControl.installOn(audioSink);
308 qWarning() <<
"Unsupported video codec";
310 videoPauseControl.installOn(videoSink);
314 capturePipeline.
add(gstEncoder, gstFileSink);
324 signalDurationChangedTimer.
start();
336 signalDurationChangedTimer.
stop();
338 capturePipeline.
dumpGraph(
"before-pause");
344 capturePipeline.
dumpGraph(
"before-resume");
347 signalDurationChangedTimer.
start();
356 qCDebug(qLcMediaEncoderGst) <<
"stop";
359 signalDurationChangedTimer.
stop();
361 qCDebug(qLcMediaEncoderGst) <<
">>>>>>>>>>>>> sending EOS";
365void QGstreamerMediaEncoder::finalize()
367 if (!m_session || gstEncoder.
isNull())
370 qCDebug(qLcMediaEncoderGst) <<
"finalize";
375 m_finalizing =
false;
394 if (m_session == captureSession)
407 capturePipeline = {};
410 m_session = captureSession;
414 capturePipeline = captureSession->capturePipeline;
415 capturePipeline.
set(
"message-forward",
true);
static QString currentPath()
Returns the absolute path of the application's current directory.
int exec(ProcessEventsFlags flags=AllEvents)
Enters the main event loop and waits until exit() is called.
void quit()
Tells the event loop to exit normally.
static QByteArray encodeName(const QString &fileName)
Converts fileName to an 8-bit encoding that you can use in native APIs.
std::enable_if_t<(std::is_base_of_v< QGstElement, Ts > &&...), void add)(const Ts &...ts)
static QGstBin createFromFactory(const char *factory, const char *name)
std::enable_if_t<(std::is_base_of_v< QGstElement, Ts > &&...), void stopAndRemoveElements)(Ts... ts)
void setResolution(QSize)
QGstPad getRequestPad(const char *name) const
bool setStateSync(GstState state, std::chrono::nanoseconds timeout=std::chrono::seconds(1))
bool syncStateWithParent()
static QGstElement createFromFactory(const char *factory, const char *name=nullptr)
const char * name() const
void set(const char *property, const char *str)
GstObject * object() const
void addProbe(T *instance, GstPadProbeType type)
void installMessageFilter(QGstreamerSyncMessageFilter *filter)
void dumpGraph(const char *fileName)
void removeMessageFilter(QGstreamerSyncMessageFilter *filter)
void modifyPipelineWhileNotRunning(Functor &&fn)
static QGstreamerIntegration * instance()
QGstStructure structure() const
QGstObject source() const
GstMessageType type() const
GstMessage * message() const
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
constexpr bool isValid() const noexcept
Returns true if both the width and height is equal to or greater than 0; otherwise returns false.
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
void stop()
Stops the timer.
Type get() const noexcept
static QUrl fromLocalFile(const QString &localfile)
Returns a QUrl representation of localFile, interpreted as a local file.
Combined button and popup list for selecting options.
std::enable_if_t<(std::is_base_of_v< QGstElement, Ts > &&...), void qLinkGstElements)(const Ts &...ts)
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
static QString toLocalFile(const QString &url)
QSettings settings("MySoft", "Star Runner")
[0]