最近公司需要做一个flv播放器,而且只要播放声音即可。刚开始找到了Vitamio,发现用它来播放flv确实不怎么样,而且没有iOS的源码,感觉很不让人放心。于是开始了编译FFmpeg的历程。话说Github上有一键编译的各种脚本,但是难点不是编译,而是如何设定参数来满足公司的需求。要知道FFmpeg支持的编码非常之多,而我仅仅关心flv。
发现 一个FFmpeg大神,地址:
下面我来一一介绍几种一键编译方案,希望大家喜欢。
这个项目,好就好在它同时具有iOS和android的一键编译脚本。
build_ios_local.sh文件,好吧,这个文件需要我们手动复制到$HOME目录下,至于里面的内容,也很简单。配置一下路径和SDK版本,例如下面这样:
# Please make a copy for this file named 'build_ios_local.sh', and copy to $HOME
# directory, then fix out bellow configure lines to fit yourself.
## DEVELOPER & SDKVERSION setting sample,
export DEVELOPER="/Users/nuoerlz/Applications/Xcode.app/Contents/Developer"
export SDKVERSION="6.1"
记得将注释#解开。
然后,我们来继续看build_ios.sh文件,在20几行,我们发现它还引入了SSL的支持,如果我们不想支持SSL,我们可以去掉。当然,记得删除所有SSL的代码,要不然后边编译会非常麻烦。再接下来我们会看到两个比较大的函数:doConfigureOnline() 和 doConfigureAll()这两个函数,是用来配置ffmpeg 编译选项的,当然,我们可以只编译其中一个版本,至于选项的问题,请查看这篇文章->传送门 。在第205行,我们看到build_archs="arm64 x86_64 armv7 armv7s i386",它支持的版本还是比较全的。起码arm64是我们目前想要的。
另外,这个脚本还需要一个命令的支持gas-preprocessor.pl ,这个命令至关重要,而且它已经经过修改,和后面我们要用到的同名文件有一定的区别。详情请看https://raw.github.com/libav/gas-preprocessor/master/gas-preprocessor.pl 你需要将这个文件放到/usr/bin/目录下。
univslib目录里边发现合并在一起的FFmpeg.a文件。
(二)使用一键编译项目FFmpeg-iOS-build-script ->传送门
yasm 、gas-preprocessor.pl甚至会自己下载FFmpeg源代码,我们只需要等着就行了。不过它内部设定的参数有点少,如果想我一样需求明确的话,最好还是修改一二。这样编译出来的包会小很多。
使用方法:
编译所有版本:
./build-ffmpeg.sh
只编译arm64版本:
./build-ffmpeg.sh arm64
编译 armv7 and x86_64 (64-bit simulator)版本:
./build-ffmpeg.sh armv7 x86_64
合并包:
./build-ffmpeg.sh lipo
(三)使用开源的 kxmovie -> 传送门
这是一个开源的ios播放器程序,支持基本上所有类型的音频和视频,你需要做的就是把github上的代码clone下来,运行Rakefile文件,它会自动下载FFmpeg的相关文件,接下来你只需要坐等编译成功即可。
$ rake
编译完成之后,你就可以运行kxmovie.xcworkspace来看看成果了~~
编译好的ffmpeg默认只包含:armv7、armv7s、arm64、i386,如果你想继续集成 x86_64(加上它之后会非常大!) ,可以参考下面的rakefile:
require "pathname"
require "fileutils"
def system_or_exit(cmd, stdout = nil)
puts "Executing #{cmd}"
cmd += " >#{stdout}" if stdout
system(cmd) or raise "******** Build failed ********"
end
## build ffmpeg
SDK_VERSION='8.2'
MIN_IOS_VERSION='7.0'
XCODE_PATH='/Applications/Xcode.app/Contents/Developer/Platforms'
GCC_PATH='/Applications/XCode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang'
LIB_PATH='/usr/lib/system'
GASPREP_DEST_PATH='/usr/local/bin'
PLATOFRM_PATH_SIM ='/iPhoneSimulator.platform'
PLATOFRM_PATH_IOS ='/iPhoneOS.platform'
SDK_PATH_SIM="/Developer/SDKs/iPhoneSimulator#{SDK_VERSION}.sdk"
SDK_PATH_IOS="/Developer/SDKs/iPhoneOS#{SDK_VERSION}.sdk"
MY_SELF_PLATFORM_ARGS = [
'--disable-shared',
'--disable-small',
'--disable-runtime-cpudetect',
'--disable-programs',
'--enable-network',
'--disable-muxers',
'--disable-filters',
'--enable-parsers',
'--disable-parser=hevc',
'--enable-protocol=file',
'--enable-protocol=http',
'--enable-demuxer=flv',
'--enable-demuxer=mp3',
'--enable-decoder=flv',
'--enable-decoder=mp3',
'--enable-cross-compile',
]
FFMPEG_BUILD_ARGS_SIM = [
'--disable-everything',
'--assert-level=2',
'--disable-mmx',
'--arch=i386',
'--cpu=i386',
"--extra-ldflags='-arch i386 -miphoneos-version-min=#{MIN_IOS_VERSION}'",
"--extra-cflags='-arch i386 -miphoneos-version-min=#{MIN_IOS_VERSION}'",
'--disable-asm',
]
FFMPEG_BUILD_ARGS_SIM_64 = [
'--assert-level=2',
'--disable-mmx',
'--arch=x86_64',
'--cpu=x86_64',
"--extra-ldflags='-arch x86_64 -miphoneos-version-min=7.0'",
"--extra-cflags='-arch x86_64 -miphoneos-version-min=7.0'",
'--disable-asm',
]
FFMPEG_BUILD_ARGS_ARMV7 = [
'--disable-everything',
'--arch=arm',
'--cpu=cortex-a8',
'--enable-pic',
"--extra-cflags='-arch armv7 -miphoneos-version-min=#{MIN_IOS_VERSION}'",
"--extra-ldflags='-arch armv7 -miphoneos-version-min=#{MIN_IOS_VERSION}'",
"--extra-cflags='-mfpu=neon -mfloat-abi=softfp'",
'--enable-neon',
# '--disable-neon',
'--enable-optimizations',
'--disable-debug',
'--disable-armv5te',
'--disable-armv6',
'--disable-armv6t2',
'--enable-small',
]
FFMPEG_BUILD_ARGS_ARMV7S = [
'--disable-everything',
'--arch=arm',
'--cpu=cortex-a9',
'--enable-pic',
"--extra-cflags='-arch armv7s -miphoneos-version-min=#{MIN_IOS_VERSION}'",
"--extra-ldflags='-arch armv7s -miphoneos-version-min=#{MIN_IOS_VERSION}'",
"--extra-cflags='-mfpu=neon -mfloat-abi=softfp'",
'--enable-neon',
# '--disable-neon',
'--enable-optimizations',
'--disable-debug',
'--disable-armv5te',
'--disable-armv6',
'--disable-armv6t2',
'--enable-small',
]
FFMPEG_BUILD_ARGS_ARM64 = [
'--disable-everything',
'--arch=arm64',
# '--cpu=cortex-a9',
'--enable-pic',
"--extra-cflags='-arch arm64 -miphoneos-version-min=#{MIN_IOS_VERSION}'",
"--extra-ldflags='-arch arm64 -miphoneos-version-min=#{MIN_IOS_VERSION}'",
"--extra-cflags='-mfpu=neon -mfloat-abi=softfp'",
'--enable-neon',
# '--disable-neon',
'--enable-optimizations',
'--disable-debug',
'--disable-armv5te',
'--disable-armv6',
'--disable-armv6t2',
'--enable-small',
]
FFMPEG_BUILD_ARGS = [
'--disable-ffmpeg',
'--disable-ffplay',
'--disable-ffserver',
'--disable-ffprobe',
'--disable-doc',
'--disable-bzlib',
'--target-os=darwin',
'--enable-cross-compile',
#'--enable-nonfree',
# '--enable-gpl',
'--enable-version3',
]
FFMPEG_LIBS = [
'libavcodec',
'libavformat',
'libavutil',
'libswscale',
'libswresample',
]
def mkArgs(platformPath, sdkPath, platformArgs)
cc = '--cc=' + GCC_PATH
as = ""
sysroot = '--sysroot=' + XCODE_PATH + platformPath + sdkPath
# extra = '--extra-ldflags=-L' + XCODE_PATH + platformPath + sdkPath + LIB_PATH
extra = ""
args = FFMPEG_BUILD_ARGS + platformArgs + MY_SELF_PLATFORM_ARGS
args << cc
args << as
args << sysroot
args << extra
args.join(' ')
end
def moveLibs(dest)
FFMPEG_LIBS.each do |x|
FileUtils.move Pathname.new("FFmpeg/#{x}/#{x}.a"), dest
end
end
def ensureDir(path)
dest = Pathname.new path
if dest.exist?
FileUtils.rm Dir.glob("#{path}/*.a")
else
dest.mkpath
end
dest
end
def buildArch(arch)
case arch
when 'i386'
args = mkArgs(PLATOFRM_PATH_SIM, SDK_PATH_SIM, FFMPEG_BUILD_ARGS_SIM)
when 'x86_64'
args = mkArgs(PLATOFRM_PATH_SIM, SDK_PATH_SIM, FFMPEG_BUILD_ARGS_SIM_64)
when 'armv7'
args = mkArgs(PLATOFRM_PATH_IOS, SDK_PATH_IOS, FFMPEG_BUILD_ARGS_ARMV7)
when 'armv7s'
args = mkArgs(PLATOFRM_PATH_IOS, SDK_PATH_IOS, FFMPEG_BUILD_ARGS_ARMV7S)
when 'arm64'
args = mkArgs(PLATOFRM_PATH_IOS, SDK_PATH_IOS, FFMPEG_BUILD_ARGS_ARM64)
else
raise "Build failed: unknown arch: #{arch}"
end
dest = ensureDir('FFmpeg/' + arch)
system_or_exit "cd FFmpeg; ./configure #{args}"
system_or_exit "cd FFmpeg; make"
moveLibs(dest)
system_or_exit "cd FFmpeg; [ -f -.d ] && rm -- -.d; make clean"
end
def mkLipoArgs(lib)
"-create -arch armv7 armv7/#{lib}.a -arch armv7 armv7s/#{lib}.a -arch arm64 arm64/#{lib}.a -arch i386 i386/#{lib}.a -arch x86_64 x86_64/#{lib}.a -output universal/#{lib}.a"
end
desc "check gas-preprocessor.pl"
task :check_gas_preprocessor do
found = false
ENV['PATH'].split(':').each do |x|
p = Pathname.new(x) + 'gas-preprocessor.pl'
if p.exist? && p.writable?
found = true
break;
end
end
unless found
# See http://stackoverflow.com/questions/5056600/how-to-install-gas-preprocessor for more info.
puts "Installing the gas-preprocessor to #{GASPREP_DEST_PATH}"
FileUtils.move Pathname.new("gas-preprocessor/gas-preprocessor.pl"), Pathname.new(GASPREP_DEST_PATH)
system_or_exit "chmod +x #{GASPREP_DEST_PATH}/gas-preprocessor.pl"
# raise "Build failed: first install gas-preprocessor.pl.\nSee http://stackoverflow.com/questions/5056600/how-to-install-gas-preprocessor for more info."
end
end
desc "Clean ffmpeg"
task :clean_ffmpeg do
system_or_exit "cd FFmpeg; [ -f -.d ] && rm -- -.d; make clean"
end
desc "Build ffmpeg i386 libs"
task :build_ffmpeg_i386 do
buildArch('i386')
end
desc "Build ffmpeg x86_64 libs"
task :build_ffmpeg_x86_64 do
buildArch('x86_64')
end
desc "Build ffmpeg armv7 libs"
task :build_ffmpeg_armv7 do
buildArch('armv7')
end
desc "Build ffmpeg armv7s libs"
task :build_ffmpeg_armv7s do
buildArch('armv7s')
end
desc "Build ffmpeg arm64 libs"
task :build_ffmpeg_arm64 do
buildArch('arm64')
end
desc "Build ffmpeg universal libs"
task :build_ffmpeg_universal do
ensureDir('FFmpeg/universal')
FFMPEG_LIBS.each do |x|
args = mkLipoArgs(x)
system_or_exit "cd FFmpeg; xcrun -sdk iphoneos lipo #{args}"
end
dest = ensureDir('libs/FFmpeg/')
FFMPEG_LIBS.each do |x|
FileUtils.move Pathname.new("FFmpeg/universal/#{x}.a"), dest
end
end
## build libkxmovie
def cleanMovieLib(config)
buildDir = Pathname.new 'tmp/build'
system_or_exit "xcodebuild -project kxmovie.xcodeproj -target kxmovie -configuration #{config} -sdk iphoneos#{SDK_VERSION} clean SYMROOT=#{buildDir}"
system_or_exit "xcodebuild -project kxmovie.xcodeproj -target kxmovie -configuration #{config} -sdk iphonesimulator#{SDK_VERSION} clean SYMROOT=#{buildDir}"
end
desc "Clean libkxmovie-debug"
task :clean_movie_debug do
cleanMovieLib 'Debug'
end
desc "Clean libkxmovie-release"
task :clean_movie_release do
cleanMovieLib 'Release'
end
desc "Build libkxmovie-debug"
task :build_movie_debug do
buildDir = Pathname.new 'tmp/build'
system_or_exit "xcodebuild -project kxmovie.xcodeproj -target kxmovie -configuration Debug -sdk iphoneos#{SDK_VERSION} build SYMROOT=#{buildDir} -arch armv7s"
FileUtils.move Pathname.new('tmp/build/Debug-iphoneos/libkxmovie.a'), Pathname.new('tmp/build/Debug-iphoneos/libkxmovie_armv7s.a')
system_or_exit "xcodebuild -project kxmovie.xcodeproj -target kxmovie -configuration Debug -sdk iphoneos#{SDK_VERSION} build SYMROOT=#{buildDir} -arch arm64"
FileUtils.move Pathname.new('tmp/build/Debug-iphoneos/libkxmovie.a'), Pathname.new('tmp/build/Debug-iphoneos/libkxmovie_arm64.a')
system_or_exit "xcodebuild -project kxmovie.xcodeproj -target kxmovie -configuration Debug -sdk iphoneos#{SDK_VERSION} build SYMROOT=#{buildDir} -arch armv7"
system_or_exit "xcodebuild -project kxmovie.xcodeproj -target kxmovie -configuration Debug -sdk iphonesimulator#{SDK_VERSION} build SYMROOT=#{buildDir} -arch x86_64"
FileUtils.move Pathname.new('tmp/build/Debug-iphonesimulator/libkxmovie.a'), Pathname.new('tmp/build/Debug-iphonesimulator/libkxmovie_x86_64.a')
system_or_exit "xcodebuild -project kxmovie.xcodeproj -target kxmovie -configuration Debug -sdk iphonesimulator#{SDK_VERSION} build SYMROOT=#{buildDir}"
system_or_exit "lipo -create -arch armv7 tmp/build/Debug-iphoneos/libkxmovie.a -arch armv7 tmp/build/Debug-iphoneos/libkxmovie_armv7s.a -arch arm64 tmp/build/Debug-iphoneos/libkxmovie_arm64.a -arch x86_64 tmp/build/Debug-iphonesimulator/libkxmovie_x86_64.a -arch i386 tmp/build/Debug-iphonesimulator/libkxmovie.a -output tmp/build/libkxmovie.a"
end
desc "Build libkxmovie-release"
task :build_movie_release do
buildDir = Pathname.new 'tmp/build'
system_or_exit "xcodebuild -project kxmovie.xcodeproj -target kxmovie -configuration Release -sdk iphoneos#{SDK_VERSION} build SYMROOT=#{buildDir} -arch armv7s"
FileUtils.move Pathname.new('tmp/build/Release-iphoneos/libkxmovie.a'), Pathname.new('tmp/build/Release-iphoneos/libkxmovie_armv7s.a')
system_or_exit "xcodebuild -project kxmovie.xcodeproj -target kxmovie -configuration Release -sdk iphoneos#{SDK_VERSION} build SYMROOT=#{buildDir} -arch arm64"
FileUtils.move Pathname.new('tmp/build/Release-iphoneos/libkxmovie.a'), Pathname.new('tmp/build/Release-iphoneos/libkxmovie_arm64.a')
system_or_exit "xcodebuild -project kxmovie.xcodeproj -target kxmovie -configuration Release -sdk iphoneos#{SDK_VERSION} build SYMROOT=#{buildDir} -arch armv7"
system_or_exit "xcodebuild -project kxmovie.xcodeproj -target kxmovie -configuration Debug -sdk iphonesimulator#{SDK_VERSION} build SYMROOT=#{buildDir} -arch x86_64"
FileUtils.move Pathname.new('tmp/build/Debug-iphonesimulator/libkxmovie.a'), Pathname.new('tmp/build/Debug-iphonesimulator/libkxmovie_x86_64.a')
system_or_exit "xcodebuild -project kxmovie.xcodeproj -target kxmovie -configuration Debug -sdk iphonesimulator#{SDK_VERSION} build SYMROOT=#{buildDir}"
system_or_exit "lipo -create -arch armv7 tmp/build/Release-iphoneos/libkxmovie.a -arch armv7 tmp/build/Release-iphoneos/libkxmovie_armv7s.a -arch arm64 tmp/build/Release-iphoneos/libkxmovie_arm64.a -arch x86_64 tmp/build/Debug-iphonesimulator/libkxmovie_x86_64.a -arch i386 tmp/build/Debug-iphonesimulator/libkxmovie.a -output tmp/build/libkxmovie.a"
#FileUtils.copy Pathname.new('tmp/build/Release-iphoneos/libkxmovie.a'), buildDir
end
desc "Copy to output folder"
task :copy_movie do
dest = ensureDir 'output'
FileUtils.move Pathname.new('tmp/build/libkxmovie.a'), dest
FileUtils.copy Pathname.new('libs/FFmpeg/libavcodec.a'), dest
FileUtils.copy Pathname.new('libs/FFmpeg/libavformat.a'), dest
FileUtils.copy Pathname.new('libs/FFmpeg/libavutil.a'), dest
FileUtils.copy Pathname.new('libs/FFmpeg/libswscale.a'), dest
FileUtils.copy Pathname.new('libs/FFmpeg/libswresample.a'), dest
FileUtils.copy Pathname.new('kxmovie/KxMovieViewController.h'), dest
FileUtils.copy Pathname.new('kxmovie/KxAudioManager.h'), dest
FileUtils.copy Pathname.new('kxmovie/KxMovieDecoder.h'), dest
FileUtils.copy_entry Pathname.new('kxmovie/kxmovie.bundle'), dest + 'kxmovie.bundle'
end
##
task :clean => [:clean_movie_debug, :clean_movie_release, :clean_ffmpeg]
task :build_ffmpeg => [:check_gas_preprocessor, :build_ffmpeg_armv7, :build_ffmpeg_armv7s, :build_ffmpeg_arm64, :build_ffmpeg_i386, :build_ffmpeg_x86_64, :build_ffmpeg_universal]
#task :build_movie => [:build_movie_debug, :copy_movie]
task :build_movie => [:build_movie_release, :copy_movie]
task :build_all => [:build_ffmpeg, :build_movie]
# task :default => [:build_all]
task :default => [:build_ffmpeg]
此文件添加了 MY_SELF_PLATFORM_ARGS编译选项,仅仅支持播放flv和mp3文件(项目需要),因此可以大大缩小编译后的文件大小。此外还定义了
MIN_IOS_VERSION = ‘7.0’
另外,将ffmpeg运用在你自己的工程里边的话,处理好头文件路径是非常重要和关键的步骤,切记!
最近公司需要做一个flv播放器,而且只要播放声音即可。刚开始找到了Vitamio,发现用它来播放flv确实不怎么样,而且没有iOS的源码,感觉很不让人放心。于是开始了编译FFmpeg的历程。话说Github上有一键编译的各种脚本,但是难点不是编译,而是如何设定参数来满足公司的需求。要知道FFmpeg支持的编码非常之多,而我仅仅关心flv。