View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0002841 | DCP-o-matic | Bugs | public | 2024-06-29 00:16 | 2024-07-04 00:17 |
| Reporter | bradel | Assigned To | carl | ||
| Priority | normal | Severity | minor | Reproducibility | always |
| Status | resolved | Resolution | fixed | ||
| Platform | 64-bit | OS | Linux | OS Version | Arch |
| Product Version | 2.16.87 | ||||
| Summary | 0002841: DCPoMatic does not compile with ffmpeg 7 due to API changes channel_layout -> ch_layout | ||||
| Description | Dear Carl, Arch Linux recently rolled ffmpeg 7 out, which has changed the API regarding the channel_layout. I have attempted to adapt DCPoMatic for ffmpeg 7 (see attached patch), however I am by no means an expert in using ffmpeg or in the DCPoMatic code base :). So I am not sure that my patch is actually correct. Also, the patch does not yet consider the installed ffmpeg version, making it basically incompatible with older ffmpeg versions. Best regards, | ||||
| Steps To Reproduce | Compile DCPoMatic with ffmpeg 7 | ||||
| Additional Information | Additionally I receive the following warnings: ../src/lib/ffmpeg_file_encoder.cc: In destructor ‘ExportAudioStream::~ExportAudioStream()’: ../src/lib/ffmpeg_examiner.cc: In constructor ‘FFmpegExaminer::FFmpegExaminer(std::shared_ptr<const FFmpegContent>, std::shared_ptr<Job>)’: ../test/image_filename_sorter_test.cc: In member function ‘void image_filename_sorter_test2::test_method()’: | ||||
| Tags | No tags attached. | ||||
| Attached Files | 0002-Use-new-ffmpeg-7-API-for-channel_layout-ch_layout.patch (6,325 bytes)
From 8686d7e237476e677c3bd7d0bcc962f49022aca5 Mon Sep 17 00:00:00 2001
From: Benjamin Radel <benjamin@radel.tk>
Date: Sat, 29 Jun 2024 00:57:24 +0200
Subject: [PATCH] Use new ffmpeg-7 API for channel_layout -> ch_layout
Adapt DCPoMatic for using the new ffmpeg 7 ch_layout API.
Currently, this commit makes DCPoMatic incompatible with older
ffmpeg versions.
---
src/lib/audio_filter_graph.cc | 15 +++++++--------
src/lib/audio_filter_graph.h | 2 +-
src/lib/ffmpeg_decoder.cc | 2 +-
src/lib/ffmpeg_examiner.cc | 7 +++----
src/lib/ffmpeg_file_encoder.cc | 8 +++++---
5 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/src/lib/audio_filter_graph.cc b/src/lib/audio_filter_graph.cc
index 4e3052d57..d601e9d02 100644
--- a/src/lib/audio_filter_graph.cc
+++ b/src/lib/audio_filter_graph.cc
@@ -49,9 +49,9 @@ AudioFilterGraph::AudioFilterGraph (int sample_rate, int channels)
so we need to tell it we're using 16 channels if we are using more than 8.
*/
if (_channels > 8) {
- _channel_layout = av_get_default_channel_layout (16);
+ av_channel_layout_default (&_channel_layout, 16);
} else {
- _channel_layout = av_get_default_channel_layout (_channels);
+ av_channel_layout_default (&_channel_layout, _channels);
}
_in_frame = av_frame_alloc ();
@@ -69,7 +69,7 @@ string
AudioFilterGraph::src_parameters () const
{
char layout[64];
- av_get_channel_layout_string (layout, sizeof(layout), 0, _channel_layout);
+ av_channel_layout_describe (&_channel_layout, layout, sizeof(layout));
char buffer[256];
snprintf (
@@ -88,8 +88,7 @@ AudioFilterGraph::set_parameters (AVFilterContext* context) const
int r = av_opt_set_int_list (context, "sample_fmts", sample_fmts, AV_SAMPLE_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
DCPOMATIC_ASSERT (r >= 0);
- int64_t channel_layouts[] = { _channel_layout, -1 };
- r = av_opt_set_int_list (context, "channel_layouts", channel_layouts, -1, AV_OPT_SEARCH_CHILDREN);
+ r = av_opt_set_chlayout (context, "channel_layouts", &_channel_layout, AV_OPT_SEARCH_CHILDREN);
DCPOMATIC_ASSERT (r >= 0);
int sample_rates[] = { _sample_rate, -1 };
@@ -114,7 +113,7 @@ void
AudioFilterGraph::process (shared_ptr<AudioBuffers> buffers)
{
DCPOMATIC_ASSERT (buffers->frames() > 0);
- int const process_channels = av_get_channel_layout_nb_channels (_channel_layout);
+ int const process_channels = _channel_layout.nb_channels;
DCPOMATIC_ASSERT (process_channels >= buffers->channels());
if (buffers->channels() < process_channels) {
@@ -144,8 +143,8 @@ AudioFilterGraph::process (shared_ptr<AudioBuffers> buffers)
_in_frame->nb_samples = buffers->frames ();
_in_frame->format = AV_SAMPLE_FMT_FLTP;
_in_frame->sample_rate = _sample_rate;
- _in_frame->channel_layout = _channel_layout;
- _in_frame->channels = process_channels;
+ _in_frame->ch_layout = _channel_layout;
+ // _in_frame->channels = process_channels;
int r = av_buffersrc_write_frame (_buffer_src_context, _in_frame);
diff --git a/src/lib/audio_filter_graph.h b/src/lib/audio_filter_graph.h
index e5c55fa27..1ac2b071b 100644
--- a/src/lib/audio_filter_graph.h
+++ b/src/lib/audio_filter_graph.h
@@ -47,7 +47,7 @@ protected:
private:
int _sample_rate;
int _channels;
- int64_t _channel_layout;
+ AVChannelLayout _channel_layout;
AVFrame* _in_frame;
};
diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc
index 45983795b..88b867904 100644
--- a/src/lib/ffmpeg_decoder.cc
+++ b/src/lib/ffmpeg_decoder.cc
@@ -260,7 +260,7 @@ deinterleave_audio(AVFrame* frame)
/* XXX: can't we use swr_convert() to do the format conversion? */
- int const channels = frame->channels;
+ int const channels = frame->ch_layout.nb_channels;
int const frames = frame->nb_samples;
int const total_samples = frames * channels;
auto audio = make_shared<AudioBuffers>(channels, frames);
diff --git a/src/lib/ffmpeg_examiner.cc b/src/lib/ffmpeg_examiner.cc
index 51ade8e89..1a435482a 100644
--- a/src/lib/ffmpeg_examiner.cc
+++ b/src/lib/ffmpeg_examiner.cc
@@ -76,9 +76,8 @@ FFmpegExaminer::FFmpegExaminer (shared_ptr<const FFmpegContent> c, shared_ptr<Jo
/* This is a hack; sometimes it seems that _audio_codec_context->channel_layout isn't set up,
so bodge it here. No idea why we should have to do this.
*/
-
- if (s->codecpar->channel_layout == 0) {
- s->codecpar->channel_layout = av_get_default_channel_layout (s->codecpar->channels);
+ if (s->codecpar->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) {
+ av_channel_layout_default (&s->codecpar->ch_layout, s->codecpar->ch_layout.nb_channels);
}
DCPOMATIC_ASSERT (_format_context->duration != AV_NOPTS_VALUE);
@@ -91,7 +90,7 @@ FFmpegExaminer::FFmpegExaminer (shared_ptr<const FFmpegContent> c, shared_ptr<Jo
s->id,
s->codecpar->sample_rate,
llrint ((double(_format_context->duration) / AV_TIME_BASE) * s->codecpar->sample_rate),
- s->codecpar->channels,
+ s->codecpar->ch_layout.nb_channels,
s->codecpar->bits_per_raw_sample ? s->codecpar->bits_per_raw_sample : s->codecpar->bits_per_coded_sample
)
);
diff --git a/src/lib/ffmpeg_file_encoder.cc b/src/lib/ffmpeg_file_encoder.cc
index 6d1ad68f7..19a07801e 100644
--- a/src/lib/ffmpeg_file_encoder.cc
+++ b/src/lib/ffmpeg_file_encoder.cc
@@ -73,8 +73,8 @@ public:
_codec_context->bit_rate = channels * 128 * 1024;
_codec_context->sample_fmt = sample_format;
_codec_context->sample_rate = frame_rate;
- _codec_context->channel_layout = av_get_default_channel_layout (channels);
- _codec_context->channels = channels;
+ av_channel_layout_default (&_codec_context->ch_layout, channels);
+ //_codec_context->channels = channels;
int r = avcodec_open2 (_codec_context, _codec, 0);
if (r < 0) {
@@ -132,6 +132,8 @@ public:
DCPOMATIC_ASSERT (size);
auto frame = av_frame_alloc ();
+ AVChannelLayout ch_layout;
+ av_channel_layout_default (&ch_layout, channels);
DCPOMATIC_ASSERT (frame);
int line_size;
@@ -143,7 +145,7 @@ public:
frame->nb_samples = size;
frame->format = _codec_context->sample_fmt;
- frame->channels = channels;
+ frame->ch_layout = ch_layout;
int r = avcodec_fill_audio_frame (frame, channels, _codec_context->sample_fmt, (const uint8_t *) samples, buffer_size, 0);
DCPOMATIC_ASSERT (r >= 0);
--
2.45.2
| ||||
| Branch | |||||
| Estimated weeks required | |||||
| Estimated work required | |||||
|
|
I have reworked the patch and now included a test for the presence of the AVChannelLayout struct. The new patch should now be compatible with previous ffmpeg versions and ffmpeg 7 0002-Use-new-ffmpeg-7-API-for-channel_layout-ch_layout_V2.patch (8,398 bytes)
From 498d071f8e2c7c46a54ebb7add24d0a4bc43d1b7 Mon Sep 17 00:00:00 2001
From: Benjamin Radel <benjamin@radel.tk>
Date: Sat, 29 Jun 2024 00:57:24 +0200
Subject: [PATCH] Use new ffmpeg-7 API for channel_layout -> ch_layout
Adapt DCPoMatic for using the new ffmpeg 7 ch_layout API if detected.
---
src/lib/audio_filter_graph.cc | 25 ++++++++++++++++++++++++-
src/lib/audio_filter_graph.h | 4 ++++
src/lib/ffmpeg_decoder.cc | 4 ++++
src/lib/ffmpeg_examiner.cc | 11 ++++++++++-
src/lib/ffmpeg_file_encoder.cc | 15 +++++++++++++--
wscript | 12 ++++++++++++
6 files changed, 67 insertions(+), 4 deletions(-)
diff --git a/src/lib/audio_filter_graph.cc b/src/lib/audio_filter_graph.cc
index 4e3052d57..fc506f1ef 100644
--- a/src/lib/audio_filter_graph.cc
+++ b/src/lib/audio_filter_graph.cc
@@ -49,9 +49,17 @@ AudioFilterGraph::AudioFilterGraph (int sample_rate, int channels)
so we need to tell it we're using 16 channels if we are using more than 8.
*/
if (_channels > 8) {
+#ifdef DCPOMATIC_HAVE_AVCHANNELLAYOUT
+ av_channel_layout_default (&_channel_layout, 16);
+#else
_channel_layout = av_get_default_channel_layout (16);
+#endif
} else {
+#ifdef DCPOMATIC_HAVE_AVCHANNELLAYOUT
+ av_channel_layout_default (&_channel_layout, _channels);
+#else
_channel_layout = av_get_default_channel_layout (_channels);
+#endif
}
_in_frame = av_frame_alloc ();
@@ -69,8 +77,11 @@ string
AudioFilterGraph::src_parameters () const
{
char layout[64];
+#ifdef DCPOMATIC_HAVE_AVCHANNELLAYOUT
+ av_channel_layout_describe (&_channel_layout, layout, sizeof(layout));
+#else
av_get_channel_layout_string (layout, sizeof(layout), 0, _channel_layout);
-
+#endif
char buffer[256];
snprintf (
buffer, sizeof(buffer), "time_base=1/1:sample_rate=%d:sample_fmt=%s:channel_layout=%s",
@@ -88,8 +99,12 @@ AudioFilterGraph::set_parameters (AVFilterContext* context) const
int r = av_opt_set_int_list (context, "sample_fmts", sample_fmts, AV_SAMPLE_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
DCPOMATIC_ASSERT (r >= 0);
+#ifdef DCPOMATIC_HAVE_AVCHANNELLAYOUT
+ r = av_opt_set_chlayout (context, "channel_layouts", &_channel_layout, AV_OPT_SEARCH_CHILDREN);
+#else
int64_t channel_layouts[] = { _channel_layout, -1 };
r = av_opt_set_int_list (context, "channel_layouts", channel_layouts, -1, AV_OPT_SEARCH_CHILDREN);
+#endif
DCPOMATIC_ASSERT (r >= 0);
int sample_rates[] = { _sample_rate, -1 };
@@ -114,7 +129,11 @@ void
AudioFilterGraph::process (shared_ptr<AudioBuffers> buffers)
{
DCPOMATIC_ASSERT (buffers->frames() > 0);
+#ifdef DCPOMATIC_HAVE_AVCHANNELLAYOUT
+ int const process_channels = _channel_layout.nb_channels;
+#else
int const process_channels = av_get_channel_layout_nb_channels (_channel_layout);
+#endif
DCPOMATIC_ASSERT (process_channels >= buffers->channels());
if (buffers->channels() < process_channels) {
@@ -144,8 +163,12 @@ AudioFilterGraph::process (shared_ptr<AudioBuffers> buffers)
_in_frame->nb_samples = buffers->frames ();
_in_frame->format = AV_SAMPLE_FMT_FLTP;
_in_frame->sample_rate = _sample_rate;
+#ifdef DCPOMATIC_HAVE_AVCHANNELLAYOUT
+ _in_frame->ch_layout = _channel_layout;
+#else
_in_frame->channel_layout = _channel_layout;
_in_frame->channels = process_channels;
+#endif
int r = av_buffersrc_write_frame (_buffer_src_context, _in_frame);
diff --git a/src/lib/audio_filter_graph.h b/src/lib/audio_filter_graph.h
index e5c55fa27..9bbd28949 100644
--- a/src/lib/audio_filter_graph.h
+++ b/src/lib/audio_filter_graph.h
@@ -47,7 +47,11 @@ protected:
private:
int _sample_rate;
int _channels;
+#ifdef DCPOMATIC_HAVE_AVCHANNELLAYOUT
+ AVChannelLayout _channel_layout;
+#else
int64_t _channel_layout;
+#endif
AVFrame* _in_frame;
};
diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc
index 45983795b..76e52e272 100644
--- a/src/lib/ffmpeg_decoder.cc
+++ b/src/lib/ffmpeg_decoder.cc
@@ -260,7 +260,11 @@ deinterleave_audio(AVFrame* frame)
/* XXX: can't we use swr_convert() to do the format conversion? */
+#ifdef DCPOMATIC_HAVE_AVCHANNELLAYOUT
+ int const channels = frame->ch_layout.nb_channels;
+#else
int const channels = frame->channels;
+#endif
int const frames = frame->nb_samples;
int const total_samples = frames * channels;
auto audio = make_shared<AudioBuffers>(channels, frames);
diff --git a/src/lib/ffmpeg_examiner.cc b/src/lib/ffmpeg_examiner.cc
index 51ade8e89..0ed2aa5c1 100644
--- a/src/lib/ffmpeg_examiner.cc
+++ b/src/lib/ffmpeg_examiner.cc
@@ -76,10 +76,15 @@ FFmpegExaminer::FFmpegExaminer (shared_ptr<const FFmpegContent> c, shared_ptr<Jo
/* This is a hack; sometimes it seems that _audio_codec_context->channel_layout isn't set up,
so bodge it here. No idea why we should have to do this.
*/
-
+#ifdef DCPOMATIC_HAVE_AVCHANNELLAYOUT
+ if (s->codecpar->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) {
+ av_channel_layout_default (&s->codecpar->ch_layout, s->codecpar->ch_layout.nb_channels);
+ }
+#else
if (s->codecpar->channel_layout == 0) {
s->codecpar->channel_layout = av_get_default_channel_layout (s->codecpar->channels);
}
+#endif
DCPOMATIC_ASSERT (_format_context->duration != AV_NOPTS_VALUE);
DCPOMATIC_ASSERT (codec->name);
@@ -91,7 +96,11 @@ FFmpegExaminer::FFmpegExaminer (shared_ptr<const FFmpegContent> c, shared_ptr<Jo
s->id,
s->codecpar->sample_rate,
llrint ((double(_format_context->duration) / AV_TIME_BASE) * s->codecpar->sample_rate),
+#ifdef DCPOMATIC_HAVE_AVCHANNELLAYOUT
+ s->codecpar->ch_layout.nb_channels,
+#else
s->codecpar->channels,
+#endif
s->codecpar->bits_per_raw_sample ? s->codecpar->bits_per_raw_sample : s->codecpar->bits_per_coded_sample
)
);
diff --git a/src/lib/ffmpeg_file_encoder.cc b/src/lib/ffmpeg_file_encoder.cc
index 6d1ad68f7..196b8aa98 100644
--- a/src/lib/ffmpeg_file_encoder.cc
+++ b/src/lib/ffmpeg_file_encoder.cc
@@ -36,7 +36,6 @@ extern "C" {
#include "i18n.h"
-
using std::cout;
using std::make_shared;
using std::shared_ptr;
@@ -73,9 +72,12 @@ public:
_codec_context->bit_rate = channels * 128 * 1024;
_codec_context->sample_fmt = sample_format;
_codec_context->sample_rate = frame_rate;
+#ifdef DCPOMATIC_HAVE_AVCHANNELLAYOUT
+ av_channel_layout_default (&_codec_context->ch_layout, channels);
+#else
_codec_context->channel_layout = av_get_default_channel_layout (channels);
_codec_context->channels = channels;
-
+#endif
int r = avcodec_open2 (_codec_context, _codec, 0);
if (r < 0) {
throw EncodeError (N_("avcodec_open2"), N_("ExportAudioStream::ExportAudioStream"), r);
@@ -134,6 +136,11 @@ public:
auto frame = av_frame_alloc ();
DCPOMATIC_ASSERT (frame);
+#ifdef DCPOMATIC_HAVE_AVCHANNELLAYOUT
+ AVChannelLayout ch_layout;
+ av_channel_layout_default (&ch_layout, channels);
+#endif
+
int line_size;
int const buffer_size = av_samples_get_buffer_size (&line_size, channels, size, _codec_context->sample_fmt, 0);
DCPOMATIC_ASSERT (buffer_size >= 0);
@@ -143,7 +150,11 @@ public:
frame->nb_samples = size;
frame->format = _codec_context->sample_fmt;
+#ifdef DCPOMATIC_HAVE_AVCHANNELLAYOUT
+ frame->ch_layout = ch_layout;
+#else
frame->channels = channels;
+#endif
int r = avcodec_fill_audio_frame (frame, channels, _codec_context->sample_fmt, (const uint8_t *) samples, buffer_size, 0);
DCPOMATIC_ASSERT (r >= 0);
diff --git a/wscript b/wscript
index 744e45416..cb1ffadf7 100644
--- a/wscript
+++ b/wscript
@@ -501,6 +501,18 @@ def configure(conf):
define_name='DCPOMATIC_HAVE_AVCOMPONENTDESCRIPTOR_DEPTH_MINUS1',
mandatory=False)
+ # Check to see if we have the AVChannelLayout struct introduced in ffmpeg 7
+ conf.check_cxx(fragment="""
+ extern "C" {\n
+ #include <libavutil/channel_layout.h>\n
+ }\n
+ int main () { AVChannelLayout ch_layout = {}; }\n
+ """,
+ msg='Checking for AVChannelLayout',
+ uselib='AVUTIL',
+ define_name='DCPOMATIC_HAVE_AVCHANNELLAYOUT',
+ mandatory=False)
+
# See if we have av_register_all and avfilter_register_all
conf.check_cxx(fragment="""
extern "C" {\n
--
2.45.2
|
|
|
Thank you! I think this new API has already been used in DCP-o-matic on the |
|
|
Ah I am sorry, I missed that you have already adapted the v2.17.x branch. I tried building v2.17.18 and it works if I remove line 146 in AudioFilterGraph. The channels field in the AVFrame struct has been removed in ffmpeg 7. |
|
|
Great, I fixed up the 2.17 branch to work with FFmpeg 7.0.1 in 5555e580ecbfe6612ac5d18391fc0f6f96b96ac5 and b42699ccbf7865fc84b8c6218c070a1f06d2703a. I added an Thanks for the note and the patch! |
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2024-06-29 00:16 | bradel | New Issue | |
| 2024-06-29 00:16 | bradel | File Added: 0002-Use-new-ffmpeg-7-API-for-channel_layout-ch_layout.patch | |
| 2024-06-30 14:32 | bradel | Note Added: 0006468 | |
| 2024-06-30 14:32 | bradel | File Added: 0002-Use-new-ffmpeg-7-API-for-channel_layout-ch_layout_V2.patch | |
| 2024-06-30 22:49 | carl | Assigned To | => carl |
| 2024-06-30 22:49 | carl | Status | new => acknowledged |
| 2024-06-30 22:50 | carl | Note Added: 0006470 | |
| 2024-07-01 20:05 | bradel | Note Added: 0006471 | |
| 2024-07-04 00:17 | carl | Note Added: 0006475 | |
| 2024-07-04 00:17 | carl | Status | acknowledged => resolved |
| 2024-07-04 00:17 | carl | Resolution | open => fixed |