building ffmpeg on Windows (2 of n)

by jbohl 15. May 2013 14:20

In the last post we built an ffmpeg-binary using the cygwin-gcc-compiler. One of the drawbacks is that it is dependent on a cygwin-environment - it relies on the cygwin-DLLs and can work only inside a complete cygwin-installation. 

The binary cannot deal with traditional Windows-filenames - it will use the translation into "cygwin"-paths. On the one hand, this is an advantage - inside the cygwin-environment everything works smooth.

So, next we will build ffmpeg with the mingw-gcc-compiler. This will give us a binary which will work outside of the cygwin-environment.

The mingw-gcc-compiler is available as a cygwin-package, and we could probably go that way - however, I chose a different approach. We use Zeranoe's mingw-build-script in order to download and build the mingw-gcc-compiler ourselves. This script should do it in one sweep:

#!/bin/bash

ROOTDIR="`pwd`"

getmingwscript() {
cat <<EOF
Now downloading the mingw-installer script from http://www.zeranoe.com.
After the download has completed, the script will be executed.
EOF
zeranoe_url="http://www.zeranoe.com/scripts/mingw_w64_build"
scriptname="mingw-w64-build-3.2.3"
if [ -f $scriptname ];
then
	rm $scriptname
fi
wget $zeranoe_url/$scriptname
mkdir mingw

# for whatever reasons, the svn-checkout sometimes fails (most of the time on a slow machine) -> just run an update in case of failure
sed 's/svn checkout http:\/\/mingw-w64.svn.sourceforge.net\/svnroot\/mingw-w64\/trunk || exit 1/svn checkout http:\/\/mingw-w64.svn.sourceforge.net\/svnroot\/mingw-w64\/trunk || svn update trunk\/ || exit 1/' <$scriptname >mingw/$scriptname 
rm $scriptname

cd mingw
chmod +x ./$scriptname
./$scriptname --build-type=win32 --cpu-count="$(grep -c processor /proc/cpuinfo)" --default-configure
cd ..
}

getffmpeg() {
cd source
git clone git://source.ffmpeg.org/ffmpeg.git ffmpeg
cd ..
}

cleanmingw() {
rm -rf $ROOTDIR/mingw
}

cleansource() {
rm -rf $ROOTDIR/source
}

cleansoftware() {
rm -rf $ROOTDIR/software
}

makesoftwarefolders() {
[ -d $ROOTDIR/software ] || mkdir $ROOTDIR/software
[ -d $ROOTDIR/software/packages ] || mkdir $ROOTDIR/software/packages
[ -d $ROOTDIR/software/packages/win32 ] || mkdir $ROOTDIR/software/packages/win32
[ -d $ROOTDIR/software/packages/win32/lib ] || mkdir $ROOTDIR/software/packages/win32/lib
[ -d $ROOTDIR/software/packages/win32/pkgconfig ] || mkdir $ROOTDIR/software/packages/win32/lib/pkgconfig
[ -d $ROOTDIR/software/packages/win32/include ] || mkdir $ROOTDIR/software/packages/win32/include
}

buildffmpeg() {
cd source/ffmpeg
[ -f config.mak ] && make distclean
export PKG_CONFIG_PATH="$ROOTDIR/software/packages/win32/lib/pkgconfig" 
export LDFLAGS="-L$ROOTDIR/software/packages/win32/lib" 
export CFLAGS="-I$ROOTDIR/software/packages/win32/include"
./configure  --prefix="$ROOTDIR/software/packages/win32" --enable-memalign-hack --arch=x86 --target-os=mingw32 --cross-prefix=i686-w64-mingw32- --enable-gpl --enable-nonfree 
make
make install
}

yes_no_sel () {
unset user_input
question="$1"
shift
while [[ "$user_input" != [YyNn] ]]; do
    echo -n "$question"
    read user_input
    if [[ "$user_input" != [YyNn] ]]; then
        echo "Your selection was not vaild, please try again."; echo ""
    fi
done
}

yes_no_sel "Would you like to start from scratch (download and build mingw)? [y/n]: "
if [[ "$user_input" = [Yy] ]]; then
    cleanmingw
    getmingwscript
fi

cleansource
cleansoftware
[ -d source ] || mkdir source

getffmpeg

export PATH="$PATH:$ROOTDIR/mingw/mingw-w64-i686/bin"

makesoftwarefolders

buildffmpeg

You have to place this script into some folder (and name it e.g. buildffmpeg.sh), then run it. It will ask you whether you want to download and build mingw from scratch - the first time you run it, you will have to say "y[es]", when running it a second time you may choose to skip this step (and use the already existing mingw-gcc-compiler).

After the script has finished its job (without errors I assume...) you should find three new folders: mingw (the sources and the binaries for the mingw-gcc-compiler), source (the ffmpeg-sources) and software (the results from the ffmpeg-build). The ffmpeg-binary is to be found at ...\software\packages\win32\bin.

OK, now the harder part is to run this binary through the FATE-test-suite - the problem is that binary is now expecting Windows-filenames, and FATE (being a Unix-script) is passing Unix-filenames to the executable. We might be able to get away by arranging our directory-layout in a way that Windows- and Unix-syntax come out to the same result, but there is another way: FATE allows to specify a wrapper ('TARGET_EXEC') which is used to run the tests, and we can use this wrapper to convert the paths passed to the executable. This script will do the trick:

#! /bin/sh
 
 function tweakcygwinpath()
 {
	local tweaked
	if [[ $1 == *./tests/data/lavf/lavf.gxf ]];
	then
		echo "./tests/data/lavf/lavf.gxf"
	else
		if [[ $1 == *./tests/data/lavf/lavf.mkv ]];
		then
			echo "./tests/data/lavf/lavf.mkv"
		else
			if [[ $1 == */tests/vsynth1/00.pgm ]];
			then
				echo "./tests/vsynth1/00.pgm"
			else
				tweaked="$(cygpath -w $1)"
				echo "$tweaked"
			fi
		fi
	fi
 }
 
 cmd=$1
 
 declare -a argstweaked
 
 shift 1
 index=0
 for ARG in "$@"
 do
    if [[ $ARG == /cygdrive/* || $ARG == /home/* ]];
	then
		argstweaked[$index]=$(tweakcygwinpath $ARG)
	else
		if [[ $ARG == amovie=*/amrwb/seed-12k65.awb,silencedetect=d=-20dB ]];
		then
			filename=`echo "$ARG" | sed -E 's/amovie=(.*),.*|.*/\1/'`
			if [ ! -d "./temp" ]; then
				mkdir ./temp
			fi
			cp "$filename" ./temp/
			argstweaked[$index]="amovie=./temp/seed-12k65.awb,silencedetect=d=-20dB"
		else
			if [[ $ARG == amovie=*/filter/seq-3341-7_seq-3342-5-24bit.flac,ebur128=metadata=1 ]];
			then
				filename=`echo "$ARG" | sed -E 's/amovie=(.*),.*|.*/\1/'`
				if [ ! -d "./temp" ]; then
					mkdir ./temp
				fi	
				cp "$filename" ./temp/
				argstweaked[$index]="amovie=./temp/seq-3341-7_seq-3342-5-24bit.flac,ebur128=metadata=1"
			else
				argstweaked[$index]=$ARG
			fi
		fi
	fi
	
	((index++))
done

$cmd "${argstweaked[@]}"

So now we can run FATE with this command

make  TARGET_EXEC=./tweakpaths.sh fate SAMPLES=/cygdrive/z/fate-suite/

assuming we have placed the above script in a file "tweakpaths.sh" and the FATE-samples are available at /cygdrive/z/fate-suite.

Some comments on the script: lines 37-53 deal with the FATE-tests "filter-metadata-silencedetect" and "filter-metadata-ebur128". The problem is that a path appears in an argument (for a filtergraph iirc), and the parser cannot handle a Windows-path (this is something to look into...). The desperate workaround is to copy the file, so that it can be accessed using a relative path. TODO: we should delete the copied files afterwards.

Tags:

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading

About the author

Living in Munich, the author is making his living as a software developer and is trying to make his way through the digital revolution.

Month List