summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/ffmpeg/README.chromium
blob: 9ddeab21b594de89c080cf55e05525c9aafb72ef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
Name: ffmpeg
URL: http://ffmpeg.org/
License: LGPL 2.1
License File: LICENSE
Upstream Git: git://source.ffmpeg.org/ffmpeg.git
Last Upstream Merge: 100184ccffbf8a25098a943b71b1cd2e599de2ec, Apr 24 2013

This file documents the layout of the Chromium copy of FFmpeg git, some common
tasks, how to produce the FFmpeg include directory, and how to create the
ffmpeg.gyp file and related configurations.

FFmpeg Git Layout:
==================

Chromium's copy of FFmpeg is a fork of the upstream git repository, see the tags
above for up-to-date cut information.  All of the chromium specific bits, minus
the gyp files, are located under the chromium/ folder off the root.

    ffmpeg.gyp: See the section on ffmpeg.gyp below.

    ffmpeg_generated.gypi: Pregenerated gyp listing of files necessary to build
      every platform.  See chromium/scripts/generate_gyp.py for more details.

    chromium/binaries/c99conv.exe: Prebuilt binary for converting FFmpeg sources
      from C99 to C89 for compilation with Visual C++.

    chromium/scripts: Utilities for building the gyp and config files.

    chromium/config/...: Pregenerated FFmpeg config options for each platform
      and architecture; e.g., ChromeOS: ARM-Neon, Linux: X64, etc.

    chromium/patches/...: Chromium specific changes which haven't yet made it
      upstream.  See chromium/patches/README for more details on each patch.

      Historically, the .patch files were staged on top of a source tarball
      instead of the Git repository we have now.  The .patch files are kept for
      tracking purposes.  The new system only requires that you add an entry to
      the README file with a link to the tracking issue and code review.

Help w/ Common Tasks:
=====================

-- Submitting changes to Chromium's FFmpeg git repository.

The goal of Chromium's FFmpeg repository is to just be a mirror of the upstream
Git repository.  Which means every change made must be upstreamed.  If you make
a change, please add an entry to chromium/patches/README with a link to the
tracking issue and code review for your change.

Unfortunately the normal Chromium CL submission process through Rietveld does
not work with Git DEPS like FFmpeg, so you must use Gerrit to upload your change
for review:

  git push ssh://gerrit.chromium.org:29418/chromium/third_party/ffmpeg \
  HEAD:refs/for/master

Note: You'll need a Gerrit account, see:

  http://www.chromium.org/chromium-os/developer-guide/gerrit-guide

If your change adds new files to the repository, you'll need to regenerate the
GYP defines by following the directions in chromium/scripts/generate_gyp.py.

After all that's done and your change has landed in the Git repository, you'll
need to export it to the Subversion repository.  See the next help entry.

-- Exporting the Git repository to Subversion.

Sadly, as of this writing (Oct 2012) Chromium does not support building from Git
repos.  The builders rely on an export of the Git repo to SVN for builds.  A
DEPS entry controls which revision the builders are currently using.

The steps for doing this are:

  cd <some path outside of ffmpeg Git>
  svn co svn://svn.chromium.org/chrome/trunk/deps/third_party/ffmpeg
  <path to ffmpeg Git>/chromium/scripts/sync_svn.py <Git path> <SVN path>
  cd <svn repo>
  svn commit -m "<Some happy message about updating FFmpeg SVN.>"

You'll need to roll DEPS once your SVN changes are committed.

-- Performing an upstream merge.

The upstream merge process follows the normal Git merge process:
  # First, modify the origin url to enable push of merge result later.
  # e.g., change remote.origin.url from:
  #  https://chromium.googlesource.com/chromium/third_party/ffmpeg.git
  # to:
  #  ssh://gerrit.chromium.org:29418/chromium/third_party/ffmpeg.git
  # One way is to use custom_deps in .gclient.  Another might be to run
  # git config -e within this folder and edit the URLs if already synced,
  # though this alternative could have danger.

  git remote add upstream git://source.ffmpeg.org/ffmpeg.git
  git fetch upstream
  git merge upstream/master

  # If conflicts:
  git mergetool

  <Except for a different push method, follow rest of "Submitting changes to
  Chromium's FFmpeg git repository.">

  # Use git push for submission so commit history is kept.  Might require merge
  # approval on your Gerrit account.  Do not commit any other way.
  git push origin master

  <Follow the steps under "Exporting the Git repository to Subversion."

-- Upstreaming a patch.

  <checkout copy of upstream repo>
  git checkout <hash of last Chromium FFmpeg, see tag above> -b my_patch
  git apply <patch. pulled from code review or cherry-picked from this repo>
  git rebase origin/master
  < Follow FFmpeg guide: http://ffmpeg.org/developer.html#Submitting-patches-1 >

Once your change has been upstreamed, please update the chromium/patches/README
file with the status.  The next time an upstream merge is done, the committer
will clear out all the patches which have been upstreamed.

-- Cherry-picking a patch from upstream.

  # Tell our repo about the upstream one.
  git remote add upstream git://source.ffmpeg.org/ffmpeg.git
  git fetch upstream

  # Create a new branch based off of master for committing our patch.
  git checkout master -b my_new_branch

  # Pull the patch out of upstream.
  git cherry-pick <hash of commit in upstream>

  <Follow rest of "Submitting changes to Chromium's FFmpeg git repository.">

Building:
=========

-- FFmpeg headers in the 'chromium/include' directory.

The include directory contains FFmpeg's public header files from the output of
a "make install" command.  The header files are from Chromium's copy of FFmpeg.

Steps to reproduce:
  1) If on Windows, refer to our MinGW/MSYS environment setup:
       http://src.chromium.org/viewvc/chrome/trunk/deps/third_party/mingw/
  2) Chromium's copy of FFmpeg, should already have it if you're reading this.
  3) Follow the instructions to build and install.
  4) Go to your install location and copy the following into the Chromium tree:
       /path/to/install/include/libavcodec
       /path/to/install/include/libavformat
       /path/to/install/include/libavutil

On Windows, the libraries are linked in using /DELAYLOAD to avoid having the
DLLs present at run-time.  On POSIX systems, dlopen() is used to achieve a
similar effect.

We don't use the import libraries generated from building FFmpeg because they
export every method by ordinal, which makes binary compatibility with different
builds of FFmpeg difficult if not impossible.  Furthermore, it is much easier
to update a DEF file instead of rebuilding FFmpeg to generate new import
libraries.


-- Recreating the ffmpeg.gyp file and populating the config directory.
The ffmpeg.gyp file is meant to be used in place of FFmpeg's

   ./configure && make

steps.  The file was created by inspecting the build log from above.
The FFmpeg build is relatively straightforward.  All files are built with
the same CFLAGS.  The config.h and version.h files are the only files generated
by ./configure that are included elsewhere.  They require a small bit of
post-processing.

Other than the configure step, FFmpeg just compiles its .c files, assembles a
few more using yasm, and that's it.  Exact instructions for reproducing
ffmpeg.gyp are in the "Detailed Directions" section.

Here is a list of gotchas that have shown up.
  1) FFmpeg requires special configure (--disable-optimizations) in order
     to be built with -O0 successfully due to some of the hand-written
     assembler using ebp.  -O0 implies -fno-omit-frame-pointer which breaks
     this. This will produce compiler errors like:
       libavcodec/cabac.h:527: error: can't find a register in class
       'GENERAL_REGS' while reloading 'asm'
       cabac.h:527: error: 'asm' operand has impossible constraints

  2) Sometimes, with -O0, invalid code will be exposed because dead-branch
     pruning is disabled in gcc.  This can manifest itself as strange link
     issues or compile issues.  Be careful to read all warnings in this case.

  3) Since config.h is generated via ./configure, the generated file will
     be sensitive to the configuration of the machine it was produced on.
     In particular, yasm does not seem to always be detected if
     cross-compiling for 32-bit on a 64-bit machine. Since yasm is built in
     tree, make sure to force things with --enable-yasm.

  4) yasm needs to be installed on mac and windows if not already there.

  5) Similar to issue #3, ./configure may detect the presence of SDL and
     adjust config.h accordingly. This is harmless because all the SDL
     related code has been disabled in our configuration.

  6) On Mac ia32, we want to be able to compile WITHOUT -fomit-frame-pointer
     (so breakpad can function).  To do this, we need to disable the use of the
     EBP register, otherwise some of FFmpeg's inline assembly will cause
     compilation errors similar to gotcha #1.  For more details, see the file
     comment in the munge_config_optimizations.sh. This script will fix up
     the generated config.h to be building without -fomit-frame-pointer.

  7) On Windows, FFmpeg must first be run through a preprocessor to be compiled
     via MSVC++ because it doesn't support the C99 syntax used by FFmpeg.  The
     converter is open source and built on libclang.  The c99conv.exe in the
     chromium/scripts directory is a statically linked version of the converter
     from: https://github.com/rbultje/c99-to-c89 . Compiling the dynamic linked
     library is relatively easy, generating a statically linked one is not.  To
     build the dynamic version you first need libclang:

       git clone http://llvm.org/git/llvm.git
       cd tools; git clone http://llvm.org/git/clang.git

     Now you need to run cmake, see http://llvm.org/docs/GettingStartedVS.html,
     step #5.  From there you can start the Visual Studio IDE with the .vcproj
     or .sln files generated by cmake.  Then select "Release" from the build
     drop down menu.  You're ready to build.  Right click on the libclang target
     and select build.  Once complete you should have a libclang.dll in
     <llvm root>\out\bin\Release.  Now you can build the c99-to-c89 converter
     using the packed makefile.  If you're building the dynamic version you'll
     need to ensure c99conv.exe and libclang.dll remain in the same directory.

     Note: Building the statically linked version is painful and requires
     changes to both the llvm project and the converter.  Proceed at your own
     risk.  First, you need to modify the libclang project and change every
     target's "Project Defaults" from "Dynamic Library .DLL" to "Static Library
     (.lib)" and under "Code Generation" change every targets "Runtime Library"
     from "Multi-threaded DLL (/MD)" to "Multi-threaded (/MT)" then rebuild the
     libclang project.  Afterward, you will have a lot of lib files in <llvm
     root>\out\lib\Release and will need to specify all of them under LIBS in
     the c99-to-c89 makefile as well as Advapi32.lib and Shell32.lib.  Before
     compiling c99conv.exe you will need to modify libclang a bit, open
     "tools\clang\include\clang-c\Platform.h" and remove the
     "__declspec(dllimport)" entry.  You can now compile as normal and will only
     need to package the c99conv.exe.

     It's not necessary to build the statically linked version, but it's nice to
     only have a single binary checked in.

  8) On various platforms, ffmpeg configure may detect external iconv library
     and include it by default.  FFmpeg used by chromium does not depend on this
     library, and the lib may not exist on target despite existing in the build
     environment.  Hence, we need to change CONFIG_ICONV to 0 in the config.h
     (and config.asm where appropriate.)  build_ffmpeg.sh does this with
     configure parameter --disable-iconv.  See http://crbug.com/223295


Short Directions:
=================
  1) Create config.h and config.asm as needed.
     On Linux run
       ./chromium/scripts/build_ffmpeg.sh linux ia32 <absolute path to .>
       ./chromium/scripts/build_ffmpeg.sh linux x64 <absolute path to .>

     On Linux with MIPS cross-toolchain in $PATH
       ./chromium/scripts/build_ffmpeg.sh linux mipsel <absolute path to .>

     On Linux chroot run
       ./chromium/scripts/build_ffmpeg.sh linux arm <absolute path to .>
       ./chromium/scripts/build_ffmpeg.sh linux arm-neon <absolute path to .>

     On Mac run
       ./chromium/scripts/build_ffmpeg.sh mac ia32 <absolute path to .>
       ./chromium/scripts/build_ffmpeg.sh mac x64 <absolute path to .>

     On Windows run
       ./chromium/scripts/build_ffmpeg.sh win ia32 <absolute path to .>
       ./chromium/scripts/build_ffmpeg.sh win x64 <absolute path to .>
       ./chromium/scripts/build_ffmpeg.sh win-vs2013 ia32 <absolute path to .>
       ./chromium/scripts/build_ffmpeg.sh win-vs2013 x64 <absolute path to .>

  2) Finally, collect all these directories and copy all config files
     into the source tree using

       ./chromium/scripts/copy_config.sh

Detailed Directions:
====================
  1) Run the configure in a directory out of the tree with the arguments you
     want.  To see what was used before, find the config.h for the platform
     of interest in:

       src/third_party/ffmpeg/source/config/[branding]/[platform]/[variant]

     The value of the FFMPEG_CONFIGURATION macro should have the configure
     commandline that generated the file.

     Note that if you are trying to build a 32-bit FFmpeg for linux on a
     64-bit box, the extra flags you want to pass to ./configure are

       --arch=i686 --extra-cflags=-m32 --extra-ldflags=-m32

     Also, as noted in gotcha #4, explicitly setting --enable-yasm is
     a good idea. (These flags have been added to build_ffmpeg.sh.)

  2) Copy the newly generated config.h and version.h into the correct platform
     location:

       src/third_party/ffmpeg/chromium/config/[branding]/[platform]/[variant]

     Make sure to double-check that config.h and version.h are the only files
     of interest.  By that, I mean check that the other generated files are
     makefiles, documentation, .pc files, or something else that is not
     relevant to our build.

     TODO(ajwong): Check if we can modify version.h to tag our builds.

  3) If on ia32, handle gotcha #6 by munging the geneated config.h file to
     disable use of EBP.  Call the munge_config_optimizations.sh script on
     the config.h for each ia32 variant. (This has been implemented in
     build_ffmpeg.sh.)

     ** This script is not idempotent. Don't run it twice **

     Remember, this is only necessary for ia32 config.h files.  Running this
     on config.h files for other platforms (in particular, for x64) will
     likely result in unecessarily slow code, or compile failures.

  4) Handle gotcha #8 by using --disable-iconv configure option.
     This is implemented in build_ffmpeg.sh.

  5) Next, capture all the output from a build of libavcodec.so and
     libavformat.so.  We will use the build log as a reference for making
     the ffmpeg.gyp file.

       make libavcodec/libavcodec.so libavformat/libavformat.so \
          > ffmpeg_build_log 2> ffmpeg_build_err

     For Mac, replace the ".so" in the files above with ".dylib".

     To get detailed output you might have to comment in common.mak

       #$(foreach VAR,$(BRIEF), \
       #    $(eval override $(VAR) = $($(VAR))))

  6) Check ffmpeg_build_err to see if there are any significant
     anomalies.  FFmpeg source generates a lot of compiler warnings; it
     is safe to ignore those.

  7) Examine all non-gcc commands to see if we're missing anything
     interesting:

       grep -v '^gcc' ffmpeg_build_log

     There should be yasm commands for assembling two yasm files, but nothing
     else.  Include those yasm files in the sources list for gyp.  That means

       grep -v '^gcc\|^yasm'

     should generate nothing beyond "cd" and "ln" commands.

  8) Verify that the all the gcc commands have the same compiler flags.
     Do that with the following "one-liner":

       grep - '^gcc' ffmpeg_build_log |
       grep -v ' -MM ' |
       grep -v ' -shared ' |
       sed -e 's/ -MF .*$//' |
       sort | uniq -c

     This should find all gcc commands, exclude the dependency generation
     lines, the link lines, and strip the output/input file names leaving
     just the compiler flags + invocation.  You should only see one "line"
     of output.  If there is more than one, figure out if the differences
     in compiler flags are significant, and then use your best judgment.

  9) Examine the output from step 7 and update the compiler flags in
     ffmpeg.gyp. For easier cut/paste, append the following to the previous
     command line to isolate each flag on its own line and add
     single-quotes:

       tr -s ' ' | tr ' ' '\n' | sed -e "s/\(.*\)/'\1',/" | sort -u

 10) Next, examine the link flags to see if anything interesting appears.

        grep ' -shared ' ffmpeg_build_log  |
        tr ' ' '\n' |
        grep -Ev '^[^-].*' |
        grep -v rpath |
        grep -Ev '^-L' |
        sort -u

     This should find all link lines, move each flag to its own line,
     remove any argument that isn't a flag, remove all the rpaths (not
     useful for us anyways), and remove all the -L lines (also not useful
     for us).

     The most interesting will likely be the -Wl,.* lines. Update the
     ldflags section in ffmpeg.gyp accordingly.

 11) Lastly, Find all the build .c files and update the sources line (this is
     very similar to step 7):

       grep -E '^gcc' ffmpeg_build_log |
       grep -v ' -MM ' |
       grep -v ' -shared ' |
       sed -e "s|.* -o .* \(.*\)$|'source/patched-ffmpeg/\1',|" |
       sort

 12) Attempt to build. :)

*13) Update the the sources! clause to exclude files that should only be built
     for Chromium.  For this, you basically need to do the steps above once
     with the configure options for Chrome, then once with the options for
     Chromium and diff the list of .c and .asm source files.