Archives

Categories

Conversion of Video Files

To convert video files between formats I use Makefiles, this means I can run “make -j2” on my dual-core server to get both cores going at once. avconv uses 8 threads for it’s computation and I’ve seen it take up to 190% CPU time for brief periods of time, but overall it seems to average a lot less, if nothing else then running two copies at once allows one to calculate while the other is waiting for disk IO.

Here is a basic Makefile to generate a subdirectory full of mp4 files from a directory full of flv files. I used to use this to convert my Youtube music archive for my Android devices until I installed MX Player which can play every type of video file you can imagine [1]. I’ll probably encounter some situation where this script becomes necessary again so I keep it around. It’s also a very simple example of how to run a batch conversion of video files.

MP4S:=$(shell for n in *.flv ; do echo $$n | sed -e s/^/mp4\\// -e s/flv$$/mp4/ ; done)

all: $(MP4S)

mp4/%.mp4: %.flv
        avconv -i $< -strict experimental -b $$(~/bin/video-encoding-rate $<) $@ > /dev/null

Here is a more complex Makefile. I use it on my directory of big videos (more than 1280*720 resolution) and scales them down for my favorite Android devices (Samsung Galaxy S3, Samsung Galaxy S, and Sony Ericsson Xperia X10). My Galaxy S3 can’t play a FullHD version of Gangnam Style without going slow so I need to do this even for the fastest phones. This makefile generates three subdirectories of mp4 files for the three devices.

S3MP4S:=$(shell for n in *.mp4 ; do echo $$n | sed -e s/^/s3\\// -e s/.mp4$$/-s3.mp4/ -e s/.flv$$/-s3.mp4/; done)
XPERIAMP4S:=$(shell for n in *.mp4 ; do echo $$n | sed -e s/^/xperiax10\\// -e s/.mp4$$/-xperiax10.mp4/ -e s/.flv$$/-xperiax10.mp4/; done)
SMP4S:=$(shell for n in *.mp4 ; do echo $$n | sed -e s/^/galaxys\\// -e s/.mp4$$/-galaxys.mp4/ -e s/.flv$$/-galaxys.mp4/; done)

all: $(S3MP4S) $(XPERIAMP4S) $(SMP4S)

s3/%-s3.mp4: %.mp4
        avconv -i $< -strict experimental -s $(shell ~/bin/video-scale-resolution 1280 720 $<) $@ > /dev/null

galaxys/%-galaxys.mp4: %.mp4
        echo avconv -i $< -strict experimental -s $(shell ~/bin/video-scale-resolution 800 480 $<) $@ > /dev/null

xperiax10/%-xperiax10.mp4: %.mp4
        echo avconv -i $< -strict experimental -s $(shell ~/bin/video-scale-resolution 854 480 $<) $@ > /dev/null

The following script is used by the above Makefile to determine the resolution to use. Some Youtube videos have unusual combinations of width and height (Linkin Park seems to like doing this) so I scale them down so it fits the phone in one dimension and the other dimension is scaled appropriately. This requires a script from the Mplayer package and expects it to be in the location that it’s used in the Debian package, for distributions other than Debian a minor change will be required.

#!/bin/bash
set -e
OUT_VIDEO_WIDTH=$1
OUT_VIDEO_HEIGHT=$2

eval $(/usr/share/mplayer/midentify.sh $3)
XMULT=$(echo $ID_VIDEO_WIDTH*100/$OUT_VIDEO_WIDTH | bc)
YMULT=$(echo $ID_VIDEO_HEIGHT*100/$OUT_VIDEO_HEIGHT | bc)
if [ $XMULT -gt $YMULT ]; then
  NEWX=$OUT_VIDEO_WIDTH
  NEWY=$(echo $OUT_VIDEO_WIDTH*$ID_VIDEO_HEIGHT/$ID_VIDEO_WIDTH/2*2|bc)
else
  NEWX=$(echo $OUT_VIDEO_HEIGHT*$ID_VIDEO_WIDTH/$ID_VIDEO_HEIGHT/2*2|bc)
  NEWY=$OUT_VIDEO_HEIGHT
fi
echo ${NEWX}x${NEWY}

Note that I can’t preserve TAB characters in a blog post. So those Makefiles won’t work until you replace strings of 8 spaces with a TAB character.

3 comments to Conversion of Video Files

  • flv files use exactly the same codecs as mp4 files, so if you ever need to convert without reducing the resolution, then you do it much more quickly with this:

    avconv -i file.flv -acodec copy -vcodec copy -copyts file.mp4

  • Ouch, you make my eyes hurt…

    MP4S:=$(shell for n in *.flv ; do echo $$n | sed -e s/^/mp4\\// -e s/flv$$/mp4/ ; done)

    Better written as:

    MP4S:=$(shell for n in *.flv; do echo mp4/$${n%flv}mp4; done)

    That’s even POSIX. And I stopped reading there.

  • Anonymous

    You might try “make -l N” rather than “make -j N” when running CPU-bound tasks like this; that way, you’ll automatically run jobs up to the load limit of the box, but also handle programs that can successfully make use of multiple cores themselves.