Using FFMPEG to reliably convert videos to mp4 for iphone/ipod and flash players
I need to convert videos for use in both a flash player and the iphone/ipod touch. I'm using the following batch script with ffmpeg:
@echo off
ffmpeg.exe -i %1 -s qvga -acodec libfaac -ar 22050 -ab 128k -vcodec libx264 -threads 0 -f ipod %2
This always outputs an mp4 file, and I can always play it on my PC. The videos also seem to play fine on my iphone 3GS. But with some input files it won't work for older iphone versions (3G and iPod touch).
Here's the ffmpeg output from one such file:
D:\ffmpeg>encode.bat d:\temp\recording.flv d:\temp\out.m4v
FFmpeg version SVN-r18709, Copyright (c) 2000-2009 Fabrice Bellard, et al.
configuration: --enable-memalign-hack --prefix=/mingw --cross-prefix=i686-ming
w32- --cc=ccache-i686-mingw32-gcc --target-os=mingw32 --arch=i686 --cpu=i686 --e
nable-avisynth --enable-gpl --enable-zlib --enable-bzlib --enable-libgsm --enabl
e-libfaac --enable-libfaad --enable-pthreads --enable-libvorbis --enable-libtheo
ra --enable-libspeex --enable-libmp3lame --enable-libopenjpeg --enable-libxvid -
-enable-libschroedinger --enable-libx264
libavutil 50. 3. 0 / 50. 3. 0
libavcodec 52.27. 0 / 52.27. 0
libavformat 52.32. 0 / 52.32. 0
libavdevice 52. 2. 0 / 52. 2. 0
libswscale 0. 7. 1 / 0. 7. 1
built on Apr 28 2009 04:04:42, gcc: 4.2.4
[flv @ 0x187d650]skipping flv packet: type 18, size 164, flags 0
Input #0, flv, from 'd:\temp\recording.flv':
Duration: 00:00:07.17, start: 0.001000, bitrate: N/A
Stream #0.0: Video: flv, yuv420p, 320x240, 1k tbr, 1k tbn, 1k tbc
Stream #0.1: Audio: nellymoser, 44100 Hz, mono, s16
[libx264 @ 0x13518b0]using cpu capabilities: MMX2 SSE2Fast SSSE3 FastShuffle SSE
4.2
[libx264 @ 0x13518b0]profile Baseline, level 4.2
Output #0, ipod, to 'd:\temp\out.m4v':
Stream #0.0: Video: libx264, yuv420p, 320x240, q=2-31, 200 kb/s, 1k tbn, 1k
tbc
Stream #0.1: Audio: libfaac, 22050 Hz, mono, s16, 128 kb/s
Stream mapping:
Stream #0.0 -> #0.0
Stream #0.1 开发者_Python百科-> #0.1
Press [q] to stop encoding
frame= 90 fps= 0 q=-1.0 Lsize= 128kB time=6.87 bitrate= 152.4kbits/s
video:92kB audio:32kB global headers:1kB muxing overhead 2.620892%
[libx264 @ 0x13518b0]slice I:8 Avg QP:29.62 size: 7047
[libx264 @ 0x13518b0]slice P:82 Avg QP:30.83 size: 467
[libx264 @ 0x13518b0]mb I I16..4: 17.9% 0.0% 82.1%
[libx264 @ 0x13518b0]mb P I16..4: 0.6% 0.0% 0.0% P16..4: 23.1% 0.0% 0.0%
0.0% 0.0% skip:76.3%
[libx264 @ 0x13518b0]final ratefactor: 57.50
[libx264 @ 0x13518b0]SSIM Mean Y:0.9544735
[libx264 @ 0x13518b0]kb/s:8412.6
My suspicion is that it has something to do with the audio encoding. If so, does anyone know how to force it to reencode the audio to the proper format?
Any other ideas?
WARNING: this answer is 10 years old and reported not to work anymore.
I think the issue is the H.264 level being level 4.2.
Some of the Apple devices only support up to 3.0.
Here's the FFMPEG settings I usually use:
ffmpeg -i YOUR-INPUT.wmv -s qvga -b 384k -vcodec libx264 -r 23.976 -acodec libfaac -ac 2 -ar 44100 -ab 64k -vpre baseline -crf 22 -deinterlace -o YOUR-OUTPUT.MP4
You can adjust the rate, size and bitrate as needed. The important settings are in the baseline config param.
The ffmpeg wiki provides some useful up to date guidance on how to encode H.264 for particular devices. Here's an excerpt from Apple's docs with corresponding profiles:
iOS Compatability
Profile Level Devices Options
Baseline 3.0 All devices -profile:v baseline -level 3.0
Baseline 3.1 iPhone 3G and later, iPod touch 2nd generation and later -profile:v baseline -level 3.1
Main 3.1 iPad (all vers), Apple TV 2 and later, iPhone 4 and later -profile:v main -level 3.1
Main 4.0 Apple TV 3 and later, iPad 2 and later, iPhone 4s and later -profile:v main -level 4.0
High 4.0 Apple TV 3 and later, iPad 2 and later, iPhone 4s and later -profile:v high -level 4.0
High 4.1 iPad 2 and later, iPhone 4s and later, iPhone 5c and later -profile:v high -level 4.1
High 4.2 iPad Air and later, iPhone 5s and later -profile:v high -level 4.2
The listed ffmpeg settings didn't work for me (I don't seem to have the "baseline" preset listed), ffmpeg settings that don't reference baseline, I posted over here: iPhone "cannot play" .mp4 H.264 video file
Spoiler:
ffmpeg -i INPUT -s 320x240 -r 30000/1001 -b 200k -bt 240k -vcodec libx264 -coder 0 -bf 0 -refs 1 -flags2 -wpred-dct8x8 -level 30 -maxrate 10M -bufsize 10M -acodec libfaac -ac 2 -ar 48000 -ab 192k OUTPUT.mp4
The official Apple reference on the subject: http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/CreatingVideoforSafarioniPhone/CreatingVideoforSafarioniPhone.html
Try this python script.
I wrote it for myself. Maybe you will find it useful too. It converts files to mp4.
Because of SO rules here the complete source code:
#!/usr/bin/python
# Copyright (C) 2007-2010 CDuke
# This program is free software. You may distribute it under the terms of
# the GNU General Public License as published by the Free Software
# Foundation, version 2.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# This program converts video files to mp4, suitable to be played on an iPod
# or an iPhone. It is careful about maintaining the proper aspect ratio.
from __future__ import division
from datetime import datetime
import sys
import argparse
import os
import re
import shlex
import time
from subprocess import Popen, PIPE
DEFAULT_ARGS = '-f mp4 -y -vcodec libxvid -maxrate 1000k -mbd 2 -qmin 3 -qmax 5 -g 300 -bf 0 -acodec libfaac -ac 2 -flags +mv4 -trellis 2 -cmp 2 -subcmp 2'
#DEFAULT_ARGS = '-f mp4 -y -vcodec mpeg4 -vtag xvid -maxrate 1000k -mbd 2 -qmin 3 -qmax 5 -g 300 -bf 0 -acodec libfaac -ac 2 -r 30000/1001 -flags +mv4 -trellis 2 -cmp 2 -subcmp 2'
#DEFAULT_ARGS = '-y -f mp4 -vcodec libxvid -acodec libfaac'
DEFAULT_BUFSIZE = '4096k'
DEFAULT_AUDIO_BITRATE = '128k'
DEFAULT_VIDEO_BITRATE = '400k'
FFMPEG = '/usr/bin/ffmpeg'
class device:
'''Describe properties of device'''
def __init__(self, name, width, height):
self.name = name
self.width = width
self.height = height
class videoFileInfo:
def __init__(self, width, height, duration):
self.width = width
self.height = height
self.duration = duration
devices = [device('ipod', 320, 240), device('iphone', 480, 320),
device('desire', 800, 480)]
def getOutputFileName(inputFileName, outDir):
if outDir == None:
outFileName = os.path.splitext(inputFileName)[0] + '.mp4'
else:
outFileName = os.path.join(outDir, os.path.basename(inputFileName))
return outFileName
def getVideoFileInfo(fileName):
p = Popen([FFMPEG, '-i', fileName], stdout = PIPE, stderr = PIPE)
fileInfo = p.communicate()[1]
videoRes = re.search(b'Video:.+ (\d+)x(\d+)', fileInfo)
w = float(videoRes.group(1))
h = float(videoRes.group(2))
duratMatch = re.search(b'Duration:\s+(\d+):(\d+):(\d+)\.(\d+)', fileInfo)
duration = float(duratMatch.group(1)) * 3600
duration += float(duratMatch.group(2)) * 60
duration += float(duratMatch.group(3))
duration += float(duratMatch.group(4)) / 10
fileInfo = videoFileInfo(w, h, duration)
return fileInfo
def getArguments(width, height, aspect):
args = {}
w = width
h = w // aspect
h -= (h % 2)
if h <= height:
pad = (height - h) // 2
pad -= (pad % 2)
pady = pad
padx = 0
else:
# recalculate using the height as the baseline rather than the width
h = height
w = int(h * aspect)
width -= (width % 2)
pad = (width - w) // 2
pad -= (pad % 2)
padx = pad
pady = 0
args['width'] = w
args['height'] = h
args['padx'] = padx
args['pady'] = pady
return args
def getProgressBar(perc):
convInfo = 'Converted: [{}] {:.2%} \r'
num_hashes = round(perc * 100 // 2)
bar = '=' * num_hashes + ' ' * (50 - num_hashes)
return convInfo.format(bar, perc)
def convert(inputFileName, outputFileName, args, audioBitrate, videoBitrate, devWidth, devHeight, aspect, duration):
cmd = '{ffmpeg} -i {inFile} {defaultArgs} -bufsize {bufsize} -s {width}x{height} -vf "pad={devWidth}:{devHeight}:{padx}:{pady},aspect={aspect}" -ab {audioBitrate} -b {videoBitrate} {outFile}'.format(ffmpeg=FFMPEG, inFile=inputFileName, defaultArgs=DEFAULT_ARGS, bufsize=DEFAULT_BUFSIZE, devWidth=devWidth, devHeight=devHeight, padx=args['padx'], pady=args['pady'], width=args['width'], height=args['height'], aspect=aspect, audioBitrate=audioBitrate, videoBitrate=videoBitrate, outFile=outputFileName)
# cmd = '{ffmpeg} -i {inFile} {defaultArgs} -bufsize {bufsize} -s {width}x{height} -ab {audioBitrate} -b {videoBitrate} {outFile}'.format(ffmpeg=FFMPEG, inFile=inputFileName, defaultArgs=DEFAULT_ARGS, bufsize=DEFAULT_BUFSIZE, width=args['width'], height=args['height'], audioBitrate=audioBitrate, videoBitrate=videoBitrate, outFile=outputFileName)
print(cmd)
print()
start = datetime.today()
print('Converting started at ' + str(start))
conv = Popen(shlex.split(cmd), shell=False, stdout=PIPE, stderr=PIPE)
while conv.poll() is None:
out = os.read(conv.stderr.fileno(), 2048)
last = out.splitlines()[-1]
timeMatch = re.search(b'time=([^\s]+)', last)
if timeMatch:
timeDone = float(timeMatch.group(1))
perc = timeDone / duration
if sys.version_info > (3, 0):
exec("print(getProgressBar(perc), end='')")
else:
exec("print getProgressBar(perc),")
sys.stdout.flush()
# else:
# print(out)
time.sleep(0.5)
print(getProgressBar(1))
end = datetime.today()
print('Converting ended at ' + str(end))
print('Spended time: ' + str(end - start))
class mp4Converter(argparse.Action):
def __call__(self, parser, namespace, values, option_string = None):
outdir = namespace.outdir
for f in values:
outFileName = getOutputFileName(f.name, outdir)
fileInfo = getVideoFileInfo(f.name)
aspect = fileInfo.width / fileInfo.height
dev = next(d for d in devices if d.name == namespace.device)
args = getArguments(dev.width, dev.height, aspect)
convert(f.name, outFileName, args, namespace.AUDIO_BITRATE, namespace.VIDEO_BITRATE, dev.width, dev.height, aspect, fileInfo.duration)
print('file "{0}" converted successful'.format(f.name))
opts = argparse.ArgumentParser(
description = 'Converter to MP4',
epilog = 'made by CDuke 2010')
opts.add_argument('-V','--version',
action = 'version',
version = '0.0.1')
opts.add_argument('-v', '--verbose',
action = 'store_true',
default = False,
help = 'verbose')
opts.add_argument('-a', '--audio',
dest = 'AUDIO_BITRATE',
default = DEFAULT_AUDIO_BITRATE,
help = 'override default audio bitrate {0}'.format(DEFAULT_AUDIO_BITRATE))
opts.add_argument('-b', '--video',
dest = 'VIDEO_BITRATE',
default = DEFAULT_VIDEO_BITRATE,
help = 'override default video bitrate {0}'.format(DEFAULT_VIDEO_BITRATE))
opts.add_argument('-d', '--device',
choices = [d.name for d in devices],
default = 'ipod',
help = 'device that will play video')
opts.add_argument('-o', '--outdir',
help = 'write files to given directory')
opts.add_argument('file',
nargs = '+',
type = argparse.FileType('r'),
action = mp4Converter,
help = 'file that will be converted')
opts.parse_args()
ffmpeg -i test.mov -profile:v baseline -level 3.0 test.mp4
This disables some features but offers greater compatibility.
Also, here are some useful optional tags to add for working with the quality and file size:
-preset: ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow, placebo
-crf: 0-51
(preset modifies how long it takes to compress your video, with faster getting a bigger file size, and slower getting a smaller file size, whereas crf modifies the video quality, with higher quality having a bigger file size, and lower quality having a smaller file size.)
ffmpeg -i input.mov -c:v libx264 -pix_fmt yuv420p -profile:v main -crf 1 -preset medium -c:a aac -movflags +faststart output.mp4
ffmpeg.exe -i "Video.mp4" -vcodec libx264 -preset fast -profile:v baseline -lossless 1 -vf "scale=720:540,setsar=1,pad=720:540:0:0" -acodec aac -ac 2 -ar 22050 -ab 48k "Video (SD).mp4"
Got here because the simplest ffmpeg conversion approach was not producing an mp4 that would play on iOS for some reason.
Found settings that work for me in 2019 here:
https://gist.github.com/jaydenseric/220c785d6289bcfd7366
ffmpeg -i input.mov -c:v libx264 -pix_fmt yuv420p -profile:v baseline -level 3.0 -crf 22 -preset veryslow -vf scale=1280:-2 -c:a aac -strict experimental -movflags +faststart -threads 0 output.mp4
精彩评论