From a132fe58d8071ef4a231b00bb94f6580ad32fa8a Mon Sep 17 00:00:00 2001 From: Daniel Flores Date: Thu, 2 Oct 2025 00:33:33 -0400 Subject: [PATCH 1/7] enable local build --- src/torchcodec/_core/CMakeLists.txt | 2 ++ src/torchcodec/_core/ops.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/torchcodec/_core/CMakeLists.txt b/src/torchcodec/_core/CMakeLists.txt index ada56bdc8..ab6583526 100644 --- a/src/torchcodec/_core/CMakeLists.txt +++ b/src/torchcodec/_core/CMakeLists.txt @@ -304,6 +304,8 @@ else() set(ffmpeg_major_version "6") elseif (${libavcodec_major_version} STREQUAL "61") set(ffmpeg_major_version "7") + elseif (${libavcodec_major_version} STREQUAL "62") + set(ffmpeg_major_version "8") else() message( FATAL_ERROR diff --git a/src/torchcodec/_core/ops.py b/src/torchcodec/_core/ops.py index 10059da88..b7fff11fc 100644 --- a/src/torchcodec/_core/ops.py +++ b/src/torchcodec/_core/ops.py @@ -41,7 +41,7 @@ def load_torchcodec_shared_libraries(): # libraries do not meet those conditions. exceptions = [] - for ffmpeg_major_version in (7, 6, 5, 4): + for ffmpeg_major_version in (8, 7, 6, 5, 4): pybind_ops_module_name = _get_pybind_ops_module_name(ffmpeg_major_version) decoder_library_name = f"libtorchcodec_core{ffmpeg_major_version}" custom_ops_library_name = f"libtorchcodec_custom_ops{ffmpeg_major_version}" From 9e311322586c3474d5d6378cf2a6dac3504a2c21 Mon Sep 17 00:00:00 2001 From: Daniel Flores Date: Mon, 6 Oct 2025 11:09:33 -0400 Subject: [PATCH 2/7] handle deprecated filter ctx function --- src/torchcodec/_core/FFMPEGCommon.cpp | 62 +++++++++++++++++++++++++++ src/torchcodec/_core/FFMPEGCommon.h | 6 +++ src/torchcodec/_core/FilterGraph.cpp | 24 ++--------- 3 files changed, 72 insertions(+), 20 deletions(-) diff --git a/src/torchcodec/_core/FFMPEGCommon.cpp b/src/torchcodec/_core/FFMPEGCommon.cpp index 94c666d79..72140bc9c 100644 --- a/src/torchcodec/_core/FFMPEGCommon.cpp +++ b/src/torchcodec/_core/FFMPEGCommon.cpp @@ -8,6 +8,11 @@ #include +extern "C" { +#include +#include +} + namespace facebook::torchcodec { AutoAVPacket::AutoAVPacket() : avPacket_(av_packet_alloc()) { @@ -374,6 +379,63 @@ SwrContext* createSwrContext( return swrContext; } +AVFilterContext* createBuffersinkFilter( + AVFilterGraph* filterGraph, + const char* name, + enum AVPixelFormat outputFormat) { + const AVFilter* buffersink = avfilter_get_by_name("buffersink"); + if (!buffersink) { + return nullptr; + } + + AVFilterContext* sinkContext = nullptr; + int status; + +// av_opt_set_int_list was replaced by av_opt_set() in FFmpeg 8. +#if LIBAVUTIL_VERSION_MAJOR >= 60 // FFmpeg >= 8 + // Output options like pixel_formats must be set before filter init + sinkContext = avfilter_graph_alloc_filter(filterGraph, buffersink, name); + if (!sinkContext) { + return nullptr; + } + // av_opt_set uses the string representation of a pixel format + const char* fmt_name = av_get_pix_fmt_name(outputFormat); + if (!fmt_name) { + return nullptr; + } + status = av_opt_set( + sinkContext, "pixel_formats", fmt_name, AV_OPT_SEARCH_CHILDREN); + if (status < 0) { + return nullptr; + } + status = avfilter_init_str(sinkContext, nullptr); + if (status < 0) { + return nullptr; + } +#else // FFmpeg <= 7 + // For older FFmpeg versions, create filter and then set options + status = avfilter_graph_create_filter( + &sinkContext, buffersink, name, nullptr, nullptr, filterGraph); + if (status < 0) { + return nullptr; + } + + enum AVPixelFormat pix_fmts[] = {outputFormat, AV_PIX_FMT_NONE}; + + status = av_opt_set_int_list( + sinkContext, + "pix_fmts", + pix_fmts, + AV_PIX_FMT_NONE, + AV_OPT_SEARCH_CHILDREN); + if (status < 0) { + return nullptr; + } +#endif + + return sinkContext; +} + UniqueAVFrame convertAudioAVFrameSamples( const UniqueSwrContext& swrContext, const UniqueAVFrame& srcAVFrame, diff --git a/src/torchcodec/_core/FFMPEGCommon.h b/src/torchcodec/_core/FFMPEGCommon.h index 58589fe60..780f04f93 100644 --- a/src/torchcodec/_core/FFMPEGCommon.h +++ b/src/torchcodec/_core/FFMPEGCommon.h @@ -23,6 +23,7 @@ extern "C" { #include #include #include +#include #include #include #include @@ -237,4 +238,9 @@ int64_t computeSafeDuration( const AVRational& frameRate, const AVRational& timeBase); +AVFilterContext* createBuffersinkFilter( + AVFilterGraph* filterGraph, + const char* name, + enum AVPixelFormat outputFormat); + } // namespace facebook::torchcodec diff --git a/src/torchcodec/_core/FilterGraph.cpp b/src/torchcodec/_core/FilterGraph.cpp index 70bc2b5dd..39d3ebcc9 100644 --- a/src/torchcodec/_core/FilterGraph.cpp +++ b/src/torchcodec/_core/FilterGraph.cpp @@ -5,6 +5,7 @@ // LICENSE file in the root directory of this source tree. #include "src/torchcodec/_core/FilterGraph.h" +#include "src/torchcodec/_core/FFMPEGCommon.h" extern "C" { #include @@ -63,7 +64,6 @@ FilterGraph::FilterGraph( } const AVFilter* buffersrc = avfilter_get_by_name("buffer"); - const AVFilter* buffersink = avfilter_get_by_name("buffersink"); UniqueAVBufferSrcParameters srcParams(av_buffersrc_parameters_alloc()); TORCH_CHECK(srcParams, "Failed to allocate buffersrc params"); @@ -93,26 +93,10 @@ FilterGraph::FilterGraph( "Failed to create filter graph : ", getFFMPEGErrorStringFromErrorCode(status)); - status = avfilter_graph_create_filter( - &sinkContext_, buffersink, "out", nullptr, nullptr, filterGraph_.get()); + sinkContext_ = createBuffersinkFilter( + filterGraph_.get(), "out", filtersContext.outputFormat); TORCH_CHECK( - status >= 0, - "Failed to create filter graph: ", - getFFMPEGErrorStringFromErrorCode(status)); - - enum AVPixelFormat pix_fmts[] = { - filtersContext.outputFormat, AV_PIX_FMT_NONE}; - - status = av_opt_set_int_list( - sinkContext_, - "pix_fmts", - pix_fmts, - AV_PIX_FMT_NONE, - AV_OPT_SEARCH_CHILDREN); - TORCH_CHECK( - status >= 0, - "Failed to set output pixel formats: ", - getFFMPEGErrorStringFromErrorCode(status)); + sinkContext_ != nullptr, "Failed to create and configure buffersink"); UniqueAVFilterInOut outputs(avfilter_inout_alloc()); UniqueAVFilterInOut inputs(avfilter_inout_alloc()); From fddf741c8d0fdb746b48cb1ce1de4baa4222539b Mon Sep 17 00:00:00 2001 From: Daniel Flores Date: Mon, 6 Oct 2025 11:17:47 -0400 Subject: [PATCH 3/7] rebase --- src/torchcodec/_core/FFMPEGCommon.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/torchcodec/_core/FFMPEGCommon.cpp b/src/torchcodec/_core/FFMPEGCommon.cpp index 72140bc9c..4c171ce1a 100644 --- a/src/torchcodec/_core/FFMPEGCommon.cpp +++ b/src/torchcodec/_core/FFMPEGCommon.cpp @@ -387,7 +387,6 @@ AVFilterContext* createBuffersinkFilter( if (!buffersink) { return nullptr; } - AVFilterContext* sinkContext = nullptr; int status; From c4d0df8e21f91902baddc9fa885459240c862302 Mon Sep 17 00:00:00 2001 From: Daniel Flores Date: Wed, 8 Oct 2025 10:49:21 -0400 Subject: [PATCH 4/7] use av_opt_set_array to avoid av_get_pix_fmt_name --- src/torchcodec/_core/FFMPEGCommon.cpp | 15 ++++++++------- src/torchcodec/_core/FFMPEGCommon.h | 1 - 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/torchcodec/_core/FFMPEGCommon.cpp b/src/torchcodec/_core/FFMPEGCommon.cpp index 4c171ce1a..dca346af7 100644 --- a/src/torchcodec/_core/FFMPEGCommon.cpp +++ b/src/torchcodec/_core/FFMPEGCommon.cpp @@ -397,13 +397,14 @@ AVFilterContext* createBuffersinkFilter( if (!sinkContext) { return nullptr; } - // av_opt_set uses the string representation of a pixel format - const char* fmt_name = av_get_pix_fmt_name(outputFormat); - if (!fmt_name) { - return nullptr; - } - status = av_opt_set( - sinkContext, "pixel_formats", fmt_name, AV_OPT_SEARCH_CHILDREN); + status = av_opt_set_array( + sinkContext, + "pixel_formats", + AV_OPT_SEARCH_CHILDREN, + 0, // start_elem + 1, // nb_elems + AV_OPT_TYPE_PIXEL_FMT, + &outputFormat); if (status < 0) { return nullptr; } diff --git a/src/torchcodec/_core/FFMPEGCommon.h b/src/torchcodec/_core/FFMPEGCommon.h index 780f04f93..8aead0544 100644 --- a/src/torchcodec/_core/FFMPEGCommon.h +++ b/src/torchcodec/_core/FFMPEGCommon.h @@ -23,7 +23,6 @@ extern "C" { #include #include #include -#include #include #include #include From 4d41abbaadd3e4ffebd14d770742563a8074a2e6 Mon Sep 17 00:00:00 2001 From: Daniel Flores Date: Wed, 8 Oct 2025 11:34:06 -0400 Subject: [PATCH 5/7] replace nullptrs with torch check --- src/torchcodec/_core/FFMPEGCommon.cpp | 40 +++++++++++++++------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/src/torchcodec/_core/FFMPEGCommon.cpp b/src/torchcodec/_core/FFMPEGCommon.cpp index dca346af7..5a79ab94c 100644 --- a/src/torchcodec/_core/FFMPEGCommon.cpp +++ b/src/torchcodec/_core/FFMPEGCommon.cpp @@ -384,9 +384,8 @@ AVFilterContext* createBuffersinkFilter( const char* name, enum AVPixelFormat outputFormat) { const AVFilter* buffersink = avfilter_get_by_name("buffersink"); - if (!buffersink) { - return nullptr; - } + TORCH_CHECK(buffersink != nullptr, "Failed to get buffersink filter."); + AVFilterContext* sinkContext = nullptr; int status; @@ -394,9 +393,9 @@ AVFilterContext* createBuffersinkFilter( #if LIBAVUTIL_VERSION_MAJOR >= 60 // FFmpeg >= 8 // Output options like pixel_formats must be set before filter init sinkContext = avfilter_graph_alloc_filter(filterGraph, buffersink, name); - if (!sinkContext) { - return nullptr; - } + TORCH_CHECK( + sinkContext != nullptr, "Failed to allocate buffersink filter context."); + status = av_opt_set_array( sinkContext, "pixel_formats", @@ -405,20 +404,24 @@ AVFilterContext* createBuffersinkFilter( 1, // nb_elems AV_OPT_TYPE_PIXEL_FMT, &outputFormat); - if (status < 0) { - return nullptr; - } + TORCH_CHECK( + status >= 0, + "Failed to set pixel format for buffersink filter: ", + getFFMPEGErrorStringFromErrorCode(status)); + status = avfilter_init_str(sinkContext, nullptr); - if (status < 0) { - return nullptr; - } + TORCH_CHECK( + status >= 0, + "Failed to initialize buffersink filter: ", + getFFMPEGErrorStringFromErrorCode(status)); #else // FFmpeg <= 7 // For older FFmpeg versions, create filter and then set options status = avfilter_graph_create_filter( &sinkContext, buffersink, name, nullptr, nullptr, filterGraph); - if (status < 0) { - return nullptr; - } + TORCH_CHECK( + status >= 0, + "Failed to create buffersink filter: ", + getFFMPEGErrorStringFromErrorCode(status)); enum AVPixelFormat pix_fmts[] = {outputFormat, AV_PIX_FMT_NONE}; @@ -428,9 +431,10 @@ AVFilterContext* createBuffersinkFilter( pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN); - if (status < 0) { - return nullptr; - } + TORCH_CHECK( + status >= 0, + "Failed to set pixel formats for buffersink filter: ", + getFFMPEGErrorStringFromErrorCode(status)); #endif return sinkContext; From c5fa1e12551653bdbfe7b1e26bac1a0100921be4 Mon Sep 17 00:00:00 2001 From: Daniel Flores Date: Thu, 9 Oct 2025 09:45:29 -0400 Subject: [PATCH 6/7] incorporate suggestions --- src/torchcodec/_core/FFMPEGCommon.cpp | 16 ++++++++-------- src/torchcodec/_core/FFMPEGCommon.h | 1 - src/torchcodec/_core/FilterGraph.cpp | 4 ++-- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/torchcodec/_core/FFMPEGCommon.cpp b/src/torchcodec/_core/FFMPEGCommon.cpp index 5a79ab94c..085e4c641 100644 --- a/src/torchcodec/_core/FFMPEGCommon.cpp +++ b/src/torchcodec/_core/FFMPEGCommon.cpp @@ -7,7 +7,6 @@ #include "src/torchcodec/_core/FFMPEGCommon.h" #include - extern "C" { #include #include @@ -381,18 +380,21 @@ SwrContext* createSwrContext( AVFilterContext* createBuffersinkFilter( AVFilterGraph* filterGraph, - const char* name, enum AVPixelFormat outputFormat) { const AVFilter* buffersink = avfilter_get_by_name("buffersink"); TORCH_CHECK(buffersink != nullptr, "Failed to get buffersink filter."); AVFilterContext* sinkContext = nullptr; int status; + const char* filterName = "out"; + + enum AVPixelFormat pix_fmts[] = {outputFormat, AV_PIX_FMT_NONE}; -// av_opt_set_int_list was replaced by av_opt_set() in FFmpeg 8. +// av_opt_set_int_list was replaced by av_opt_set_array() in FFmpeg 8. #if LIBAVUTIL_VERSION_MAJOR >= 60 // FFmpeg >= 8 // Output options like pixel_formats must be set before filter init - sinkContext = avfilter_graph_alloc_filter(filterGraph, buffersink, name); + sinkContext = + avfilter_graph_alloc_filter(filterGraph, buffersink, filterName); TORCH_CHECK( sinkContext != nullptr, "Failed to allocate buffersink filter context."); @@ -403,7 +405,7 @@ AVFilterContext* createBuffersinkFilter( 0, // start_elem 1, // nb_elems AV_OPT_TYPE_PIXEL_FMT, - &outputFormat); + pix_fmts); TORCH_CHECK( status >= 0, "Failed to set pixel format for buffersink filter: ", @@ -417,14 +419,12 @@ AVFilterContext* createBuffersinkFilter( #else // FFmpeg <= 7 // For older FFmpeg versions, create filter and then set options status = avfilter_graph_create_filter( - &sinkContext, buffersink, name, nullptr, nullptr, filterGraph); + &sinkContext, buffersink, filterName, nullptr, nullptr, filterGraph); TORCH_CHECK( status >= 0, "Failed to create buffersink filter: ", getFFMPEGErrorStringFromErrorCode(status)); - enum AVPixelFormat pix_fmts[] = {outputFormat, AV_PIX_FMT_NONE}; - status = av_opt_set_int_list( sinkContext, "pix_fmts", diff --git a/src/torchcodec/_core/FFMPEGCommon.h b/src/torchcodec/_core/FFMPEGCommon.h index 8aead0544..92a262d26 100644 --- a/src/torchcodec/_core/FFMPEGCommon.h +++ b/src/torchcodec/_core/FFMPEGCommon.h @@ -239,7 +239,6 @@ int64_t computeSafeDuration( AVFilterContext* createBuffersinkFilter( AVFilterGraph* filterGraph, - const char* name, enum AVPixelFormat outputFormat); } // namespace facebook::torchcodec diff --git a/src/torchcodec/_core/FilterGraph.cpp b/src/torchcodec/_core/FilterGraph.cpp index 39d3ebcc9..afc44d96d 100644 --- a/src/torchcodec/_core/FilterGraph.cpp +++ b/src/torchcodec/_core/FilterGraph.cpp @@ -93,8 +93,8 @@ FilterGraph::FilterGraph( "Failed to create filter graph : ", getFFMPEGErrorStringFromErrorCode(status)); - sinkContext_ = createBuffersinkFilter( - filterGraph_.get(), "out", filtersContext.outputFormat); + sinkContext_ = + createBuffersinkFilter(filterGraph_.get(), filtersContext.outputFormat); TORCH_CHECK( sinkContext_ != nullptr, "Failed to create and configure buffersink"); From 7f96f98d5bef979d57776c352d1e932d3eb9eca1 Mon Sep 17 00:00:00 2001 From: Daniel Flores Date: Thu, 9 Oct 2025 11:44:01 -0400 Subject: [PATCH 7/7] add comment explaining nb_elements --- src/torchcodec/_core/FFMPEGCommon.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/torchcodec/_core/FFMPEGCommon.cpp b/src/torchcodec/_core/FFMPEGCommon.cpp index 085e4c641..172bfeb76 100644 --- a/src/torchcodec/_core/FFMPEGCommon.cpp +++ b/src/torchcodec/_core/FFMPEGCommon.cpp @@ -7,6 +7,7 @@ #include "src/torchcodec/_core/FFMPEGCommon.h" #include + extern "C" { #include #include @@ -398,6 +399,8 @@ AVFilterContext* createBuffersinkFilter( TORCH_CHECK( sinkContext != nullptr, "Failed to allocate buffersink filter context."); + // When setting pix_fmts, only the first element is used, so nb_elems = 1 + // AV_PIX_FMT_NONE acts as a terminator for the array in av_opt_set_int_list status = av_opt_set_array( sinkContext, "pixel_formats",