There are different ways of optimizing and I am not sure which one you are looking for.
You could optimize for reducing file size, reducing video encoding time, etc
So, you might be aiming to reduce frame rate, as your way to optimize this, since it is for a still image video, with some mp3 audio. To have 1 frame after each 10 s time, you could do it like this:
ffmpeg -loop 1 -framerate 1/10 -i "img.png" -i "<your_sound>.mp3" -c:v libx264 -c:a copy -tune stillimage -shortest "<your_video_output_ex1>.mp4"
-framerate refers to the "input stream", so encoding is very fast. In case you decided to use
-r, you would get the same result, but really slower encoding time, because it refers to the output frame rate. ffmpeg would create lots of frames and then internally discard them to produce the same result.
However, I am not sure if this is what you asked for. Even though you get constant frame rate, the encoder will still encode key frames and lots of I- and B-frames between them.
In case you want your video to have only key-frames, which is not much clear but somehow seems to be your request, here is a method. This consists on creating a video "building block" with only its initial key frame and then concatenating that video many times.
1 - Create a clip of video with the duration that you want to have between key frames, and having only 1 single frame, as key frame. I will assume 10 s:
ffmpeg -loop 1 -framerate 1/10 -i "img.png" -i "<your_sound>.mp3" -c:v libx264 -ss 00:00:00.000 -t 00:00:10.000 -c:a copy -tune stillimage -shortest "building_block.mp4"
Be warned that the number "10" appeared 2x in this command, one for the frame rate and the other for the duration of the video.
You can check that there is only 1 frame in the video, with the following command, that shows you how many frames there are:
ffprobe -v error -select_streams v:0 -count_frames -show_entries stream=nb_read_frames "building_block.mp4"
Being only 1 frame, it is obviously a key frame, as I think you intend.
2 - Concatenate that building block many times to reach the intended duration of the final video.
To create successive copies of the video stream without any reencoding, you need to create a text file, for example "sequence.txt" listing the sequence of clips that will be concatenated, using the following format inside the text file:
One line per clip. You could also decide to use different files in the sequence, if you want. Here I am just concatenating always the same building block along time.
Then ask ffmpeg to concatenate all the sequence into a single video:
ffmpeg -f concat -safe 0 -i sequence.txt -c copy concatenated_building_blocks.mp4
This video contains a sequence of only key frames with your image. For now, sound is also a repetition of the contents of the building_block.mp4-
3 - Finally, replace the audio by the one you want to have there:
ffmpeg -i concatenated_building_blocks.mp4 -i "<your_sound>.mp3" -map 0:v:0 -map 1:a:0 -c:v copy -c:a copy -shortest "<your_final_video_ex2>.mp4"
Maybe this is what you asked for.
File size is greater that that of "<your_video_output_ex1>.mp4", from the first command I shared but, while ex1 has I-, P- and B-frames in it, ex2 only has I-frames, or exact copies of the same single one.
Final note1: I think video players were not intended for very low frame rates. If you experience difficulties playing this kind of video, you may wish to increase the frame rate. I think mpv and firefox browser are among the ones that best support variable frame rate and low frame rates.
Final note2: If you decide to compress "<your_final_video_ex2>.mp4" using 7-zip or some other compressor with large enough dictionary you will see that it compresses really a lot, because of the copies inside. (.zip does not work because its 32KiB or 64KiB dictionary is not enough most probably.)