Code Monkey home page Code Monkey logo

zfleeman / ffmpeg4discord Goto Github PK

View Code? Open in Web Editor NEW
31.0 2.0 1.0 615 KB

ffmpeg4discord is a Python package tailored for Two-Pass encoding, enabling efficient video compression to meet desired file sizes. Ideal for users seeking to compress videos for Discord sharing within file size limitations.

Home Page: https://pypi.org/project/ffmpeg4discord/

License: GNU General Public License v3.0

Python 72.87% HTML 27.13%
ffmpeg discord encoding libx264 codecs ffmpeg-python video video-processing flask h264

ffmpeg4discord's Introduction

ffmpeg4discord (ff4d) -- Target File Size Video Compression for Discord with FFmpeg

This repository houses scripts and applications to assist with compressing a video file to a desired size.

ff4d takes a video file as its input and encodes it to be less than a target file size. Discord's free-tier file size sharing limit is 25MB. You can change the file's name in a way that trims the file to a timestamped section. I developed this package specifically for swift sharing of large NVIDIA ShadowPlay clips on Discord, eliminating the need for a visual editor.

The TwoPass() class presents a 2-pass encoding approach for the ffmpeg-python library, which is not showcased in that package's documentation. Additionally, the class extends support to various FFmpeg video filters such as cropping and resolution scaling, making it adaptable to a range of audio/video workflows.

Installation

This package works with Python >= 3.8. For Windows users, ensure that Python is added to your system's PATH. I highly recommend that you use the python.org Python installation.

Install this package with the following command.

pip install ffmpeg4discord

You must first have FFmpeg installed on your system. ffmpeg needs to be registered in your PATH. macOS or Linux users can use their favorite package manager to do this, but this process is a little more tricky for Windows users.

Help for Windows users

After installing this package, Windows users can run this command in a terminal to download the necessary ffmpeg binaries:

install-ffmpeg-windows

This will place ffmpeg.exe, ffprobe.exe, and ffplay.exe into the same location as your Python executable.

Usage

Use ff4d in your favorite terminal like this:

ff4d path-to-file.mp4 <optional-flags>

This command tries to compress the whole video file down to the default output file size of 25MB:

ff4d cool_clip.mp4

This will trim a 20 second section out of cool_clip.mp4 starting at 10 seconds in and ending at 30 seconds. More on the optional flags.

ff4d cool_clip.mp4 --from 00:00:10 --to 00:00:30

I've had a good time using this command with a Batch file on Windows. Refer to the Sample Batch File section for more information.

Optional Flags

Flag Default Example Description
-o
--output
current working directory -o "C:/Users/zflee/A Folder"
-o "C:/Users/zflee/Desktop/A Folder/filename.mp4"
If you want your smaller clips to go to a specific folder, use this option. You can also choose a custom output filename, just make sure to include the correct file extension for your video codec.
-s
--filesize
25 -s 50 Increase or decrease this value if you want to compress your video to something other than the 25MB Discord limit.
-a
--audio-br
96 -a 128 You can change this value if you want to increase or decrease your audio bitrate. Lowering it will allow for a slight increase in the compressed file's video bitrate.
-r
--resolution
No default -r 1280x720 Modify this value to change the output resolution of your video file.
-x
--crop
No default -x 255x0x1410x1080 FFmpeg crop documentation. From the top-left of your video, this example goes 255 pixels to the right, 0 pixels down, and it carves out a 1410x1080 section of the video.
-c
--codec
libx264 -c libvpx-vp9 Options: libx264 or libvpx-vp9
Specify the video codec that you want to use. The default option creates .mp4 files, while libvpx-vp9 creates .webm video files.
libvpx-vp9 creates better looking video files with the same bitrates, but it takes significantly longer to encode. VP9 is also not as compatible with as many devices or browsers. I can view .webm videos on the desktop installtion of Discord, but they are not viewable on my iOS Discord installation.
--web No default. Boolean flag. --web Launch the Web UI for this job. A Boolean flag. No value is needed after the flag. See Web UI for more information on the Web UI.
-p
--port
No default. Picks a random port if not specified. -p 5333 Run the Web UI on a specific port.
--config No default --config config.json Path to a JSON file containing the configuration for the above parameters. This config file takes precedence over all of the other flags. See JSON Configuration.
--from No default --from 00:01:00 Start time for trimming the video file to a desired section.
--to No default --to 00:01:20 End time for trimming the video file to a desired section.
--filename-times No default. Boolean flag. --filename-times Generate From/To timestamps from the clip's file name. See File Name Formatting
--approx No default. Boolean flag. --approx Approximate file size. The job will not loop to output the file under the target size. It will get close enough to the target on the first run.

File Name Formatting

Enable this feature with --filename-times. You can edit the name of your video file if you need to trim it to a specific section. Here are a few examples.

  1. 000020.mp4
    • This trims and compresses the video from 00:00:20 to the end of the clip.
  2. 000020-000145.mp4
    • This trims and compresses the video from 00:00:20 to 00:01:45.
  3. SomethingElse.mp4
    • Compresses the entire video if the first six characters of the file's name aren't numeric.

JSON Configuration

If your encoding job will always be the same, you can reference a JSON configuration file instead of passing a long list of arguments to the command line.

{
    "target_filesize": 8.0,
    "audio_br": 96,
    "crop": "",
    "resolution": "",
    "codec": "libx264",
    "times": {
        "from": "00:00:00",
        "to": "00:00:40"
    }
}

Notes:

  • All of the keys except for "from" and "to" must always be present. Those entries can be deleted if you do not have a timestamp entry for the given field. Examples:
    • "times": {} -> if you do not wish to trim the start and stop time of the file.
    • "times": {"from": "00:00:10"} -> trim the clip from 00:00:10 to the end of the file
    • "times": {"to": "00:00:20"} -> trim the clip from the beginning of the file up to 00:00:20
  • You can set audio_br to null if you want to maintain the clip's audio bitrate.

Detailed Example

ff4d 000050-000145.mp4 \
    -x 1280x0x2560x1440 \
    -r 1920x1080 \
    -s 50 \
    -a 48 \
    -o D:/shadowplay/ \
    --filename-times

The example above takes a 5120x1440 resolution video as its input. The script trims the video from 00:00:50 to 00:01:45 (specified in the file name, and enabled with --filename-times). It crops a 2560x1440 section starting at 1280 pixels from the top-left and 0 pixels down (-x). The output file will be located in D:/shadowplay/ (-o) with a new resolution of 1920x1080 (-r), and it will be 50MB (-s). The audio bitrate will be reduced to 48k (-a) as well, but that's probably going to sound terrible.

Web UI

The web UI can be activated by adding --web to your ff4d call.

ff4d cool_clip.mp4 -r 1280x720 -s 20 --web

That command will spin up a Flask server on your local machine and launch a rendered webpage with the video as the centerpiece. The flags you provide to ff4d will fill in the defaults for the form. You can override/replace the values with the web form.

You can drag the video playhead to different portions of the video and click the "Set Start/End Time" buttons to specify the section of the video you want to be clipped out. You can also use the range sliders underneath the buttons if you prefer. A "Preview Selection" button is provided for your convenience, and it does what it sounds like.

showcase.mp4

Note that the Flask server doesn't automatically shut down, so you'll need to manually terminate it by closing the terminal window where it's running.

Sample Batch File

To enable "drag and drop" functionality for this package, Windows users can create a .bat file with the following code snippet. Once the file is created, you can drag and drop any .mp4 file on top of it, and it will run with the flags specified in the "Optional Flags" section. This example is a Batch file that will launch the web UI.

@echo off
Set filename=%1
ff4d %filename% -o "C:/output/folder/" --web
PAUSE

Thanks!

Yes, this is a simple collection of Python files using FFmpeg tricks that is masquerading as a robust Audio/Video tool. But! I use this nearly every day to quickly share videos with people on various messaging apps that have built-in video players. I don't have to share a link that embeds a video player this way, and I guess that's important to me?

I like working on this! Enjoy!

ffmpeg4discord's People

Contributors

zfleeman avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

anonusername

ffmpeg4discord's Issues

Add support for overlays with cropped video or image stills

It would be fun to add support for overlaying parts of the video file on top of the output video. Ultrawide+ monitor captures that are cropped to a more reasonable aspect ratio may have important segments of their video that are cropped out. This would allow users to select rectangular sections to overlay onto the final output.

This would be an addition to the video filters section.

File name jobs and web ui jobs have different file size outputs.

During an encoding run, I noticed that the target file size was not being reached on the first attempt when dragging and dropping a file that had a single timestamp as its file name. But when I ran the exact same file with the same timestamp in the Web UI, the job finished in one run.

This has to do with the "to" timestamp not being generated when the file name job is only given one (starting) timestamp. Generate a "to" timestamp regardless of whether or not it is specified.

"to" can be the timestamp_from_seconds() value of the total clip duration in this case.

Better error handling around `ffprobe` call

There are a lot of assumptions that I make about the metadata available in the video file. I've fixed the "display_aspect_ratio" problem in this commit, but I should check for more issues like:

  • "display_aspect_ratio" is not always tagged on a video file
  • ["format"]["duration"]
  • ["streams"]
  • No audio stream video files break in the self.run() function

File Path Issues

First off, thanks for this. There are other discord scripts out there but none this robust.

Apologies if this pollutes your repo: I know I have scripts that work perfectly for me, that I have no interest in supporting for others. But in case this helps you or anyone else:

I am running on Windows 10 x64 and Python 3.12. My ffmpeg version is vintage 2023:

ffmpeg version 6.1-full_build-www.gyan.dev Copyright (c) 2000-2023 the FFmpeg developers
  built with gcc 12.2.0 (Rev10, Built by MSYS2 project)
  configuration: --enable-gpl --enable-version3 --enable-static --pkg-config=pkgconf --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-bzlib --enable-lzma --enable-libsnappy --enable-zlib --enable-librist --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-libbluray --enable-libcaca --enable-sdl2 --enable-libaribb24 --enable-libaribcaption --enable-libdav1d --enable-libdavs2 --enable-libuavs3d --enable-libzvbi --enable-librav1e --enable-libsvtav1 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs2 --enable-libxvid --enable-libaom --enable-libjxl --enable-libopenjpeg --enable-libvpx --enable-mediafoundation --enable-libass --enable-frei0r --enable-libfreetype --enable-libfribidi --enable-libharfbuzz --enable-liblensfun --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-ffnvcodec --enable-nvdec --enable-nvenc --enable-dxva2 --enable-d3d11va --enable-libvpl --enable-libshaderc --enable-vulkan --enable-libplacebo --enable-opencl --enable-libcdio --enable-libgme --enable-libmodplug --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libshine --enable-libtheora --enable-libtwolame --enable-libvo-amrwbenc --enable-libcodec2 --enable-libilbc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-ladspa --enable-libbs2b --enable-libflite --enable-libmysofa --enable-librubberband --enable-libsoxr --enable-chromaprint
  libavutil      58. 29.100 / 58. 29.100
  libavcodec     60. 31.102 / 60. 31.102
  libavformat    60. 16.100 / 60. 16.100
  libavdevice    60.  3.100 / 60.  3.100
  libavfilter     9. 12.100 /  9. 12.100
  libswscale      7.  5.100 /  7.  5.100
  libswresample   4. 12.100 /  4. 12.100
  libpostproc    57.  3.100 / 57.  3.100
Hyper fast Audio and Video encoder
usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...

I can split these into separate issues if you want.

Config file conflicts with parser defaults

The argparse module at utils/arguments.py sets defaults (e.g. 8mb file max). i think it would be more intuitive to pull these from conf.json.

Poor parsing of paths on windows

I spent about an hour trying to track this down, with no luck. I originally was trying to drag a file from g:\ onto the batch file on my c:\ drive. The batch then looked for a config file in the folder on g:. I iterated on this error many times, trying to shave it into something more manageable. You can set a path type in argparse, but it's kind of annoying - the discussion is over my head but you can see more here and here

What eventually worked was hardcoding the config path and passing a fake config file in the command line. I kept seeing my conf.json getting overwritten. Presumably this was from the "with open()" code but I couldn't get to the bottom of that either. (You'd think it wouldn't happen with "r" mode, but idk.) You need to have the fake config file to trigger the init_from_config() part of the code path.

I also had to put the video file in the same folder as the script. Anything more complicated seemed fraught.


    def init_from_config(self, config_file: str) -> None:
        """
        Set the Class values from a json file
        :param config_file: path to a json file containing parameters for TwoPass()
        """
        # with open(cc.name) as f:
        import pathlib

        pp = pathlib.Path(r"c:/apps/ffmpeg4discord/conf.json")
        with open(pp, "r", encoding="utf-8") as f:

Discord free limit is now 25 MB

So the default should change accordingly.

Make audio codec configurable

So opus can be set.


These are subjective:

VP9 + Opus are maximum quality supported on discord

At the expense of encode time, VP9 and Opus are better than h264 and aac.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.