pythonffmpegvideo-subtitles

how to add subtitles in video with ffmpeg filter?


I am having hard time adding .srt subtitles to the newly creating video. I am using Python.

subtitles:

f"{PROJECT_PATH}/data/subtitles/final_subtitle_srt/all_slides.srt"

I have checked they are correct.

pieces of my code that does not work:

audio = f'{PROJECT_PATH}/data/ppt-elements/audio_{file_id}.txt'
        images = f'{PROJECT_PATH}/data/ppt-elements/images_{file_id}.txt'

        image_input = ffmpeg.input(images, f='concat', safe=0, t=seconds).video
        audio_input = ffmpeg.input(audio, f='concat', safe=0, t=seconds).audio

inputs = [image_input, audio_input]
 
command = (
            ffmpeg.filter('subtitles', f"{PROJECT_PATH}/data/subtitles/final_subtitle_srt/all_slides.srt")
            .output(*inputs,f"{PROJECT_PATH}/data/subtitles/final_subtitle_srt_all_slides.srt", 
                f"{PROJECT_PATH}/data/final-{file_id}.mp4", 
                vf="fps=10,format=yuv420p",
                preset="veryfast", 
                shortest=None, 
                r=10, 
                max_muxing_queue_size=4000,
                **additional_parameters,
            )
)

Am I using subtitles filter well?


Solution

  • subtitles filter applies the video, we may use it as follows:

    image_input = ffmpeg.input(images, r=fps, f='concat', safe=0, t=seconds).video.filter('subtitles', f"{PROJECT_PATH}/all_slides.srt") 
    

    In case there are other video filters to be chain we may chain the filters:

    image_input = ffmpeg.input(images, r=fps, f='concat', safe=0, t=seconds).video.filter('fps', fps=fps).filter('format', pix_fmts='yuv420p').filter('subtitles', f"{PROJECT_PATH}/all_slides.srt")
    

    We don't need to pass the subtitles stream as an input stream (use the subtitles only in the subtitles filter).


    Code sample:

    import ffmpeg
    
    PROJECT_PATH = '/Tmp/ffmpeg'
    file_id = '1'
    audio = f'{PROJECT_PATH}/audio_{file_id}.txt'
    images = f'{PROJECT_PATH}/images_{file_id}.txt'
    seconds = 10
    fps = 10
    
    #image_input = ffmpeg.input(images, r=fps, f='concat', safe=0, t=seconds).video.filter('fps', fps=fps).filter('format', pix_fmts='yuv420p').filter('subtitles', f"{PROJECT_PATH}/all_slides.srt")
    image_input = ffmpeg.input(images, r=fps, f='concat', safe=0, t=seconds).video.filter('subtitles', f"{PROJECT_PATH}/all_slides.srt")
    audio_input = ffmpeg.input(audio, f='concat', safe=0, t=seconds).audio
    
    command = (
        ffmpeg.
        output(image_input, audio_input, f"{PROJECT_PATH}/final-{file_id}.mp4",
        vcodec='libx264',    
        preset="veryfast", 
        acodec='aac',
        shortest=None,
        #r=fps,
        max_muxing_queue_size=4000)
        .global_args('-report')  # Create a report file
    )
    
    command.overwrite_output().run()
    

    Note that concatenating images using concat demuxer is not a good practice because images don't have timetags.
    I recommend you to rename the images to numbered sequence 0001.png, 0002.png, 0003.png... and use ffmpeg.input('%04d', r=fps, ...) without fps filter and without r=fps for the output.