Skip to content

Commit c2faa4c

Browse files
Dan-FloresDaniel Flores
andauthored
Handle AVCodec fields deprecated in FFmpeg 7 (#898)
Co-authored-by: Daniel Flores <[email protected]>
1 parent 1acff9c commit c2faa4c

File tree

3 files changed

+82
-11
lines changed

3 files changed

+82
-11
lines changed

src/torchcodec/_core/Encoder.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,21 +33,22 @@ torch::Tensor validateSamples(const torch::Tensor& samples) {
3333
}
3434

3535
void validateSampleRate(const AVCodec& avCodec, int sampleRate) {
36-
if (avCodec.supported_samplerates == nullptr) {
36+
const int* supportedSampleRates = getSupportedSampleRates(avCodec);
37+
if (supportedSampleRates == nullptr) {
3738
return;
3839
}
3940

40-
for (auto i = 0; avCodec.supported_samplerates[i] != 0; ++i) {
41-
if (sampleRate == avCodec.supported_samplerates[i]) {
41+
for (auto i = 0; supportedSampleRates[i] != 0; ++i) {
42+
if (sampleRate == supportedSampleRates[i]) {
4243
return;
4344
}
4445
}
4546
std::stringstream supportedRates;
46-
for (auto i = 0; avCodec.supported_samplerates[i] != 0; ++i) {
47+
for (auto i = 0; supportedSampleRates[i] != 0; ++i) {
4748
if (i > 0) {
4849
supportedRates << ", ";
4950
}
50-
supportedRates << avCodec.supported_samplerates[i];
51+
supportedRates << supportedSampleRates[i];
5152
}
5253

5354
TORCH_CHECK(
@@ -73,27 +74,30 @@ static const std::vector<AVSampleFormat> preferredFormatsOrder = {
7374
AV_SAMPLE_FMT_U8};
7475

7576
AVSampleFormat findBestOutputSampleFormat(const AVCodec& avCodec) {
77+
const AVSampleFormat* supportedSampleFormats =
78+
getSupportedOutputSampleFormats(avCodec);
79+
7680
// Find a sample format that the encoder supports. We prefer using FLT[P],
7781
// since this is the format of the input samples. If FLTP isn't supported
7882
// then we'll need to convert the AVFrame's format. Our heuristic is to encode
7983
// into the format with the highest resolution.
80-
if (avCodec.sample_fmts == nullptr) {
84+
if (supportedSampleFormats == nullptr) {
8185
// Can't really validate anything in this case, best we can do is hope that
8286
// FLTP is supported by the encoder. If not, FFmpeg will raise.
8387
return AV_SAMPLE_FMT_FLTP;
8488
}
8589

8690
for (AVSampleFormat preferredFormat : preferredFormatsOrder) {
87-
for (int i = 0; avCodec.sample_fmts[i] != -1; ++i) {
88-
if (avCodec.sample_fmts[i] == preferredFormat) {
91+
for (int i = 0; supportedSampleFormats[i] != -1; ++i) {
92+
if (supportedSampleFormats[i] == preferredFormat) {
8993
return preferredFormat;
9094
}
9195
}
9296
}
9397
// We should always find a match in preferredFormatsOrder, so we should always
9498
// return earlier. But in the event that a future FFmpeg version defines an
9599
// additional sample format that isn't in preferredFormatsOrder, we fallback:
96-
return avCodec.sample_fmts[0];
100+
return supportedSampleFormats[0];
97101
}
98102

99103
} // namespace

src/torchcodec/_core/FFMPEGCommon.cpp

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,46 @@ int64_t getDuration(const UniqueAVFrame& avFrame) {
5656
#endif
5757
}
5858

59+
const int* getSupportedSampleRates(const AVCodec& avCodec) {
60+
const int* supportedSampleRates = nullptr;
61+
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100)
62+
int numSampleRates = 0;
63+
int ret = avcodec_get_supported_config(
64+
nullptr,
65+
&avCodec,
66+
AV_CODEC_CONFIG_SAMPLE_RATE,
67+
0,
68+
reinterpret_cast<const void**> & supportedSampleRates,
69+
&numSampleRates);
70+
if (ret < 0 || supportedSampleRates == nullptr) {
71+
TORCH_CHECK(false, "Couldn't get supported sample rates from encoder.");
72+
}
73+
#else
74+
supportedSampleRates = avCodec.supported_samplerates;
75+
#endif
76+
return supportedSampleRates;
77+
}
78+
79+
const AVSampleFormat* getSupportedOutputSampleFormats(const AVCodec& avCodec) {
80+
const AVSampleFormat* supportedSampleFormats = nullptr;
81+
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100) // FFmpeg >= 7
82+
int numSampleFormats = 0;
83+
int ret = avcodec_get_supported_config(
84+
nullptr,
85+
&avCodec,
86+
AV_CODEC_CONFIG_SAMPLE_FORMAT,
87+
0,
88+
reinterpret_cast<const void**> & supportedSampleFormats,
89+
&numSampleFormats);
90+
if (ret < 0 || supportedSampleFormats == nullptr) {
91+
TORCH_CHECK(false, "Couldn't get supported sample formats from encoder.");
92+
}
93+
#else
94+
supportedSampleFormats = avCodec.sample_fmts;
95+
#endif
96+
return supportedSampleFormats;
97+
}
98+
5999
int getNumChannels(const UniqueAVFrame& avFrame) {
60100
#if LIBAVFILTER_VERSION_MAJOR > 8 || \
61101
(LIBAVFILTER_VERSION_MAJOR == 8 && LIBAVFILTER_VERSION_MINOR >= 44)
@@ -109,7 +149,31 @@ void setDefaultChannelLayout(UniqueAVFrame& avFrame, int numChannels) {
109149
}
110150

111151
void validateNumChannels(const AVCodec& avCodec, int numChannels) {
112-
#if LIBAVFILTER_VERSION_MAJOR > 7 // FFmpeg > 4
152+
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100) // FFmpeg >= 7
153+
std::stringstream supportedNumChannels;
154+
const AVChannelLayout* supported_layouts = nullptr;
155+
int num_layouts = 0;
156+
int ret = avcodec_get_supported_config(
157+
nullptr,
158+
&avCodec,
159+
AV_CODEC_CONFIG_CHANNEL_LAYOUT,
160+
0,
161+
reinterpret_cast<const void**> & supported_layouts,
162+
&num_layouts);
163+
if (ret < 0 || supported_layouts == nullptr) {
164+
TORCH_CHECK(false, "Couldn't get supported channel layouts from encoder.");
165+
return;
166+
}
167+
for (int i = 0; supported_layouts[i].nb_channels != 0; ++i) {
168+
if (i > 0) {
169+
supportedNumChannels << ", ";
170+
}
171+
supportedNumChannels << supported_layouts[i].nb_channels;
172+
if (numChannels == supported_layouts[i].nb_channels) {
173+
return;
174+
}
175+
}
176+
#elif LIBAVFILTER_VERSION_MAJOR > 7 // FFmpeg > 4
113177
if (avCodec.ch_layouts == nullptr) {
114178
// If we can't validate, we must assume it'll be fine. If not, FFmpeg will
115179
// eventually raise.
@@ -131,7 +195,7 @@ void validateNumChannels(const AVCodec& avCodec, int numChannels) {
131195
}
132196
supportedNumChannels << avCodec.ch_layouts[i].nb_channels;
133197
}
134-
#else
198+
#else // FFmpeg <= 4
135199
if (avCodec.channel_layouts == nullptr) {
136200
// can't validate, same as above.
137201
return;

src/torchcodec/_core/FFMPEGCommon.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,9 @@ std::string getFFMPEGErrorStringFromErrorCode(int errorCode);
162162
// support.
163163
int64_t getDuration(const UniqueAVFrame& frame);
164164

165+
const int* getSupportedSampleRates(const AVCodec& avCodec);
166+
const AVSampleFormat* getSupportedOutputSampleFormats(const AVCodec& avCodec);
167+
165168
int getNumChannels(const UniqueAVFrame& avFrame);
166169
int getNumChannels(const UniqueAVCodecContext& avCodecContext);
167170

0 commit comments

Comments
 (0)