Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/torchcodec/_core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
66 changes: 66 additions & 0 deletions src/torchcodec/_core/FFMPEGCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@

#include <c10/util/Exception.h>

extern "C" {
#include <libavfilter/avfilter.h>
#include <libavfilter/buffersink.h>
}

namespace facebook::torchcodec {

AutoAVPacket::AutoAVPacket() : avPacket_(av_packet_alloc()) {
Expand Down Expand Up @@ -374,6 +379,67 @@ SwrContext* createSwrContext(
return swrContext;
}

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;

// 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);
TORCH_CHECK(
sinkContext != nullptr, "Failed to allocate buffersink filter context.");

status = av_opt_set_array(
sinkContext,
"pixel_formats",
AV_OPT_SEARCH_CHILDREN,
0, // start_elem
1, // nb_elems
AV_OPT_TYPE_PIXEL_FMT,
&outputFormat);
TORCH_CHECK(
status >= 0,
"Failed to set pixel format for buffersink filter: ",
getFFMPEGErrorStringFromErrorCode(status));

status = avfilter_init_str(sinkContext, nullptr);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this? In #935 (review) the only thing we had to change was to replace av_opt_set_int_list with av_opt_set_array, but I think we can still rely on avfilter_graph_create_filter for FFmpeg 8 ? Same above with avfilter_graph_alloc_filter which may not be needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately the new flow of allocation -> set flags -> init is required to set the pixel_formats flag. If we try to retain the previous pattern, this error appears:
Option 'pixel_formats' is not a runtime option and so cannot be set after the object has been initialized

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);
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",
pix_fmts,
AV_PIX_FMT_NONE,
AV_OPT_SEARCH_CHILDREN);
TORCH_CHECK(
status >= 0,
"Failed to set pixel formats for buffersink filter: ",
getFFMPEGErrorStringFromErrorCode(status));
#endif

return sinkContext;
}

UniqueAVFrame convertAudioAVFrameSamples(
const UniqueSwrContext& swrContext,
const UniqueAVFrame& srcAVFrame,
Expand Down
5 changes: 5 additions & 0 deletions src/torchcodec/_core/FFMPEGCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,4 +237,9 @@ int64_t computeSafeDuration(
const AVRational& frameRate,
const AVRational& timeBase);

AVFilterContext* createBuffersinkFilter(
AVFilterGraph* filterGraph,
const char* name,
enum AVPixelFormat outputFormat);

} // namespace facebook::torchcodec
24 changes: 4 additions & 20 deletions src/torchcodec/_core/FilterGraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <libavfilter/buffersink.h>
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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());
Expand Down
2 changes: 1 addition & 1 deletion src/torchcodec/_core/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
Expand Down
Loading