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 | |
4 | #ifndef QFFMPEGFRAME_P_H |
5 | #define QFFMPEGFRAME_P_H |
6 | |
7 | // |
8 | // W A R N I N G |
9 | // ------------- |
10 | // |
11 | // This file is not part of the Qt API. It exists purely as an |
12 | // implementation detail. This header file may change from version to |
13 | // version without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | |
18 | #include "qffmpeg_p.h" |
19 | #include "playbackengine/qffmpegcodec_p.h" |
20 | #include "playbackengine/qffmpegpositionwithoffset_p.h" |
21 | #include "QtCore/qsharedpointer.h" |
22 | #include "qpointer.h" |
23 | #include "qobject.h" |
24 | |
25 | #include <optional> |
26 | |
27 | QT_BEGIN_NAMESPACE |
28 | |
29 | namespace QFFmpeg { |
30 | |
31 | struct Frame |
32 | { |
33 | struct Data |
34 | { |
35 | Data(const LoopOffset &offset, AVFrameUPtr f, const Codec &codec, qint64, quint64 sourceId) |
36 | : loopOffset(offset), codec(codec), frame(std::move(f)), sourceId(sourceId) |
37 | { |
38 | Q_ASSERT(frame); |
39 | if (frame->pts != AV_NOPTS_VALUE) |
40 | pts = codec.toUs(ts: frame->pts); |
41 | else |
42 | pts = codec.toUs(ts: frame->best_effort_timestamp); |
43 | |
44 | if (frame->sample_rate && codec.context()->codec_type == AVMEDIA_TYPE_AUDIO) |
45 | duration = qint64(1000000) * frame->nb_samples / frame->sample_rate; |
46 | |
47 | if (auto frameDuration = getAVFrameDuration(frame: *frame)) { |
48 | duration = codec.toUs(ts: frameDuration); |
49 | } else { |
50 | const auto &avgFrameRate = codec.stream()->avg_frame_rate; |
51 | duration = mul(a: qint64(1000000), b: { .num: avgFrameRate.den, .den: avgFrameRate.num }).value_or(u: 0); |
52 | } |
53 | } |
54 | Data(const LoopOffset &offset, const QString &text, qint64 pts, qint64 duration, |
55 | quint64 sourceId) |
56 | : loopOffset(offset), text(text), pts(pts), duration(duration), sourceId(sourceId) |
57 | { |
58 | } |
59 | |
60 | QAtomicInt ref; |
61 | LoopOffset loopOffset; |
62 | std::optional<Codec> codec; |
63 | AVFrameUPtr frame; |
64 | QString text; |
65 | qint64 pts = -1; |
66 | qint64 duration = -1; |
67 | quint64 sourceId = 0; |
68 | }; |
69 | Frame() = default; |
70 | |
71 | Frame(const LoopOffset &offset, AVFrameUPtr f, const Codec &codec, qint64 pts, |
72 | quint64 sourceIndex) |
73 | : d(new Data(offset, std::move(f), codec, pts, sourceIndex)) |
74 | { |
75 | } |
76 | Frame(const LoopOffset &offset, const QString &text, qint64 pts, qint64 duration, |
77 | quint64 sourceIndex) |
78 | : d(new Data(offset, text, pts, duration, sourceIndex)) |
79 | { |
80 | } |
81 | bool isValid() const { return !!d; } |
82 | |
83 | AVFrame *avFrame() const { return data().frame.get(); } |
84 | AVFrameUPtr takeAVFrame() { return std::move(data().frame); } |
85 | const Codec *codec() const { return data().codec ? &data().codec.value() : nullptr; } |
86 | qint64 pts() const { return data().pts; } |
87 | qint64 duration() const { return data().duration; } |
88 | qint64 end() const { return data().pts + data().duration; } |
89 | QString text() const { return data().text; } |
90 | quint64 sourceId() const { return data().sourceId; }; |
91 | const LoopOffset &loopOffset() const { return data().loopOffset; }; |
92 | qint64 absolutePts() const { return pts() + loopOffset().pos; } |
93 | qint64 absoluteEnd() const { return end() + loopOffset().pos; } |
94 | |
95 | private: |
96 | Data &data() const |
97 | { |
98 | Q_ASSERT(d); |
99 | return *d; |
100 | } |
101 | |
102 | private: |
103 | QExplicitlySharedDataPointer<Data> d; |
104 | }; |
105 | |
106 | } // namespace QFFmpeg |
107 | |
108 | QT_END_NAMESPACE |
109 | |
110 | Q_DECLARE_METATYPE(QFFmpeg::Frame); |
111 | |
112 | #endif // QFFMPEGFRAME_P_H |
113 | |