How to add "anullsrc" to a video stream prior to concatenation.
I am trying to convert DVD (VOB) files into an MP4. The first 2 files, don't have an audio track.
What is the proper syntax for adding an "anullsrc" audio track to video streams that do not have one, prior to concatenation?
ffmpeg command generate:
ffmpeg -i /Volumes/My Passport/Project/DVD_Files/VIDEO_TS/VIDEO_TS.VOB -i /Volumes/My Passport/Project/DVD_Files/VIDEO_TS/VTS_01_0.VOB -i /Volumes/My Passport/Project/DVD_Files/VIDEO_TS/VTS_01_1.VOB -i /Volumes/My Passport/Project/DVD_Files/VIDEO_TS/VTS_01_2.VOB -i /Volumes/My Passport/Project/DVD_Files/VIDEO_TS/VTS_01_3.VOB -i /Volumes/My Passport/Project/DVD_Files/VIDEO_TS/VTS_01_4.VOB -i /Volumes/My Passport/Project/DVD_Files/VIDEO_TS/VTS_02_0.VOB -i /Volumes/My Passport/Project/DVD_Files/VIDEO_TS/VTS_02_1.VOB -filter_complex [0:a]nullsrc=r=480000[s0];[0:v][s0]concat=n=2[s1];[1:a]nullsrc=r=480000[s2];[1:v][s2]concat=n=2[s3];[s1][s3][2][3][4][5][6][7]concat=n=8[s4] -map [s4] /tmp/test.mp4
import os
import ffmpeg
global_args = {
'vcodec' : 'h264_videotoolbox',
'acodec' : 'aac',
'vb' : '7750k',
'ab' : '192k',
}
concat_args = {
'v' : 1,
'a' : 1
}
input_args = {
}
nullsrc = {
'filter_name' : 'nullsrc',
'r' : 480000
}
# Path shorted for readability (DIRECTORY is set)
# python.ffmpeg set up this way for debugging purposes.
vob_stream = list()
file1 = (ffmpeg.input(DIRECTORY + '/VIDEO_TS/VIDEO_TS.VOB'))
file2 = (ffmpeg.input(DIRECTORY + '/VIDEO_TS/VTS_01_0.VOB'))
file3 = (ffmpeg.input(DIRECTORY + '/VIDEO_TS/VTS_01_1.VOB'))
file4 = (ffmpeg.input(DIRECTORY + '/VIDEO_TS/VTS_01_2.VOB'))
file5 = (ffmpeg.input(DIRECTORY + '/VIDEO_TS/VTS_01_3.VOB'))
file6 = (ffmpeg.input(DIRECTORY + '/VIDEO_TS/VTS_01_4.VOB'))
file7 = (ffmpeg.input(DIRECTORY + '/VIDEO_TS/VTS_02_0.VOB'))
file8 = (ffmpeg.input(DIRECTORY + '/VIDEO_TS/VTS_02_1.VOB'))
video1 = file1.video
audio1 = file1.audio.filter(**nullsrc)
media1 = ffmpeg.concat(video1,audio1)
video2 = file2.video
audio2 = file2.audio.filter(**nullsrc)
media2 = ffmpeg.concat(video2,audio2)
merged = ffmpeg.concat(media1,media2,file3,file4,file5,file6,file7,file8)
output = ffmpeg.output(merged,mp4_out)
output.run()
This produces the following errors.
Input #0, mpeg, from '/Volumes/My Passport/Project/DVD_Files/VIDEO_TS/VIDEO_TS.VOB':
Duration: 00:00:00.03, start: 0.060000, bitrate: 1964 kb/s
Stream #0:0[0x1bf]: Data: dvd_nav_packet
Stream #0:1[0x1e0]: Video: mpeg2video (Main), yuv420p(tv, smpte170m, progressive), 720x480 [SAR 8:9 DAR 4:3], 9000 kb/s, 29.97 tbr, 90k tbn, 59.94 tbc
Input #1, mpeg, from '/Volumes/My Passport/Project/DVD_Files/VIDEO_TS/VTS_01_0.VOB':
Duration: 00:00:00.11, start: 0.060000, bitrate: 10443 kb/s
Stream #1:0[0x1bf]: Data: dvd_nav_packet
Stream #1:1[0x1e0]: Video: mpeg2video (Main), yuv420p(tv, smpte170m, progressive), 720x480 [SAR 8:9 DAR 4:3], 9000 kb/s, 29.97 tbr, 90k tbn, 59.94 tbc
Stream #1:2[0x20]: Subtitle: dvd_subtitle
Input #2, mpeg, from '/Volumes/My Passport/Project/DVD_Files/VIDEO_TS/VTS_01_1.VOB':
Duration: 00:17:42.16, start: 0.060000, bitrate: 8086 kb/s
Stream #2:0[0x1bf]: Data: dvd_nav_packet
Stream #2:1[0x1e0]: Video: mpeg2video (Main), yuv420p(tv, bottom first), 720x480 [SAR 8:9 DAR 4:3], 7758 kb/s, 29.97 fps, 29.97 tbr, 90k tbn, 59.94 tbc
Stream #2:2[0x80]: Audio: ac3, 48000 Hz, stereo, fltp, 192 kb/s
[mpeg2video @ 0x7fe489829c00] Invalid frame dimensions 0x0.
Last message repeated 13 times
Input #3, mpeg, from '/Volumes/My Passport/Project/DVD_Files/VIDEO_TS/VTS_01_2.VOB':
Duration: 00:17:41.70, start: 1062.172000, bitrate: 8090 kb/s
Stream #3:0[0x1e0]: Video: mpeg2video (Main), yuv420p(tv, bottom first), 720x480 [SAR 8:9 DAR 4:3], 7758 kb/s, 29.97 fps, 29.97 tbr, 90k tbn, 59.94 tbc
Stream #3:1[0x80]: Audio: ac3, 48000 Hz, stereo, fltp, 192 kb/s
Stream #3:2[0x1bf]: Data: dvd_nav_packet
[mpeg2video @ 0x7fe489027e00] Invalid frame dimensions 0x0.
Last message repeated 7 times
Input #4, mpeg, from '/Volumes/My Passport/Project/DVD_Files/VIDEO_TS/VTS_01_3.VOB':
Duration: 00:17:41.91, start: 2123.932000, bitrate: 8088 kb/s
Stream #4:0[0x1e0]: Video: mpeg2video (Main), yuv420p(tv, bottom first), 720x480 [SAR 8:9 DAR 4:3], 7758 kb/s, 29.97 fps, 29.97 tbr, 90k tbn, 59.94 tbc
Stream #4:1[0x80]: Audio: ac3, 48000 Hz, stereo, fltp, 192 kb/s
Stream #4:2[0x1bf]: Data: dvd_nav_packet
[mpeg2video @ 0x7fe48d007c00] Invalid frame dimensions 0x0.
Last message repeated 13 times
Input #5, mpeg, from '/Volumes/My Passport/Project/DVD_Files/VIDEO_TS/VTS_01_4.VOB':
Duration: 00:04:08.42, start: 3185.788000, bitrate: 8088 kb/s
Stream #5:0[0x1e0]: Video: mpeg2video (Main), yuv420p(tv, bottom first), 720x480 [SAR 8:9 DAR 4:3], 7758 kb/s, 29.97 fps, 29.97 tbr, 90k tbn, 59.94 tbc
Stream #5:1[0x80]: Audio: ac3, 48000 Hz, stereo, fltp, 192 kb/s
Stream #5:2[0x1bf]: Data: dvd_nav_packet
Input #6, mpeg, from '/Volumes/My Passport/Project/DVD_Files/VIDEO_TS/VTS_02_0.VOB':
Duration: 00:00:00.03, start: 0.060000, bitrate: 1964 kb/s
Stream #6:0[0x1bf]: Data: dvd_nav_packet
Stream #6:1[0x1e0]: Video: mpeg2video (Main), yuv420p(tv, smpte170m, progressive), 720x480 [SAR 8:9 DAR 4:3], 9000 kb/s, 29.97 tbr, 90k tbn, 59.94 tbc
Input #7, mpeg, from '/Volumes/My Passport/Project/DVD_Files/VIDEO_TS/VTS_02_1.VOB':
Duration: 00:00:32.38, start: 0.060000, bitrate: 8076 kb/s
Stream #7:0[0x1bf]: Data: dvd_nav_packet
Stream #7:1[0x1e0]: Video: mpeg2video (Main), yuv420p(tv, bottom first), 720x480 [SAR 8:9 DAR 4:3], 7758 kb/s, 29.97 fps, 29.97 tbr, 90k tbn, 59.94 tbc
Stream #7:2[0x80]: Audio: ac3, 48000 Hz, stereo, fltp, 192 kb/s
[AVFilterGraph @ 0x7fe488d06900] Too many inputs specified for the "nullsrc" filter.

I've the exact same problem and after some research I think that this kind of filters (judging by their syntax in vanilla ffmpeg) are only operating on inputs (-i parameter). Here is an example usage for such filter:
ffmpeg -f lavfi -i anullsrc=channel_layout=stereo:sample_rate=44100 -i video.mov
-shortest -c:v copy -c:a aac output.mov
Basically when you use audio.filter() you operate on some input that is defined as audio stream. That stream can only be a file from your PC that you provide file path for, or a stream taken out of your video.
It is worth to mention that there is #62 that I think would solve that problem but somehow it got stuck. It would be really nice if @kkroening could say anything about that.
I think the best way to solve that for now is to provide some dummy audio file and expanding its range to fit the video length.
Hmm, yeah we really should get #62 mergeable since it's a commonly requested feature. There are a few changes that are still needed on that branch, so I'll bump up the priority of it in my TODO list and try to get to it soon 🙂
Hey @kkroening! Any updates on this? Having issues using anullsrc too.
@kkroening @jbitton here is a code snippet for adding null audio
def generate_empty_audio(duration):
"""
it is used to generate an empty audio
Parameters
----------
duration : int/float
duration for the blank audio
Return
------
string
it will return the path of the generated empty audio
"""
try:
path = settings.MEDIA_ROOT + f"{str(uuid4())}_audio.aac"
stream = ffmpeg.input("anullsrc=cl=stereo:r=44100").output(path)
compiled = ffmpeg.compile(stream.audio, overwrite_output=True)
ffmpegargs = patch_audio(compiled, duration)
subprocess.run(ffmpegargs, stdout=subprocess.PIPE)
empty_audio.append(path)
return path
except ffmpeg.Error as e:
print(e.stderr)
raise Exception(str(e))
def patch_audio(arglist, duration):
"""
to make the command of ffmpeg for creation of blank audio
Parameters
----------
arglist : list
list of commands created by the python-ffmpeg
duration : int/float
duration for the blank audio
Return
------
list
it will return the list of command that would be compiled in the process.run
"""
try:
for i, arg in enumerate(arglist):
if arg == 'anullsrc=cl=stereo:r=44100':
return arglist[:i-1] + ['-f', 'lavfi'] + ['-t', f"{duration}"] + arglist[i-1:]
return arglist
except Exception as identifier:
raise Exception(str(identifier))
If you guys just want to add the pause in the start you can use for video set_pts(f"PTS-STARTPTS"+{<time in seconds here>/TB}) and for audio filter_('adelay', <time in miliseconds>)
audio_cmd = 'anullsrc=r=16000:cl=mono:d={}'.format(duration)
audio_stream = ffmpeg.input(audio_cmd, f='lavfi')
I add anullsrc in ffmpeg-python like above and works for me, in case anyone is still looking for solution to this in 2022