File size: 1,838 Bytes
4c5f593
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c84d708
4c5f593
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import subprocess

import numpy as np


def ffmpeg_stream(youtube_url, sampling_rate=16_000, chunk_duration_ms=5000, pad_duration_ms=200):
    """
    Helper function to read an audio file through ffmpeg.
    """
    chunk_len = int(sampling_rate * chunk_duration_ms / 1000)
    pad_len = int(sampling_rate * pad_duration_ms / 1000)
    read_chunk_len = chunk_len + pad_len * 2

    ar = f"{sampling_rate}"
    ac = "1"
    format_for_conversion = "f32le"
    dtype = np.float32
    size_of_sample = 4

    ffmpeg_command = [
        "ffmpeg",
        "-i",
        "pipe:",
        "-ac",
        ac,
        "-ar",
        ar,
        "-f",
        format_for_conversion,
        "-hide_banner",
        "-loglevel",
        "quiet",
        "pipe:1",
    ]

    ytdl_command = ["yt-dlp", "-f", "bestaudio", youtube_url, "--quiet", "-o", "-"]

    try:
        ffmpeg_process = subprocess.Popen(ffmpeg_command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, bufsize=-1)
        ytdl_process = subprocess.Popen(ytdl_command, stdout=ffmpeg_process.stdin)
    except FileNotFoundError:
        raise ValueError("ffmpeg was not found but is required to stream audio files from filename")

    acc = b""
    leftover = np.zeros((0,), dtype=np.float32)
    while ytdl_process.poll() is None:
        buflen = read_chunk_len * size_of_sample

        raw = ffmpeg_process.stdout.read(buflen)
        if raw == b"":
            break

        if len(acc) + len(raw) > buflen:
            acc = raw
        else:
            acc += raw

        audio = np.frombuffer(acc, dtype=dtype)
        audio = np.concatenate([leftover, audio])
        if len(audio) < pad_len * 2:
            # TODO: handle end of stream better than this
            break
        yield audio

        leftover = audio[-pad_len * 2 :]
        read_chunk_len = chunk_len