diff mbox

[FFmpeg-devel] build: Allow libffmpeg to be built for Chromium-based browsers

Message ID 20170728100716.8143-1-chewi@gentoo.org
State New
Headers show

Commit Message

James Le Cuirot July 28, 2017, 10:07 a.m. UTC
Google Chrome ships with support for proprietary codecs and Chromium
can be built with support for them, either using the bundled FFmpeg or
a system copy.

This leaves other browsers such as Opera and Vivaldi, which ship with
a libffmpeg that does not support proprietary codecs, presumably for
cost reasons. These projects actively encourage users to swap this
library with an alternative.

Official instructions say to download the very large Chromium tarball
and use its build system to configure and build libffmpeg. This
involves building a lot of extra baggage that simply isn't needed
because libffmpeg is literally just the main FFmpeg libraries
combined. Binary-based distributions can easily take this hit but for
source-based distributions, this hit is passed onto the end user.

This Makefile snippet allows libffmpeg to be created without the help
of Chromium's build system. It uses the CONFIG_SHARED variable to
decide whether to link the FFmpeg libraries statically or
dynamically. In the latter case, libffmpeg is just a wrapper with no
symbols of its own.

At this current time, recent Chromium versions support the 3.x ABI
with just one major exception. Unless built against the system copy,
-DFF_API_CONVERGENCE_DURATION=0 is used. This means that, other
factors notwithstanding, full compatibility will not be seen until
libavcodec hits 59. This is why I have provided the ability to link
FFmpeg statically.

This is how to build libffmpeg for a recent Chromium-based release:

 ./configure --disable-shared --enable-static --enable-pic --extra-cflags="-DFF_API_CONVERGENCE_DURATION=0"
 make libffmpeg
 make install-libffmpeg

I have tested this with FFmpeg 3.3.2 and latest master. I have tested
it against current Opera Stable, Opera Beta, Opera Developer, Vivaldi
Stable, and Vivaldi Snapshot.
---
 Makefile              |  1 +
 ffbuild/libffmpeg.mak | 21 +++++++++++++++++++++
 2 files changed, 22 insertions(+)
 create mode 100644 ffbuild/libffmpeg.mak

Comments

Hendrik Leppkes July 28, 2017, 10:20 p.m. UTC | #1
On Fri, Jul 28, 2017 at 12:07 PM, James Le Cuirot <chewi@gentoo.org> wrote:
> Google Chrome ships with support for proprietary codecs and Chromium
> can be built with support for them, either using the bundled FFmpeg or
> a system copy.
>
> This leaves other browsers such as Opera and Vivaldi, which ship with
> a libffmpeg that does not support proprietary codecs, presumably for
> cost reasons. These projects actively encourage users to swap this
> library with an alternative.
>
> Official instructions say to download the very large Chromium tarball
> and use its build system to configure and build libffmpeg. This
> involves building a lot of extra baggage that simply isn't needed
> because libffmpeg is literally just the main FFmpeg libraries
> combined. Binary-based distributions can easily take this hit but for
> source-based distributions, this hit is passed onto the end user.
>
> This Makefile snippet allows libffmpeg to be created without the help
> of Chromium's build system. It uses the CONFIG_SHARED variable to
> decide whether to link the FFmpeg libraries statically or
> dynamically. In the latter case, libffmpeg is just a wrapper with no
> symbols of its own.
>
> At this current time, recent Chromium versions support the 3.x ABI
> with just one major exception. Unless built against the system copy,
> -DFF_API_CONVERGENCE_DURATION=0 is used. This means that, other
> factors notwithstanding, full compatibility will not be seen until
> libavcodec hits 59. This is why I have provided the ability to link
> FFmpeg statically.
>
> This is how to build libffmpeg for a recent Chromium-based release:
>
>

I don't think ffmpeg is the right place to maintain special makefiles
for Chromium.

- Hendrik
Dominik 'Rathann' Mierzejewski July 28, 2017, 10:34 p.m. UTC | #2
On Saturday, 29 July 2017 at 00:20, Hendrik Leppkes wrote:
> On Fri, Jul 28, 2017 at 12:07 PM, James Le Cuirot <chewi@gentoo.org> wrote:
[...]
> > This Makefile snippet allows libffmpeg to be created without the help
> > of Chromium's build system. It uses the CONFIG_SHARED variable to
> > decide whether to link the FFmpeg libraries statically or
> > dynamically. In the latter case, libffmpeg is just a wrapper with no
> > symbols of its own.
[...]
> I don't think ffmpeg is the right place to maintain special makefiles
> for Chromium.

I concur. Instead, Chromium should be fixed to link against individual
FFmpeg libraries properly.

Regards,
Dominik
Ivan Kalvachev July 28, 2017, 11:05 p.m. UTC | #3
On 7/29/17, Dominik 'Rathann' Mierzejewski <dominik@greysector.net> wrote:
> On Saturday, 29 July 2017 at 00:20, Hendrik Leppkes wrote:
>> On Fri, Jul 28, 2017 at 12:07 PM, James Le Cuirot <chewi@gentoo.org>
>> wrote:
> [...]
>> > This Makefile snippet allows libffmpeg to be created without the help
>> > of Chromium's build system. It uses the CONFIG_SHARED variable to
>> > decide whether to link the FFmpeg libraries statically or
>> > dynamically. In the latter case, libffmpeg is just a wrapper with no
>> > symbols of its own.
> [...]
>> I don't think ffmpeg is the right place to maintain special makefiles
>> for Chromium.
>
> I concur. Instead, Chromium should be fixed to link against individual
> FFmpeg libraries properly.

To be honest, I do not find the combined library such a bad idea.

Actually I think that going this way has been discussed before,
long before Chromium existed.

For example, if you have to dlopen ffmpeg libs, it takes a lot of care
to load all the interlinked libraries in the correct order.
And imagine the fun if you have multiple versions installed.

Having one front-end to load all correct libraries is
logical improvement and simplification.
This is why Chromium has done it on their own.
This is why FFmpeg should do it too.


Also, the changes are isolated to a separate file in the build system,
it should not interfere with normal build process or merges.

I do however object on hardcoding "chromium" codepaths in it.

Best Regards.
Reimar Döffinger July 29, 2017, 9:17 a.m. UTC | #4
On 29.07.2017, at 01:05, Ivan Kalvachev <ikalvachev@gmail.com> wrote:

> On 7/29/17, Dominik 'Rathann' Mierzejewski <dominik@greysector.net> wrote:
>> On Saturday, 29 July 2017 at 00:20, Hendrik Leppkes wrote:
>>> On Fri, Jul 28, 2017 at 12:07 PM, James Le Cuirot <chewi@gentoo.org>
>>> wrote:
>> [...]
>>>> This Makefile snippet allows libffmpeg to be created without the help
>>>> of Chromium's build system. It uses the CONFIG_SHARED variable to
>>>> decide whether to link the FFmpeg libraries statically or
>>>> dynamically. In the latter case, libffmpeg is just a wrapper with no
>>>> symbols of its own.
>> [...]
>>> I don't think ffmpeg is the right place to maintain special makefiles
>>> for Chromium.
>> 
>> I concur. Instead, Chromium should be fixed to link against individual
>> FFmpeg libraries properly.
> 
> To be honest, I do not find the combined library such a bad idea.

I think it is, or at least this approach is.
If nothing else, it does not allow using the same libraries as the system or other programs use.
It seems to me a better approach would be to make such a libffmpeg an actual wrapper that just passes all the function calls through.

> For example, if you have to dlopen ffmpeg libs, it takes a lot of care
> to load all the interlinked libraries in the correct order.

I don't see why? The order should not matter.

> And imagine the fun if you have multiple versions installed.

Unless you mean you need to know which major versions fit together?
That seems like a valid point, but would also be solved by such a "wrapper" without needing to duplicate all the code, which also risks causing a mess if a program loads libffmpeg but also a library that loads libavcodec in turn, you couldn't predict which one actually gets used.
Also a problem for a wrapper, wouldn't want to create an endless loop of the wrapper calling itself...
Reimar Döffinger July 29, 2017, 9:20 a.m. UTC | #5
On 28.07.2017, at 12:07, James Le Cuirot <chewi@gentoo.org> wrote:
> diff --git a/ffbuild/libffmpeg.mak b/ffbuild/libffmpeg.mak
> new file mode 100644
> index 0000000..992cf3c
> --- /dev/null
> +++ b/ffbuild/libffmpeg.mak
> @@ -0,0 +1,21 @@
> +LIBFFMPEG = $(SLIBPREF)ffmpeg$(SLIBSUF)
> +LIBFFMPEG_LINK = $(LD) -shared -Wl,-soname,$(LIBFFMPEG) -Wl,-Bsymbolic -Wl,-z,now -Wl,-z,relro -Wl,-z,defs -Wl,--gc-sections $(LDFLAGS) $(LDLIBFLAGS) -o $(LIBFFMPEG)
> +
> +libffmpeg-: libavcodec/$(LIBPREF)avcodec$(LIBSUF) libavformat/$(LIBPREF)avformat$(LIBSUF) libavutil/$(LIBPREF)avutil$(LIBSUF) libswresample/$(LIBPREF)swresample$(LIBSUF)
> +    $(LIBFFMPEG_LINK) -Wl,--whole-archive $^ -Wl,--no-whole-archive $(FFEXTRALIBS)
> +
> +libffmpeg-yes: libavcodec/$(SLIBPREF)avcodec$(SLIBSUF) libavformat/$(SLIBPREF)avformat$(SLIBSUF) libavutil/$(SLIBPREF)avutil$(SLIBSUF)
> +    $(LIBFFMPEG_LINK) -Wl,--no-as-needed -lavcodec -lavformat -lavutil

I don't see you using a version file to filter out the private symbols?
That is a VERY dangerous thing to forget.
Also I don't like that it doesn't reuse the standard linking options used for the main libraries.
Nicolas George July 29, 2017, 9:40 a.m. UTC | #6
Le decadi 10 thermidor, an CCXXV, James Le Cuirot a écrit :
> This Makefile snippet allows libffmpeg to be created without the help
> of Chromium's build system. It uses the CONFIG_SHARED variable to
> decide whether to link the FFmpeg libraries statically or
> dynamically. In the latter case, libffmpeg is just a wrapper with no
> symbols of its own.

I concur with the other remarks: this is not the right approach, and it
has many flaws.

But on the other hand, I strongly support the underlying idea: having
many libraries causes no end of trouble, for users a little but for
developers mostly. See for example the proliferation of avpriv symbols
whenever code needs to be factored between libraries but too complex for
a public API.

So if you were interested in making this right: make it the default and
only library for the project, to be applied at / instead of the next
major bump, I would strongly support it, and help to the extent of my
ability.

If not, it is still something I intend to work on, but I have other more
pressing projects.

Regards,
James Le Cuirot Aug. 9, 2017, 7:34 p.m. UTC | #7
On Sat Jul 29 12:20:05 EEST 2017
Reimar Döffinger <Reimar.Doeffinger at gmx.de> wrote:

> On 28.07.2017, at 12:07, James Le Cuirot <chewi at gentoo.org> wrote:
> > diff --git a/ffbuild/libffmpeg.mak b/ffbuild/libffmpeg.mak
> > new file mode 100644
> > index 0000000..992cf3c
> > --- /dev/null
> > +++ b/ffbuild/libffmpeg.mak
> > @@ -0,0 +1,21 @@
> > +LIBFFMPEG = $(SLIBPREF)ffmpeg$(SLIBSUF)
> > +LIBFFMPEG_LINK = $(LD) -shared -Wl,-soname,$(LIBFFMPEG) -Wl,-Bsymbolic -Wl,-z,now -Wl,-z,relro -Wl,-z,defs -Wl,--gc-sections $(LDFLAGS) $(LDLIBFLAGS) -o $(LIBFFMPEG)
> > +
> > +libffmpeg-: libavcodec/$(LIBPREF)avcodec$(LIBSUF) libavformat/$(LIBPREF)avformat$(LIBSUF) libavutil/$(LIBPREF)avutil$(LIBSUF) libswresample/$(LIBPREF)swresample$(LIBSUF)
> > +    $(LIBFFMPEG_LINK) -Wl,--whole-archive $^ -Wl,--no-whole-archive $(FFEXTRALIBS)
> > +
> > +libffmpeg-yes: libavcodec/$(SLIBPREF)avcodec$(SLIBSUF) libavformat/$(SLIBPREF)avformat$(SLIBSUF) libavutil/$(SLIBPREF)avutil$(SLIBSUF)
> > +    $(LIBFFMPEG_LINK) -Wl,--no-as-needed -lavcodec -lavformat -lavutil
> 
> I don't see you using a version file to filter out the private
> symbols? That is a VERY dangerous thing to forget.
> Also I don't like that it doesn't reuse the standard linking options
> used for the main libraries.

If you mean LD_O and SHFLAGS, I didn't use them because -o $@ and
-Wl,-soname,$$(@F) were using "libffmpeg-" as the name. My Make-fu
isn't that great and I'd love to know if there is some way to do this
properly.

If you mean the additional linker flags, these are the same flags that
Chromium uses to create libffmpeg. Maybe they're not strictly required.

SHFLAGS also applies the version scripts. Chromium doesn't use one so I
didn't either. My knowledge here is sketchy so I'm not sure if it makes
any difference when this library won't be used at build time but I came
up with a new script anyway. It makes av* global, leaving everything
else local, and this seems to work. The version label doesn't matter
for this use case so I simply put LIBFFMPEG but I guess it could be
something like LIBFFMPEG_57.55.55.
James Le Cuirot Aug. 9, 2017, 9:12 p.m. UTC | #8
On Sat, 29 Jul 2017 11:40:30 +0200
Nicolas George <george@nsup.org> wrote:

> Le decadi 10 thermidor, an CCXXV, James Le Cuirot a écrit :
> > This Makefile snippet allows libffmpeg to be created without the help
> > of Chromium's build system. It uses the CONFIG_SHARED variable to
> > decide whether to link the FFmpeg libraries statically or
> > dynamically. In the latter case, libffmpeg is just a wrapper with no
> > symbols of its own.  
> 
> I concur with the other remarks: this is not the right approach, and it
> has many flaws.
> 
> But on the other hand, I strongly support the underlying idea: having
> many libraries causes no end of trouble, for users a little but for
> developers mostly. See for example the proliferation of avpriv symbols
> whenever code needs to be factored between libraries but too complex for
> a public API.
> 
> So if you were interested in making this right: make it the default and
> only library for the project, to be applied at / instead of the next
> major bump, I would strongly support it, and help to the extent of my
> ability.

I am merely an end user here so I'm afraid my interest in this only goes
as far as the Chromium use case.

I'm not sure whether it's the default but it actually can be built to
link directly against the individual libraries and this is exactly what
Gentoo's Chromium package does when the system-ffmpeg flag is enabled.

I don't know why Opera and Vivaldi build libffmpeg.so as a separate
component or why Chromium even makes this an option in the first place.
A distro may not have the same library versions available but that
doesn't stop these browsers bundling the individual libraries. Perhaps
it's to make swapping it out easier but then it's just one file instead
of three.

I wasn't too optimistic about this being accepted but the Gentoo FFmpeg
maintainer insisted that I put it forward anyway. Hopefully I can
still convince him to carry the patch, otherwise users like me will
lose out. Several others expressed interest.
diff mbox

Patch

diff --git a/Makefile b/Makefile
index 29870d7..1e267e7 100644
--- a/Makefile
+++ b/Makefile
@@ -65,6 +65,7 @@  all: all-yes
 
 include $(SRC_PATH)/tools/Makefile
 include $(SRC_PATH)/ffbuild/common.mak
+include $(SRC_PATH)/ffbuild/libffmpeg.mak
 
 FF_EXTRALIBS := $(FFEXTRALIBS)
 FF_DEP_LIBS  := $(DEP_LIBS)
diff --git a/ffbuild/libffmpeg.mak b/ffbuild/libffmpeg.mak
new file mode 100644
index 0000000..992cf3c
--- /dev/null
+++ b/ffbuild/libffmpeg.mak
@@ -0,0 +1,21 @@ 
+LIBFFMPEG = $(SLIBPREF)ffmpeg$(SLIBSUF)
+LIBFFMPEG_LINK = $(LD) -shared -Wl,-soname,$(LIBFFMPEG) -Wl,-Bsymbolic -Wl,-z,now -Wl,-z,relro -Wl,-z,defs -Wl,--gc-sections $(LDFLAGS) $(LDLIBFLAGS) -o $(LIBFFMPEG)
+
+libffmpeg-: libavcodec/$(LIBPREF)avcodec$(LIBSUF) libavformat/$(LIBPREF)avformat$(LIBSUF) libavutil/$(LIBPREF)avutil$(LIBSUF) libswresample/$(LIBPREF)swresample$(LIBSUF)
+	$(LIBFFMPEG_LINK) -Wl,--whole-archive $^ -Wl,--no-whole-archive $(FFEXTRALIBS)
+
+libffmpeg-yes: libavcodec/$(SLIBPREF)avcodec$(SLIBSUF) libavformat/$(SLIBPREF)avformat$(SLIBSUF) libavutil/$(SLIBPREF)avutil$(SLIBSUF)
+	$(LIBFFMPEG_LINK) -Wl,--no-as-needed -lavcodec -lavformat -lavutil
+
+$(LIBFFMPEG): libffmpeg-$(CONFIG_SHARED)
+libffmpeg: $(LIBFFMPEG)
+
+install-libffmpeg: $(LIBFFMPEG)
+	$(Q)mkdir -p "$(SHLIBDIR)/chromium"
+	$(INSTALL) -m 755 $< "$(SHLIBDIR)/chromium/$<"
+	$(STRIP) "$(SHLIBDIR)/chromium/$<"
+
+uninstall-libffmpeg:
+	$(RM) "$(SHLIBDIR)/chromium/$(LIBFFMPEG)"
+
+.PHONY: libffmpeg libffmpeg-* install-libffmpeg