@@ -14,69 +14,18 @@ extern "C" {
1414}
1515
1616namespace facebook ::torchcodec {
17- class FORCE_PUBLIC_VISIBILITY AudioEncoder {
18- public:
19- ~AudioEncoder ();
20-
21- AudioEncoder (
22- const torch::stable::Tensor& samples,
23- int sampleRate,
24- std::string_view fileName,
25- const AudioStreamOptions& audioStreamOptions);
26-
27- AudioEncoder (
28- const torch::stable::Tensor& samples,
29- int sampleRate,
30- std::string_view formatName,
31- std::unique_ptr<AVIOContextHolder> avioContextHolder,
32- const AudioStreamOptions& audioStreamOptions);
33-
34- void encode ();
35-
36- torch::stable::Tensor encodeToTensor ();
37-
38- private:
39- void initializeEncoder (const AudioStreamOptions& audioStreamOptions);
40- UniqueAVFrame maybeConvertAVFrame (const UniqueAVFrame& avFrame);
41- void encodeFrameThroughFifo (
42- AutoAVPacket& autoAVPacket,
43- const UniqueAVFrame& avFrame,
44- bool flushFifo = false );
45- void encodeFrame (AutoAVPacket& autoAVPacket, const UniqueAVFrame& avFrame);
46- void maybeFlushSwrBuffers (AutoAVPacket& autoAVPacket);
47- void flushBuffers ();
48-
49- UniqueEncodingAVFormatContext avFormatContext_;
50- UniqueAVCodecContext avCodecContext_;
51- int streamIndex_;
52- UniqueSwrContext swrContext_;
53- AudioStreamOptions audioStreamOptions;
54-
55- const torch::stable::Tensor samples_;
56-
57- int outNumChannels_ = -1 ;
58- int outSampleRate_ = -1 ;
59- int inSampleRate_ = -1 ;
60-
61- UniqueAVAudioFifo avAudioFifo_;
62-
63- std::unique_ptr<AVIOContextHolder> avioContextHolder_;
64-
65- bool encodeWasCalled_ = false ;
66- int64_t lastEncodedAVFramePts_ = 0 ;
67- };
6817
6918/* clang-format off */
7019//
7120// Note: [Encoding loop, sample rate conversion and FIFO]
7221//
7322// The input samples are in a given format, sample rate, and number of channels.
7423// We may want to change these properties before encoding. The conversion is
75- // done in maybeConvertAVFrame () and we rely on libswresample. When sample rate
76- // conversion is needed, this means two things:
24+ // done in maybeConvertAudioAVFrame () and we rely on libswresample. When sample
25+ // rate conversion is needed, this means two things:
7726// - swr will be storing samples in its internal buffers, which we'll need to
7827// flush at the very end of the encoding process.
79- // - the converted AVFrame we get back from maybeConvertAVFrame () typically
28+ // - the converted AVFrame we get back from maybeConvertAudioAVFrame () typically
8029// won't have the same number of samples as the original AVFrame. And that's
8130// a problem, because some encoders expect AVFrames with a specific and
8231// constant number of samples. If we were to send it as-is, we'd get an error
@@ -85,100 +34,14 @@ class FORCE_PUBLIC_VISIBILITY AudioEncoder {
8534// from which we can pull the exact number of samples that we need. Note that
8635// this involves at least 2 additional copies.
8736//
88- // To be clear, the FIFO is only used if BOTH the following conditions are met:
89- // - sample rate conversion is needed (inSampleRate_ != outSampleRate_)
90- // - the encoder expects a specific number of samples per AVFrame (fixed frame size)
91- // This is not the case for all encoders, e.g. WAV doesn't care about frame size.
92- //
93- // Also, the FIFO is either:
94- // - used for every single frame during the encoding process, or
95- // - not used at all.
96- // There is no scenario where a given Encoder() instance would sometimes use a
97- // FIFO, sometimes not.
98- //
99- // Drawing made with https://asciiflow.com/, can be copy/pasted there if it
100- // needs editing:
101- //
102- // ┌─One─iteration─of─main─encoding─loop─(encode())───────────────────────────────────────────┐
103- // │ │
104- // │ Converts: │
105- // │ - num channels │
106- // │ - format │
107- // │ - sample rate │
108- // │ If sample rate is converted, stores data in swr buffers, │
109- // │ which will need to be flushed by maybeFlushSwrBuffers() │
110- // │ │
111- // │ ▲ │
112- // │ │ ┌─EncodeFrameThroughFifo()──────────────┐│
113- // │ │ │ ││
114- // │ AVFrame ──────► MaybeConvertAVFrame()───▲──│─┬──► NO FIFO ─►┬──▲────►encodeFrame() ││
115- // │ with │ │ │ │ │ ││
116- // │ input │ │ │ │ │ ││
117- // │ samples │ │ │ │ │ ││
118- // │ │ │ │ │ │ ││
119- // │ │ │ └────► FIFO ─►─┘ │ ││
120- // │ │ └───────────────────┼───────────────────┘│
121- // └──────────────────────────────────────────────┼──────────────────────┼────────────────────┘
122- // │ │
123- // AVFrame from maybeFlushSwrBuffers() ───┘ │
124- // Only if sample rate conversion was needed nullptr, to flush
125- // The call to maybeFlushSwrBuffers() will FFmpeg buffers
126- // also instruct to flush the FIFO, if it exists.
127- //
128- //
37+ // Unlike the old single-stream AudioEncoder where the FIFO was only used when
38+ // sample rate conversion was needed with a fixed-frame-size encoder, the
39+ // MultiStreamEncoder always creates a FIFO. This is because addSamples() can
40+ // be called multiple times with arbitrary chunk sizes, so we always need to
41+ // buffer and re-chunk samples into frame_size-sized batches.
12942//
13043/* clang-format on */
13144
132- class FORCE_PUBLIC_VISIBILITY VideoEncoder {
133- public:
134- ~VideoEncoder ();
135-
136- // Rule of Five requires that we define copy and move
137- // constructors and assignment operators.
138- // Both are deleted because we have unique_ptr members
139- VideoEncoder (const VideoEncoder&) = delete ;
140- VideoEncoder& operator =(const VideoEncoder&) = delete ;
141-
142- // Move operators deleted since UniqueAVDictionary member is not movable
143- VideoEncoder (VideoEncoder&&) = delete ;
144- VideoEncoder& operator =(VideoEncoder&&) = delete ;
145-
146- VideoEncoder (
147- const torch::stable::Tensor& frames,
148- double frameRate,
149- std::string_view fileName,
150- const VideoStreamOptions& videoStreamOptions);
151-
152- VideoEncoder (
153- const torch::stable::Tensor& frames,
154- double frameRate,
155- std::string_view formatName,
156- std::unique_ptr<AVIOContextHolder> avioContextHolder,
157- const VideoStreamOptions& videoStreamOptions);
158-
159- void encode ();
160-
161- torch::stable::Tensor encodeToTensor ();
162-
163- private:
164- void initializeEncoder (const VideoStreamOptions& videoStreamOptions);
165- void encodeFrame (AutoAVPacket& autoAVPacket, const UniqueAVFrame& avFrame);
166- void flushBuffers ();
167-
168- UniqueEncodingAVFormatContext avFormatContext_;
169- UniqueAVCodecContext avCodecContext_;
170- AVStream* avStream_ = nullptr ;
171-
172- const torch::stable::Tensor frames_;
173- double inFrameRate_;
174-
175- std::unique_ptr<AVIOContextHolder> avioContextHolder_;
176- std::unique_ptr<DeviceInterface> deviceInterface_;
177-
178- bool encodeWasCalled_ = false ;
179- UniqueAVDictionary avFormatOptions_;
180- };
181-
18245class FORCE_PUBLIC_VISIBILITY MultiStreamEncoder {
18346 public:
18447 ~MultiStreamEncoder ();
0 commit comments