UltraStar-Deluxe / USDX

The free and open source karaoke singing game UltraStar Deluxe, inspired by Sony SingStarâ„¢
https://usdx.eu
GNU General Public License v2.0
880 stars 162 forks source link

Compiling fails because of ffmpeg library version checks #538

Closed MrEMU closed 3 years ago

MrEMU commented 4 years ago

When i recently updated my Arch Linux, i couldn't compile the recent USDX repo. When checking the errors I noticed, that the checks for the ffmpeg libraries max versions failed. I've been wondering why there where such strict checks and when i removed them like in my forked branch everything worked just fine. Checked also with multiple micros. Why are these checks there? Should i open a PR to remove them?

Actual behaviour

Compiling fails with error messages like:

USDX/src/lib/ffmpeg-4.0/avutil.pas(81,4) Error: User defined: Linked version of libavutil is not yet supported!

Expected behaviour

Compiles without error

Steps to reproduce

  1. On a current updated Arch Linux clone the repo.
  2. cd USDX
  3. ./autogen.sh
  4. ./configure
  5. make

Details

Provide some additional information:

basisbit commented 4 years ago

those checks are there because whenever ffmpeg changes their headers, the translated headers in our project should be changed accordingly, too. Just blindly ignoring those changes will eventually result in very hard to track + analyze bugs.

s09bQ5 commented 4 years ago

In theory the version check in configure should be enough because ffmpeg nowadays follows strict rules to raise the version numbers in specific ways when ABI compatibility is broken. In practice there is a single old code line in USDX that accesses a private structure element that regularly moves around.

In FFmpeg 4.0 on x86-64 AVCodec::flush is at offset 216. In 4.3 it is at 208. If you have a fix for #259, we can think about relaxing the version requirement.

jose1711 commented 4 years ago

As a workaround for Arch Linux users downgrade to ffmpeg 2:4.2.3-2 and put to IgnorePkg.

MrEMU commented 4 years ago

Yeah I will use that workaround for now. Thanks for all your quick replies.

freddii commented 3 years ago

on: Debian testing bullseye

same issue: "Linked version of libavutil is not yet supported!"

s09bQ5 commented 3 years ago

I'm working on it.

ericbrandwein commented 3 years ago

Any advances on this?

deuteragenie commented 3 years ago

Facing the same issue on a fresh install of Ubuntu 21.04 Here are the version details of the ffmpeg libraries that are pre-installed on that OS:

ffmpeg version 4.3.2-0+deb11u1ubuntu1 Copyright (c) 2000-2021 the FFmpeg developers built with gcc 10 (Ubuntu 10.2.1-20ubuntu1) configuration: --prefix=/usr --extra-version=0+deb11u1ubuntu1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libdav1d --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librabbitmq --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-pocketsphinx --enable-libmfx --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-nvenc --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared libavutil 56. 51.100 / 56. 51.100 libavcodec 58. 91.100 / 58. 91.100 libavformat 58. 45.100 / 58. 45.100 libavdevice 58. 10.100 / 58. 10.100 libavfilter 7. 85.100 / 7. 85.100 libavresample 4. 0. 0 / 4. 0. 0 libswscale 5. 7.100 / 5. 7.100 libswresample 3. 7.100 / 3. 7.100 libpostproc 55. 7.100 / 55. 7.100

deuteragenie commented 3 years ago

Comparing the 4.2 branch of ffmpeg with the 4.3 branch, folder libavutil:

No other changes took place.

deuteragenie commented 3 years ago

Comparing the 4.3 branch of ffmpeg with the 4.4 branch, folder libavutil:

No other changes took place.

s09bQ5 commented 3 years ago

I know I promised to take care of that and I have already converted most of the 4.3 headers, but I am not yet done. We can't use the 4.0 units because we access the flush member of AVCodec, which is not part of the public API. This element has moved. There are also a few bugs in the old units. Some of them have been caused by incorrect porting of the preprocessor ifs. I will finish the work if nobody beats me to it.

In August I wrote a script to compare the offset and size of structure members as well as the values of constants between the ffmpeg units configured in USDX and the C headers. I don't remember how complete it is, but it lists three mismatches on x86-64 Linux when comparing the 4.0 units to the 4.3 headers. It checks only the structure elements and constants I found in USDX. For structures allocated by pascal code also the size and alignment are checked. checkffabi.sh.txt

And I once wrote a C++ application to create a minimal unit. It is ugly and IIRC had problems to force Free Pascal to use the correct structure alignment. Also there is ambiguity how to convert pointer arguments (keep as pointer or pass with var or out). typedump.cpp.txt

deuteragenie commented 3 years ago

Maybe I am mistaking, but I thought that USDX is compatible with ffmpeg 4.2 (not 4.0) ? Is that not the case ?

s09bQ5 commented 3 years ago

It is. The flush element did not move between 4.0 and 4.2, so the 4.0 units can be used for 4.2.

Unless the ffmpeg people make a mistake, libraries with matching major version number are compatible except for things like flush which are not part of the public API. ffmpeg libavutil libavformat libavcodec libswscale libswresample
3.4.x 55.78.100 57.83.100 57.107.100 4.8.100 2.9.100
4.0.x 56.14.100 58.12.100 58.18.100 5.1.100 3.1.100
4.1.x 56.22.100 58.20.100 58.35.100 5.3.100 3.3.100
4.2.x 56.31.100 58.29.100 58.54.100 5.5.100 3.5.100
4.3.x 56.51.100 58.45.100 58.91.100 5.7.100 3.7.100
4.4 56.70.100 58.76.100 58.134.100 5.9.100 3.9.100

We could use the same units for all ffmpeg versions where libavutil is version 56.x, libavformat is version 58.x, libavcodec is version 58.x, libswscale is version 5.x, and libswresample is version 3.x if we didn't access flush and didn't want to use features added after 4.0.

deuteragenie commented 3 years ago

mmm. Strange.

See ./src/lib/ffmpeg-4.0/avio.pas

The element "must-flush" has been removed from the structure in ffmpeg in Nov 2017 but was not removed in the pascal headers. Wonder how this is working.

See https://github.com/FFmpeg/FFmpeg/commit/ca940ed2d5ad8b0f00d289f0216bb19f115bac85#diff-a88ee2e8298a7e9a17a4f71eb29d6adefa3a255fc305cb7aa7c10be3f2733a3e

=> Maybe that explains the difference in offset you have seen (216 vs 208) ?

s09bQ5 commented 3 years ago

Yes, that's one of the errors made when support for 4.0 was added in 2018.

s09bQ5 commented 3 years ago

=> Maybe that explains the difference in offset you have seen (216 vs 208) ?

No, the reason is FFmpeg/FFmpeg@1f4cf92cfbd3accbae582ac63126ed5570ddfd37 (removes init_thread_copy).

The superfluous must_flush on x86-64 just messes up the offset of eof_reached and the following two elements write_flag and max_packet_size (not used by USDX) because of the 4 bytes padding added by the compiler to align checksum. On 32 bit platforms all elements after must_flush have a wrong offset.

Note that init_thread_copy and flush are below the comment

    /*****************************************************************
     * No fields below this line are part of the public API. They
     * may not be used outside of libavcodec and can be changed and
     * removed at will.
     * New public fields should be added right above.
     *****************************************************************
     */
deuteragenie commented 3 years ago

I wonder if using GDB (maybe https://www.gdbgui.com/) to browse the structures and offsets in the original ffmpeg libs and the USDX equivalents would not be the fastest way to uncover any discrepancy ? Or maybe pahole (https://manpages.debian.org/unstable/dwarves/pahole.1.en.html) is even better ?

s09bQ5 commented 3 years ago

Which gdb command do you have in mind? info types does not print the contents of structures. On Linux there is a tool called pahole, but it crashes on the ultrastardx binary.

deuteragenie commented 3 years ago

I am thinking of this gdb command (requires gdb 8.1+ I believe):

ptype /o struct <structname>

or alternatively use the gdbgui

s09bQ5 commented 3 years ago

ptype has problems with function pointers inside structures. It prints them as single byte value followed by a 7 byte hole.

C (FFmpeg 4.3):

(gdb) ptype /o AVCodec
type = struct AVCodec {
/*    0      |     8 */    const char *name;
/*    8      |     8 */    const char *long_name;
/*   16      |     4 */    enum AVMediaType type;
/*   20      |     4 */    enum AVCodecID id;
/*   24      |     4 */    int capabilities;
/* XXX  4-byte hole  */
/*   32      |     8 */    const AVRational *supported_framerates;
/*   40      |     8 */    const enum AVPixelFormat *pix_fmts;
/*   48      |     8 */    const int *supported_samplerates;
/*   56      |     8 */    const enum AVSampleFormat *sample_fmts;
/*   64      |     8 */    const uint64_t *channel_layouts;
/*   72      |     1 */    uint8_t max_lowres;
/* XXX  7-byte hole  */
/*   80      |     8 */    const AVClass *priv_class;
/*   88      |     8 */    const AVProfile *profiles;
/*   96      |     8 */    const char *wrapper_name;
/*  104      |     4 */    int priv_data_size;
/* XXX  4-byte hole  */
/*  112      |     8 */    struct AVCodec *next;
/*  120      |     8 */    int (*update_thread_context)(struct AVCodecContext *, const struct AVCodecContext *);
/*  128      |     8 */    const AVCodecDefault *defaults;
/*  136      |     8 */    void (*init_static_data)(struct AVCodec *);
/*  144      |     8 */    int (*init)(struct AVCodecContext *);
/*  152      |     8 */    int (*encode_sub)(struct AVCodecContext *, uint8_t *, int, const struct AVSubtitle *);
/*  160      |     8 */    int (*encode2)(struct AVCodecContext *, struct AVPacket *, const struct AVFrame *, int *);
/*  168      |     8 */    int (*decode)(struct AVCodecContext *, void *, int *, struct AVPacket *);
/*  176      |     8 */    int (*close)(struct AVCodecContext *);
/*  184      |     8 */    int (*send_frame)(struct AVCodecContext *, const struct AVFrame *);
/*  192      |     8 */    int (*receive_packet)(struct AVCodecContext *, struct AVPacket *);
/*  200      |     8 */    int (*receive_frame)(struct AVCodecContext *, struct AVFrame *);
/*  208      |     8 */    void (*flush)(struct AVCodecContext *);
/*  216      |     4 */    int caps_internal;
/* XXX  4-byte hole  */
/*  224      |     8 */    const char *bsfs;
/*  232      |     8 */    const struct AVCodecHWConfigInternal **hw_configs;
/*  240      |     8 */    const uint32_t *codec_tags;

                           /* total size (bytes):  248 */
                         }

Pascal (FFmpeg 4.0):

(gdb) ptype /o TAVCodec
type = struct TAVCODEC {
/*    0      |     8 */    PChar name;
/*    8      |     8 */    PChar long_name;
/*   16      |     4 */    TAVMediaType type_;
/*   20      |     4 */    TAVCodecID id;
/*   24      |     4 */    LongInt capabilities;
/* XXX  4-byte hole  */
/*   32      |     8 */    PAVRational supported_framerates;
/*   40      |     8 */    PAVPixelFormat pix_fmts;
/*   48      |     8 */    pcint supported_samplerates;
/*   56      |     8 */    PAVSampleFormatArray sample_fmts;
/*   64      |     8 */    pcuint64 channel_layouts;
/*   72      |     1 */    Byte max_lowres;
/* XXX  7-byte hole  */
/*   80      |     8 */    PAVClass priv_class;
/*   88      |     8 */    PAVProfile profiles;
/*   96      |     8 */    PChar wrapper_name;
/*  104      |     4 */    LongInt priv_data_size;
/* XXX  4-byte hole  */
/*  112      |     8 */    PAVCodec next;
/*  120      |     1 */    pcint init_thread_copy(PAVCodecContext);
/* XXX  7-byte hole  */
/*  128      |     1 */    LongInt update_thread_context(PAVCodecContext, PAVCodecContext);
/* XXX  7-byte hole  */
/*  136      |     8 */    Pointer defaults;
/*  144      |     1 */    void init_static_data(PAVCodec);
/* XXX  7-byte hole  */
/*  152      |     1 */    LongInt init(PAVCodecContext);
/* XXX  7-byte hole  */
/*  160      |     1 */    LongInt encode_sub(PAVCodecContext, PByteArray, LongInt, PAVSubtitle);
/* XXX  7-byte hole  */
/*  168      |     1 */    LongInt encode2(PAVCodecContext, PAVPacket, PAVFrame, pcint);
/* XXX  7-byte hole  */
/*  176      |     1 */    LongInt decode(PAVCodecContext, Pointer, LongInt, PAVPacket);
/* XXX  7-byte hole  */
/*  184      |     1 */    LongInt close(PAVCodecContext);
/* XXX  7-byte hole  */
/*  192      |     1 */    LongInt send_frame(PAVCodecContext, PAVFrame);
/* XXX  7-byte hole  */
/*  200      |     1 */    LongInt receive_packet(PAVCodecContext, PAVPacket);
/* XXX  7-byte hole  */
/*  208      |     1 */    LongInt receive_frame(PAVCodecContext, PAVFrame);
/* XXX  7-byte hole  */
/*  216      |     1 */    void flush(PAVCodecContext);
/* XXX  7-byte hole  */
--Type <RET> for more, q to quit, c to continue without paging--
/*  224      |     4 */    LongInt caps_internal;
/* XXX  4-byte hole  */
/*  232      |     8 */    PChar bsfs;
/*  240      |     8 */    PPointer hw_configs;

                           /* total size (bytes):  248 */
                         }
deuteragenie commented 3 years ago

That looks already very good to validate the total size and alignment of each offset! One can see that for this example, the problem starts at offset 120.

s09bQ5 commented 3 years ago

We need more people who test #583 to get the fix merged.

jose1711 commented 3 years ago

Arch Linux users can build the test version like this:

wget -qO- https://aur.archlinux.org/cgit/aur.git/snapshot/ultrastardx-git.tar.gz | tar xvzf -
cd ultrastardx-git
sed -i '/source=/s/USDX\.git/&#branch=ffmpeg-4.3-4.4/' PKGBUILD
makepkg -fi
jose1711 commented 3 years ago

All looking good here with this patch. Arch Linux, x86_64