294

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?

Peter Mortensen
  • 12,090
  • 23
  • 70
  • 90
matteo
  • 4,199
  • 6
  • 20
  • 22
  • I just tried your command line and it worked as expected. Your problem might lie with the sound format. Does transcoding the sound work? – Captain Giraffe May 04 '11 at 17:49
  • By "as expected" do you mean the resulting video has the same duration as the audio input? Have you played it? Isn't it one-frame-long? – matteo May 04 '11 at 17:59
  • Sound format is not the problem, transcoding the sound works – matteo May 04 '11 at 17:59
  • I had a order of params issue too and it cost me hours! Too bad these sorts of problems aren't covered in the help. http://gregoire.org/2009/12/05/fun-with-ffmpeg/ – Paul Gregoire May 19 '11 at 13:20
  • Hi, I am also searching a way to create a video by combining an audio file and an image, within the android code. I figured out the command for that: ffmpeg -i allmapeople.mp3 -i Penguins.jpg video_finale.mpg I tried many 2 tutorials using ffmpeg that generates the .so file. But I still could not find out a way to combine an audio and an image. Please help me!!! – TharakaNirmana Jan 15 '13 at 05:21
  • 10
    this is better than chosen answer, i experimented and it's fast and file size is small..`ffmpeg -y -i image.png -i audio.mp3 -c:a copy result.avi` – Muhammad Umer Jul 07 '14 at 06:05
  • related: https://stackoverflow.com/questions/25381086/convert-mp3-video-with-static-image-ffmpeg-libav-bash – Ciro Santilli OurBigBook.com Sep 01 '18 at 07:59
  • 1
    @MuhammadUmer Youtube can't process video created this way. – Eric Feb 12 '20 at 22:04
  • This answer works: https://askubuntu.com/a/868831/216272 – Eric Feb 12 '20 at 22:11
  • can this also be done using a cloud service like Zapier, etc? – Open the way Apr 23 '22 at 07:36

15 Answers15

242

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

ffmpeg -loop 1 -i img.jpg -i music.mp3 -shortest -acodec copy -vcodec mjpeg result.mkv

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 ima.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 than the MJPEG codec used above. The audio is AAC, with the built-in ffmpeg AAC encoder.

Vitaly Zdanevich
  • 190
  • 1
  • 3
  • 18
matteo
  • 4,199
  • 6
  • 20
  • 22
  • 20
    How come the files end up so much bigger than [size of image] + [size of audio file]? I would expect the video compression to go crazy with a constant frame? – Alec Jacobson Apr 13 '12 at 07:01
  • 1
    Great, that worked. However, given a 4MB mp3 and a 200 KB jpeg, it created a 100 MB video. Obviously, the file doesn't need to be any bigger than 4.2 MB. Any way to make it more efficient? – Colonel Panic Apr 15 '14 at 22:13
  • @matteo: alternatively, you could just unaccept. I moderately agree with the edit to remove that disclaimer, as it seems a bit hostile in its current state (I appreciate that is not your intention though!) and thus would be distracting for future readers. I expect the various well-intentioned editors of this question would not agree that their edits were arbitrary! `;-)` – halfer Feb 14 '16 at 20:06
  • 3
    `Option shortest (finish encoding within shortest input) cannot be applied to input file image.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.` – wim Dec 16 '13 at 01:14
  • How would you use a short video instead of an image and loop the video until the audio ends? Like loop a 10 second video until the 3 minute audio file ends? – JZ11 Nov 09 '15 at 18:42
  • 1
    Worked but very very slow :( can we get fast speed of ffmpeg processing ?? Any command which is running from ffmpeg very slow. – Ahmad Arslan Apr 06 '15 at 07:46
  • 9
    use `ffmpeg -y -i image.png -i audio.mp3 -c:a copy result.avi` this works better!!!?!??!?! – Muhammad Umer Jul 07 '14 at 06:07
  • 2
    This answer is currently being [discussed](http://meta.stackoverflow.com/questions/316817/overly-zealous-editing-of-answer-what-to-do) on meta. – DavidPostill Feb 14 '16 at 08:42
  • 3
    It depends on the video codec you use. If you are copying the commands in my examples, I'm using mjpeg as the codec, which compresses each frame separately, so it takes no advantage of the fact that all frames are equal. Also, I think that even other codecs would recode the whole frame every once in a while, i.e. every N-th frame, so you would get a much smaller file but still much bigger than just the size of the image+sound. They do so because (a) otherwise the decoder would need to read the whole file from the beginning even if you just want to jump to the last frame, and – matteo Apr 13 '12 at 10:43
  • 1
    (b) any error or bit corruption during the transmission at a given moment would affect the decoded video starting from that point forever, would never recover – matteo Apr 13 '12 at 10:43
  • 1
    @Arslan Ahmad, to speed things up copy the audio like in the comment above and drop the framerate with `-framerate 1`. Should be very fast. Some video codecs get horrible seeking at playback tho. – toster-cx Nov 07 '15 at 21:15
  • @jonrsharpe how do I turn the answer into wiki-whatever? – matteo Feb 15 '16 at 01:51
  • 1
    @jonrsharpe strongly disagree. If the original author does not agree with edits that alter the code, they are free to rollback the change and in no way are obligated to accept the changes or make the answer a community wiki. @ matteo consider reverting the changes you disagree with, instead of adding a disclaimer. – HugoRune Feb 14 '16 at 10:32
  • 2
    @matteo click 'edit' under answer, and in the bottom right corner there'll be a button labelled 'community whatever' and you toggle it and save – TankorSmash Feb 15 '16 at 04:37
  • 2
    With the 1st example I had same experience as http://superuser.com/a/1041823/16966, `-shortest` had to be moved near end of argument list – matt wilkie Feb 21 '16 at 20:47
  • I was creating mp4 from images and audio in two step process and then finally concatenating the multiple videos to create final one. The final video was not playing in my Android App with error "Cant play the video ". with your options it worked like charm and video is working in Android app. thanks. – Amit Mar 23 '16 at 15:07
  • @Amit I need to combine a set of images, video clips and an audio track to create a single video file (preferably ogg, but that is less relevant at this point). In addition, I need to create some transition effects between adjacent images. Is there any way to script this whole task using ffmpeg and/or other command line tools? The goal is to automate the task and using a command line process. – Web User Aug 17 '16 at 17:35
  • 1
    @Web User - First make individual videos for each image and corresponding audio using cmd - "ffmpeg -loop 1 -i "+imgName+" -i "+audioFileName+" -c:v libx264 -tune stillimage -c:a aac -strict experimental -b:a 192k -pix_fmt yuv420p -shortest "+videoOutFilename ; Then use following to concatenate all videos to amke a single one.. "ffmpeg -f concat -i " +listfilename+" -c copy " +outputDir+"Final_Video.mp4" where listfilename is a file containng names of all video files – Amit Aug 18 '16 at 06:04
  • @Amit thanks for the commands! How about transitions? e.g. a cross-fade effect lasting 3 seconds between two images. – Web User Aug 18 '16 at 17:24
  • This solution worked perfect for me. – maniempire Sep 21 '16 at 13:15
  • The mjpeg option should just be deleted. It was outdated then and now is just archaic. There's very few reasons to encode in mjpeg and those are only streaming/record reasons. – user287352 May 12 '19 at 06:53
  • I am getting a huge tail silence using the exact parameters you provided above here is my post with detail, can you please help. https://stackoverflow.com/questions/75828734/getting-a-lot-of-tail-silence-when-combining-an-image-and-audio-into-mp4-movie ("S:\_BINS\ffmpeg-2023-03-20\bin\ffmpeg.exe" -loop 1 -i "HELLO.JPG" -i "HELLO.MP3" -c:v libx264 -tune stillimage -c:a aac -b:a 192k -pix_fmt yuv420p -y -shortest "HELLO_aac.mp4") – Meryan Apr 01 '23 at 01:57
69

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 :-)

PJ Brunet
  • 1,462
  • 11
  • 9
  • Also it's possible your audio file won't be compatible with your .flv container. In that case, you should just try a different (output) container, like .webm, .avi or whatever format, till you find a container format that's compatible with your audio file. – PJ Brunet Sep 29 '15 at 02:50
  • 2
    Used this for a .JPG and .MP3 to make an MP4 - worked perfectly. The FLV I created from the JPG/MP3 didn't seem to work - which may be as per the previous comments warning. –  Oct 29 '15 at 14:37
  • 3
    The updated version works, for Youtube. I thought it was stuck at 95% but finally it worked. – Basj Feb 28 '16 at 10:24
  • got this: `No pixel format specified, yuvj420p for H.264 encoding chosen. Use -pix_fmt yuv420p for compatibility with outdated media players. [libx264 @ 0x2b5c940] height not divisible by 2 (700x457)` ... this works: `ffmpeg -r 1 -loop 1 -i ep1.jpg -i ep1.wav -acodec copy -r 1 -shortest -vf scale=1280:-2 video.mp4` – NineCattoRules Mar 03 '17 at 17:58
  • what about multiple images? I need the image to change at some specific time to another image. I'd like to be able to specify them on the command line with a time parameter for each one. –  Jun 08 '17 at 13:23
  • Thanks, A Lot, It helped me, for batch convert check my [answer](https://superuser.com/a/1229214/664948) below based on his answer. – Suraj Jain Jul 12 '17 at 16:18
  • This way worked for me, the extra settings broke the process. – Jesse Feb 03 '19 at 08:19
  • 8
    `ffmpeg -r 1 -loop 1 -y -i 1.jpg -i 1.m4a -c:a copy -r 1 -vcodec libx264 -shortest 1.avi` this should be the best answer, '__') only took 2 secs to encode, the other answers took more than 10 minutes and resulting in a very huge size – Kokizzu Nov 08 '19 at 05:00
  • 2
    Awesome! The second update worked for youtube – Foo Oct 23 '20 at 08:22
  • confirmed this works with mp3 to produce .mov which play in Quicktime on Mac OS 11; ie, ffmpeg -r 1 -loop 1 -i m.jpg -i m.mp3 -acodec copy -r 1 -shortest -vf scale=1280:720 m.mov – Tony M Dec 06 '20 at 21:22
  • 1
    It works well, thank you. Btw it is not necessary to set `-r` twice, you can find it on the wiki page: https://trac.ffmpeg.org/wiki/Slideshow#Framerates – mbelsky Apr 17 '22 at 17:53
47

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.

  • I must be using a different version than youurs (if you have tried your command and it works as you describe), because, as I already mention in the question, I had already tried your exact same command and I get a video of the duration of 1 frame (a fraction of a second), NOT the duration of the audio file. I did expect it to be intelligent, but (in my version) it proved to be not. – matteo Dec 16 '12 at 19:59
  • 2
    "no output can have odd-number height- or width attributes" Not true. Set pix_fmt to something that doesn't have chroma subsampling, like rgb24 or yuv444p, then make sure the codec and container support it and have no further restrictions. With regards to pix_fmt, FFmpeg is less than intelligent; it assumes yuv420p (which has chroma subsampling) unless you tell it otherwise. – Jonathan Baldwin May 29 '13 at 02:49
  • @ShinMuraoka `Mine is a win-64 ffmpeg build compiled on: Jan 6 2013, at: 16:16:53` Neither your solution nor @matteo solution worked for me. Also, I downloaded your files from Google Drive, but it didn't gave the expected output (the output file was black contained only audio). Please help me in figuring out the right command to be used. – coding_idiot Jan 08 '13 at 17:47
  • 2
    **Hey Matteo**, yes, I did execute that code, and yes, it works as advertised. I'm sure there are plenty of halfwits that would be so careless as to make such claims without testing them, so I'll try not to be offended :) In a full post below I will supply Pastebin links to FFmpeg console output and MediaInfo data on input files and final output file. My input files, my batch file, my output file are on a GoogleDrive where they are [freely downloadable](https://docs.google.com/folder/d/0BxafXIRt8NlPRk94QWd5aDBQdm8/edit), if you would like to test them against your FFmpeg build. –  Jan 05 '13 at 12:59
  • what about multiple images? I need the image to change at some specific time to another image. I'd like to be able to specify them on the command line with a time parameter for each one. –  Jun 08 '17 at 13:23
  • libvo_aacenc has been deprecated due to it being low quality, aac is the recommended audio encoder now - according to https://askubuntu.com/a/1034195/624083 – Vix Dec 25 '19 at 20:10
  • Unknown encoder 'libvo_aacenc' for `ffmpeg version 3.4.8-0ubuntu0.2 Copyright (c) 2000-2020 the FFmpeg developers` – Shakiba Moshiri Mar 09 '21 at 20:56
  • But `-r 1` is increase encoding time and reduce file size (because of 1 FPS). – Vitaly Zdanevich Feb 07 '22 at 02:56
24

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
  • 369
  • 3
  • 5
  • 3
    Thanks for this. Most of the other answers didnt work for me (using ffmpeg on Alpine linux). This answer has the shortest command that worked flawlessly for me. – DannyB Jul 06 '17 at 13:38
  • ffmpeg -loop 1 -y -i slide02.jpg -i slide02.aac -shortest slide02.mp4 # thanks just what I needed – zzapper Jun 16 '20 at 18:32
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
  • what about multiple images? I need the image to change at some specific time to another image. I'd like to be able to specify them on the command line with a time parameter for each one. –  Jun 08 '17 at 13:23
6

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
  • 657
  • 8
  • 13
  • 1
    When I tried creating a video using this method, my version of Movist (a macOS video player) only played the video for a split second, and my version of VLC displayed a black background instead of the background image. A video created using PJ Brunet's method played correctly in VLC, but there was no audio in Movist. I didn't really even need a background image, so I ended up using a low-resolution black background to reduce file size and encoding time: `convert -size 256x144 xc:black /tmp/a.png;ffmpeg -loop 1 -i /tmp/a.png -i input.m4a -c:v libx264 -crf 51 -c:a copy -shortest output.mp4`. – nisetama Apr 13 '20 at 17:01
  • `-r 1` set FPS to 1 and improve encoding time and file size. – Vitaly Zdanevich Feb 07 '22 at 02:58
  • So why do I get a black picture instead of the one I specify ?? "S:\_BINS\ffmpeg-2023-03-20\bin\ffmpeg.exe" -i "HELLO.JPG" -i "HELLO.MP3" -c:v libx264 -tune stillimage -c:a aac -b:a 192k -pix_fmt yuv420p -y -r 1 "HELLO_aac.mp4" I am a total ffmpeg novice thanks for explaining some of the params above – Meryan Apr 01 '23 at 07:19
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
  • 657
  • 8
  • 13
Colonel Panic
  • 12,303
  • 21
  • 63
  • 81
  • 3
    `-shortest` is an output option and may be ignored as an input option as you are using it. – llogan Feb 15 '16 at 21:55
3

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,715
  • 3
  • 16
  • 26
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).

  • `-shortest` is an output option, but you're using it as an input option. Move it before the output file and you can eliminate the `-t 10`, but then your answer will be pretty much the same as the others. – llogan Feb 15 '16 at 21:51
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,089
  • 8
  • 24
  • 37
Suraj Jain
  • 111
  • 6
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
  • 2
  • 6
  • 13
  • I too am on MacOS and my sound file is also MP3, but your command took longer and generated a larger MP4 then just letting `ffmpeg` figure it out as @PJ Brunet suggests: `ffmpeg -i image.jpeg -i audio.mp3 result.mp4` `ffmpeg version N-98301-gce297b44d3-tessus` – Chris Wolf Sep 13 '21 at 17:01
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.

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 "/data/image.jpeg" -i "/data/myAudio.WMA" -c:v libx264 -preset medium -tune stillimage -crf 18 -c:a aac -b:a 128k -shortest -pix_fmt yuv420p "/data/myVideoForYT.mp4" -stats'

        # for .mp3
        #command: ' -loop 1 -framerate 2 -i "/data/image.jpeg" -i "/data/myAudio.mp3" -c:v libx264 -preset medium -tune stillimage -crf 18 -c:a copy -shortest -pix_fmt yuv420p "/data/myVideoForYT.mp4" -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)

-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,390
  • 26
  • 45
  • 52
  • 3
    This is an incomplete command that couldn't possibly work. Although I can fix and debug your command, I won't do your work for you, so please edit your answer and fix it yourself. I also noticed that your video size is not what matteo wanted. – karel May 24 '16 at 08:20