[FFmpeg-devel] [RFC] avpriv cleanup

Nicolas George george at nsup.org
Sun Mar 25 23:24:31 EEST 2018


First of all, thanks for taking the time to discuss this. It has been
too long, and the arguments need to be sharpened.


James Almer (2018-03-25):
> Considering most are pretty small but not small enough to be dumped into
> a header, no, I'm not joking.
> Maybe avpriv_dnxhd_get_frame_size() should stay as is since it requires
> a huge table and duplicating it would be a waste of space, but
> avpriv_dca_convert_bitstream() seems simple enough that i don't see the
> benefits from having it like this, when it could be in both avcodec and
> avformat and weight maybe 1kb on each of them.

The weight in code size is far from being the most important criterion.
The case against code duplication is maintenance: when a bug is found,
it requires fixing in all copies of the code. You can be sure it will
not happen: only the copy where the bug was diagnosed will be fixed. The
same goes for optimizations, evolutions, etc. This in turn causes
another nightmare, when results are expected to be identical but are not
because they come from two copies of the same code that evolved
differently.

> If they used distro packages then they wouldn't have any power over what
> gets built or shipped. Distro packages are the "Enable everything" kind
> of build, so I'm of course talking about projects shipping their own
> builds of the libraries.

I have nothing to add to that. But you only answered half the question.
The other half was: do they use static or dynamic linking?

I am not sure how familiar you are with the precise workings of both
solutions, so let me summarize a bit.

With static linking, libraries are just archives or object files (*.o),
with an index of symbols. The linker will examine each archive in turn
and select the object files that contains required symbols.

With dynamic linking, the linker takes notes of all the libraries,
checks that all symbols are resolved and registers as dependencies of
the executable file.

What is remarkable about static linking is that it only takes the object
files that are necessary, nothing more. It does not matter whether there
are one library, eight or two thousands (one for each object file in the
project), the linker will take what it needs in all of that.

Therefore, these project who insist on small libraries could achieve
their goal with the simplest possible solution: they should be using
static linking. It would work automatically, because linkers have been
designed that way.

It is possible that for some reason, they need a shared library. In that
case, the best solution is to make their own: put all the functions that
use lav* together somewhere (most projects will abstract the lav* APIs
to suit their own design choices anyway), and link that statically with
FFmpeg, making a shared library perfectly tailored to the needs of the
project.

And if you think about it, you will realize that what I propose has the
consequence of making that simpler for them.

> Steam, Foobar2000, Firefox, Chromium, only four examples of projects
> where the av*.dll files they ship have long configure lines where they
> manually disable all kinds of things beyond the standard
> "--disable-everything --enable-decoder=foo" use case, including entire
> libraries and frameworks, because they only need a handful of software
> decoders.

This is true, but misleading. First of all, I would like to emphasize
that the framework code is very small compared to the code of the
components.

But most importantly, the granularity of the modules is not the correct
one. Consider an application that needs to decode from a few files. It
requires the lavc decoder framework and a few decoders, and the lavf
demuxing framework and a few demuxers. All encoders and all muxers are
disabled. Yet, it will include the encoding framework and the muxing
framework.

Now, you may say that it calls for more modularity, like you advocate
below, and you would be right. But this is missing something, see below.

> And Chromium as I said even goes the extra mile by manually striping
> libavutil of virtually everything except the core modules, something our
> build system currently doesn't support.

And with my full proposal, our build system should actually support it.

> Building a single monolithic library will force the presence of a lot of
> public symbols that currently can be avoided by simply building ffmpeg
> for one decoder and effectively require just avcodec and avutil.
> The direction we should head towards is making the libraries even more
> modular and independent, starting with libavutil.

You are entirely right here, but it is actually not really related to
the number of libraries.

Modularity has a cost: tracking the dependencies between components. If
you implement modularity with many libraries, you push that complexity
into the build system. This is a waste, since the linker already has all
the algorithms to track dependencies.

As I have explained above, static linking already achieves maximum
modularity automatically, and irregardless of whether there is one
library or many.

To achieve maximum modularity with dynamic linking, we should just try
to imitate what happens with static linking. And this is easier with a
single shared library, since we can rely on the linker to track the
dependencies.

For comparison, imagine what would be required with separate libraries.
Frequently, you will find functions that are required by both a demuxer
and a decoder. The function cannot be in lavc, since you may want to
enable only the demuxer; for the same reason the function cannot be in
lavf. But it cannot be in lavu either, because it would make it
unconditional. With that logic, you would need a separate library for
each individual avpriv function. It amounts to reinventing the job of
the linker, and as always when reinventing the wheel, it would be
square.

> Not the core framework and public API for each library. Those are
> unconditional and would remain so in a monolithic library, but with the
> added drawback that instead of only needing those from avcodec/avutil in
> a single decoder build, you'd be forced to also compile and ship those
> from avfilter/swscale/swresample/avdevice.

Whether we choose a single library or many, we can consider proposing
build options to disable even public parts of the API. We just need to
make sure to give a different SONAME to the library in that case.

In short, my proposal would be a single libffmpeg with the following
options:

- For people who do not care about size, a default enable-everything
  library is perfect.

- For people who care about size, static linking will achieve the
  optimum automatically.

- For people who care about size and for some reason need dynamic
  linking, allow disabling large parts of the libraries, which would be
  named libffmpeg-custom.so maybe, or libffmpeg-custom-$sign.so, where
  $sign is a signature (hash) of the components that are enabled.

This would achieve maximum modularity with minimum efforts.

Regards,

-- 
  Nicolas George
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: Digital signature
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20180325/a0929402/attachment.sig>


More information about the ffmpeg-devel mailing list