Wednesday, April 30, 2014

Gotcha of the Day: ffmpeg converted flv file won't play in Windows Media Player

I'm using ffmpeg to convert flv files to avi files. The goal is to generate videos that any old version of Windows Media Player can play back.

I was using the command:

  ffmpeg -i foo.flv -codec:v mpeg4 -flags:v +qscale \
    -global_quality:v 0 -codec:a libmp3lame \
    foo.avi

And while the video played fine on my machine and using VLC, there were some Windows computers where Windows Media Player would kick back a useless error message, and refused to play the file video.

My first thought was that the codec was to blame. Using ffprobe I was able to find out the codec:

 $ ffprobe foo.avi
 ffprobe version N-62756-g2cf5143 Copyright (c) 2007-2014 the FFmpeg developers
 ...many lines trimmed...
 Stream #0:0: Video: mpeg4 (Simple Profile) (FMP4 / 0x34504D46), yuv420p, 320x230 [SAR 1:1 DAR 32:23], 1k tbr, 1k tbn, 1k tbc
 Stream #0:1: Audio: mp3 (U[0][0][0] / 0x0055), 44100 Hz, mono, s16p, 64 kb/s

But alas, I had videos encoded with FMP4 that played back fine on the same computers that were choking on this newly generated video.

For the heck of it, I ran a file against the generated avi file:

foo.avi: RIFF (little-endian) data, AVI320 230 >30 fps, video: FFMpeg MPEG-4, audio: MPEG-1 Layer 3 (mono, 44100 Hz)

Whoa, that >30 fps is suspicious.

A quick check of the ffmpeg docs told me about -r:

‘-r[:stream_specifier] fps (input/output,per-stream)`
Set frame rate (Hz value, fraction or abbreviation).

As an input option, ignore any timestamps stored in the file and instead generate timestamps assuming constant frame rate fps.

As an output option, duplicate or drop input frames to achieve constant output frame rate fps.

This looked promising!

Indeed, I ran the exact same command as above but added -r 30 and now file reports:

foo.avi:  RIFF (little-endian) data, AVI320 230 30.00 fps, video: FFMpeg MPEG-4, audio: MPEG-1 Layer 3 (mono, 44100 Hz)

And best of all, Windows Media Player plays the file just fine.

Turns out, you can figure out the frame rate using the following ffmpeg command:

ffprobe foo.avi -show_entries stream=time_base -select_streams v -of compact=nk=1:p=0 

And I had the frame rate set to 1/1000, instead of 1/30. Ooops.

No comments:

Post a Comment