0

I have created a python script which creates audio trims of youtube videos using ffmpeg.

The script works fine for small videos of about <20m, however my intention is to use this for large videos most of which are several hours long. It appears ffmpeg may be streaming the entire audio while seeking the trim points, not only is this slow but it adds a lot of unnecessary network overhead, especially since the trims I'm making are barely a minute long.

Here is the script:

from yt_dlp import YoutubeDL as ydl
import ffmpeg, sys, getopt


default_url = "https://youtu.be/FtutLA63Cp8"
default_start = "6"
default_end = "36"


def get_secs(time_str) -> int:

    h = "0"
    m = "0"
    s = "0"

    time_hms = time_str.split(":")

    if len(time_hms) == 1:
        s = time_hms[0]
    elif len(time_hms) == 2:
        m, s = time_hms
    elif len(time_hms) == 3:
        h, m, s = time_hms

    secs = (int(h) * 3600) + (int(m) * 60) + int(s)
    return secs


# Extract Url
def get_url(url):

    ydl_opts = {}
    info = ydl(ydl_opts).extract_info(url, download=False)  # dict of lists
    # info = ydl.sanitize_info(info)

    title = info["title"].strip() + ".mp4"

    formats = info["formats"]  # list of dicts
    audio_direct_url = ""
    for format in formats:
        if format["audio_ext"] != "none":
            audio_direct_url = format["url"]
            break

    # return r["formats"][-1]["url"]
    return audio_direct_url, title


def snip_url(url, title, start, end):
    input = ffmpeg.input(url)
    pts = "PTS-STARTPTS"
    audio = input.filter_("atrim", start=start, end=end).filter_("asetpts", pts)
    out = ffmpeg.output(audio, ("out/" + title))

    return ffmpeg.run(out)


def mince():
    pass


def main(argv):
    usage_str = "main.py -u <url> -o <outputfile> -s <starttime> -t <stoptime>"
    target_url = ""
    out_filename = ""
    start_time = default_start
    stop_time = default_end

    try:
        opts, args = getopt.getopt(
            argv, "hu:o:s:t:", ["url=", "ofile=", "start=", "terminate="]
        )

    except getopt.GetoptError:
        print(usage_str)
        sys.exit(2)

    for opt, arg in opts:
        if opt == "-h":
            print(usage_str)
            sys.exit()
        elif opt in ("-u", "--url"):
            target_url = arg
        elif opt in ("-o", "--ofile"):
            out_filename = arg
        elif opt in ("-s", "--start"):
            start_time = arg
        elif opt in ("-t", "--terminate"):
            stop_time = arg

        if target_url == "":
            print(usage_str)
            sys.exit(2)

        # URLs may have seperators, remove them
        target_url = target_url.rsplit("?")[0]

    stream_url, title = get_url(target_url)
    if out_filename != "":
        title = out_filename
    start_time = get_secs(start_time)
    stop_time = get_secs(stop_time)
    snip_url(stream_url, title, start_time, stop_time)


if __name__ == "__main__":

    main(sys.argv[1:])

There is a similar question on this site, however this involves grabbing still frames and not audio sections.

I have also looked through both theffmpeg-python and regular ffmpeg documentation and not found anything relevant.

Is there a way to get ffmpeg to 'skip' to the desired trim position without streaming the entire audio? Preferrably using the ffmpeg-python library.

If not, are there ways I can reduce the bandwidth overhead and/or speed up this process.

I am also open to using other software (preferrably python libraries) similar to ffmpeg that can achieve the same task.

nash
  • 89
  • 2
  • 5
  • 1
    Have you tried `-ss` **input** option? If it works on streaming data, that's probably what you're looking for. – kesh Oct 24 '22 at 18:51

0 Answers0