Log in

No account? Create an account
30 August 2009 @ 11:11 am
Converting video files for Palm Pre  
This may work for other phones with 480x320 screens, and could easily be adapted for others. I played around with mencoder and found settings that work to play video on my phone using the built-in codecs.

I wrote it into a bash script for Linux, but the settings themselves should work for Mac or Windows. For batch processing, for now I'll just run the command several times on different files with && between them, but more automation would be nice.

Edit: The first few files worked fine, and then the next kept getting:

Too many video packets in the buffer: (1008 in 8395438 bytes).
Maybe you are playing a non-interleaved stream/file or the codec failed?
For AVI files, try to force non-interleaved mode with the -ni option.

I tried adding -ni but still getting the error. Will troubleshoot later.

The audio and subtitle options match most of what I watch, Japanese audio and English subtitles.

The video files I'm using are 1280x720. When I scale the width down to 480 proportionally, the height winds up 272. If I play the file, it expands the width to match the height and cuts off some video and messes with the subtitles. I can press a button to zoom it how I like every time I play a file, or I can use "expand" to add black lines and expand it to a height of 320.

With mencoder in Linux anyway, this tends to leave subtitle artefacts in the black lines if I encode it all at once, so I actually make a second pass just to add these black lines.

I had -noskip in there, copied from someone else's conversion for a different phone, but that was causing some "Too many video packets in the buffer:" errors. Thanks for the suggestion, repura! Also took the suggestion to loop it while it has input so I can, say, ./preconv.sh *.mkv


#!/usr/bin/env bash

for input_file in "$@";

touch temp.mp4
rm -f temp.mp4

subtitle_width="-subwidth 90"
subtitle_font_text_scale="-subfont-text-scale 4"
subtitle_language="-slang eng,und"
audio_language="-alang jpn,und"
audio_codec="-oac lavc"
video_codec="-ovc lavc"
lavc_options="-lavcopts aglobal=1:vglobal=1:acodec=libfaac:abitrate=128:vcodec=mpeg4:keyint=25"
output_format="-of lavf"
lavf_options="-lavfopts format=mp4"
audio_filter="-af lavcresample=44100"
video_filter1="-vf harddup,scale=480:272"
video_filter2="-vf harddup,expand=480:320"
maximum_sync_correction_per_frame="-mc 0"

/usr/bin/mencoder $input_file -o temp.mp4 $subtitle_width $subtitle_font_text_scale $subtitle_language $audio_language $audio_codec $video_codec $lavc_options $output_format $lavf_options $audio_filter $video_filter1 $maximum_sync_correction_per_frame $force_non_interleaved

/usr/bin/mencoder temp.mp4 -o $output_file $audio_codec $video_codec $lavc_options $output_format $lavf_options $audio_filter $video_filter2 $maximum_sync_correction_per_frame


When I run it with sample.mkv, it does this:

/usr/bin/mencoder sample.mkv -o temp.mp4 -subwidth 90 -subfont-text-scale 4 -slang eng,und -alang jpn,und -oac lavc -ovc lavc -lavcopts aglobal=1:vglobal=1:acodec=libfaac:abitrate=128:vcodec=mpeg4:keyint=25 -of lavf -lavfopts format=mp4 -af lavcresample=44100 -vf harddup,scale=480:272 -mc 0 -ni

/usr/bin/mencoder temp.mp4 -o sample.mkv.mp4 -oac lavc -ovc lavc -lavcopts aglobal=1:vglobal=1:acodec=libfaac:abitrate=128:vcodec=mpeg4:keyint=25 -of lavf -lavfopts format=mp4 -af lavcresample=44100 -vf harddup,expand=480:320 -mc 0
Current Mood: accomplished
repura on August 30th, 2009 09:45 pm (UTC)
For running it on several files you might put it all in a

for input_file in "$@"; do [script goes here]; done

so you can pass it multiple files as arguments (like ./script.sh *.avi) or

while read input_file; do [etc]; done

so you can feed it multiple files through stdin (like ls *.avi | ./script.sh)

You can change output_file to output_file="${input_file}.mp4" then. (or maybe "${input_file%.*}.mp4"?)

If you want to stop in case mencoder fails you can test $? each time you call it, like
mencoder [...]
if [ $? -ne 0 ]; then exit 1; fi

Also, "too many packets in buffer" error might be because of -noskip? Every time I got that it was because mencoder was trying to make too much of a weird framerate conversion (usually because of the file reporting weird rates [e.g. 1000 fps] like some wmvs do), so you could try setting -fps and -ofps for that particular video.
ashi: kasumiashi on August 31st, 2009 07:24 pm (UTC)
Thanks! That did the trick. Now to find more files to put on my phone for my train commute...
repura on September 2nd, 2009 12:42 am (UTC)
Glad to help :)

Here are a couple more tips, if you don't mind:
You don't need to touch temp.mp4 before removing it, "rm -f" ignores nonexistent files:
$ rm -f temp.mp4 && rm -f temp.mp4 && echo "success"

Also, you can move all variable attributions (except for output_file) out of the loop, so they won't be reattributed every time (not that it will make a noticeable difference, but it will be theoretically more efficient :))
ashi: arrrr!ashi on September 2nd, 2009 08:43 pm (UTC)
Cool, I'll tidy up the rm temp.mp4 code.

All the variable attributions are mostly there so I remember what does what in case I want to change anything. :) The man page for mencoder is huge.
repura on September 2nd, 2009 10:02 pm (UTC)
I understand why you have them, I just meant it would be more efficient to do all attributions (except output_file, which is supposed to change) before you enter the for loop.

If you do var="whatever"; for i in `seq 1 5`; do echo $var; done, bash will set var to "whatever" once and then echo it 5 times, but if you do for i in `seq 1 5`; do var="whatever"; echo $var; done, then it will set var to "whatever" 5 times before echoing it, despite the fact that that was already its current value on the last 4 times. The result is the same and you won't even be able to measure a difference in execution time, but the first one will make the cpu work just a bit less (84% cpu 0.011s vs 89% cpu 0.011s here).

OTOH if it ain't broken, don't fix it, right? I'm just nitpicking, so feel free to ignore me. :)
ashi: charybdisashi on September 2nd, 2009 10:21 pm (UTC)
Oh! It's assigning variables in the for loop. That makes sense, yup.
(Anonymous) on November 26th, 2009 04:48 am (UTC)
put double quotes around the $input_file's and $output_file to let the script handle files with spaces in the filename.