325

This should be pretty trivial, but I can't find a way to get it to work.

I want FFmpeg to take one JPEG image and an audio file as input and generate a video file of the same duration as the audio file (by stretching the still image for the whole duration).

I don't care very much about what video codec is used for output, but it is vital that I can use "copy" as the audio codec (i.e. copy the audio stream without transcoding it).

What is the right command line that would do that?

I tried:

ffmpeg -i image8.jpg -i sound11.amr -acodec copy test.avi

and tried a lot of combinations with and without -s 640x360, -loop_input, -shortest, -t xxx, -r 0.1 (artificially low frame rate in the hope that the video would be longer) and -f image2

Either I get errors or I get a video file of the duration of one frame.

I've googled around and found a dozen of proposed solutions (supposedly to this very same question) none of which works.

Can anybody suggest a working command and explain the rationale behind it?

matteo
  • 4,559

17 Answers17

271

The order of options in the command line matters. The following works for my case:

ffmpeg -loop 1 -i img.jpg -i audio.wav -shortest out.mp4

In a more general case, where image.jpg and audio.wav are your input, you can use the following command, adapted from the FFmpeg wiki:

ffmpeg -loop 1 -i image.jpg -i audio.wav -c:v libx264 -tune stillimage -c:a aac -b:a 192k -pix_fmt yuv420p -shortest out.mp4

This would use the libx264 encoder and provide you with better compression due to its tune preset. The audio is AAC, with the built-in ffmpeg AAC encoder, you can use other options like mp3 or -c:a copy if you'd like to avoid re-encoding the audio.

ginjaemocoes
  • 2,151
matteo
  • 4,559
80

Even easier:

ffmpeg -i ep1.png -i ep1.wav ep1.flv

FFmpeg will try to pick the best codec automatically, depending on the extension of your output file.

Update: I noticed YouTube has difficulty processing the video (gets stuck at 95%) I think because there's only one frame. The solution I found to make YouTube happy: add more frames. Also, I added-acodec copy to preserve the audio quality. You need -shortest or it loops forever. (It stops at the end of the shortest stream, which is the audio, because the image loop is infinite.) The order of your options is very important for speed, as filters (and such) are processed in the order you specify. If you change the order of these parameters, the results are dramatically different.

ffmpeg -r 1 -loop 1 -i ep1.jpg -i ep1.wav -acodec copy -r 1 -shortest -vf scale=1280:720 ep1.flv

Also notice that I set the frame rate twice, that's not an accident--the first frame rate is for the input, second is for the output. If you do this correctly, there should only be one frame per second of video, which means it encodes relatively fast. Also I set the resolution to 720p here, which means you should get HD audio on YouTube :-)

Jay Brunet
  • 1,592
49

You're making it way harder than it has to be. FFmpeg is a lot smarter than you give it credit for--it knows you want the video to be the same length as your audio track.

ffmpeg -i still.png -i narrate.wav -acodec libvo_aacenc -vcodec libx264 final.flv

pause

The only attributes you have to specify are the input filenames, the output codecs, and the output filename (which eo ipso includes the output container, ).

Of course, it makes sense to start with a still image that shares the same dimensions as your eventual video; if you are using a dedicated image editor instead of specifying output dimensions for FFmpeg to meet, you need to make sure your input dimensions are even numbers.

Output size is one of FFmpeg's most common hang-ups; some codecs are more restricted in output dimensions than others, but no output can have odd-number height- or width attributes.

The pause command at the end of the batch file keeps the CLI open--the best way to debug your command line is by reading the error messages it generates. They are extremely specific--and the best documentation FFmpeg has--but the developers' hard work is wasted if you allow the window to close before you can read them.

The command shell has a switch cmd /k that maintains an open window where you can run the same the same instructions from your batch script at the command prompt.

FFmpeg and avconv will both make you use -c:a for -acodec and -c:v for -vcodec eventually, but the old instructions work fine in the builds I use.

Nota Bene: Every commit has idiosyncracies. If your command line is failing for no apparent reason, it is often helpful to try another build--or follow the fork over to libav, where FFmpeg's most active developers have been for the last couple of years. Their transcoding tool has been renamed avconv but your batch files should work with either one.

25

The version that worked for me:

 ffmpeg -loop 1 -y -i pic.jpg -i sound.amr -shortest video.mp4

Checkout the the option -shortest must to be in front of the output file if not I get the below error:

Option shortest (finish encoding within shortest input) cannot be applied to input file pic.jpg -- you are trying to apply an input option to an output file or vice versa. Move this option before the file it belongs to. Error parsing options for input file pic.jpg.

fguillen
  • 391
8

Here is a full explanation:

ffmpeg -i image.jpg -i audio.mp3 -c:v libx264 -tune stillimage -c:a copy out.mp4
  • -i image.jpg -i audio.mp3: Image and audio inputs

  • -c:v libx264: use x264 to encode video.

  • -tune stillimage: x264 setting to optimize video for still image encoding

  • -c:a copy: copies the codec used for the input audio. You may change this if you want a different audio codec.

I did not use -loop 1 or -shortest. -loop 1 drastically slows down the encoding and creates a larger file. -shortest should not be used without -loop 1 since then the video will be one frame long. However YouTube does not like videos with one frame (see PJ Brunet's answer) so then both options should be used.

qwr
  • 1,005
7

From the ffmpeg manpage:

ffmpeg [[infile options][-i infile]]... {[outfile options] outfile}...

As you discovered, the infile options must come before the infile to which they apply.

This is not a bug, however, just a mechanism by which you can specify which infile arguments apply to.

ComputerDruid
  • 213
  • 1
  • 6
5

This worked for me:

ffmpeg -loop 1 -shortest -y -i image.jpg -i audio.mp3 -acodec copy -vcodec libx264 video.avi

I found vcodec libx264 created much smaller files than mpjeg (10 MB rather than 100 MB).

qwr
  • 1,005
Colonel Panic
  • 12,549
4

Cloned from PJ Brunet's answer:

ffmpeg -r 1 -loop 1 -y -i 1.jpg -i 1.m4a -c:a copy -r 1 -vcodec libx264 -shortest 1.avi

This resulting the smallest size (18MB) and fastest encoding time (only took 2 secs for 17MB m4a file)

Kokizzu
  • 1,807
2

I was trying to do as @matteo, but without the audio, and @Colonel Panic's solution worked best :

ffmpeg -loop 1 -shortest -y -i still.png -vcodec libx264 -t 10 video.avi

I only had to add a duration argument in seconds (-t 10).

1

In case someone wants to batch convert them, try this.

You can set the input and output Folder, and also the format in which you want the video to be in. In this case I set it to AVI.

This answer Combine one image + one audio file to make one video using FFmpeg helped me a lot.

 @echo off
 set "sourcedir=C:\Users\CodeHard\Desktop\BOX\Newfolder"  
 set "outputdir=C:\Users\CodeHard\Desktop\BOX\Converted" 

 PUSHD "%sourcedir%"

 for %%F in (*.mp3) DO ffmpeg -r 1 -loop 1 -i abc.jpeg -i "%%F" -acodec copy -r 1 -shortest -vf scale=1280:720 "%outputdir%\%%F.avi"  

 POPD
Glorfindel
  • 4,158
1

I used a combination of a couple of the commands mentioned in this post, including -pix_fmt yuv420p to make sure it works on Quicktime (Mac).

ffmpeg -loop 1 -y -i image.jpg -i music.mp3 -shortest -pix_fmt yuv420p output.mp4

For me, this worked perfectly on macOS.

Hay
  • 783
0

ffmpeg -loop 1 -i img.jpg -i audio.wav -c:v libx264 -c:a aac -strict experimental -b:a 192k -shortest out.mp4

0

Since only one image is displayed throughout the entire video, we can reduce the framerate to match the duration of the audio. Then, we simply remux the image and audio together in an mkv container.

  1. Find the length of the audio file
ffprobe -i <audio input> -show_entries format=duration -v quiet -of csv="p=0"
  1. Encode the video
ffmpeg -framerate 1/<length> -i <image input> -i <audio input> -vcodec copy -acodec copy output.mkv

The resulting video stream doesn't appear for me in VLC but after uploading it to YouTube, I was able to confirm that it still worked.

Richie Bendall
  • 423
  • 3
  • 10
0

Docker

I have similar problem with .wma (audio files) to .mp4 conversion and upload result to youtube - I will left working docker solution for future reades.

version: '3.7'

services: convert: image: jrottenberg/ffmpeg volumes: - ./mp3:/data

    # for WMV
    command: ' -loop 1 -framerate 2 -i &quot;/data/image.jpeg&quot; -i &quot;/data/myAudio.WMA&quot; -c:v libx264 -preset medium -tune stillimage -crf 18 -c:a aac -b:a 128k -shortest -pix_fmt yuv420p &quot;/data/myVideoForYT.mp4&quot; -stats'

    # for .mp3
    #command: ' -loop 1 -framerate 2 -i &quot;/data/image.jpeg&quot; -i &quot;/data/myAudio.mp3&quot; -c:v libx264 -preset medium -tune stillimage -crf 18 -c:a copy -shortest -pix_fmt yuv420p &quot;/data/myVideoForYT.mp4&quot; -stats'

Save below code inside docker-composer.yml file, I assume that mp3 directory (with myAudio.wma file) will be in same directory. And run it by docker compose run convert (you should see progress/duration durgin processing)

0

if you like hardware speed too, here, create a video of a single still image with an audio of ~500mb in less than 10 seconds. (on amd CPU & GPU)

ffmpeg -hwaccel vaapi -hwaccel_output_format yuv420p -vaapi_device /dev/dri/renderD128 -r 0.01 -loop 1 -i image.jpg -i audio.mp3 -c:v libx264 -tune stillimage -preset ultrafast -c:a copy -pix_fmt yuv420p -shortest output_fast.mp4

0

I found that preparing a long video without sound and then merge the sound create a video of smaller size (1.5 instead of 2.1 mb) with a reasonable time especially if you need to do it often you can reuse the same static video the second step is instantaneous, only first one take a little.

this is to create the static video (around 15s) for 10 minutes

ffmpeg -r 1 -loop 1 -i Sound-wave-2.png \
-t 600 -acodec copy -r 1 -vf scale=1280:720 -c:v libx264 -preset ultrafast -crf 30 \
static_video.mp4

and this is to use it with an mp3

ffmpeg -i static_video.mp4 -i input.mp3 -c:v copy -c:a copy -shortest output.mp4
bormat
  • 169
-2

Try this command. It is worked for me.

-y -i /storage/emulated/0/images.jpg -i /storage/emulated/0/audio.wav -acodec aac -vcodec mpeg4 -s 480*320 -f mp4 -r 2 /storage/emulated/0/output.mp4"
karel
  • 13,706