FFMpeg 64bit x86_64 / amd64 on Solaris 10

By Alasdair Lumsden on 3 May 2009

I wanted to post this before I move onto my next problem, so excuse the brevity. When compiling ffmpeg on Solaris 10 for 64bit, you may encounter this particular block of errors, which come out of the assembly found inside libavcodec/cabac.h:

/var/tmp//ccC7vvHU.s:8035: Error: `-1(%ebx)' is not a valid 64 bit base/index expression
/var/tmp//ccC7vvHU.s:8038: Error: `ff_h264_norm_shift(%ecx)' is not a valid 64 bit base/index expression
/var/tmp//ccC7vvHU.s:8060: Error: `ff_h264_lps_range(%eax,%esi,2)' is not a valid 64 bit base/index expression
/var/tmp//ccC7vvHU.s:8070: Error: `ff_h264_norm_shift(%esi)' is not a valid 64 bit base/index expression
/var/tmp//ccC7vvHU.s:8072: Error: `ff_h264_mlps_state+128(%eax)' is not a valid 64 bit base/index expression
/var/tmp//ccC7vvHU.s:8084: Error: `-1(%ebx)' is not a valid 64 bit base/index expression
/var/tmp//ccC7vvHU.s:8087: Error: `ff_h264_norm_shift(%ecx)' is not a valid 64 bit base/index expression
/var/tmp//ccC7vvHU.s:8107: Error: `ff_h264_lps_range(%eax,%esi,2)' is not a valid 64 bit base/index expression
/var/tmp//ccC7vvHU.s:8117: Error: `ff_h264_norm_shift(%esi)' is not a valid 64 bit base/index expression
...
/var/tmp//ccC7vvHU.s:32827: Error: `ff_h264_norm_shift(%esi)' is not a valid 64 bit base/index expression

The issue is that FFMpeg has failed to detect “BROKEN_RELOCATIONS”. Simply set this in your config.h like so:

export CFLAGS=-m64
export LDFLAGS=-m64
./configure --prefix=/tmp/ffmpeg --arch=x86_64 --cpu=nocona --disable-encoder=nellymoser
echo '#define BROKEN_RELOCATIONS 1' >> config.h
gmake-3.81

I’ve missed a lot of detail out here, such as all the patches we use to get ffmpeg building on Solaris, but I’ll hopefully find more time tomorrow to post a blog entry about it.

Some interesting tidbits of information: FFMpeg with –enable-shared is 3 times slower, so I wouldn’t advise enabling this flag unless you absolutely need it. And the 64bit ffmpeg binary is twice as fast at transcoding wmv to flv over a 32bit one (in the basic not-very-fancy test I used). So it is worth investing time in compiling up a 64bit version.

Here’s a performance comparison going from a 32bit ffmpeg with –enable-shared and –disable-mmx on gcc 3.4, to a 64bit ffmpeg with –disable-shared and –enable-mmx on gcc 4.4:

# time /opt/ec/bin/ffmpeg -y -i ~/test2.wmv ~/test2.flv
FFmpeg version 0.5, Copyright (c) 2000-2009 Fabrice Bellard, et al.
  configuration: --prefix=/opt/ec --enable-shared --enable-nonfree --enable-gpl --enable-libamr-nb --enable-libamr-wb --enable-libdirac --enable-libfaac --enable-libfaad --enable-libmp3lame --enable-libopenjpeg --enable-libschroedinger --enable-libtheora --enable-libvorbis --enable-libx264 --enable-libxvid --disable-encoder=nellymoser --disable-mmx --enable-avfilter --disable-debug --enable-swscale --enable-postproc --enable-pthreads
  libavutil     49.15. 0 / 49.15. 0
  libavcodec    52.20. 0 / 52.20. 0
  libavformat   52.31. 0 / 52.31. 0
  libavdevice   52. 1. 0 / 52. 1. 0
  libavfilter    0. 4. 0 /  0. 4. 0
  libswscale     0. 7. 1 /  0. 7. 1
  libpostproc   51. 2. 0 / 51. 2. 0
  built on May  1 2009 14:25:24, gcc: 3.4.3 (csl-sol210-3_4-branch+sol_rpath)

Seems stream 1 codec frame rate differs from container frame rate: 1000.00 (1000/1) -> 25.00 (25/1)
Input #0, asf, from '/export/home/alasdair/test2.wmv':
  Duration: 00:11:04.65, start: 3.000000, bitrate: 172 kb/s
    Stream #0.0: Audio: wmav2, 44100 Hz, mono, s16, 32 kb/s
    Stream #0.1: Video: wmv1, yuv420p, 320x240, 180 kb/s, 25 tbr, 1k tbn, 1k tbc
Output #0, flv, to '/export/home/alasdair/test2.flv':
    Stream #0.0: Video: flv, yuv420p, 320x240, q=2-31, 200 kb/s, 90k tbn, 25 tbc
    Stream #0.1: Audio: libmp3lame, 44100 Hz, mono, s16, 64 kb/s
Stream mapping:
  Stream #0.1 -> #0.0
  Stream #0.0 -> #0.1
Press [q] to stop encoding
frame=16637 fps=263 q=12.6 Lsize=   22485kB time=665.48 bitrate= 276.8kbits/s
video:16626kB audio:5200kB global headers:0kB muxing overhead 3.016455%

real    1m3.285s
user    1m0.043s
sys     0m0.471s
# time ./ffmpeg-64 -y -i ~/test2.wmv ~/test2.flv
FFmpeg version 0.5, Copyright (c) 2000-2009 Fabrice Bellard, et al.
  configuration: --prefix=/tmp/ffmpeg --arch=x86_64 --cpu=nocona --disable-encoder=nellymoser
  libavutil     49.15. 0 / 49.15. 0
  libavcodec    52.20. 0 / 52.20. 0
  libavformat   52.31. 0 / 52.31. 0
  libavdevice   52. 1. 0 / 52. 1. 0
  built on May  3 2009 04:42:52, gcc: 4.4.0

Seems stream 1 codec frame rate differs from container frame rate: 1000.00 (1000/1) -> 25.00 (25/1)
Input #0, asf, from '/export/home/alasdair/test2.wmv':
  Duration: 00:11:04.65, start: 3.000000, bitrate: 172 kb/s
    Stream #0.0: Audio: wmav2, 44100 Hz, mono, s16, 32 kb/s
    Stream #0.1: Video: wmv1, yuv420p, 320x240, 180 kb/s, 25 tbr, 1k tbn, 1k tbc
Output #0, flv, to '/export/home/alasdair/test2.flv':
    Stream #0.0: Video: flv, yuv420p, 320x240, q=2-31, 200 kb/s, 90k tbn, 25 tbc
    Stream #0.1: Audio: adpcm_swf, 44100 Hz, mono, s16, 64 kb/s
Stream mapping:
  Stream #0.1 -> #0.0
  Stream #0.0 -> #0.1
Press [q] to stop encoding
frame=16637 fps=1799 q=12.0 Lsize=   31483kB time=665.48 bitrate= 387.6kbits/s
video:16624kB audio:14375kB global headers:0kB muxing overhead 1.561981%

real    0m9.356s
user    0m8.937s
sys     0m0.291s

The encode time has gone from 63 seconds to just 9 seconds! That’s a *huge* speed up. I’m rather impressed.

I’m also guessing that compiling all the ffmpeg dependencies as shared object .so files will have the same slowdown as ffmpeg with –enable-shared, so I’m going to try building all the dependencies as static libraries instead.

It’s now approaching 5am so I should really go off to bed, but I’m glad I finally got this knocked on the head.