Build fails with FFmpeg 9.0

The place to discuss linux version of MakeMKV
Toad King
Posts: 143
Joined: Sun Jul 03, 2022 6:46 pm

Build fails with FFmpeg 9.0

Post by Toad King »

New version of FFmpeg removed some APIs MakeMKV was using.

Code: Select all

libffabi/src/ffabi.c: In function ‘set_codec_info_extended’:
libffabi/src/ffabi.c:542:22: error: ‘AVCodec’ has no member named ‘ch_layouts’
  542 |     if (NULL != codec->ch_layouts) {
      |                      ^~
libffabi/src/ffabi.c:543:26: error: ‘AVCodec’ has no member named ‘ch_layouts’
  543 |         while (0 != codec->ch_layouts[count_ch_layouts_in].nb_channels)
      |                          ^~
libffabi/src/ffabi.c:561:45: error: ‘AVCodec’ has no member named ‘ch_layouts’
  561 |         if (AV_CHANNEL_ORDER_NATIVE != codec->ch_layouts[i].order) continue;
      |                                             ^~
libffabi/src/ffabi.c:562:56: error: ‘AVCodec’ has no member named ‘ch_layouts’
  562 |         channel_layouts[count_ch_layouts_out++] = codec->ch_layouts[i].u.mask;
      |                                                        ^~
libffabi/src/ffabi.c: In function ‘ffm_audio_get_codec_information’:
libffabi/src/ffabi.c:589:31: error: ‘AVCodec’ has no member named ‘supported_samplerates’
  589 |     info->sample_rates = codec->supported_samplerates;
      |                               ^~
libffabi/src/ffabi.c:593:22: error: ‘AVCodec’ has no member named ‘ch_layouts’
  593 |     if (NULL == codec->ch_layouts) {
      |                      ^~
libffabi/src/ffabi.c:612:14: error: ‘AVCodec’ has no member named ‘sample_fmts’
  612 |     if (codec->sample_fmts) {
      |              ^~
libffabi/src/ffabi.c:614:22: error: ‘AVCodec’ has no member named ‘sample_fmts’
  614 |             if (codec->sample_fmts[i]==AV_SAMPLE_FMT_NONE)
      |                      ^~
libffabi/src/ffabi.c:616:77: error: ‘AVCodec’ has no member named ‘sample_fmts’
  616 |             info->sample_formats[i]=(uint8_t)back_translate_sample_fmt(codec->sample_fmts[i]);
      |                                                                             ^~
echo_x
Posts: 1
Joined: Tue Aug 11, 2026 5:17 pm

Re: Build fails with FFmpeg 9.0

Post by echo_x »

I ran into the same issue.
I downloaded both tarballs and extracted them to their own folders.
While running make:
I received this error message:

Code: Select all

objcopy --strip-all --strip-debug --strip-unneeded --discard-all out/libdriveio.so.0.full out/libdriveio.so.0
mkdir -p tmp/libffabi/src/
gcc -c -g -O2 -D_linux_ -Wno-deprecated-declarations  -D_GNU_SOURCE -D_REENTRANT -otmp/libffabi/src/ffabi.c.o -I./libabi/inc -I.
/libffabi/inc \
-DHAVE_BUILDINFO_H -Itmp  -fPIC libffabi/src/ffabi.c
libffabi/src/ffabi.c: In function ‘set_codec_info_extended’:
libffabi/src/ffabi.c:542:22: error: ‘AVCodec’ has no member named ‘ch_layouts’
 542 |     if (NULL != codec**->ch_layouts) {
     |                      ^~
libffabi/src/ffabi.c:543:26: error: ‘AVCodec’ has no member named ‘ch_layouts’
 543 |         while (0 != codec->ch_layouts[count_ch_layouts_in].nb_channels)
     |                          ^~
libffabi/src/ffabi.c:561:45: error: ‘AVCodec’ has no member named ‘ch_layouts’
 561 |         if (AV_CHANNEL_ORDER_NATIVE != codec->ch_layouts[i].order) continue;
     |                                             ^~
libffabi/src/ffabi.c:562:56: error: ‘AVCodec’ has no member named ‘ch_layouts’
 562 |         channel_layouts[count_ch_layouts_out++] = codec->ch_layouts[i].u.mask;
     |                                                        ^~
libffabi/src/ffabi.c: In function ‘ffm_audio_get_codec_information’:
libffabi/src/ffabi.c:589:31: error: ‘AVCodec’ has no member named ‘supported_samplerates’
 589 |     info->sample_rates = codec->supported_samplerates;
     |                               ^~
libffabi/src/ffabi.c:593:22: error: ‘AVCodec’ has no member named ‘ch_layouts’
 593 |     if (NULL == codec->ch_layouts) {
     |                      ^~
libffabi/src/ffabi.c:612:14: error: ‘AVCodec’ has no member named ‘sample_fmts’
 612 |     if (codec->sample_fmts) {
     |              ^~
libffabi/src/ffabi.c:614:22: error: ‘AVCodec’ has no member named ‘sample_fmts’
 614 |             if (codec->sample_fmts[i]==AV_SAMPLE_FMT_NONE)
     |                      ^~
libffabi/src/ffabi.c:616:77: error: ‘AVCodec’ has no member named ‘sample_fmts’
 616 |             info->sample_formats[i]=(uint8_t)back_translate_sample_fmt(codec->**sample_fmts[i]);
     |                                                                             ^~
make: *** [Makefile:84: tmp/libffabi/src/ffabi.c.o] Error 1
I used Python to modify libffabi/src/ffabi.c to change the API calls

Code: Select all

python - <<'PY'
from pathlib import Path

p = Path("libffabi/src/ffabi.c")
s = p.read_text()

start = s.index("#ifndef FFABI_HAVE_OLD_CHANNEL_LAYOUT\nstatic int set_codec_info_extended")
end = s.index("\nFFM_AudioConvert* __cdecl ffm_audio_convert_alloc", start)

replacement = r'''#ifndef FFABI_HAVE_OLD_CHANNEL_LAYOUT
static int set_codec_info_extended(FFM_CodecInfo* info, const AVCodec* codec)
{
    char* exinfo;
    size_t len;
    int count_ch_layouts_in = 0;
    unsigned int count_ch_layouts_out = 0;
    uint64_t* channel_layouts;
    const AVChannelLayout* ch_layouts = NULL;
    unsigned int i;
    int ret;

    len = strlen(codec->name);
    if (len >= FFM_CODEC_INFO_NAME_MAX_LENGTH) return -1;

    ret = avcodec_get_supported_config(
        NULL, codec, AV_CODEC_CONFIG_CHANNEL_LAYOUT, 0,
        (const void**)&ch_layouts, &count_ch_layouts_in
    );

    if (ret < 0) return -1;

    exinfo = (char*)ffabi_memalign(
        sizeof(uint64_t),
        FFM_CODEC_INFO_NAME_MAX_LENGTH +
        FFM_CODEC_INFO_EXMARK_LENGTH +
        ((count_ch_layouts_in + 1) * sizeof(uint64_t))
    );

    if (NULL == exinfo) return -1;

    memcpy(exinfo, codec->name, len + 1);
    memcpy(exinfo + FFM_CODEC_INFO_NAME_MAX_LENGTH,
           FFM_CODEC_INFO_EXMARK_MAGIC,
           FFM_CODEC_INFO_EXMARK_LENGTH);

    channel_layouts = (uint64_t*)(
        exinfo +
        FFM_CODEC_INFO_NAME_MAX_LENGTH +
        FFM_CODEC_INFO_EXMARK_LENGTH
    );

    info->name = exinfo;
    info->channel_layouts = channel_layouts;

    for (i = 0; i < (unsigned int)count_ch_layouts_in; i++) {
        if (AV_CHANNEL_ORDER_NATIVE != ch_layouts[i].order)
            continue;

        channel_layouts[count_ch_layouts_out++] =
            ch_layouts[i].u.mask;
    }

    channel_layouts[count_ch_layouts_out] = 0;

    return 0;
}
#endif

int __cdecl ffm_audio_get_codec_information(
    FFM_CodecInfo* info,
    const char* name,
    int encode)
{
    AVCodec* codec;
    const int* sample_rates = NULL;
    const enum AVSampleFormat* sample_fmts = NULL;
#ifndef FFABI_HAVE_OLD_CHANNEL_LAYOUT
    const AVChannelLayout* ch_layouts = NULL;
#endif
    int num_sample_rates = 0;
    int num_sample_fmts = 0;
#ifndef FFABI_HAVE_OLD_CHANNEL_LAYOUT
    int num_ch_layouts = 0;
#endif
    int ret;
    int i;

    memset(info, 0, sizeof(*info));

    if (encode) {
        codec = (AVCodec*)avcodec_find_encoder_by_name(name);
    } else {
        codec = (AVCodec*)avcodec_find_decoder_by_name(name);
    }

    if (!codec)
        return ffmerr(1, encode);

    info->name = codec->name;
    info->long_name = codec->long_name;

    ret = avcodec_get_supported_config(
        NULL, codec, AV_CODEC_CONFIG_SAMPLE_RATE, 0,
        (const void**)&sample_rates, &num_sample_rates
    );

    if (ret < 0)
        return ffmerr(2, 0);

    info->sample_rates = sample_rates;

#ifdef FFABI_HAVE_OLD_CHANNEL_LAYOUT
    info->channel_layouts = codec->channel_layouts;
#else
    ret = avcodec_get_supported_config(
        NULL, codec, AV_CODEC_CONFIG_CHANNEL_LAYOUT, 0,
        (const void**)&ch_layouts, &num_ch_layouts
    );

    if (ret < 0)
        return ffmerr(2, 0);

    if (NULL == ch_layouts) {
        info->channel_layouts = NULL;
    } else {
        if (set_codec_info_extended(info, codec))
            return ffmerr(2, 0);
    }
#endif

    info->id = codec->id;
    info->capabilities = codec->capabilities;

    if (codec->profiles) {
        for (i = 0; i < 32; i++) {
            if (codec->profiles[i].profile == AV_PROFILE_UNKNOWN)
                break;

            info->profiles_names[i] = codec->profiles[i].name;
            info->profiles_values[i] = codec->profiles[i].profile;
            info->profiles_count = i + 1;
        }
    }

    ret = avcodec_get_supported_config(
        NULL, codec, AV_CODEC_CONFIG_SAMPLE_FORMAT, 0,
        (const void**)&sample_fmts, &num_sample_fmts
    );

    if (ret < 0)
        return ffmerr(2, 0);

    if (sample_fmts) {
        for (i = 0; i < num_sample_fmts && i < 16; i++) {
            info->sample_formats[i] =
                (uint8_t)back_translate_sample_fmt(sample_fmts[i]);
            info->sample_formats_count = i + 1;
        }
    }

    return 0;
}
'''

p.write_text(s[:start] + replacement + s[end:])
print("Patched:", p)
PY
I then used make clean and continued through the install.
Afterwards, I was able to open the software
Sayaka
Posts: 341
Joined: Sat Feb 28, 2026 3:00 pm

Re: Build fails with FFmpeg 9.0

Post by Sayaka »

I have not yet attempted to rip a disc from my Arch distrobox after patching, but I have to thank you for this. After updating to ffmpeg 9 and using your patch, I was able to launch MakeMKV with no issues.

For anyone who's wondering, this is what I did on my Arch distrobox on my Ubuntu LTS-based system :

1) Used "sudo pacman -Rcn makemkv" to remove the AUR package
2) Used the makemkv-oss-1.18.4 and and makemkv-bin-1.18.4 that I had previously downloaded from the main website, rather than the AUR package
3) Created an empty file named "ffmpegpatch.py" inside the makemkv-oss-1.18.4 folder
4) Pasted the following code into the file then saved the file :

Code: Select all

from pathlib import Path

p = Path("libffabi/src/ffabi.c")
s = p.read_text()

start = s.index("#ifndef FFABI_HAVE_OLD_CHANNEL_LAYOUT\nstatic int set_codec_info_extended")
end = s.index("\nFFM_AudioConvert* __cdecl ffm_audio_convert_alloc", start)

replacement = r'''#ifndef FFABI_HAVE_OLD_CHANNEL_LAYOUT
static int set_codec_info_extended(FFM_CodecInfo* info, const AVCodec* codec)
{
    char* exinfo;
    size_t len;
    int count_ch_layouts_in = 0;
    unsigned int count_ch_layouts_out = 0;
    uint64_t* channel_layouts;
    const AVChannelLayout* ch_layouts = NULL;
    unsigned int i;
    int ret;

    len = strlen(codec->name);
    if (len >= FFM_CODEC_INFO_NAME_MAX_LENGTH) return -1;

    ret = avcodec_get_supported_config(
        NULL, codec, AV_CODEC_CONFIG_CHANNEL_LAYOUT, 0,
        (const void**)&ch_layouts, &count_ch_layouts_in
    );

    if (ret < 0) return -1;

    exinfo = (char*)ffabi_memalign(
        sizeof(uint64_t),
        FFM_CODEC_INFO_NAME_MAX_LENGTH +
        FFM_CODEC_INFO_EXMARK_LENGTH +
        ((count_ch_layouts_in + 1) * sizeof(uint64_t))
    );

    if (NULL == exinfo) return -1;

    memcpy(exinfo, codec->name, len + 1);
    memcpy(exinfo + FFM_CODEC_INFO_NAME_MAX_LENGTH,
           FFM_CODEC_INFO_EXMARK_MAGIC,
           FFM_CODEC_INFO_EXMARK_LENGTH);

    channel_layouts = (uint64_t*)(
        exinfo +
        FFM_CODEC_INFO_NAME_MAX_LENGTH +
        FFM_CODEC_INFO_EXMARK_LENGTH
    );

    info->name = exinfo;
    info->channel_layouts = channel_layouts;

    for (i = 0; i < (unsigned int)count_ch_layouts_in; i++) {
        if (AV_CHANNEL_ORDER_NATIVE != ch_layouts[i].order)
            continue;

        channel_layouts[count_ch_layouts_out++] =
            ch_layouts[i].u.mask;
    }

    channel_layouts[count_ch_layouts_out] = 0;

    return 0;
}
#endif

int __cdecl ffm_audio_get_codec_information(
    FFM_CodecInfo* info,
    const char* name,
    int encode)
{
    AVCodec* codec;
    const int* sample_rates = NULL;
    const enum AVSampleFormat* sample_fmts = NULL;
#ifndef FFABI_HAVE_OLD_CHANNEL_LAYOUT
    const AVChannelLayout* ch_layouts = NULL;
#endif
    int num_sample_rates = 0;
    int num_sample_fmts = 0;
#ifndef FFABI_HAVE_OLD_CHANNEL_LAYOUT
    int num_ch_layouts = 0;
#endif
    int ret;
    int i;

    memset(info, 0, sizeof(*info));

    if (encode) {
        codec = (AVCodec*)avcodec_find_encoder_by_name(name);
    } else {
        codec = (AVCodec*)avcodec_find_decoder_by_name(name);
    }

    if (!codec)
        return ffmerr(1, encode);

    info->name = codec->name;
    info->long_name = codec->long_name;

    ret = avcodec_get_supported_config(
        NULL, codec, AV_CODEC_CONFIG_SAMPLE_RATE, 0,
        (const void**)&sample_rates, &num_sample_rates
    );

    if (ret < 0)
        return ffmerr(2, 0);

    info->sample_rates = sample_rates;

#ifdef FFABI_HAVE_OLD_CHANNEL_LAYOUT
    info->channel_layouts = codec->channel_layouts;
#else
    ret = avcodec_get_supported_config(
        NULL, codec, AV_CODEC_CONFIG_CHANNEL_LAYOUT, 0,
        (const void**)&ch_layouts, &num_ch_layouts
    );

    if (ret < 0)
        return ffmerr(2, 0);

    if (NULL == ch_layouts) {
        info->channel_layouts = NULL;
    } else {
        if (set_codec_info_extended(info, codec))
            return ffmerr(2, 0);
    }
#endif

    info->id = codec->id;
    info->capabilities = codec->capabilities;

    if (codec->profiles) {
        for (i = 0; i < 32; i++) {
            if (codec->profiles[i].profile == AV_PROFILE_UNKNOWN)
                break;

            info->profiles_names[i] = codec->profiles[i].name;
            info->profiles_values[i] = codec->profiles[i].profile;
            info->profiles_count = i + 1;
        }
    }

    ret = avcodec_get_supported_config(
        NULL, codec, AV_CODEC_CONFIG_SAMPLE_FORMAT, 0,
        (const void**)&sample_fmts, &num_sample_fmts
    );

    if (ret < 0)
        return ffmerr(2, 0);

    if (sample_fmts) {
        for (i = 0; i < num_sample_fmts && i < 16; i++) {
            info->sample_formats[i] =
                (uint8_t)back_translate_sample_fmt(sample_fmts[i]);
            info->sample_formats_count = i + 1;
        }
    }

    return 0;
}
'''

p.write_text(s[:start] + replacement + s[end:])
print("Patched:", p)
(I had to delete the first and last lines as they caused the python script to not work properly on my system)

5) Inside the distrobox, confirmed that the problem was happening by running "./configure" and "make" inside the makemkv-oss-1.18.4 folder
6) Ran "make clean"
7) Used the command "python ffmpegpatch.py" inside that same folder
8 ) Ran "./configure" and "make" again
9) Ran "sudo make install"
10) Inside the makemkv-bin-1.18.4 folder, ran "make", accepted the license, then ran "sudo make install"
11) Launched MakeMKV with no issues.

(Now I probably just need to do the whole symlink thingy again if I want to be 100% sure I can have direct UHD disc playback once again when using Kodi.)
TheCrazyCanuck
Posts: 34
Joined: Sat Nov 07, 2020 4:32 am

Re: Build fails with FFmpeg 9.0

Post by TheCrazyCanuck »

If you build MakeMKV from sources like me, this is how I fixed the issue on CachyOS (copy and paste from my notes):

1) Remove ffmpeg from pacman so it won't be updated automatically which caused the issue in the first place (FFMpeg 9):

a) Open /etc/pacman.conf
b) Find line with "IgnorePkg"
c) Edit the line from step 1b to IgnorePkg = ffmpeg

2) Download FFMpeg 8 from their website or git

3) Navigate to the extracted FFMpeg sources and configure it to be linkable externally

a) ./configure --enable-shared

4) Make and install FFMpeg 8:

a) make
b) sudo make install

5) Rebuild MakeMKV OSS so that it uses FFMpeg 8 moving forward.


If you want to build MakeMKV from sources there are some other packages like build-essentials which contains the compilers that need to be installed first. This is how I build the Bin and OSS:

MakeMKV OSS:

1) Unpack the source tarball: tar -xvf makemkv-oss-x.y.z.tar.gz

2) Enter the directory: cd makemkv-oss-x.y.z

3) Configure the build: ./configure

4) Compile the files: make

5) Install the binary: sudo make install


MakeKMV Bin:

1) Unpack the binary tarball: tar -xvf makemkv-bin-x.y.z.tar.gz

2) Enter the directory: cd makemkv-bin-x.y.z

3) Configure the build: ./configure

4) Compile the files: make

5) Install the binary: sudo make install
lmm5247
Posts: 3
Joined: Sat Nov 22, 2025 3:50 pm

Re: Build fails with FFmpeg 9.0

Post by lmm5247 »

There is now a patch for the AUR package on Arch

https://aur.archlinux.org/packages/makemkv
Sayaka
Posts: 341
Joined: Sat Feb 28, 2026 3:00 pm

Re: Build fails with FFmpeg 9.0

Post by Sayaka »

Thank you. I also found this :

https://aur.archlinux.org/packages/makemkv-working

Which "freezes" MakeMKV to version 1.17.7, for those who want it.
Mr. ---
Posts: 1
Joined: Fri Aug 21, 2026 9:31 am

Re: Build fails with FFmpeg 9.0

Post by Mr. --- »

Here's how I solved it

1.18.4-1 ----> 1.18.4-2

CachyOS
paru -S makemkv

After confirmation, it displays the PKGBUILD in the console.
Don't do anything yet.

## Place the two packages in the following folder

/home/***/.cache/paru/clone/makemkv/

makemkv-bin-1.18.4.tar.gz
makemkv-oss-1.18.4.tar.gz

## Open the PKGBUILD file with an editor (kate)

source=(makemkv-bin-${pkgver}.tar.gz
makemkv-oss-${pkgver}.tar.gz

## Now you can press “q” to make the PKGBUILD disappear from the console.
Then the installation should run through.
SgrtClober
Posts: 1
Joined: Wed Oct 07, 2026 3:30 am

Re: Build fails with FFmpeg 9.0

Post by SgrtClober »

The python patch works wonderfully on 2.0.0. Will update if I run into any issues
richEQ
Posts: 6
Joined: Thu Jan 29, 2015 9:36 am

Re: Build fails with FFmpeg 9.0

Post by richEQ »

Code: Select all

/* Claude produced fix for compiling v2.0 with ffmpeg v9
replace the current libffabi/src/ffabi.c with this
tried and tested 

    libMakeMKV - MKV multiplexer library

    Copyright (C) 2007-2026 GuinpinSoft inc <libmkv@makemkv.com>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

*/
#include <lgpl/ffabi.h>
#include <libavcodec/avcodec.h>
#include "mpegaudiodecheader.h"
#include <libavutil/samplefmt.h>
#include <libavutil/opt.h>
#include <string.h>
#include "internal.h"

static int                  log_print_prefix = 1;
static void*                log_context = NULL;
static ffm_log_callback_t   log_callback = NULL;
static ffm_memalign_t       proc_memalign = NULL;
static ffm_realloc_t        proc_realloc = NULL;
static ffm_free_t           proc_free = NULL;

void *ffabi_memalign(size_t align, size_t size)
{
    return (*proc_memalign)(align,size);
}

void *ffabi_realloc(void *ptr, size_t size)
{
    return (*proc_realloc)(ptr,size);
}

void ffabi_free(void *ptr)
{
    (*proc_free)(ptr);
}

static void static_log_callback(void* ptr, int level, const char* fmt, va_list vl)
{
    char line[1024];
    void* ctx2 = NULL;

    av_log_format_line(ptr, level, fmt, vl, line, sizeof(line), &log_print_prefix);

    line[sizeof(line)-1]=0;

    if (ptr) {
        struct AVClass* pclass = *((struct AVClass**)ptr);
        if (pclass) {
            if (!strcmp(pclass->class_name,"AVCodecContext")) {
                ctx2 = ((AVCodecContext*)ptr)->opaque;
            }
            if (!strcmp(pclass->class_name,"FFM_AudioMix")) {
                ctx2 = ((ffabi_Logger*)ptr)->ctx2;
            }
        }
    }

    if (log_callback) {
        (*log_callback)(log_context,ctx2,level,line);
    }
}

int __cdecl ffm_init(ffm_log_callback_t log_proc,void* log_ctx,ffm_memalign_t memalign_proc,ffm_realloc_t realloc_proc,ffm_free_t free_proc)
{
    log_context = log_ctx;
    log_callback = log_proc;
    proc_memalign = memalign_proc;
    proc_realloc = realloc_proc;
    proc_free = free_proc;

    av_log_set_callback(static_log_callback);

#ifndef FFABI_HAVE_AV_CODEC_ITERATE
    avcodec_register_all();
#endif

    ffabi_ff_mlp_init_crc();

    return 0;
}

uint64_t __cdecl ffm_avcodec_version3(void)
{
    const uint32_t flags = FFABI_VERSION_FLAG_PATCHLEVEL_VALUE;
    uint32_t version = avcodec_version()&0x7fffffff;
    return (((uint64_t)flags)<<32) | version | 0x80000000;
}

static enum AVSampleFormat translate_sample_fmt(FFM_AudioFormat fmt)
{
    enum AVSampleFormat r;

    switch(fmt) {
    case FFM_AUDIO_FMT_PCM_U8 : r = AV_SAMPLE_FMT_U8; break;
    case FFM_AUDIO_FMT_PCM_S16: r = AV_SAMPLE_FMT_S16; break;
    case FFM_AUDIO_FMT_PCM_S24: r = AV_SAMPLE_FMT_S24; break;
    case FFM_AUDIO_FMT_PCM_S32: r = AV_SAMPLE_FMT_S32; break;
    case FFM_AUDIO_FMT_PCM_FLT: r = AV_SAMPLE_FMT_FLT; break;
    case FFM_AUDIO_FMT_PCM_DBL: r = AV_SAMPLE_FMT_DBL; break;
    case FFM_AUDIO_FMT_PCM_U8P : r = AV_SAMPLE_FMT_U8P; break;
    case FFM_AUDIO_FMT_PCM_S16P: r = AV_SAMPLE_FMT_S16P; break;
    case FFM_AUDIO_FMT_PCM_S32P: r = AV_SAMPLE_FMT_S32P; break;
    case FFM_AUDIO_FMT_PCM_FLTP: r = AV_SAMPLE_FMT_FLTP; break;
    case FFM_AUDIO_FMT_PCM_DBLP: r = AV_SAMPLE_FMT_DBLP; break;
    default : r = AV_SAMPLE_FMT_NONE; break;
    }
    return r;
}

static FFM_AudioFormat back_translate_sample_fmt(enum AVSampleFormat fmt)
{
    int i;

    for (i=0;i<FFM_AUDIO_FMT_MAX_VALUE;i++) {
        if (fmt==translate_sample_fmt((FFM_AudioFormat)i)) {
            return (FFM_AudioFormat)i;
        }
    }
    return FFM_AUDIO_FMT_UNKNOWN;
}

struct _FFM_AudioDecodeContext
{
    AVCodec*                codec;
    AVCodecContext*         avctx;
    AVFrame*                frame;
    AVPacket*               pck;
    unsigned int            nb_samples;
    int                     eos;
};

FFM_AudioDecodeContext* __cdecl ffm_audio_decode_init(void* logctx,const char* name,FFM_AudioFormat fmt,const char* argp[],const uint8_t* CodecData,unsigned int CodecDataSize,unsigned int time_base,unsigned int CodecFlags)
{
    AVDictionary *opts = NULL;
    FFM_AudioDecodeContext* ctx;
    int i;

    ctx = av_mallocz(sizeof(FFM_AudioDecodeContext));
    if (!ctx) {
        return NULL;
    }

    ctx->codec = (AVCodec*) avcodec_find_decoder_by_name(name);
    if (!ctx->codec) {
        ffm_audio_decode_close(ctx);
        return NULL;
    }

    ctx->avctx = avcodec_alloc_context3(ctx->codec);
    if (!ctx->avctx) {
        ffm_audio_decode_close(ctx);
        return NULL;
    }
    ctx->avctx->opaque = logctx;
    ctx->avctx->time_base.num = 1;
    ctx->avctx->time_base.den = time_base;

    if (CodecData) {
        ctx->avctx->extradata = (uint8_t*) CodecData;
        ctx->avctx->extradata_size = CodecDataSize;
    }

    ctx->avctx->request_sample_fmt = translate_sample_fmt(fmt);

    if (argp) {
        for (i=0;argp[i];i+=2) {
            av_dict_set(&opts, argp[i], argp[i+1], 0);
        }
    }

    if (avcodec_open2(ctx->avctx,ctx->codec,&opts)) {
        av_dict_free(&opts);
        ffm_audio_decode_close(ctx);
        return NULL;
    }
    av_dict_free(&opts);

    ctx->frame = av_frame_alloc();

    if (!ctx->frame) {
        ffm_audio_decode_close(ctx);
        return NULL;
    }

    ctx->pck = av_packet_alloc();
    if (!ctx->pck) {
        ffm_audio_decode_close(ctx);
        return NULL;
    }

    return ctx;
}

int __cdecl ffm_audio_decode_close(FFM_AudioDecodeContext* ctx)
{
    av_frame_free(&ctx->frame);
    av_packet_free(&ctx->pck);

    if (ctx->avctx) {
        avcodec_free_context(&ctx->avctx);
    }

    av_free(ctx);

    return 0;
}

static int av_cold ffmerr(uint8_t type,unsigned int value)
{
    uint32_t v;

    v = 0x80000000 | (((uint32_t)type)<<28) | ((uint32_t)(value&0x0fffffff));

    return (int)(int32_t)v;
}

int __cdecl ffm_audio_decode_put_data(FFM_AudioDecodeContext* ctx,const uint8_t* data,unsigned int size,int64_t pts)
{
    int r;

    if (NULL!=data) {

        AVPacket* avpkt = ctx->pck;

        av_packet_unref(avpkt);

        avpkt->pts = pts;
        avpkt->dts = pts;
        avpkt->data = (uint8_t*)data;
        avpkt->size = size;

        r = avcodec_send_packet(ctx->avctx,avpkt);
    } else {
        if (!ctx->eos) {
            r = avcodec_send_packet(ctx->avctx,NULL);
            ctx->eos = 1;
        } else {
            r = 0;
        }
    }
    return r;
}

int __cdecl ffm_audio_decode_get_frame(FFM_AudioDecodeContext* ctx,int64_t* pts,const uint8_t* data[])
{
    int r,i,channels;

    av_frame_unref(ctx->frame);

    r = avcodec_receive_frame(ctx->avctx,ctx->frame);

    if ( (r==AVERROR_EOF) || (r==AVERROR(EAGAIN)) ) return 0;
    if (r!=0) return r;

#ifdef FFABI_HAVE_OLD_CHANNEL_LAYOUT
    channels = ctx->avctx->channels;
    if (ctx->frame->channels != channels) { return ffmerr(1,ctx->frame->channels); }
#else
    channels = ctx->avctx->ch_layout.nb_channels;
    if (ctx->frame->ch_layout.nb_channels != channels) { return ffmerr(1, ctx->frame->ch_layout.nb_channels); }
#endif
    if (ctx->frame->sample_rate != ctx->avctx->sample_rate) { return ffmerr(2,ctx->frame->sample_rate); }
    if (ctx->frame->format != ctx->avctx->sample_fmt) { return ffmerr(3,ctx->frame->format); }
    if (ctx->nb_samples) {
        if (ctx->nb_samples < ctx->frame->nb_samples) { return ffmerr(5,ctx->frame->nb_samples); }
    } else {
        ctx->nb_samples = ctx->frame->nb_samples;
    }

    *pts = ctx->frame->pts;

    data[0]=ctx->frame->data[0];

    if (av_sample_fmt_is_planar(ctx->avctx->sample_fmt)) {
        for (i=1;i<channels;i++) {
            data[i] = ctx->frame->extended_data[i];
        }
    }

    return ctx->frame->nb_samples;
}

int __cdecl ffm_audio_decode_get_info(FFM_AudioDecodeContext* ctx,FFM_AudioInfo* info)
{
    info->sample_rate = ctx->avctx->sample_rate;
#ifdef FFABI_HAVE_OLD_CHANNEL_LAYOUT
    info->channels = ctx->avctx->channels;
    info->channel_layout = ctx->avctx->channel_layout;
#else
    info->channels = ctx->avctx->ch_layout.nb_channels;
    info->channel_layout = (AV_CHANNEL_ORDER_NATIVE == ctx->avctx->ch_layout.order) ? ctx->avctx->ch_layout.u.mask : 0;
#endif
    info->frame_size = ctx->nb_samples;
    info->sample_fmt = back_translate_sample_fmt(ctx->avctx->sample_fmt);
    info->bits_per_sample = ctx->avctx->bits_per_raw_sample;
    info->profile = ctx->avctx->profile;
    return 0;
}

struct _FFM_AudioEncodeContext
{
    AVCodec*                codec;
    AVCodecContext*         avctx;
    AVFrame*                frame;
    AVPacket*               pck;
    uint8_t**               frame_extended_data;
    int                     eos;
};


FFM_AudioEncodeContext* __cdecl ffm_audio_encode_init(void* logctx,const char* name,FFM_AudioFormat fmt,FFM_AudioInfo* info,const char* argp[],unsigned int time_base,unsigned int CodecFlags)
{
    AVDictionary *opts = NULL;
    FFM_AudioEncodeContext* ctx;
    int i;

    ctx = av_mallocz(sizeof(FFM_AudioEncodeContext));
    if (!ctx) {
        return NULL;
    }

    ctx->pck = av_packet_alloc();
    if (!ctx->pck) {
        ffm_audio_encode_close(ctx);
        return NULL;
    }

    ctx->codec = (AVCodec*) avcodec_find_encoder_by_name(name);
    if (!ctx->codec) {
        ffm_audio_encode_close(ctx);
        return NULL;
    }

    ctx->avctx = avcodec_alloc_context3(ctx->codec);
    if (!ctx->avctx) {
        ffm_audio_encode_close(ctx);
        return NULL;
    }
    ctx->avctx->opaque = logctx;
    ctx->avctx->time_base.num = 1;
    ctx->avctx->time_base.den = time_base;

    ctx->avctx->sample_fmt = translate_sample_fmt(fmt);
    ctx->avctx->sample_rate = info->sample_rate;
    ctx->avctx->bits_per_raw_sample = info->bits_per_sample;

#ifdef FFABI_HAVE_OLD_CHANNEL_LAYOUT
    ctx->avctx->channels = info->channels;
    ctx->avctx->channel_layout = info->channel_layout;
#else
    if (av_channel_layout_from_mask(&ctx->avctx->ch_layout, info->channel_layout)) {
        ffm_audio_encode_close(ctx);
        return NULL;
    }
    if (ctx->avctx->ch_layout.nb_channels != info->channels) {
        ffm_audio_encode_close(ctx);
        return NULL;
    }
#endif

    ctx->avctx->profile = (info->profile != FFM_PROFILE_UNKNOWN) ?
        info->profile : AV_PROFILE_UNKNOWN;

    if ((CodecFlags&FFM_CODEC_FLAG_GLOBAL_HEADER)!=0)
        ctx->avctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

    if (argp) {
        for (i=0;argp[i];i+=2) {
            av_dict_set(&opts, argp[i], argp[i+1], 0);
        }
    }

    if (avcodec_open2(ctx->avctx,ctx->codec,&opts)) {
        av_dict_free(&opts);
        ffm_audio_encode_close(ctx);
        return NULL;
    }
    av_dict_free(&opts);

    info->frame_size = ctx->avctx->frame_size;
    info->profile = ctx->avctx->profile;

    ctx->frame = av_frame_alloc();
    if (av_sample_fmt_is_planar(ctx->avctx->sample_fmt)) {
        ctx->frame_extended_data = av_calloc(info->channels,
            sizeof(*ctx->frame_extended_data));
        if (!ctx->frame_extended_data) {
            ffm_audio_encode_close(ctx);
            return NULL;
        }
    }

    if (!ctx->frame) {
        ffm_audio_encode_close(ctx);
        return NULL;
    }

    return ctx;
}

int __cdecl ffm_audio_encode_close(FFM_AudioEncodeContext* ctx)
{
    av_packet_free(&ctx->pck);
    av_frame_free(&ctx->frame);
    av_freep(&ctx->frame_extended_data);

    if (ctx->avctx) {
        avcodec_free_context(&ctx->avctx);
    }

    av_free(ctx);

    return 0;
}

static void ffm_frame_clean(AVFrame* frame)
{
    frame->extended_data = NULL;
    frame->data[0] = (uint8_t*)(((uintptr_t)0)-3);
    frame->linesize[0] = 0x7ffffff1;
    frame->nb_samples = 0x7ffffff2;
}

int __cdecl ffm_audio_encode_put_frame(FFM_AudioEncodeContext* ctx,const uint8_t* frame_data[],unsigned int frame_size,unsigned int nb_samples,uint64_t pts)
{
    int r;
    unsigned int channels;

    if (frame_data) {

        ctx->frame->format = ctx->avctx->sample_fmt;

#ifdef FFABI_HAVE_OLD_CHANNEL_LAYOUT
        channels = ctx->avctx->channels;
        ctx->frame->channels = ctx->avctx->channels;
        ctx->frame->channel_layout = ctx->avctx->channel_layout;
#else
        r = av_channel_layout_copy(&ctx->frame->ch_layout, &ctx->avctx->ch_layout);
        if (r!=0) return r;
        channels = ctx->avctx->ch_layout.nb_channels;
#endif
        ctx->frame->nb_samples = nb_samples;
        ctx->frame->pts = pts;
        ctx->frame->linesize[0] = frame_size;

        ctx->frame->data[0] = (uint8_t*)frame_data[0];

        if (av_sample_fmt_is_planar(ctx->avctx->sample_fmt)) {
            int i;

            ctx->frame->extended_data = ctx->frame_extended_data;

            ctx->frame->extended_data[0] = ctx->frame->data[0];
            for (i=1;i<channels;i++) {
                ctx->frame->extended_data[i] = (uint8_t*)frame_data[i];
                if (i<AV_NUM_DATA_POINTERS) {
                    ctx->frame->data[i] = ctx->frame->extended_data[i];
                }
            }
        } else {
            ctx->frame->extended_data = ctx->frame->data;
        }

        r = avcodec_send_frame(ctx->avctx,ctx->frame);

        ffm_frame_clean(ctx->frame);

    } else {
        if (!ctx->eos)
        {
            r = avcodec_send_frame(ctx->avctx,NULL);
            ctx->eos = 1;
        } else {
            r = 0;
        }
    }

    return r;
}

int __cdecl ffm_audio_encode_get_data(FFM_AudioEncodeContext* ctx,unsigned int *size,int64_t *pts,const uint8_t** data)
{
    int r;

    av_packet_unref(ctx->pck);

    r = avcodec_receive_packet(ctx->avctx,ctx->pck);

    if ( (r==AVERROR_EOF) || (r==AVERROR(EAGAIN)) ) {
        *data = NULL;
        return 0;
    }
    if (r!=0) return r;

    *size = ctx->pck->size;
    *pts = ctx->pck->pts;
    *data = ctx->pck->data;

    return 0;
}

int __cdecl ffm_audio_encode_get_info(FFM_AudioEncodeContext* ctx,FFM_AudioEncodeInfo* info)
{
    info->extradata = (const uint8_t*)ctx->avctx->extradata;
    info->extradata_size = ctx->avctx->extradata_size;
    info->delay = (int32_t)ctx->avctx->delay;
    info->flags = 0;

    if ((ctx->avctx->flags&AV_CODEC_FLAG_GLOBAL_HEADER)!=0)
        info->flags |= FFM_CODEC_FLAG_GLOBAL_HEADER;

    return 0;
}

/*
 * FFmpeg 7.1 (libavcodec 61.13) added avcodec_get_supported_config() and
 * deprecated the AVCodec ch_layouts, supported_samplerates and sample_fmts
 * fields; FFmpeg 8 (libavcodec 62+) removed them. With a NULL context the
 * returned arrays are the codec's static tables, so the pointers stay valid.
 */
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100)
static const void* codec_supported_config(const AVCodec* codec, enum AVCodecConfig config)
{
	const void* out = NULL;
	if (avcodec_get_supported_config(NULL, codec, config, 0, &out, NULL) < 0)
		return NULL;
	return out;
}
#define CODEC_CH_LAYOUTS(c)    ((const AVChannelLayout*)codec_supported_config((c), AV_CODEC_CONFIG_CHANNEL_LAYOUT))
#define CODEC_SAMPLE_RATES(c)  ((const int*)codec_supported_config((c), AV_CODEC_CONFIG_SAMPLE_RATE))
#define CODEC_SAMPLE_FMTS(c)   ((const enum AVSampleFormat*)codec_supported_config((c), AV_CODEC_CONFIG_SAMPLE_FORMAT))
#else
#define CODEC_CH_LAYOUTS(c)    ((c)->ch_layouts)
#define CODEC_SAMPLE_RATES(c)  ((c)->supported_samplerates)
#define CODEC_SAMPLE_FMTS(c)   ((c)->sample_fmts)
#endif

#ifndef FFABI_HAVE_OLD_CHANNEL_LAYOUT
static int set_codec_info_extended(FFM_CodecInfo* info, const AVCodec* codec)
{
    char* exinfo;
    size_t len;
    unsigned int count_ch_layouts_in = 0;
    unsigned int count_ch_layouts_out = 0;
    uint64_t*   channel_layouts;
    unsigned int i;
    const AVChannelLayout* ch_layouts = CODEC_CH_LAYOUTS(codec);

    len = strlen(codec->name);
    if (len >= FFM_CODEC_INFO_NAME_MAX_LENGTH) return -1;

    if (NULL != ch_layouts) {
        while (0 != ch_layouts[count_ch_layouts_in].nb_channels)
        {
            count_ch_layouts_in++;
        }
    }

    exinfo = (char*)ffabi_memalign(sizeof(uint64_t), (FFM_CODEC_INFO_NAME_MAX_LENGTH + FFM_CODEC_INFO_EXMARK_LENGTH + ((count_ch_layouts_in+1)*sizeof(uint64_t))));
    if (NULL == exinfo) return -1;

    memcpy(exinfo, codec->name, len + 1);
    memcpy(exinfo + FFM_CODEC_INFO_NAME_MAX_LENGTH, FFM_CODEC_INFO_EXMARK_MAGIC, FFM_CODEC_INFO_EXMARK_LENGTH);
    channel_layouts = (uint64_t*)(exinfo + FFM_CODEC_INFO_NAME_MAX_LENGTH + FFM_CODEC_INFO_EXMARK_LENGTH);

    info->name = exinfo;
    info->channel_layouts = channel_layouts;

    for (i = 0; i < count_ch_layouts_in; i++)
    {
        if (AV_CHANNEL_ORDER_NATIVE != ch_layouts[i].order) continue;
        channel_layouts[count_ch_layouts_out++] = ch_layouts[i].u.mask;
    }
    channel_layouts[count_ch_layouts_out] = 0;

    return 0;
}
#endif

int __cdecl ffm_audio_get_codec_information(FFM_CodecInfo* info, const char* name, int encode)
{
    AVCodec* codec;
    int i;

    memset(info, 0, sizeof(*info));

    if (encode) {
        codec = (AVCodec*) avcodec_find_encoder_by_name(name);
    } else {
        codec = (AVCodec*) avcodec_find_decoder_by_name(name);
    }

    if (!codec) {
        return ffmerr(1, encode);
    }

    info->name = codec->name;
    info->long_name = codec->long_name;
    info->sample_rates = CODEC_SAMPLE_RATES(codec);
#ifdef FFABI_HAVE_OLD_CHANNEL_LAYOUT
    info->channel_layouts = codec->channel_layouts;
#else
    if (NULL == CODEC_CH_LAYOUTS(codec)) {
        info->channel_layouts = NULL;
    } else {
        if (set_codec_info_extended(info, codec)) {
            return ffmerr(2, 0);
        }
    }
#endif
    info->id = codec->id;
    info->capabilities = codec->capabilities;
    if (codec->profiles) {
        for (i=0;i<32;i++) {
            if (codec->profiles[i].profile==AV_PROFILE_UNKNOWN)
                break;
            info->profiles_names[i]=codec->profiles[i].name;
            info->profiles_values[i]=codec->profiles[i].profile;
            info->profiles_count = i+1;
        }
    }
    const enum AVSampleFormat* sample_fmts = CODEC_SAMPLE_FMTS(codec);
    if (sample_fmts) {
        for (i=0;i<16;i++) {
            if (sample_fmts[i]==AV_SAMPLE_FMT_NONE)
                break;
            info->sample_formats[i]=(uint8_t)back_translate_sample_fmt(sample_fmts[i]);
            info->sample_formats_count = i+1;
        }
    }

    return 0;
}

FFM_AudioConvert* __cdecl ffm_audio_convert_alloc(FFM_AudioFormat out_fmt,FFM_AudioFormat in_fmt,int channels)
{
    return ff_ffm_audio_convert_alloc(
        translate_sample_fmt(out_fmt),
        translate_sample_fmt(in_fmt),
        channels);
}

int __cdecl ffm_mlp_read_syncframe(const uint8_t* data,unsigned int size,FFM_AudioInfo* info,uint32_t* bitrate)
{
    AVCodec*                codec;
    AVCodecParserContext*   pctx=NULL;
    AVCodecContext*         avctx=NULL;
    int                     err,outbuf_size,rest;
    uint8_t                 *outbuf;

    codec = (AVCodec*)avcodec_find_decoder(AV_CODEC_ID_MLP);
    if (!codec) {
        err=ffmerr(1,0); goto ret;
    }

    avctx = avcodec_alloc_context3(codec);
    if (!avctx) {
        err=ffmerr(2,0); goto ret;
    }

    pctx = av_parser_init(AV_CODEC_ID_MLP);
    if (!pctx) {
        err=ffmerr(3,0); goto ret;
    }

    rest = size;
    outbuf_size = 0;
    while(rest) {
        err = av_parser_parse2(pctx,avctx,&outbuf,&outbuf_size,
            data,rest,0,0,0);
        if ( (err<0) || (err>rest) ) {
            err=ffmerr(4,(unsigned int)err); goto ret;
        }
        rest -= err;
        data += err;
    }

    if (outbuf_size!=size) {
        err=ffmerr(5,outbuf_size); goto ret;
    }

    info->sample_rate = avctx->sample_rate;
    info->bits_per_sample = avctx->bits_per_raw_sample;
#ifdef FFABI_HAVE_OLD_CHANNEL_LAYOUT
    info->channels = avctx->channels;
    info->channel_layout = avctx->channel_layout;
#else
    info->channels = avctx->ch_layout.nb_channels;
    info->channel_layout = (AV_CHANNEL_ORDER_NATIVE == avctx->ch_layout.order) ? avctx->ch_layout.u.mask : 0;
#endif

    *bitrate = avctx->bit_rate;

#ifndef FFABI_HAVE_PARSER_DURATION
    info->frame_size = avctx->frame_size;
#else
    info->frame_size = pctx->duration;
#endif

    err = 0;

ret:
    if (pctx) {
        av_parser_close(pctx);
    }

    if (avctx) {
        avcodec_free_context(&avctx);
    }
    return err;
}

int __cdecl ffm_get_channel_layout_string(char *buf,int buf_size,uint64_t channel_layout)
{
#ifdef FFABI_HAVE_OLD_CHANNEL_LAYOUT
    av_get_channel_layout_string(buf,buf_size,-1,channel_layout);
#else
    AVChannelLayout ch_layout;

    if (0!=av_channel_layout_from_mask(&ch_layout,channel_layout)) return -1;
    av_channel_layout_describe(&ch_layout,buf,buf_size);
#endif
    return 0;
}