Convert png sequence to x264 with ffmpeg

09
2013-08
  • Thucydides411

    I am trying to convert a series of pngs into an mp4 video. I am using ffmpeg, and want to encode the video with the H.264 codec. Using the command

    ffmpeg -y -r 30 -b 1800k -i _tmp%04d.png -vcodec libx264 out.mp4
    

    I get the following warning message

    Incompatible pixel format 'bgra' for codec 'libx264', auto-selecting format 'yuv420p'
    

    My understanding is that there is an alpha channel in the pngs, which the x264 encoder cannot handle. Is there a way to get around this problem? Is there, for example, a way to get the encoder to ignore the alpha channel (my pngs don't actually have any transparent elements)?

    I'm aware that I could batch convert the pngs beforehand to strip the alpha channel, but the sequence of images is produced by another program, and having to preprocess the images each time I make a video would be less than optimal.

    Edit: After stripping the alpha channel from each frame using the command

    convert in.png -background white -flatten +matte out.png
    

    ffmpeg gives the warning message

    Incompatible pixel format 'pal8' for codec 'libx264', auto-selecting format 'yuv420p'
    

    so still no dice.

  • Answers
  • LordNeckbeard

    I was thinking of using AVISynth and frame serving to get around the problem, but it looks like ffmpeg now has native support for AVISynth. Meaning you can use AVISynth scripts as input.

    So with a script, sequence.avs, you could do:
    ffmpeg -i sequence.avs -vcodec libx264 out.mp4

    Where sequence.avs is:
    ImageSource("_tmp%04d.png", start=0, end=1, fps=30).ConvertToYV12()

    Note: The optional start and end parameters reflect that I tested with two images, _tmp0000.png and _tmp0001.png.

    See also: More color formats. The ImageSource documentation.


  • Related Question

    osx - FFmpeg extract clip - stream frame rate differs from container frame rate (x264, aac)
  • fideli

    Summary
    H.264 video seems to have a really high frame rate that requires a scaling factor to the applied to the duration of video that I'm trying to extract (900x lower).

    Body
    I'm trying to extract a clip from a movie that I have in MP4 format (created using Handbrake). After trying mencoder and VLC, I decided to give FFmpeg a shot since it was the least troublesome when it came to copying the codecs. That is, compared to mencoder and VLC, the resulting file was still playable in QuickTime (I know about Perian, etc, I'm just trying to learn how all this works).

    Anyway, my command was as follows:

    ffmpeg -ss 01:15:51 -t 00:05:59 -i outofsight.mp4 \ 
    -acodec copy -vcodec copy clip.mp4
    

    During the copy, The following comes up:

    Seems stream 0 codec frame rate differs from container frame rate: 45000.00 (45000/1) -> 25.00 (25/1)
    Input #0, mov,mp4,m4a,3gp,3g2,mj2, from outofsight.mp4':
      Duration: 01:57:42.10, start: 0.000000, bitrate: 830 kb/s
        Stream #0.0(und): Video: h264, yuv420p, 720x384, 25 tbr, 22500 tbn, 45k tbc
        Stream #0.1(eng): Audio: aac, 48000 Hz, stereo, s16
    Output #0, mp4, to 'out.mp4':
        Stream #0.0(und): Video: libx264, yuv420p, 720x384, q=2-31, 90k tbn, 22500 tbc
        Stream #0.1(eng): Audio: libfaac, 48000 Hz, stereo, s16
    Stream mapping:
      Stream #0.0 -> #0.0
      Stream #0.1 -> #0.1
    Press [q] to stop encoding
    frame= 2591 fps=2349 q=-1.0 size=    8144kB time=101.60 bitrate= 656.7kbits/s
    …
    

    Instead of a 5:59 duration clip, I get the entire rest of the movie. So, to test this, I ran the ffmpeg command with -t 00:00:01. What I got was exactly a 15:00 minute clip. So I did some black box engineering and decided to scale my -t option by calculating what value to enter given that 1 second was interpreted as 900 s. For my desired 359 s clip, I calculated 0.399 s and so my ffmpeg command became:

    ffmpeg -ss 01:15.51 -t 00:00:00.399 -i outofsight.mp4 \ 
    -acodec copy -vcodec copy clip.mp4
    

    This works, but I have no idea why the duration is scaled by 900. Investigating further, each ffmpeg run has the line:

    Seems stream 0 codec frame rate differs from container frame rate: 45000.00 (45000/1) -> 25.00 (25/1)
    

    45000/25 = 1800. Must be a relation somewhere. Somehow, the obscenely high frame rate is causing issues with the timing. How is that frame rate so high? The best part about this is that the resulting clip.mp4 has the exact same feature (due to the copied video codec), and taking further clips from this needs the same scaling for the -t duration option. Therefore, I've made it available for anyone willing to check this out.

    Appendix
    The preamble for ffmpeg on my system (built using MacPorts ffmpeg port):

    FFmpeg version 0.5, Copyright (c) 2000-2009 Fabrice Bellard, et al.
      configuration: --prefix=/opt/local --disable-vhook --enable-gpl --enable-postproc --enable-swscale --enable-avfilter --enable-avfilter-lavf --enable-libmp3lame --enable-libvorbis --enable-libtheora --enable-libdirac --enable-libschroedinger --enable-libfaac --enable-libfaad --enable-libxvid --enable-libx264 --mandir=/opt/local/share/man --enable-shared --enable-pthreads --cc=/usr/bin/gcc-4.2 --arch=x86_64
      libavutil     49.15. 0 / 49.15. 0
      libavcodec    52.20. 0 / 52.20. 0
      libavformat   52.31. 0 / 52.31. 0
      libavdevice   52. 1. 0 / 52. 1. 0
      libavfilter    1. 4. 0 /  1. 4. 0
      libswscale     1. 7. 1 /  1. 7. 1
      libpostproc   51. 2. 0 / 51. 2. 0
      built on Jan  4 2010 21:51:51, gcc: 4.2.1 (Apple Inc. build 5646) (dot 1)
    

    EDIT
    Not sure whether it was a bug or not, but it seems to be fixed now in my current version of ffmpeg, at least for this video (version 0.6.1 from MacPorts).


  • Related Answers
  • Gus

    I was having this same problem and my solution was the following:

            $ffmpegout = array();           
            //10 is the number of images you want from video
            $fracduration = ($info['duration']/10);             
    

    exec('ffmpeg -y -i /testmedia/'.$info['filename'].' -vf fps=fps=1/'.$fracduration.' -f image2 /testmedia/images/output%03d.jpg 2>&1', $ffmpegout); //print_r($ffmpegout);

    This gives me 10 images for all the video no matter the length of video

  • evilsoup

    With ffmpeg, the positioning of the options matters. With your example, it is trying to apply -ss and -t to the input. Use it like this will apply the options to the output instead:

    ffmpeg -i outofsight.mp4 -ss 01:15:51 -t 00:05:59 -acodec copy -vcodec copy clip.mp4
    

    With current ffmpeg, the correct syntax would be:

    ffmpeg -i outofsight.mp4 -ss 01:15:51 -t 00:05:59 -c copy clip.mp4