Revision control

Copy as Markdown

// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFFMPEGFRAME_P_H
#define QFFMPEGFRAME_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtFFmpegMediaPluginImpl/private/qffmpeg_p.h>
#include <QtFFmpegMediaPluginImpl/private/qffmpegcodeccontext_p.h>
#include <QtFFmpegMediaPluginImpl/private/qffmpegplaybackutils_p.h>
#include <QtFFmpegMediaPluginImpl/private/qffmpegtime_p.h>
#include <QtCore/qshareddata.h>
#include <optional>
QT_BEGIN_NAMESPACE
namespace QFFmpeg {
struct Frame
{
struct Data
{
Data(const LoopOffset &offset, AVFrameUPtr f, const CodecContext &codecContext,
const PlaybackEngineObjectID &sourceID)
: loopOffset(offset),
codecContext(codecContext),
frame(std::move(f)),
sourceID(sourceID)
{
Q_ASSERT(frame);
if (frame->pts != AV_NOPTS_VALUE)
startTime = codecContext.toTrackPosition(AVStreamPosition(frame->pts));
else
startTime = codecContext.toTrackPosition(
AVStreamPosition(frame->best_effort_timestamp));
if (auto frameDuration = getAVFrameDuration(*frame)) {
duration = codecContext.toTrackDuration(AVStreamDuration(frameDuration));
} else {
// Estimate frame duration for audio stream
if (codecContext.context()->codec_type == AVMEDIA_TYPE_AUDIO) {
if (frame->sample_rate)
duration = TrackDuration(qint64(1000000) * frame->nb_samples
/ frame->sample_rate);
else
duration = TrackDuration(0); // Fallback
} else {
// Estimate frame duration for video stream
const auto &avgFrameRate = codecContext.stream()->avg_frame_rate;
duration = TrackDuration(
mul(qint64(1000000), { avgFrameRate.den, avgFrameRate.num })
.value_or(0));
}
}
}
Data(const LoopOffset &offset, const QString &text, TrackPosition pts,
TrackDuration duration, const PlaybackEngineObjectID &sourceID)
: loopOffset(offset), text(text), startTime(pts), duration(duration), sourceID(sourceID)
{
}
QAtomicInt ref;
LoopOffset loopOffset;
std::optional<CodecContext> codecContext;
AVFrameUPtr frame;
QString text;
TrackPosition startTime = 0;
TrackDuration duration = 0;
PlaybackEngineObjectID sourceID;
};
Frame() = default;
Frame(const LoopOffset &offset, AVFrameUPtr f, const CodecContext &codecContext,
const PlaybackEngineObjectID &sourceId)
: d(new Data(offset, std::move(f), codecContext, sourceId))
{
}
Frame(const LoopOffset &offset, const QString &text, TrackPosition pts, TrackDuration duration,
const PlaybackEngineObjectID &sourceId)
: d(new Data(offset, text, pts, duration, sourceId))
{
}
bool isValid() const { return !!d; }
AVFrame *avFrame() const { return data().frame.get(); }
AVFrameUPtr takeAVFrame() { return std::move(data().frame); }
const CodecContext *codecContext() const
{
return data().codecContext ? &data().codecContext.value() : nullptr;
}
TrackPosition startTime() const { return data().startTime; }
TrackDuration duration() const { return data().duration; }
TrackPosition endTime() const { return data().startTime + data().duration; }
QString text() const { return data().text; }
const PlaybackEngineObjectID &sourceID() const { return data().sourceID; };
const LoopOffset &loopOffset() const { return data().loopOffset; };
TrackPosition absolutePts() const
{
return startTime() + loopOffset().loopStartTimeUs.asDuration();
}
TrackPosition absoluteEnd() const
{
return endTime() + loopOffset().loopStartTimeUs.asDuration();
}
private:
Data &data() const
{
Q_ASSERT(d);
return *d;
}
private:
QExplicitlySharedDataPointer<Data> d;
};
} // namespace QFFmpeg
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QFFmpeg::Frame);
#endif // QFFMPEGFRAME_P_H