Artyom Boyko commited on
Commit
a8de063
·
1 Parent(s): a8e639d

Replacing the OS to Ubuntu 24.04 and fixing the current results.

Browse files
Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- FROM python:3.12.10-bookworm
2
 
3
  # ENV PIP_ROOT_USER_ACTION=ignore
4
  ARG USERNAME=mcp_user
@@ -10,26 +10,30 @@ WORKDIR /tmp/
10
  COPY requirements.txt packages.txt ./
11
 
12
  RUN apt-get -y update && apt-get -y upgrade && xargs apt -y install < packages.txt
13
- RUN pip install --no-cache-dir --upgrade pip
14
 
15
- # Install CUDA 12.8
16
 
17
- RUN wget https://developer.download.nvidia.com/compute/cuda/repos/debian12/x86_64/cuda-keyring_1.1-1_all.deb \
 
18
  && dpkg -i cuda-keyring_1.1-1_all.deb \
19
  && apt-get update \
20
  && apt-get -y install cuda-toolkit-12-8
21
 
 
 
22
  # https://docs.nvidia.com/cuda/cuda-installation-guide-linux/#post-installation-actions
23
  ENV PATH=/usr/local/cuda-12.8/bin:${PATH}
24
  ENV LD_LIBRARY_PATH=/usr/local/cuda-12.8/lib64:/usr/lib/x86_64-linux-gnu/
25
 
26
 
27
  # Install cuDNN for CUDA 12
28
- RUN wget https://developer.download.nvidia.com/compute/cuda/repos/debian12/x86_64/cuda-keyring_1.1-1_all.deb \
29
  && dpkg -i cuda-keyring_1.1-1_all.deb \
30
  && apt-get update \
31
  && apt-get -y install cudnn-cuda-12
32
 
 
 
 
33
  # Install Pytorch for CUDA 12.8
34
  RUN pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu128
35
 
@@ -41,6 +45,9 @@ RUN pip3 install --no-cache-dir -r requirements.txt
41
  RUN apt-get clean
42
  RUN rm -rf /tmp/*
43
 
 
 
 
44
  # https://huggingface.co/docs/hub/spaces-sdks-docker#permissions
45
  # Set up a new user named "user" with user ID 1000
46
  RUN useradd -m -u $USER_UID $USERNAME
 
1
+ FROM ubuntu:latest
2
 
3
  # ENV PIP_ROOT_USER_ACTION=ignore
4
  ARG USERNAME=mcp_user
 
10
  COPY requirements.txt packages.txt ./
11
 
12
  RUN apt-get -y update && apt-get -y upgrade && xargs apt -y install < packages.txt
 
13
 
 
14
 
15
+ # Install CUDA 12.8
16
+ RUN wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/x86_64/cuda-keyring_1.1-1_all.deb \
17
  && dpkg -i cuda-keyring_1.1-1_all.deb \
18
  && apt-get update \
19
  && apt-get -y install cuda-toolkit-12-8
20
 
21
+
22
+
23
  # https://docs.nvidia.com/cuda/cuda-installation-guide-linux/#post-installation-actions
24
  ENV PATH=/usr/local/cuda-12.8/bin:${PATH}
25
  ENV LD_LIBRARY_PATH=/usr/local/cuda-12.8/lib64:/usr/lib/x86_64-linux-gnu/
26
 
27
 
28
  # Install cuDNN for CUDA 12
29
+ RUN wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/x86_64/cuda-keyring_1.1-1_all.deb \
30
  && dpkg -i cuda-keyring_1.1-1_all.deb \
31
  && apt-get update \
32
  && apt-get -y install cudnn-cuda-12
33
 
34
+ # Remove EXTERNALLY-MANAGED
35
+ RUN rm -f /usr/lib/python3.12/EXTERNALLY-MANAGED
36
+
37
  # Install Pytorch for CUDA 12.8
38
  RUN pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu128
39
 
 
45
  RUN apt-get clean
46
  RUN rm -rf /tmp/*
47
 
48
+ # Delet exist user with UID 1000
49
+ RUN userdel -r ubuntu || true
50
+
51
  # https://huggingface.co/docs/hub/spaces-sdks-docker#permissions
52
  # Set up a new user named "user" with user ID 1000
53
  RUN useradd -m -u $USER_UID $USERNAME
app_srv/downloader.py ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import yt_dlp
2
+ import os
3
+ import uuid
4
+ import json
5
+ from pathlib import Path
6
+ from typing import Dict, Any
7
+ from datetime import datetime
8
+
9
+ def download_youtube_media(url: str, base_dir: str = "./downloads") -> Dict[str, Any]:
10
+ """
11
+ Downloads video and audio from YouTube, saving them to a unique GUID folder.
12
+ Metadata is saved in JSON format including download datetime and timezone.
13
+
14
+ Args:
15
+ url (str): YouTube video URL
16
+ base_dir (str): Base download directory (default './downloads')
17
+
18
+ Returns:
19
+ dict: Dictionary with file paths and information:
20
+ {
21
+ 'data_path': str, # Path to download directory
22
+ 'video_path': str, # Full path to video.mp4
23
+ 'audio_path': str, # Full path to audio.mp3
24
+ 'metadata_path': str # Full path to metadata.json
25
+ }
26
+
27
+ Raises:
28
+ RuntimeError: If download fails
29
+ """
30
+ try:
31
+ # Generate GUID and create folder
32
+ guid = str(uuid.uuid4())
33
+ download_dir = Path(base_dir) / guid
34
+ os.makedirs(download_dir, exist_ok=True)
35
+
36
+ # File paths
37
+ video_path = download_dir / "video.mp4"
38
+ audio_path = download_dir / "audio.mp3"
39
+ metadata_path = download_dir / "metadata.json"
40
+
41
+ # Record exact download start time
42
+ download_datetime = datetime.now()
43
+ current_timezone = download_datetime.astimezone().tzinfo
44
+
45
+ # 1. Download video (MP4)
46
+ video_opts = {
47
+ 'format': (
48
+ "bestvideo[height=720][ext=mp4]"
49
+ "/worstvideo[height>720][ext=mp4]"
50
+ "/bestvideo[height<=720][ext=mp4]"
51
+ ),
52
+ 'outtmpl': str(video_path),
53
+ 'quiet': True,
54
+ 'no_warnings': False,
55
+ 'restrict_filenames': True,
56
+ }
57
+
58
+ with yt_dlp.YoutubeDL(video_opts) as ydl:
59
+ video_info = ydl.extract_info(url, download=True)
60
+
61
+ # 2. Download audio (MP3)
62
+ audio_opts = {
63
+ 'format': 'bestaudio/best',
64
+ 'outtmpl': str(audio_path),
65
+ 'quiet': True,
66
+ 'postprocessors': [{
67
+ 'key': 'FFmpegExtractAudio',
68
+ 'preferredcodec': 'mp3',
69
+ 'preferredquality': '128',
70
+ }],
71
+ }
72
+
73
+ with yt_dlp.YoutubeDL(audio_opts) as ydl:
74
+ audio_info = ydl.extract_info(url, download=True)
75
+
76
+ # Format date and time for storage
77
+ formatted_date = download_datetime.strftime('%Y-%m-%d')
78
+ formatted_time = download_datetime.strftime('%H:%M:%S')
79
+
80
+ # 3. Save metadata to JSON
81
+ metadata = {
82
+ 'original_url': url,
83
+ 'guid': guid,
84
+ 'download_info': {
85
+ 'date': formatted_date,
86
+ 'time': formatted_time,
87
+ 'timezone': str(current_timezone),
88
+ 'datetime_iso': download_datetime.isoformat(),
89
+ },
90
+ 'video': {
91
+ 'path': str(video_path),
92
+ 'title': video_info.get('title'),
93
+ 'duration': video_info.get('duration'),
94
+ 'resolution': video_info.get('resolution'),
95
+ 'upload_date': video_info.get('upload_date'),
96
+ },
97
+ 'audio': {
98
+ 'path': str(audio_path),
99
+ 'bitrate': audio_info.get('abr'),
100
+ 'codec': 'mp3',
101
+ },
102
+ }
103
+
104
+ with open(metadata_path, 'w', encoding='utf-8') as f:
105
+ json.dump(metadata, f, indent=2, ensure_ascii=False)
106
+
107
+ return {
108
+ 'data_path': str(download_dir),
109
+ 'video_path': str(video_path),
110
+ 'audio_path': str(audio_path) + ".mp3",
111
+ 'metadata_path': str(metadata_path),
112
+ }
113
+
114
+ except Exception as e:
115
+ raise RuntimeError(f"Media download error: {str(e)}")
116
+
117
+ if __name__ == "__main__":
118
+ video_url = "https://www.youtube.com/watch?v=FK3dav4bA4s"
119
+ result = download_youtube_media(video_url, "./temp")
120
+ print(result)
app_srv/test.ipynb ADDED
@@ -0,0 +1,431 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "7f265e58",
6
+ "metadata": {},
7
+ "source": [
8
+ "# Download video and audio from YouTube"
9
+ ]
10
+ },
11
+ {
12
+ "cell_type": "code",
13
+ "execution_count": null,
14
+ "id": "69ee0ec3",
15
+ "metadata": {},
16
+ "outputs": [],
17
+ "source": [
18
+ "import yt_dlp\n",
19
+ "import os\n",
20
+ "import uuid\n",
21
+ "import json\n",
22
+ "from pathlib import Path\n",
23
+ "from typing import Dict, Any\n",
24
+ "from datetime import datetime\n",
25
+ "\n",
26
+ "def download_youtube_media(url: str, base_dir: str = \"./downloads\") -> Dict[str, Any]:\n",
27
+ " \"\"\"\n",
28
+ " Downloads video and audio from YouTube, saving them to a unique GUID folder.\n",
29
+ " Metadata is saved in JSON format including download datetime and timezone.\n",
30
+ " \n",
31
+ " Args:\n",
32
+ " url (str): YouTube video URL\n",
33
+ " base_dir (str): Base download directory (default './downloads')\n",
34
+ " \n",
35
+ " Returns:\n",
36
+ " dict: Dictionary with file paths and information:\n",
37
+ " {\n",
38
+ " 'data_path': str, # Path to download directory\n",
39
+ " 'video_path': str, # Full path to video.mp4\n",
40
+ " 'audio_path': str, # Full path to audio.mp3\n",
41
+ " 'metadata_path': str # Full path to metadata.json\n",
42
+ " }\n",
43
+ " \n",
44
+ " Raises:\n",
45
+ " RuntimeError: If download fails\n",
46
+ " \"\"\"\n",
47
+ " try:\n",
48
+ " # Generate GUID and create folder\n",
49
+ " guid = str(uuid.uuid4())\n",
50
+ " download_dir = Path(base_dir) / guid\n",
51
+ " os.makedirs(download_dir, exist_ok=True)\n",
52
+ " \n",
53
+ " # File paths\n",
54
+ " video_path = download_dir / \"video.mp4\"\n",
55
+ " audio_path = download_dir / \"audio.mp3\"\n",
56
+ " metadata_path = download_dir / \"metadata.json\"\n",
57
+ "\n",
58
+ " # Record exact download start time\n",
59
+ " download_datetime = datetime.now()\n",
60
+ " current_timezone = download_datetime.astimezone().tzinfo\n",
61
+ " \n",
62
+ " # 1. Download video (MP4)\n",
63
+ " video_opts = {\n",
64
+ " 'format': (\n",
65
+ " \"bestvideo[height=720][ext=mp4]\"\n",
66
+ " \"/worstvideo[height>720][ext=mp4]\"\n",
67
+ " \"/bestvideo[height<=720][ext=mp4]\"\n",
68
+ " ),\n",
69
+ " 'outtmpl': str(video_path),\n",
70
+ " 'quiet': True,\n",
71
+ " 'no_warnings': False,\n",
72
+ " 'restrict_filenames': True,\n",
73
+ " }\n",
74
+ " \n",
75
+ " with yt_dlp.YoutubeDL(video_opts) as ydl:\n",
76
+ " video_info = ydl.extract_info(url, download=True)\n",
77
+ " \n",
78
+ " # 2. Download audio (MP3)\n",
79
+ " audio_opts = {\n",
80
+ " 'format': 'bestaudio/best',\n",
81
+ " 'outtmpl': str(audio_path),\n",
82
+ " 'quiet': True,\n",
83
+ " 'postprocessors': [{\n",
84
+ " 'key': 'FFmpegExtractAudio',\n",
85
+ " 'preferredcodec': 'mp3',\n",
86
+ " 'preferredquality': '128',\n",
87
+ " }],\n",
88
+ " }\n",
89
+ " \n",
90
+ " with yt_dlp.YoutubeDL(audio_opts) as ydl:\n",
91
+ " audio_info = ydl.extract_info(url, download=True)\n",
92
+ " \n",
93
+ " # Format date and time for storage\n",
94
+ " formatted_date = download_datetime.strftime('%Y-%m-%d')\n",
95
+ " formatted_time = download_datetime.strftime('%H:%M:%S')\n",
96
+ " \n",
97
+ " # 3. Save metadata to JSON\n",
98
+ " metadata = {\n",
99
+ " 'original_url': url,\n",
100
+ " 'guid': guid,\n",
101
+ " 'download_info': {\n",
102
+ " 'date': formatted_date,\n",
103
+ " 'time': formatted_time,\n",
104
+ " 'timezone': str(current_timezone),\n",
105
+ " 'datetime_iso': download_datetime.isoformat(),\n",
106
+ " },\n",
107
+ " 'video': {\n",
108
+ " 'path': str(video_path),\n",
109
+ " 'title': video_info.get('title'),\n",
110
+ " 'duration': video_info.get('duration'),\n",
111
+ " 'resolution': video_info.get('resolution'),\n",
112
+ " 'upload_date': video_info.get('upload_date'),\n",
113
+ " },\n",
114
+ " 'audio': {\n",
115
+ " 'path': str(audio_path),\n",
116
+ " 'bitrate': audio_info.get('abr'),\n",
117
+ " 'codec': 'mp3',\n",
118
+ " },\n",
119
+ " }\n",
120
+ " \n",
121
+ " with open(metadata_path, 'w', encoding='utf-8') as f:\n",
122
+ " json.dump(metadata, f, indent=2, ensure_ascii=False)\n",
123
+ " \n",
124
+ " return {\n",
125
+ " 'data_path': str(download_dir.absolute()),\n",
126
+ " 'video_path': str(video_path.absolute()),\n",
127
+ " 'audio_path': str(audio_path.absolute()) + \".mp3\",\n",
128
+ " 'metadata_path': str(metadata_path),\n",
129
+ " }\n",
130
+ " \n",
131
+ " except Exception as e:\n",
132
+ " raise RuntimeError(f\"Media download error: {str(e)}\")\n",
133
+ "\n",
134
+ "if __name__ == \"__main__\":\n",
135
+ " video_url = \"https://www.youtube.com/watch?v=FK3dav4bA4s\"\n",
136
+ " downloaded_video = download_youtube_media(video_url, \"./temp\")\n",
137
+ " print(downloaded_video)"
138
+ ]
139
+ },
140
+ {
141
+ "cell_type": "markdown",
142
+ "id": "f62e8b83",
143
+ "metadata": {},
144
+ "source": [
145
+ "# Split video to frames in jpg"
146
+ ]
147
+ },
148
+ {
149
+ "cell_type": "code",
150
+ "execution_count": 46,
151
+ "id": "93ab88d9",
152
+ "metadata": {},
153
+ "outputs": [
154
+ {
155
+ "name": "stdout",
156
+ "output_type": "stream",
157
+ "text": [
158
+ "{}\n"
159
+ ]
160
+ },
161
+ {
162
+ "name": "stderr",
163
+ "output_type": "stream",
164
+ "text": [
165
+ "[av1 @ 0x55a7f1349040] Your platform doesn't suppport hardware accelerated AV1 decoding.\n",
166
+ "[av1 @ 0x55a7f1349040] Failed to get pixel format.\n",
167
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
168
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
169
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
170
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
171
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
172
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
173
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
174
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
175
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
176
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
177
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
178
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
179
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
180
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
181
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
182
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
183
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
184
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
185
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
186
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
187
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
188
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
189
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
190
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
191
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
192
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
193
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
194
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
195
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
196
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
197
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
198
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
199
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
200
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
201
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
202
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
203
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
204
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
205
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
206
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
207
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
208
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
209
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
210
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
211
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
212
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
213
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
214
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
215
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
216
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
217
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
218
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
219
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
220
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
221
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
222
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
223
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
224
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
225
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
226
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
227
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
228
+ "[av1 @ 0x55a7f1349040] Your platform doesn't suppport hardware accelerated AV1 decoding.\n",
229
+ "[av1 @ 0x55a7f1349040] Failed to get pixel format.\n",
230
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
231
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
232
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
233
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
234
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
235
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
236
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
237
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
238
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
239
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
240
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
241
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
242
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
243
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
244
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
245
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
246
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
247
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
248
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
249
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
250
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
251
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
252
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
253
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
254
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
255
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
256
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
257
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
258
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
259
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
260
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
261
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
262
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
263
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
264
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
265
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
266
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
267
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
268
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
269
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
270
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
271
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
272
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
273
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
274
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
275
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
276
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
277
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
278
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
279
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
280
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
281
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
282
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
283
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
284
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
285
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
286
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
287
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
288
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
289
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
290
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
291
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
292
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
293
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
294
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
295
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
296
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
297
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
298
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
299
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
300
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
301
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
302
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
303
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
304
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
305
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
306
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
307
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
308
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
309
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
310
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
311
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
312
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
313
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
314
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
315
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
316
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
317
+ "[av1 @ 0x55a7f1349040] Missing Sequence Header.\n",
318
+ "[av1 @ 0x55a7f34683c0] Your platform doesn't suppport hardware accelerated AV1 decoding.\n",
319
+ "[av1 @ 0x55a7f34683c0] Failed to get pixel format.\n"
320
+ ]
321
+ }
322
+ ],
323
+ "source": [
324
+ "import os\n",
325
+ "from pathlib import Path\n",
326
+ "from typing import Dict\n",
327
+ "import cv2\n",
328
+ "\n",
329
+ "def extract_frames_with_timestamps(\n",
330
+ " video_path: str,\n",
331
+ " output_dir: str,\n",
332
+ " time_step: float = 1.0,\n",
333
+ " quality: int = 95,\n",
334
+ " frame_prefix: str = \"frame\"\n",
335
+ ") -> Dict[str, str]:\n",
336
+ " \"\"\"\n",
337
+ " Extracts frames from video at specified time intervals using OpenCV.\n",
338
+ " \n",
339
+ " Args:\n",
340
+ " video_path: Full path to the video file\n",
341
+ " output_dir: Directory where 'frames' subfolder will be created\n",
342
+ " time_step: Interval in seconds between captured frames\n",
343
+ " quality: JPEG quality (1-100)\n",
344
+ " frame_prefix: Prefix for frame filenames\n",
345
+ "\n",
346
+ " Returns:\n",
347
+ " Dictionary mapping timestamps (HH:MM:SS) to frame paths\n",
348
+ " \"\"\"\n",
349
+ " result = {}\n",
350
+ " \n",
351
+ " try:\n",
352
+ " video_path = Path(video_path).absolute()\n",
353
+ " output_dir = Path(output_dir).absolute()\n",
354
+ " \n",
355
+ " if not video_path.exists():\n",
356
+ " raise ValueError(f\"Video file not found: {video_path}\")\n",
357
+ "\n",
358
+ " frames_dir = output_dir / \"frames\"\n",
359
+ " frames_dir.mkdir(parents=True, exist_ok=True)\n",
360
+ "\n",
361
+ " # Initialize video capture\n",
362
+ " cap = cv2.VideoCapture(str(video_path))\n",
363
+ " if not cap.isOpened():\n",
364
+ " raise RuntimeError(\"Could not open video file\")\n",
365
+ "\n",
366
+ " fps = cap.get(cv2.CAP_PROP_FPS)\n",
367
+ " if fps <= 0:\n",
368
+ " raise RuntimeError(\"Invalid frame rate\")\n",
369
+ "\n",
370
+ " frame_interval = max(1, int(round(fps * time_step)))\n",
371
+ " frame_count = 0\n",
372
+ "\n",
373
+ " while True:\n",
374
+ " ret, frame = cap.read()\n",
375
+ " if not ret:\n",
376
+ " break\n",
377
+ "\n",
378
+ " if frame_count % frame_interval == 0:\n",
379
+ " current_time = frame_count / fps\n",
380
+ " hh = int(current_time // 3600)\n",
381
+ " mm = int((current_time % 3600) // 60)\n",
382
+ " ss = current_time % 60\n",
383
+ " \n",
384
+ " timestamp = f\"{hh:02d}:{mm:02d}:{ss:06.3f}\"\n",
385
+ " safe_timestamp = timestamp.replace(':', '_').replace('.', '_')\n",
386
+ " frame_path = frames_dir / f\"{frame_prefix}_{safe_timestamp}.jpg\"\n",
387
+ " \n",
388
+ " if cv2.imwrite(str(frame_path), frame, [cv2.IMWRITE_JPEG_QUALITY, quality]):\n",
389
+ " result[timestamp] = str(frame_path)\n",
390
+ "\n",
391
+ " frame_count += 1\n",
392
+ "\n",
393
+ " cap.release()\n",
394
+ " return result\n",
395
+ "\n",
396
+ " except Exception as e:\n",
397
+ " for path in result.values():\n",
398
+ " try: os.remove(path)\n",
399
+ " except: pass\n",
400
+ " raise RuntimeError(f\"Frame extraction failed: {str(e)}\")\n",
401
+ "\n",
402
+ "\n",
403
+ "if __name__ == \"__main__\":\n",
404
+ " result = extract_frames_with_timestamps(\"/workspaces/Video_Analyser/app_srv/temp/3dee4d5e-b1f7-40f4-b4c6-84e55ad7d7b4/video.mp4\", \"/workspaces/Video_Analyser/app_srv/temp/3dee4d5e-b1f7-40f4-b4c6-84e55ad7d7b4\")\n",
405
+ "\n",
406
+ " print(result)"
407
+ ]
408
+ }
409
+ ],
410
+ "metadata": {
411
+ "kernelspec": {
412
+ "display_name": "Python 3",
413
+ "language": "python",
414
+ "name": "python3"
415
+ },
416
+ "language_info": {
417
+ "codemirror_mode": {
418
+ "name": "ipython",
419
+ "version": 3
420
+ },
421
+ "file_extension": ".py",
422
+ "mimetype": "text/x-python",
423
+ "name": "python",
424
+ "nbconvert_exporter": "python",
425
+ "pygments_lexer": "ipython3",
426
+ "version": "3.12.10"
427
+ }
428
+ },
429
+ "nbformat": 4,
430
+ "nbformat_minor": 5
431
+ }
app_srv/video_processor.py ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sys
3
+ from pathlib import Path
4
+ from typing import Optional, Tuple
5
+ import PyNvVideoCodec as nvc
6
+
7
+ def extract_frames_from_video(
8
+ video_path: str,
9
+ output_dir: str,
10
+ time_step: float = 1.0,
11
+ quality: int = 95,
12
+ frame_prefix: str = "frame_"
13
+ ) -> Optional[str]:
14
+ """
15
+ Extracts frames from MP4 video at specified time intervals using PyNvVideoCodec (NVIDIA GPU acceleration).
16
+
17
+ Args:
18
+ video_path: Full path to the MP4 video file.
19
+ output_dir: Directory where 'frames' subfolder will be created.
20
+ time_step: Interval in seconds between captured frames (can be fractional).
21
+ quality: JPEG quality (1-100).
22
+ frame_prefix: Prefix for frame filenames.
23
+
24
+ Returns:
25
+ Path to the frames directory if successful, None otherwise.
26
+
27
+ Raises:
28
+ ValueError: If input parameters are invalid.
29
+ RuntimeError: If frame extraction fails.
30
+ """
31
+ try:
32
+ # Validate input parameters
33
+ video_path = Path(video_path)
34
+ if not video_path.exists():
35
+ raise ValueError(f"Video file not found: {video_path}")
36
+ if not video_path.suffix.lower() == '.mp4':
37
+ raise ValueError("Input file must be an MP4 video")
38
+
39
+ if time_step <= 0:
40
+ raise ValueError("time_step must be positive")
41
+ if quality < 1 or quality > 100:
42
+ raise ValueError("quality must be between 1 and 100")
43
+
44
+ # Create output directory
45
+ frames_dir = Path(output_dir) / "frames"
46
+ frames_dir.mkdir(parents=True, exist_ok=True)
47
+
48
+ # Initialize NVDecoder
49
+ nv_dec = nvc.PyNvDecoder(str(video_path), 0) # 0 = GPU device ID
50
+
51
+ # Get video info
52
+ width = nv_dec.Width()
53
+ height = nv_dec.Height()
54
+ fps = nv_dec.Framerate()
55
+ total_frames = nv_dec.Framecount()
56
+ duration = total_frames / fps if fps > 0 else 0
57
+
58
+ print(f"Video Info: {width}x{height}, FPS: {fps:.2f}, Duration: {duration:.2f}s")
59
+
60
+ # Calculate frame interval based on time_step
61
+ frame_interval = int(round(fps * time_step))
62
+ if frame_interval < 1:
63
+ frame_interval = 1
64
+
65
+ frame_count = 0
66
+ saved_count = 0
67
+
68
+ # Process frames
69
+ while True:
70
+ # Decode frame
71
+ raw_frame = nv_dec.DecodeSingleFrame()
72
+ if raw_frame.empty():
73
+ break # End of video
74
+
75
+ # Save frame at specified intervals
76
+ if frame_count % frame_interval == 0:
77
+ output_path = frames_dir / f"{frame_prefix}{saved_count:06d}.jpg"
78
+ success = nvc.ConvertToJpeg(raw_frame, str(output_path), quality)
79
+ if not success:
80
+ print(f"Failed to save frame {frame_count}", file=sys.stderr)
81
+ else:
82
+ saved_count += 1
83
+
84
+ frame_count += 1
85
+
86
+ print(f"Extracted {saved_count} frames (every {frame_interval} frames)")
87
+ return str(frames_dir)
88
+
89
+ except Exception as e:
90
+ raise RuntimeError(f"Error extracting frames: {str(e)}")
91
+
92
+ if __name__ == "__main__":
packages.txt CHANGED
@@ -13,4 +13,5 @@ python-is-python3
13
  wget
14
  zlib1g
15
  net-tools
16
- lsof
 
 
13
  wget
14
  zlib1g
15
  net-tools
16
+ lsof
17
+ build-essential
requirements.txt CHANGED
@@ -3,4 +3,7 @@ datasets
3
  evaluate
4
  gradio
5
  gradio[mcp]
6
- PyNvVideoCodec
 
 
 
 
3
  evaluate
4
  gradio
5
  gradio[mcp]
6
+ ipython
7
+ ipywidgets
8
+ ffmpeg-python
9
+ opencv-python