Search code examples
pythonffmpegstreaming

FFMPEG How to extract sound from a video and combine it with a picture


I use this code,but the picture is not visible :(:
os.system(f'ffmpeg -stream_loop -1 -re -i {dir_path}/maxresdefault.jpg -re -i "{url}" -c:v libx264 -preset superfast -b:v 2500k -bufsize 3000k -maxrate 5000k -c:a aac -ar 44100 -b:a 128k -pix_fmt yuv420p -f flv rtmp://a.rtmp.youtube.com/live2/###########')
this main part of code:

 p=Playlist("https://www.youtube.com/playlist?list=PLSVhVwIpndKJyjEltpgM37o-OoH1p1840")
for video in p.videos[4:len(p.videos)]:
    url=""
    while True:
        try:
            url=video.streams.get_highest_resolution().url
            
            break
        except:
            continue
    print(video.title)
    ffmpeg(url)##code,that i wrote upper

url is youtube video


Solution

  • It looks like -stream_loop is not working as it supposed to work (I don't know the reason).

    • Add -f image2 before -i im001.jpg - force FFmpeg to get the input as an image (it supposed to be the default, but I think there is an issue when using -stream_loop).
    • Remove the -re from the video input (I think there is an issue when using -re with -stream_loop).
    • Add -r 1 for setting the frame rate of the input to 1Hz (it is not a must, but the default framerate is too high for a single image).
    • Add -vn before the audio input - make sure FFmpeg doesn't decode the video from the URL (in case there is a video stream).
    • I added -vf "setpts=N/1/TB" -af "asetpts=PTS-STARTPTS" -map:v 0:v -map:a 1:a for correcting the timestamps and the mapping (we probably don't need it). The 1 in "setpts=N/1/TB" is the video framerate.
    • I added -bsf:v dump_extra (I think we need it for FLV streaming).
    • Add -shortest -fflags +shortest for quitting when the audio ends.

    I don't know how to stream it to YouTube.
    I used localhost and FFplay as a listener (it takes some time for the video to appear).


    Here is the complete code sample:

    from pytube import YouTube, Playlist
    import subprocess as sp
    import os
    
    p = Playlist("https://www.youtube.com/playlist?list=PLSVhVwIpndKJyjEltpgM37o-OoH1p1840")
    
    rtmp_url = "rtmp://127.0.0.1:1935/live/test" # Used localhost for testing (instead of streaming to YouTube).
    
    for video in p.videos[4:len(p.videos)]:
        url=""
        while True:
            try:
                url=video.streams.get_highest_resolution().url
                break
            except:
                continue
        print(video.title)
    
        # Start the TCP server first, before the sending client.
        ffplay_process = sp.Popen(['ffplay', '-listen', '1', '-i', rtmp_url])  # Use FFplay sub-process for receiving the RTMP video.
    
        os.system(f'ffmpeg -r 1 -stream_loop -1 -f image2 -i maxresdefault.jpg -re -vn -i "{url}" -vf "setpts=N/1/TB" -af "asetpts=PTS-STARTPTS" -map:v 0:v -map:a 1:a -c:v libx264 -preset superfast -b:v 2500k -bufsize 5000k -maxrate 5000k -pix_fmt yuv420p -c:a aac -ar 44100 -b:a 128k -shortest -fflags +shortest -f flv -bsf:v dump_extra {rtmp_url}')
    
        ffplay_process.kill()  # Forcefully terminate FFplay sub-process.
    

    Please make sure it's working with FFplay first (it supposed to be reproducible).
    Replace rtmp_url in my example with rtmp://a.rtmp.youtube.com/live2/###########.