File size: 6,173 Bytes
c16a803
 
d6ab5d0
07853df
6312c58
 
998c128
956b26b
 
 
e111c44
2569d41
eab3b6a
75926ea
a56389b
065d626
6312c58
 
 
eab3b6a
 
 
 
2569d41
 
 
 
 
eab3b6a
2569d41
 
eab3b6a
c16a803
40446f2
0343e3e
7028765
956b26b
 
 
 
 
 
e111c44
 
 
 
 
 
 
 
 
 
 
 
6c154f8
 
c16a803
6c154f8
 
79683ca
07853df
79683ca
c047e75
e4ed31e
cbd85fc
 
6312c58
6c154f8
 
 
 
3c753ee
07853df
1cec1d6
6c154f8
79683ca
68e8422
 
6ae4e58
30f78b0
 
68e8422
 
 
 
089efa9
1cec1d6
 
089efa9
6312c58
30f78b0
e9309ff
089efa9
e9309ff
 
 
 
 
 
089efa9
08bc846
d7f009b
1828f72
 
 
07853df
f34662a
6ae4e58
 
f34662a
0212a08
0343e3e
 
 
2d3ac4b
0343e3e
1794bc0
 
bd750f5
2d3ac4b
 
5a36eaa
0343e3e
1794bc0
78bfc84
1794bc0
 
b14e2a2
1794bc0
30f78b0
1794bc0
 
1229389
2d3ac4b
1229389
68e8422
1794bc0
30f78b0
f56e978
e111c44
1cec1d6
d7f009b
1cec1d6
b14e2a2
 
 
1cec1d6
d7f009b
e111c44
78bfc84
 
 
998c128
8913cb5
08bc846
998c128
6c154f8
6ae4e58
68299e3
08bc846
998c128
4d4e03c
0c7d1ac
6ae4e58
1229389
99535b7
5a3efb4
998c128
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
import logging
import requests
from urllib.parse import urlparse, quote_plus
import subprocess
from pathlib import Path
from moviepy.editor import VideoFileClip
import gradio as gr
import http.server
import socketserver
import threading
import socket
import boto3
import s3fs
import os 

# Define output directory
output_dir = Path.cwd() / "output"
output_dir.mkdir(exist_ok=True)

# Set S3 credentials
AWS_S3_BUCKET = os.getenv("AWS_S3_BUCKET")
AWS_ACCESS_KEY_ID = os.getenv("AWS_ACCESS_KEY_ID")
AWS_SECRET_ACCESS_KEY = os.getenv("AWS_SECRET_ACCESS_KEY")
session = boto3.Session(
    aws_access_key_id=AWS_ACCESS_KEY_ID,
    aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
    region_name='us-east-1'
)

s3 = session.client('s3')
fs = s3fs.S3FileSystem(anon=False, client_kwargs={'region_name': 'us-east-1'})

logging.basicConfig(level=logging.INFO)

standard_resolutions = [4320, 2160, 1440, 1080, 720, 480, 360, 240]

def start_http_server(port=8000):
    handler = http.server.SimpleHTTPRequestHandler
    httpd = socketserver.TCPServer(("", port), handler)
    logging.info(f"Serving at port {port}")
    thread = threading.Thread(target=httpd.serve_forever)
    thread.start()

def get_ip_address():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        s.connect(('10.255.255.255', 1))
        IP = s.getsockname()[0]
    except Exception:
        IP = '127.0.0.1'
    finally:
        s.close()
    return IP

def download_file(url, destination):
    response = requests.get(url)
    response.raise_for_status()
    with open(destination, 'wb') as f:
        f.write(response.content)

def get_input_path(video_file, video_url):
    if video_file is not None:
        return Path(video_file.name)
    elif video_url:
        url_path = urlparse(video_url).path
        file_name = Path(url_path).name
        destination = output_dir / file_name
        download_file(video_url, destination)
        return destination
    else:
        raise ValueError("No input was provided.")

def get_output_path(input_path, res):
    output_path = output_dir / f"{Path(input_path).stem}_{res}p.m3u8"
    return output_path

def create_master_playlist(output_paths, input_filename):
    master_playlist_path = output_dir / f"{input_filename}_master_playlist.m3u8"
    with open(master_playlist_path, "w") as f:
        f.write("#EXTM3U\n")
        for path in output_paths:
            res = Path(path).stem.split("_")[1]
            f.write(f'#EXT-X-STREAM-INF:BANDWIDTH=8000000,RESOLUTION={res}\n')
            # read the .m3u8 file and replace relative links with absolute links
            with open(path, 'r') as playlist_file:
                content = playlist_file.readlines()
            content = [line.replace('.ts', f'.ts\n') if line.endswith('.ts\n') else line for line in content]
            content = [f"{quote_plus(line.rstrip())}\n" if line.endswith('.ts\n') else line for line in content]
            f.writelines(content)
    return master_playlist_path

def upload_file_to_s3(file_path, s3_path):
    print(f"Uploading {file_path} to AWS at {s3_path}")
    with open(file_path, 'rb') as file:
        file_content = file.read()

    with fs.open(s3_path, 'wb') as file:
        file.write(file_content)


def convert_video(video_file, quality, aspect_ratio, video_url):
    # Ensure either a file or a URL is provided
    if not video_file and not video_url:
        raise ValueError("Please provide either a video file or a video URL.")
    
    input_path = get_input_path(video_file, video_url)
    video = VideoFileClip(str(input_path))

    # Get the original height to avoid upscaling
    original_height = video.size[1]

    # Get the original height to avoid upscaling
    original_height = video.size[1]

    output_paths = []
    for res in reversed(standard_resolutions):
        if res > original_height:
            continue

        scale = "-1:" + str(res)
        output_path = get_output_path(input_path, str(res) + 'p')

        # use a lower CRF value for better quality
        ffmpeg_command = [
            "ffmpeg", "-i", str(input_path), "-c:v", "libx264", "-crf", str(quality),
            "-vf", f"scale={scale}:force_original_aspect_ratio=decrease,pad=ceil(iw/2)*2:ceil(ih/2)*2",
            "-hls_time", "10", "-hls_playlist_type", "vod", "-hls_segment_filename",
            str(output_dir / f"{output_path.stem}_%03d.ts"), str(output_path)
        ]

        logging.info("Running ffmpeg command: " + ' '.join(ffmpeg_command))
        subprocess.run(ffmpeg_command, check=True)

        output_paths.append(output_path)

    master_playlist_path = create_master_playlist(output_paths, Path(input_path).stem)
    output_paths.append(master_playlist_path)

    output_links = []
    for path in output_paths:
        s3_path = f"s3://{AWS_S3_BUCKET}/{Path(input_path).stem}/{Path(path).name}"
        upload_file_to_s3(path, s3_path)
        output_links.append(f'<a href="https://{AWS_S3_BUCKET}.s3.amazonaws.com/{Path(input_path).stem}/{quote_plus(Path(path).name)}" target="_blank">Download {Path(path).stem}</a>')

    # upload ts files to s3
    for path in output_dir.glob(f"{Path(input_path).stem}_*p_*.ts"):
        s3_path = f"s3://{AWS_S3_BUCKET}/{Path(input_path).stem}/{Path(path).name}"
        upload_file_to_s3(path, s3_path)

    output_html = "<br>".join(output_links)
    return output_html

video_file = gr.inputs.File(label="Your video file")
quality = gr.inputs.Slider(minimum=0, maximum=51, default=23, label="Quality (0: Highest Quality - 50: Fastest)")
aspect_ratio = gr.inputs.Dropdown(["16:9", "4:3", "1:1", "3:4", "9:16", "1:1", "2:1", "1:2"], label="Aspect Ratio", default="16:9")
video_url = gr.inputs.Textbox(lines=1, placeholder="or paste video url here", label="Video URL")

interface = gr.Interface(
    fn=convert_video, 
    inputs=[video_file, quality, aspect_ratio, video_url],
    outputs=gr.outputs.HTML(label="Download Links"),
    title="NEAR Hub Video Transcoder to m3u8",
    description="convert video files to m3u8 for VOD streaming in nearhub.club.",
    allow_flagging='never'
)

start_http_server()
interface.launch(server_name=get_ip_address(), server_port=7860)