26

I'm currently using an implementation of ffmpeg on my android app. I'm allowing users to take short videos within my app and then when they upload them to the server, I'm crunching them down with ffmpeg to decrease file size so they're not passing huge amounts of data over the wire.

the problem is, it's taking forever to encode the videos on the android device. These videos usually aren't longer than 45 seconds and can take 20 minutes to encode. I've done some playing around with different switches / parameters on the ffmpeg command line and I now have it at a more comfortable time, but the file sizes are significantly bigger. I'm just not sure what codec I should use (fastest encoding but with decent quality output), how ffmpeg handles changing size (aspect ratio) in terms of speed of encoding etc.

Here are the two commands I've been using. This first one outputs the file size / quality that I want, but it just takes way too long to encode, not to mention it makes my device get really hot while it's encoding for so long:

ffmpeg -i input.mp4 -b:v 1024k -c:a copy -vf scale=960:540 output.mp4

I've tweaked the bitrate some on that as well as changed the scale to a smaller size, but I don't want to have to make the videos really small (in terms of scale) to accomplish a faster encoding. this second command goes a lot faster but makes the file size significantly bigger:

ffmpeg -i input.mp4 -vcodec libx264 -preset fast -c:a copy -s 960x540 output.mp4

I'd like to find a happy medium (smaller file size but faster encoding) keeping the video scale size close to the original. ffmpeg just has so many different parameters / switches that it's difficult to wrap my head around what I should be doing.

EDIT: adding ffmpeg output.

ffmpeg -i input.mp4 -vcodec libx264 -crf 30 -preset veryfast -c:a copy -s 960x540 output.mp4

    09-13 11:06:28.330 10881-10881/someapp D/home: ffmpeg version n3.0.1 Copyright (c) 2000-2016 the FFmpeg developers
09-13 11:06:28.330 10881-10881/someapp D/home:   built with gcc 4.8 (GCC)
09-13 11:06:28.331 10881-10881/someapp D/home:   configuration: --target-os=linux --cross-prefix=/home/vagrant/SourceCode/ffmpeg-android/toolchain-android/bin/arm-linux-androideabi- --arch=arm --cpu=cortex-a8 --enable-runtime-cpudetect --sysroot=/home/vagrant/SourceCode/ffmpeg-android/toolchain-android/sysroot --enable-pic --enable-libx264 --enable-libass --enable-libfreetype --enable-libfribidi --enable-libmp3lame --enable-fontconfig --enable-pthreads --disable-debug --disable-ffserver --enable-version3 --enable-hardcoded-tables --disable-ffplay --disable-ffprobe --enable-gpl --enable-yasm --disable-doc --disable-shared --enable-static --pkg-config=/home/vagrant/SourceCode/ffmpeg-android/ffmpeg-pkg-config --prefix=/home/vagrant/SourceCode/ffmpeg-android/build/armeabi-v7a --extra-cflags='-I/home/vagrant/SourceCode/ffmpeg-android/toolchain-android/include -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fno-strict-overflow -fstack-protector-all' --extra-ldflags='-L/home/vagrant/SourceCode/ffmpeg-android/toolchain-android/lib -Wl,-z,relro -Wl,-z,now -pie' --extra-libs='-lpng -lexpat -lm' --extra-cxxflags=
09-13 11:06:28.331 10881-10881/someapp D/home:   libavutil      55. 17.103 / 55. 17.103
09-13 11:06:28.331 10881-10881/someapp D/home:   libavcodec     57. 24.102 / 57. 24.102
09-13 11:06:28.331 10881-10881/someapp D/home:   libavformat    57. 25.100 / 57. 25.100
09-13 11:06:28.331 10881-10881/someapp D/home:   libavdevice    57.  0.101 / 57.  0.101
09-13 11:06:28.331 10881-10881/someapp D/home:   libavfilter     6. 31.100 /  6. 31.100
09-13 11:06:28.331 10881-10881/someapp D/home:   libswscale      4.  0.100 /  4.  0.100
09-13 11:06:28.331 10881-10881/someapp D/home:   libswresample   2.  0.101 /  2.  0.101
09-13 11:06:28.331 10881-10881/someapp D/home:   libpostproc    54.  0.100 / 54.  0.100
09-13 11:06:28.430 10881-10881/someapp D/home: Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/storage/emulated/0/ExpeditionSpot/Videos/20160913110411.mp4':
09-13 11:06:28.430 10881-10881/someapp D/home:   Metadata:
09-13 11:06:28.430 10881-10881/someapp D/home:     major_brand     : mp42
09-13 11:06:28.430 10881-10881/someapp D/home:     minor_version   : 0
09-13 11:06:28.430 10881-10881/someapp D/home:     compatible_brands: isommp42
09-13 11:06:28.430 10881-10881/someapp D/home:     creation_time   : 2016-09-13 17:04:33
09-13 11:06:28.430 10881-10881/someapp D/home:     com.android.version: 6.0.1
09-13 11:06:28.430 10881-10881/someapp D/home:   Duration: 00:00:19.41, start: 0.000000, bitrate: 20222 kb/s
09-13 11:06:28.430 10881-10881/someapp D/home:     Stream #0:0(eng): Video: h264 (Baseline) (avc1 / 0x31637661), yuv420p, 1920x1080, 19963 kb/s, SAR 1:1 DAR 16:9, 30.03 fps, 30 tbr, 90k tbn, 180k tbc (default)
09-13 11:06:28.430 10881-10881/someapp D/home:     Metadata:
09-13 11:06:28.430 10881-10881/someapp D/home:       creation_time   : 2016-09-13 17:04:33
09-13 11:06:28.430 10881-10881/someapp D/home:       handler_name    : VideoHandle
09-13 11:06:28.431 10881-10881/someapp D/home:     Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 96 kb/s (default)
09-13 11:06:28.431 10881-10881/someapp D/home:     Metadata:
09-13 11:06:28.431 10881-10881/someapp D/home:       creation_time   : 2016-09-13 17:04:33
09-13 11:06:28.431 10881-10881/someapp D/home:       handler_name    : SoundHandle
09-13 11:06:28.448 10881-10881/someapp D/home: [libx264 @ 0xf71c4400] using SAR=1/1
09-13 11:06:28.448 10881-10881/someapp D/home: [libx264 @ 0xf71c4400] using cpu capabilities: none!
09-13 11:06:28.516 10881-10881/someapp D/home: [libx264 @ 0xf71c4400] profile High, level 3.1
09-13 11:06:28.516 10881-10881/someapp D/home: [libx264 @ 0xf71c4400] 264 - core 148 - H.264/MPEG-4 AVC codec - Copyleft 2003-2015 - http://www.videolan.org/x264.html - options: cabac=1 ref=1 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=2 psy=1 psy_rd=1.00:0.00 mixed_ref=0 me_range=16 chroma_me=1 trellis=0 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=0 threads=12 lookahead_threads=4 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=1 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=10 rc=crf mbtree=1 crf=27.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
09-13 11:06:28.532 10881-10881/someapp D/home: Output #0, mp4, to '/storage/emulated/0/ExpeditionSpot/.tmp/small-20160913110411.mp4':
09-13 11:06:28.532 10881-10881/someapp D/home:   Metadata:
09-13 11:06:28.532 10881-10881/someapp D/home:     major_brand     : mp42
09-13 11:06:28.533 10881-10881/someapp D/home:     minor_version   : 0
09-13 11:06:28.533 10881-10881/someapp D/home:     compatible_brands: isommp42
09-13 11:06:28.533 10881-10881/someapp D/home:     com.android.version: 6.0.1
09-13 11:06:28.533 10881-10881/someapp D/home:     encoder         : Lavf57.25.100
09-13 11:06:28.533 10881-10881/someapp D/home:     Stream #0:0(eng): Video: h264 (libx264) ([33][0][0][0] / 0x0021), yuv420p, 960x540 [SAR 1:1 DAR 16:9], q=-1--1, 30 fps, 15360 tbn, 30 tbc (default)
09-13 11:06:28.533 10881-10881/someapp D/home:     Metadata:
09-13 11:06:28.533 10881-10881/someapp D/home:       creation_time   : 2016-09-13 17:04:33
09-13 11:06:28.533 10881-10881/someapp D/home:       handler_name    : VideoHandle
09-13 11:06:28.533 10881-10881/someapp D/home:       encoder         : Lavc57.24.102 libx264
09-13 11:06:28.533 10881-10881/someapp D/home:     Side data:
09-13 11:06:28.533 10881-10881/someapp D/home:       unknown side data type 10 (24 bytes)
09-13 11:06:28.533 10881-10881/someapp D/home:     Stream #0:1(eng): Audio: aac (LC) ([64][0][0][0] / 0x0040), 48000 Hz, stereo, 96 kb/s (default)
09-13 11:06:28.533 10881-10881/someapp D/home:     Metadata:
09-13 11:06:28.533 10881-10881/someapp D/home:       creation_time   : 2016-09-13 17:04:33
09-13 11:06:28.533 10881-10881/someapp D/home:       handler_name    : SoundHandle
09-13 11:06:28.533 10881-10881/someapp D/home: Stream mapping:
09-13 11:06:28.533 10881-10881/someapp D/home:   Stream #0:0 -> #0:0 (h264 (native) -> h264 (libx264))
09-13 11:06:28.533 10881-10881/someapp D/home:   Stream #0:1 -> #0:1 (copy)
09-13 11:06:28.533 10881-10881/someapp D/home: Press [q] to stop, [?] for help
09-13 11:06:29.102 10881-10881/someapp D/home: frame=    7 fps=0.0 q=0.0 size=       0kB time=00:00:01.04 bitrate=   0.4kbits/s speed=2.08x    
09-13 11:06:29.699 10881-10881/someapp D/home: frame=   16 fps= 15 q=0.0 size=       0kB time=00:00:01.04 bitrate=   0.4kbits/s speed=0.998x    
....
09-13 11:07:12.674 10881-10881/someapp D/home: [libx264 @ 0xf71c4400] frame I:3     Avg QP:26.83  size: 21896
09-13 11:07:12.674 10881-10881/someapp D/home: [libx264 @ 0xf71c4400] frame P:279   Avg QP:28.76  size:  5859
09-13 11:07:12.674 10881-10881/someapp D/home: [libx264 @ 0xf71c4400] frame B:296   Avg QP:29.93  size:   863
09-13 11:07:12.674 10881-10881/someapp D/home: [libx264 @ 0xf71c4400] consecutive B-frames: 18.3% 32.2% 23.9% 25.6%
09-13 11:07:12.674 10881-10881/someapp D/home: [libx264 @ 0xf71c4400] mb I  I16..4: 16.9% 54.2% 28.9%
09-13 11:07:12.674 10881-10881/someapp D/home: [libx264 @ 0xf71c4400] mb P  I16..4:  7.7%  9.1%  0.4%  P16..4: 27.5% 11.1%  4.0%  0.0%  0.0%    skip:40.1%
09-13 11:07:12.674 10881-10881/someapp D/home: [libx264 @ 0xf71c4400] mb B  I16..4:  0.8%  0.6%  0.0%  B16..8: 10.9%  2.4%  0.1%  direct: 1.8%  skip:83.5%  L0:35.8% L1:54.2% BI:10.0%
09-13 11:07:12.675 10881-10881/someapp D/home: [libx264 @ 0xf71c4400] 8x8 transform intra:52.0% inter:41.3%
09-13 11:07:12.675 10881-10881/someapp D/home: [libx264 @ 0xf71c4400] coded y,uvDC,uvAC intra: 28.9% 26.0% 2.1% inter: 6.4% 5.0% 0.0%
09-13 11:07:12.675 10881-10881/someapp D/home: [libx264 @ 0xf71c4400] i16 v,h,dc,p: 57% 20% 17%  6%
09-13 11:07:12.675 10881-10881/someapp D/home: [libx264 @ 0xf71c4400] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 33% 23% 34%  1%  2%  1%  3%  2%  2%
09-13 11:07:12.675 10881-10881/someapp D/home: [libx264 @ 0xf71c4400] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 36% 21% 17%  2%  7%  4%  6%  4%  4%
09-13 11:07:12.675 10881-10881/someapp D/home: [libx264 @ 0xf71c4400] i8c dc,h,v,p: 59% 16% 23%  2%
09-13 11:07:12.675 10881-10881/someapp D/home: [libx264 @ 0xf71c4400] Weighted P-Frames: Y:16.8% UV:4.7%
09-13 11:07:12.675 10881-10881/someapp D/home: [libx264 @ 0xf71c4400] kb/s:812.09
Blair Holmes
  • 1,521
  • 2
  • 22
  • 35
  • there's nothing you can do. transcoding is a highly cpu-intensive process. you're effectively decoding AND encoding the video simultaneously. other than using a GPU offload (no idea if ffmpeg can even use gpus), you're stuck with burning up the cpu while it's doing the gajillions of math operations necessary. – Marc B Sep 13 '16 at 15:13
  • 3
    well there's obviously SOMETHING I can do because those two commands produce drastically different results (in terms of encoding time). I'm sure that some codecs are faster than others etc, just not sure which or what... – Blair Holmes Sep 13 '16 at 15:15
  • Try `ffmpeg -i input.mp4 -vcodec libx264 -crf 27 -preset veryfast -c:a copy -s 960x540 output.mp4`. But like Marc said, there's modest scope of a speedup given other constraints. – Gyan Sep 13 '16 at 15:15
  • the specific transforms you're doing can affect the time, but you're STILL decoding/reencoding the video. you cannot avoid that. using a copy rather than a scale operation will save some time, but there's no way to answer this without knowing what your specific output requirements are. scaling everything down to a one frame-per-video 1x1 image will obviously take the least time, becausing it's basically a 1x1 jpg - but not exactly useful. – Marc B Sep 13 '16 at 15:17
  • @Mulvya I will give this a try in a bit. Can you please explain what the -crf 27 means? – Blair Holmes Sep 13 '16 at 16:07
  • ffmpeg is mostly in software. getting any performance on a phone will require hardware acceleration for Android-ffmpeg. lib-stagefreight used to be a possible avenue to hwa... maybe some newer alternative now that some many mobile apps r into video .. – Robert Rowntree Sep 13 '16 at 16:22
  • It means ffmpeg will encode using constant quality method, as opposed to targeting a bitrate. – Gyan Sep 13 '16 at 16:23
  • Just upload the original and encode on the server. Encoding on a phone with software is only good for using up your clients batteries. – llogan Sep 13 '16 at 16:26
  • @LordNeckbeard and the trade off is using more of my client's data plan... – Blair Holmes Sep 13 '16 at 16:31
  • @Mulvya the -crf switch provided a good happy medium for me. Didn't take too long and the quality is still pretty good with a manageable file size. If you wanna make that an answer, I'll gladly accept it. – Blair Holmes Sep 13 '16 at 17:10
  • @LordNeckbeard in fact it does: `[libx264 @ 0xf72c4400] using cpu capabilities: none!` Can you please explain why that is bad? – Blair Holmes Sep 13 '16 at 17:40
  • @LordNeckbeard done. – Blair Holmes Sep 13 '16 at 17:52

2 Answers2

59

Try

ffmpeg -i input.mp4 -vcodec libx264 -crf 27 -preset veryfast -c:a copy -s 960x540 output.mp4

In CRF mode, x264 encodes video to maintain a certain quality throughout. Lower values produce higher quality but larger files. Combined with veryfast preset, it should provide an acceptable tradeoff between speed and size.

Gyan
  • 85,394
  • 9
  • 169
  • 201
0

ffmpeg, x264 1 pass conversion with decent compression and quality and reasonable file size, e.g.:

video:

-c:v libx264 -preset veryfast -tune film -vprofile high -crf 22 -s 640x360 -aspect 16:9 -pix_fmt yuv420p -g 250 -r 25

audio:

 -c:a aac -b:a 128k -ac 2 -ar 44100

Asamof: crf 20 to 23. The fps (-r 25) can be left out if you want to keep the original. Next to crf and size, one of the things that reduces file size the most is the gop size (-g) aka keyframe interval. However, if you plan to cut your video more precisely, I would advise a gop of (0 to) 12 (for a 25 fps film, half of the fps what). If you don't plan to cut/edit much, just want to convert as is, I would say the default gop of 250.

Audio less of influence on size. Between 96 (reasonable) and 128 kbps (CD-quality, preferred).

Of course you can do these conversions (and edits) also in Avidemux (http://fixounet.free.fr/avidemux/). In it, 'Video output, Configure', you can use Advanced mode or not (and do your own settings). The gop is situated under the 'Frame' tab.

Video container tip: mkv aka matroska = open source + more flexible than mp4.

Bye.

P.S.: Don't transcode videos on an Android device. Use a decent laptop with preferably 2 or more cores and 4 or more G(i)b ram. Other advantage of pc: you can use (linux bash or other) scripts more easily and you can type, with 1 to 10 fingers! ;-P

Donut
  • 1
  • 1