29

Theoretically both IOS and ANDROID will play h.264 files, but I can't figure out a setting to encode them so they actually work cross platform. Does anybody know how to encode for both Android and IOS using one file?

p.s. I know all about html5 video and the fallback sources, I just don't want to encode and host a new video for every device that comes down the pike.

JKirchartz
  • 15,862
  • 7
  • 54
  • 82

3 Answers3

52

Here's the ffmpeg command line we use to transcode to MPEG-4 h.264 in our production environment. We've tested the output on several Android devices, as well as iOS. You can use this as a starting point, just tweaking things like frame size/frame rate and qfactor.

ffmpeg -y 
-i #{input_file} 
-s 432x320 
-b 384k 
-vcodec libx264 
-flags +loop+mv4 
-cmp 256 
-partitions +parti4x4+parti8x8+partp4x4+partp8x8 
-subq 6 
-trellis 0 
-refs 5 
-bf 0 
-flags2 +mixed_refs 
-coder 0 
-me_range 16 
-g 250 
-keyint_min 25 
-sc_threshold 40 
-i_qfactor 0.71 
-qmin 10 -qmax 51 
-qdiff 4 
-acodec libfaac 
-ac 1 
-ar 16000 
-r 13 
-ab 32000 
-aspect 3:2 
#{output_file}

Some of the important options affecting Android compatibility are:

-coder 0      Uses CAVLAC rather than CABAC entropy encoding (CABAC not supported on Android)
-trellis 0    Should be shut off, requires CABAC
-bf 0         Turns off B-frames, not supported on Android or other h.264 Baseline Profile devices
-subq 6       Determines what algorithms are used for subpixel motion searching. 7 applies to B-frames, not supported on Android.
-refs 5       Determines how many frames are referenced prior to the current frame.  Increasing this number could affect compatibility

After we encode our video with this ffmpeg recipe, we also pass the video through qt-faststart. This step rechunks the video for streaming. We stream it over HTTP to an embedded VideoView within our Android app. No problems streaming to any Android device we're aware of.

Update 2013-06-17: I just wanted to add a note that it's best to stick with "baseline" profile for H.264 encoding for maximum compatibility across all Android devices. The above command line doesn't explicitly specify an H.264 profile, but ffmpeg does have a -profile command line flag that is useful if you are using its presets. You probably shouldn't mess with -profile. I have encoded videos for my ASUS Transformer 300 tablet (Android 4.2) using "main" rather than "baseline" profile (via Handbrake). The "main" profile gave problems with audio getting out of sync with video on playback.

mportuesisf
  • 5,517
  • 2
  • 30
  • 26
  • 3
    This is a superb post. Thank you! – Sedate Alien Jun 15 '11 at 22:25
  • Just wanted to add that although it works perfectly on iPhone on most of the androids I tested this on (lg ally, Droid X, HTC evo, nexus s) the video displayed a message asking to steam or download, and if you choose stream it fails. Might just need some tweaked settings though, I don't know why it didn't at least do progressive download, might just be android browser. – JKirchartz Jun 30 '11 at 12:55
  • I added a prior comment about streaming compatibility to the original answer, to make it more complete. – mportuesisf Jun 30 '11 at 18:00
  • 1
    +1 For ffmpeg commandline, althgouth, are all those settings really necessary? – Lennart Rolland Mar 01 '13 at 09:50
  • 1
    I wanted to provide a complete set of command line parameters. Sometimes you really want to be explicit about things, rather than have a (possible) change in ffmpeg defaults give you an output other than what you intended. – mportuesisf Jun 17 '13 at 18:12
  • Well, I have been using this much more simple command line and it works for iOS devices: ffmpeg -y -i $INPUT -c:v libx264 -pix_fmt yuv420p -preset:v slow -profile:v baseline -crf 20 $OUTPUT – MoDJ Jun 20 '13 at 01:48
  • Instead of using qt-faststart, you also can just pass -movflags faststart to ffmpeg – Mic92 Nov 17 '14 at 12:47
  • I didn't understand your comment about the `-profile` command line flag for H.264 encoding. Do you mean that I should add this flag also if I want to get H.264 encoding? I am creating some small video clips to include with the app. – Suragch Dec 09 '16 at 12:10
4

I used this to make an Android and iOS app with embedded videos. The videos played in both versions. (Android example) (iOS example)

Supplemental answer

This answer is a supplement to the accepted answer explaining some of the parameters.

ffmpeg 
-y                  # Overwrite output files without asking.
-i input_filename   # input file name    
-s 432x320          # size of output file
-b:v 384k           # bitrate for video
-vcodec libx264     # use H.264 video codec
-flags +loop+mv4    # use loop filter and four motion vector by macroblock
-cmp 256            # ??? Full pel motion estimation compare function
-partitions +parti4x4+parti8x8+partp4x4+partp8x8      #???
-subq 6             # determines algorythms for subpixel motion searching and partition decision
-trellis 0          # optimal rounding choices
-refs 5             # number of frames referenced prior to current frame
-bf 0               # turn of B-frames, something to do with H.264 and Baseline Profile
-flags2 +mixed_refs # ??? gave me an error so I just deleted it
-coder 0            # turn of the CABAC entropy encoder
-me_range 16        # max range of the motion search
-g 250              # GOP length (250 is the recommended default)
-keyint_min 25      # Minimum GOP length (25 is the recommended default)
-sc_threshold 40    # adjusts sensitivity of x264's scenecut detection (default is 40) 
-i_qfactor 0.71     # Qscale difference between I-frames and P-frames (0.71 is the recommended default)
-qmin 10 -qmax 51   # min and max quantizer (10 and 51 are the recommended defaults)
-qdiff 4            # max QP step (4 is recommended default)
-c:a aac            # Set the audio codec to use AAC
-ac 1               # number of audio channels 
-ar 16000           # audio sampling frequency
-r 13               # frames per second
-ab 32000           # audio bitrate
-aspect 3:2         # sample aspect ratio
output_filename     # name of the output file

Feel free to edit this if you can fill in some of the details I wasn't sure about.

Here it is again in a cut-and-paste format. (I also had to add the -strict -2 parameter to get aac to work on my computer.)

ffmpeg -y -i input_file.avi -s 432x320 -b:v 384k -vcodec libx264 -flags +loop+mv4 -cmp 256 -partitions +parti4x4+parti8x8+partp4x4+partp8x8 -subq 6 -trellis 0 -refs 5 -bf 0 -coder 0 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -qmin 10 -qmax 51 -qdiff 4 -c:a aac -ac 1 -ar 16000 -r 13 -ab 32000 -aspect 3:2 -strict -2 output_file.mp4

Further Study

Most of this information I found at the following links:

See also

Suragch
  • 364,799
  • 232
  • 1,155
  • 1,198
-1

See Android Supported Media Formats, which states that h.264 is only supported in Android 3.0+. Earlier versions of Android support h.263. EDIT: As mportuesisf mentions below, I misinterpreted the linked table. Ignore this answer.

Joe
  • 41,230
  • 11
  • 43
  • 60
  • 2
    This is incorrect. Android 3.0+ added h.264 support for encode. Earlier versions of Android can play h.264 just fine. You need to carefully choose the encoding parameters when encoding content for playback on Android, which is what the OP was asking. Generally, you want to encode using 'baseline profile' for compatbility with Android devices. – mportuesisf Jun 15 '11 at 21:34
  • Android 2.1+ supports decoding h.264. – kinakuta Jun 16 '11 at 02:39
  • @mportuesisf: you're right, my mistake.. I overlooked the "Encoder" column, and assumed the "Android 3.0+" comment applied to both encoding and decoding. – Joe Jun 19 '11 at 10:48