├── LICENSE ├── README.md └── Hardcode_subtitles_on_video.ipynb /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Anil Chandra Naidu Matcha 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Free Media Tools 2 | A list of free media tools for use without login and running completely in browser 3 | 4 | ### Open-source code youtube tutorial -> https://youtu.be/VbDLNjoKdt4 5 | 6 | ## Free Video Tools 7 | 8 | Here are some of the video tools available: 9 | 10 | - [Compress Video](https://tools.vadoo.tv/compress-video) 11 | - [Cut Video](https://tools.vadoo.tv/cut-video) 12 | - [Add subtitle to video](https://tools.vadoo.tv/add-subtitle-to-video) -> [Code](https://github.com/Anil-matcha/Free-Video-Tools/blob/main/Hardcode_subtitles_on_video.ipynb) 13 | - [Add audio to video](https://tools.vadoo.tv/add-audio-to-video) 14 | - [Add image to video](https://tools.vadoo.tv/add-image-to-video) 15 | - [Change Video Speed](https://tools.vadoo.tv/change-video-speed) 16 | - [Resize Video](https://tools.vadoo.tv/resize-video) 17 | - [Join multiple video](https://tools.vadoo.tv/merge-video) 18 | - [MP4 converter](https://tools.vadoo.tv/mp4-converter) 19 | - [AVI converter](https://tools.vadoo.tv/avi-converter) 20 | - [MKV converter](https://tools.vadoo.tv/mkv-converter) 21 | - [MOV converter](https://tools.vadoo.tv/mov-converter) 22 | - [WEBM converter](https://tools.vadoo.tv/webm-converter) 23 | - [WMV converter](https://tools.vadoo.tv/wmv-converter) 24 | 25 | ## Free Audio Tools 26 | 27 | Here are some of the audio tools available: 28 | 29 | - [Join multiple audio](https://tools.vadoo.tv/merge-audio) 30 | - [Change audio speed](https://tools.vadoo.tv/change-audio-speed) 31 | - [Compress audio](https://tools.vadoo.tv/compress-audio) 32 | - [Cut audio](https://tools.vadoo.tv/cut-audio) 33 | - [Merge audio](https://tools.vadoo.tv/merge-audio) 34 | - [Add image to audio](https://tools.vadoo.tv/add-image-to-audio) 35 | - [Convert to MP3](https://tools.vadoo.tv/audio-converter/mp3-converter) 36 | - [Convert to AIFF](https://tools.vadoo.tv/audio-converter/aiff-converter) 37 | - [Convert to ALAC](https://tools.vadoo.tv/audio-converter/alac-converter) 38 | - [Convert to AMR](https://tools.vadoo.tv/audio-converter/amr-converter) 39 | - [Convert to FLAC](https://tools.vadoo.tv/audio-converter/flac-converter) 40 | - [Convert to M4A](https://tools.vadoo.tv/audio-converter/m4a-converter) 41 | - [Convert to M4R](https://tools.vadoo.tv/audio-converter/m4r-converter) 42 | - [Convert to OGG](https://tools.vadoo.tv/audio-converter/ogg-converter) 43 | - [Convert to OPUS](https://tools.vadoo.tv/audio-converter/opus-converter) 44 | - [Convert to WAV](https://tools.vadoo.tv/audio-converter/wav-converter) 45 | - [Convert to WMA](https://tools.vadoo.tv/audio-converter/wma-converter) 46 | 47 | 48 | ## Contributing 49 | 50 | We welcome contributions! Please open an issue or submit a pull request if you have any improvements or new features to add. 51 | 52 | ## License 53 | 54 | This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details. 55 | -------------------------------------------------------------------------------- /Hardcode_subtitles_on_video.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "provenance": [], 7 | "authorship_tag": "ABX9TyMXhFPGEH2vgmn5vdAmLI2L", 8 | "include_colab_link": true 9 | }, 10 | "kernelspec": { 11 | "name": "python3", 12 | "display_name": "Python 3" 13 | }, 14 | "language_info": { 15 | "name": "python" 16 | } 17 | }, 18 | "cells": [ 19 | { 20 | "cell_type": "markdown", 21 | "metadata": { 22 | "id": "view-in-github", 23 | "colab_type": "text" 24 | }, 25 | "source": [ 26 | "\"Open" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "source": [ 32 | "Step 1: Install Required Libraries" 33 | ], 34 | "metadata": { 35 | "id": "JkNVzDFHZ6kh" 36 | } 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": 1, 41 | "metadata": { 42 | "colab": { 43 | "base_uri": "https://localhost:8080/" 44 | }, 45 | "id": "WJdBemqCP8Mo", 46 | "outputId": "a19c0c5e-d4a5-4c72-ae28-cca888adc9f7" 47 | }, 48 | "outputs": [ 49 | { 50 | "output_type": "stream", 51 | "name": "stdout", 52 | "text": [ 53 | "Requirement already satisfied: moviepy in /usr/local/lib/python3.10/dist-packages (1.0.3)\n", 54 | "Collecting pysrt\n", 55 | " Downloading pysrt-1.1.2.tar.gz (104 kB)\n", 56 | "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m104.4/104.4 kB\u001b[0m \u001b[31m2.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", 57 | "\u001b[?25h Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", 58 | "Requirement already satisfied: decorator<5.0,>=4.0.2 in /usr/local/lib/python3.10/dist-packages (from moviepy) (4.4.2)\n", 59 | "Requirement already satisfied: tqdm<5.0,>=4.11.2 in /usr/local/lib/python3.10/dist-packages (from moviepy) (4.66.4)\n", 60 | "Requirement already satisfied: requests<3.0,>=2.8.1 in /usr/local/lib/python3.10/dist-packages (from moviepy) (2.31.0)\n", 61 | "Requirement already satisfied: proglog<=1.0.0 in /usr/local/lib/python3.10/dist-packages (from moviepy) (0.1.10)\n", 62 | "Requirement already satisfied: numpy>=1.17.3 in /usr/local/lib/python3.10/dist-packages (from moviepy) (1.25.2)\n", 63 | "Requirement already satisfied: imageio<3.0,>=2.5 in /usr/local/lib/python3.10/dist-packages (from moviepy) (2.31.6)\n", 64 | "Requirement already satisfied: imageio-ffmpeg>=0.2.0 in /usr/local/lib/python3.10/dist-packages (from moviepy) (0.5.1)\n", 65 | "Requirement already satisfied: chardet in /usr/local/lib/python3.10/dist-packages (from pysrt) (5.2.0)\n", 66 | "Requirement already satisfied: pillow<10.1.0,>=8.3.2 in /usr/local/lib/python3.10/dist-packages (from imageio<3.0,>=2.5->moviepy) (9.4.0)\n", 67 | "Requirement already satisfied: setuptools in /usr/local/lib/python3.10/dist-packages (from imageio-ffmpeg>=0.2.0->moviepy) (67.7.2)\n", 68 | "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests<3.0,>=2.8.1->moviepy) (3.3.2)\n", 69 | "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests<3.0,>=2.8.1->moviepy) (3.7)\n", 70 | "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests<3.0,>=2.8.1->moviepy) (2.0.7)\n", 71 | "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests<3.0,>=2.8.1->moviepy) (2024.6.2)\n", 72 | "Building wheels for collected packages: pysrt\n", 73 | " Building wheel for pysrt (setup.py) ... \u001b[?25l\u001b[?25hdone\n", 74 | " Created wheel for pysrt: filename=pysrt-1.1.2-py3-none-any.whl size=13443 sha256=f195fb1c3e52a37f2fab3195aa9c3cd0b7df8ab71b4bb9dc16ca401cddb882ba\n", 75 | " Stored in directory: /root/.cache/pip/wheels/30/7f/e8/55de9a9b07302d9e7fe47c27910e3bea0c48536153e74bd7e6\n", 76 | "Successfully built pysrt\n", 77 | "Installing collected packages: pysrt\n", 78 | "Successfully installed pysrt-1.1.2\n" 79 | ] 80 | } 81 | ], 82 | "source": [ 83 | "!pip install moviepy pysrt" 84 | ] 85 | }, 86 | { 87 | "cell_type": "markdown", 88 | "source": [ 89 | "Setup ImageMagick" 90 | ], 91 | "metadata": { 92 | "id": "wqbSGHmWaBaX" 93 | } 94 | }, 95 | { 96 | "cell_type": "code", 97 | "source": [ 98 | "!apt install imagemagick &> /dev/null\n", 99 | "!sed -i '///' /etc/ImageMagick-6/policy.xml\n", 101 | "!sudo sed -i 's///' /etc/ImageMagick-6/policy.xml" 102 | ], 103 | "metadata": { 104 | "id": "tUOo_gMcQ-xS" 105 | }, 106 | "execution_count": 2, 107 | "outputs": [] 108 | }, 109 | { 110 | "cell_type": "markdown", 111 | "source": [ 112 | "Step 2: Import Libraries\n", 113 | "\n", 114 | "Let's import the libraries we need.\n", 115 | "\n" 116 | ], 117 | "metadata": { 118 | "id": "tnJ1vALaaGMh" 119 | } 120 | }, 121 | { 122 | "cell_type": "code", 123 | "source": [ 124 | "import moviepy.editor as mp\n", 125 | "import pysrt\n", 126 | "from IPython.display import HTML" 127 | ], 128 | "metadata": { 129 | "id": "M8wWTR6GaJb1" 130 | }, 131 | "execution_count": 14, 132 | "outputs": [] 133 | }, 134 | { 135 | "cell_type": "markdown", 136 | "source": [ 137 | "Step 3: Define Functions for Adding Subtitles\n", 138 | "\n", 139 | "3.1 Function: srt_to_moviepy_subtitles\n", 140 | "\n", 141 | "This function converts an SRT subtitle file into moviepy text clips and overlays them onto the video." 142 | ], 143 | "metadata": { 144 | "id": "b2oTW_d0aPxj" 145 | } 146 | }, 147 | { 148 | "cell_type": "code", 149 | "source": [ 150 | "def srt_to_moviepy_subtitles(srt_file, video_clip):\n", 151 | " subs = pysrt.open(srt_file)\n", 152 | " subtitle_clips = []\n", 153 | "\n", 154 | " for sub in subs:\n", 155 | " start_time = sub.start.to_time()\n", 156 | " end_time = sub.end.to_time()\n", 157 | " start_seconds = start_time.hour * 3600 + start_time.minute * 60 + start_time.second + start_time.microsecond / 1e6\n", 158 | " end_seconds = end_time.hour * 3600 + end_time.minute * 60 + end_time.second + end_time.microsecond / 1e6\n", 159 | " duration = end_seconds - start_seconds\n", 160 | "\n", 161 | " # Formatting text to handle newlines properly\n", 162 | " formatted_text = sub.text.replace('\\n', ' ')\n", 163 | "\n", 164 | " # Create a text clip with a black background and white text\n", 165 | " text_clip = (mp.TextClip(formatted_text, fontsize=24, color='yellow', bg_color='black', method='caption', size=(video_clip.w - 20, None))\n", 166 | " .set_start(start_seconds)\n", 167 | " .set_duration(duration)\n", 168 | " .set_position(('center', video_clip.h - 50))) # Position near the bottom with padding\n", 169 | "\n", 170 | " # Add the text clip to the list of subtitle clips\n", 171 | " subtitle_clips.append(text_clip)\n", 172 | "\n", 173 | " return mp.CompositeVideoClip([video_clip] + subtitle_clips)" 174 | ], 175 | "metadata": { 176 | "id": "q3HQUtNfaTW9" 177 | }, 178 | "execution_count": 15, 179 | "outputs": [] 180 | }, 181 | { 182 | "cell_type": "markdown", 183 | "source": [ 184 | "Explanation:\n", 185 | "\n", 186 | "pysrt.open(srt_file): Opens the subtitle file and parses it.\n", 187 | "\n", 188 | "start_time and end_time: Convert subtitle start and end times to Python datetime objects.\n", 189 | "\n", 190 | "start_seconds and end_seconds: Calculate subtitle start and end times in seconds.\n", 191 | "\n", 192 | "formatted_text: Replace newlines in the subtitle text with spaces.\n", 193 | "\n", 194 | "mp.TextClip: Creates a video clip containing text.\n", 195 | "\n", 196 | "Parameters:\n", 197 | "- fontsize: Font size of the text.\n", 198 | "- color: Color of the text.\n", 199 | "- bg_color: Background color of the text clip.\n", 200 | "- method='caption': Text rendering method.\n", 201 | "- size: Size of the text clip. Here it is adjusted to fit within the video frame width.\n", 202 | "- set_start: Sets the start time of the subtitle clip.\n", 203 | "- set_duration: Sets how long the subtitle will be displayed.\n", 204 | "- set_position: Sets the position of the text clip on the video frame.\n", 205 | "\n", 206 | "mp.CompositeVideoClip: Combines the original video clip with the subtitle clips." 207 | ], 208 | "metadata": { 209 | "id": "B6jo_odpaYx7" 210 | } 211 | }, 212 | { 213 | "cell_type": "markdown", 214 | "source": [ 215 | "3.2 Function: burn_subtitles\n", 216 | "\n", 217 | "This function applies the subtitles to a video file and saves the output." 218 | ], 219 | "metadata": { 220 | "id": "sBQ9JylaapHJ" 221 | } 222 | }, 223 | { 224 | "cell_type": "code", 225 | "source": [ 226 | "def burn_subtitles(video_file, srt_file, output_file):\n", 227 | " video_clip = mp.VideoFileClip(video_file)\n", 228 | " video_with_subs = srt_to_moviepy_subtitles(srt_file, video_clip)\n", 229 | " video_with_subs.write_videofile(output_file, codec='libx264', audio_codec='aac')" 230 | ], 231 | "metadata": { 232 | "id": "X77xxN2YarhY" 233 | }, 234 | "execution_count": 16, 235 | "outputs": [] 236 | }, 237 | { 238 | "cell_type": "markdown", 239 | "source": [ 240 | "Explanation:\n", 241 | "\n", 242 | "- mp.VideoFileClip(video_file): Loads the video file into a moviepy video clip.\n", 243 | "- srt_to_moviepy_subtitles: Calls the previously defined function to add subtitles to the video.\n", 244 | "- write_videofile: Writes the final video with subtitles to a file.\n", 245 | "\n", 246 | "Parameters:\n", 247 | " - codec='libx264': Specifies the video codec.\n", 248 | " - audio_codec='aac': Specifies the audio codec." 249 | ], 250 | "metadata": { 251 | "id": "JVPf73csazPJ" 252 | } 253 | }, 254 | { 255 | "cell_type": "markdown", 256 | "source": [ 257 | "### Upload input files" 258 | ], 259 | "metadata": { 260 | "id": "RXNx3sLQbIIN" 261 | } 262 | }, 263 | { 264 | "cell_type": "code", 265 | "source": [ 266 | "from google.colab import files\n", 267 | "uploaded_files = files.upload()\n", 268 | "\n", 269 | "# Save uploaded files to disk\n", 270 | "video_file_path = None\n", 271 | "srt_file_path = None\n", 272 | "\n", 273 | "for file_name in uploaded_files.keys():\n", 274 | " if file_name.endswith('.mp4'):\n", 275 | " video_file_path = file_name\n", 276 | " with open(file_name, 'wb') as f:\n", 277 | " f.write(uploaded_files[file_name])\n", 278 | " elif file_name.endswith('.srt'):\n", 279 | " srt_file_path = file_name\n", 280 | " with open(file_name, 'wb') as f:\n", 281 | " f.write(uploaded_files[file_name])\n", 282 | "\n", 283 | "if video_file_path and srt_file_path:\n", 284 | " print(f\"Uploaded video file: {video_file_path}\")\n", 285 | " print(f\"Uploaded subtitle file: {srt_file_path}\")\n", 286 | "else:\n", 287 | " raise ValueError(\"Please upload both a .mp4 video file and a .srt subtitle file.\")" 288 | ], 289 | "metadata": { 290 | "colab": { 291 | "base_uri": "https://localhost:8080/", 292 | "height": 145 293 | }, 294 | "id": "JLiy6QPnQCUW", 295 | "outputId": "ec8b6c50-2ae0-4dd7-9027-29a65bd55069" 296 | }, 297 | "execution_count": 23, 298 | "outputs": [ 299 | { 300 | "output_type": "display_data", 301 | "data": { 302 | "text/plain": [ 303 | "" 304 | ], 305 | "text/html": [ 306 | "\n", 307 | " \n", 309 | " \n", 310 | " Upload widget is only available when the cell has been executed in the\n", 311 | " current browser session. Please rerun this cell to enable.\n", 312 | " \n", 313 | " " 489 | ] 490 | }, 491 | "metadata": {} 492 | }, 493 | { 494 | "output_type": "stream", 495 | "name": "stdout", 496 | "text": [ 497 | "Saving input.mp4 to input.mp4\n", 498 | "Saving input.srt to input.srt\n", 499 | "Uploaded video file: input.mp4\n", 500 | "Uploaded subtitle file: input.srt\n" 501 | ] 502 | } 503 | ] 504 | }, 505 | { 506 | "cell_type": "markdown", 507 | "source": [ 508 | "### Generate and download output" 509 | ], 510 | "metadata": { 511 | "id": "357uE8PncCPx" 512 | } 513 | }, 514 | { 515 | "cell_type": "code", 516 | "source": [ 517 | "output_file_name = 'output.mp4'\n", 518 | "burn_subtitles(video_file_path, srt_file_path, output_file_name)\n", 519 | "\n", 520 | "# Provide a link to download the output file\n", 521 | "files.download(output_file_name)" 522 | ], 523 | "metadata": { 524 | "colab": { 525 | "base_uri": "https://localhost:8080/", 526 | "height": 216 527 | }, 528 | "id": "XXIa9vOVZOUo", 529 | "outputId": "b983a561-ef37-466d-dae8-0d1a138488bf" 530 | }, 531 | "execution_count": 24, 532 | "outputs": [ 533 | { 534 | "output_type": "stream", 535 | "name": "stdout", 536 | "text": [ 537 | "Moviepy - Building video output.mp4.\n", 538 | "MoviePy - Writing audio in outputTEMP_MPY_wvf_snd.mp4\n" 539 | ] 540 | }, 541 | { 542 | "output_type": "stream", 543 | "name": "stderr", 544 | "text": [] 545 | }, 546 | { 547 | "output_type": "stream", 548 | "name": "stdout", 549 | "text": [ 550 | "MoviePy - Done.\n", 551 | "Moviepy - Writing video output.mp4\n", 552 | "\n" 553 | ] 554 | }, 555 | { 556 | "output_type": "stream", 557 | "name": "stderr", 558 | "text": [ 559 | "t: 99%|█████████▉| 866/873 [00:16<00:00, 70.20it/s, now=None]WARNING:py.warnings:/usr/local/lib/python3.10/dist-packages/moviepy/video/io/ffmpeg_reader.py:123: UserWarning: Warning: in file input.mp4, 641280 bytes wanted but 0 bytes read,at frame 872/873, at time 34.88/34.90 sec. Using the last valid frame instead.\n", 560 | " warnings.warn(\"Warning: in file %s, \"%(self.filename)+\n", 561 | "\n" 562 | ] 563 | }, 564 | { 565 | "output_type": "stream", 566 | "name": "stdout", 567 | "text": [ 568 | "Moviepy - Done !\n", 569 | "Moviepy - video ready output.mp4\n" 570 | ] 571 | }, 572 | { 573 | "output_type": "display_data", 574 | "data": { 575 | "text/plain": [ 576 | "" 577 | ], 578 | "application/javascript": [ 579 | "\n", 580 | " async function download(id, filename, size) {\n", 581 | " if (!google.colab.kernel.accessAllowed) {\n", 582 | " return;\n", 583 | " }\n", 584 | " const div = document.createElement('div');\n", 585 | " const label = document.createElement('label');\n", 586 | " label.textContent = `Downloading \"${filename}\": `;\n", 587 | " div.appendChild(label);\n", 588 | " const progress = document.createElement('progress');\n", 589 | " progress.max = size;\n", 590 | " div.appendChild(progress);\n", 591 | " document.body.appendChild(div);\n", 592 | "\n", 593 | " const buffers = [];\n", 594 | " let downloaded = 0;\n", 595 | "\n", 596 | " const channel = await google.colab.kernel.comms.open(id);\n", 597 | " // Send a message to notify the kernel that we're ready.\n", 598 | " channel.send({})\n", 599 | "\n", 600 | " for await (const message of channel.messages) {\n", 601 | " // Send a message to notify the kernel that we're ready.\n", 602 | " channel.send({})\n", 603 | " if (message.buffers) {\n", 604 | " for (const buffer of message.buffers) {\n", 605 | " buffers.push(buffer);\n", 606 | " downloaded += buffer.byteLength;\n", 607 | " progress.value = downloaded;\n", 608 | " }\n", 609 | " }\n", 610 | " }\n", 611 | " const blob = new Blob(buffers, {type: 'application/binary'});\n", 612 | " const a = document.createElement('a');\n", 613 | " a.href = window.URL.createObjectURL(blob);\n", 614 | " a.download = filename;\n", 615 | " div.appendChild(a);\n", 616 | " a.click();\n", 617 | " div.remove();\n", 618 | " }\n", 619 | " " 620 | ] 621 | }, 622 | "metadata": {} 623 | }, 624 | { 625 | "output_type": "display_data", 626 | "data": { 627 | "text/plain": [ 628 | "" 629 | ], 630 | "application/javascript": [ 631 | "download(\"download_82d10352-fbb7-4d30-a5c3-11fcc93142cd\", \"output.mp4\", 1866895)" 632 | ] 633 | }, 634 | "metadata": {} 635 | } 636 | ] 637 | } 638 | ] 639 | } --------------------------------------------------------------------------------