libpromeki 1.0.0-alpha
PROfessional MEdia toolKIt
 
Loading...
Searching...
No Matches
quicktimemediaio.h
Go to the documentation of this file.
1
8#pragma once
9
10
11#include <promeki/config.h>
12#if PROMEKI_ENABLE_PROAV
13#include <promeki/ancdesc.h>
14#include <promeki/audiobuffer.h>
15#include <promeki/audiodesc.h>
18#include <promeki/framecount.h>
19#include <promeki/framenumber.h>
20#include <promeki/framerate.h>
23#include <promeki/namespace.h>
24#include <promeki/quicktime.h>
25#include <promeki/string.h>
26#include <promeki/timecode.h>
27
28PROMEKI_NAMESPACE_BEGIN
29
70class QuickTimeMediaIO : public DedicatedThreadMediaIO {
71 PROMEKI_OBJECT(QuickTimeMediaIO, DedicatedThreadMediaIO)
72 public:
74 static inline constexpr int DefaultFragmentFrames = 30;
75
77 QuickTimeMediaIO(ObjectBase *parent = nullptr);
78
80 ~QuickTimeMediaIO() override;
81
82 Error proposeInput(const MediaDesc &offered, MediaDesc *preferred) const override;
83
84 protected:
85 Error executeCmd(MediaIOCommandOpen &cmd) override;
86 Error executeCmd(MediaIOCommandClose &cmd) override;
87 Error executeCmd(MediaIOCommandRead &cmd) override;
88 Error executeCmd(MediaIOCommandWrite &cmd) override;
89 Error executeCmd(MediaIOCommandSeek &cmd) override;
90
91 private:
92 // True when @p pd is a PixelFormat this writer knows how
93 // to serialise into a valid QuickTime sample entry plus
94 // mdat payload. See proposeInput() for the supported
95 // set and the rationale for each omission.
96 static bool isSupportedPixelFormat(const PixelFormat &pd);
97
98 // Picks the closest writer-supported PixelFormat for an
99 // offered shape, preserving bit depth, chroma
100 // subsampling, and YUV / RGB family where possible so
101 // the planner-inserted CSC stays cheap.
102 static PixelFormat pickSupportedPixelFormat(const PixelFormat &offered);
103
104 // Rewrites @p desc's audio descriptors to the compressed
105 // AudioFormat named by MediaConfig::QuickTimeAudioCodec when it
106 // selects a real codec, so the planner splices an AudioEncoder.
107 // PCM / Invalid leaves the audio untouched.
108 void rewriteAudioForCodec(MediaDesc &desc) const;
109
110 // Rewrites @p desc's (uncompressed) image descriptors to the
111 // compressed PixelFormat of MediaConfig::QuickTimeVideoCodec when
112 // it selects a real codec, so the planner splices a VideoEncoder
113 // (the codec is recovered via VideoCodec::fromPixelFormat).
114 // Invalid / already-compressed video is left untouched.
115 void rewriteVideoForCodec(MediaDesc &desc) const;
116
117 // Resolves the scan mode to write into the video track's fiel
118 // box: MediaConfig::VideoScanMode when it names a concrete mode,
119 // else the source ImageDesc's @p descScanMode, else Unknown
120 // (progressive).
121 VideoScanMode resolveWriteScanMode(const VideoScanMode &descScanMode) const;
122
123 Error readVideoFrame(const FrameNumber &frameIndex, Frame &outFrame);
124 Error readAudioSlice(uint64_t startSample, size_t samples, MediaPayload::Ptr &out);
125 Error setupWriterFromFrame(const Frame &frame);
126 Error drainWriterAudio(bool flush);
127
128 QuickTime _qt;
129 bool _isOpen = false;
130 bool _isWrite = false;
131 String _filename;
132 int _videoTrackIndex = -1;
133 int _audioTrackIndex = -1;
134 int _ancTrackIndex = -1;
135 int _captionTrackIndex = -1;
136 QuickTimeCaptionReadPolicy _captionReadPolicy{QuickTimeCaptionReadPolicy::Auto};
137 FrameNumber _currentFrame{0};
138 FrameCount _frameCount{0};
139 FrameRate _frameRate;
140 Timecode _anchorTimecode;
141 uint64_t _audioSampleCursor = 0;
142 // PCM samples produced by one compressed audio access unit
143 // (e.g. 1024 for AAC-LC). Zero for PCM tracks. Used to pace
144 // compressed-audio reads against the video timeline so the
145 // decoded PCM keeps up with the frame rate.
146 uint64_t _audioCompressedFrameSamples = 0;
147 AudioDesc _audioDesc;
148 AncDesc _ancDesc;
149
150 bool _writerTracksRegistered = false;
151 uint32_t _writerVideoTrackId = 0;
152 uint32_t _writerAudioTrackId = 0;
153 uint32_t _writerAncTrackId = 0;
154 uint32_t _writerCaptionTrackId = 0;
155 uint32_t _writerTimecodeTrackId = 0;
156 FrameCount _writerFrameCount{0};
157 int _writerFragmentFrames = DefaultFragmentFrames;
158 FrameCount _writerFramesSinceFlush{0};
159 AudioBuffer _writerAudioFifo;
160 AudioDesc _writerAudioStorage;
161};
162
167class QuickTimeFactory : public MediaIOFactory {
168 public:
169 QuickTimeFactory() = default;
170
171 String name() const override { return String("QuickTime"); }
172 String displayName() const override { return String("QuickTime / MOV"); }
173 String description() const override {
174 return String("QuickTime / ISO-BMFF container files (.mov, .mp4, .m4v)");
175 }
176 StringList extensions() const override {
177 return {String("mov"), String("qt"), String("mp4"), String("m4v")};
178 }
179
180 bool canBeSource() const override { return true; }
181 bool canBeSink() const override { return true; }
182
183 bool canHandleDevice(IODevice *device) const override;
184 Config::SpecMap configSpecs() const override;
185 Metadata defaultMetadata() const override;
186
187 MediaIO *create(const Config &config, ObjectBase *parent = nullptr) const override;
188};
189
190PROMEKI_NAMESPACE_END
191
192#endif // PROMEKI_ENABLE_PROAV