<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Peter Naftaliev</title>
    <description>The latest articles on DEV Community by Peter Naftaliev (@pinter).</description>
    <link>https://dev.to/pinter</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2314031%2F8098ffce-5611-4b49-b38d-3f09221e529d.jpg</url>
      <title>DEV Community: Peter Naftaliev</title>
      <link>https://dev.to/pinter</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pinter"/>
    <language>en</language>
    <item>
      <title>Video Generation APIs for No-Code Workflows</title>
      <dc:creator>Peter Naftaliev</dc:creator>
      <pubDate>Tue, 05 Aug 2025 13:42:25 +0000</pubDate>
      <link>https://dev.to/pinter/video-generation-apis-for-no-code-workflows-f8n</link>
      <guid>https://dev.to/pinter/video-generation-apis-for-no-code-workflows-f8n</guid>
      <description>&lt;p&gt;Video generation is experiencing a boom thanks to advances in AI and no-code tools that make it easier than ever to build automated media pipelines for social media, educational content, TV content, ads creation and more.&lt;/p&gt;

&lt;p&gt;As the team behind &lt;a href="//rendi.dev"&gt;rendi.dev&lt;/a&gt;, we're persnickety about video generation. In this post, we list the different things to consider when picking a video generation API for your use case. The top available APIs in the market:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rendi&lt;/li&gt;
&lt;li&gt;Cloudinary&lt;/li&gt;
&lt;li&gt;Json2Video&lt;/li&gt;
&lt;li&gt;Creatomate&lt;/li&gt;
&lt;li&gt;Shotstack&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Video APIs, including all the ones listed in this post, use FFmpeg behind the scene. FFmpeg is the go-to developer tool for processing, analyzing and generating videos. Video APIs, including all the ones listed in this post, use FFmpeg behind the scene. You can use FFmpeg commands to create any media asset you require, in any output you require. It supports all possible editing features, transition, trimming, transcoding, image generation, audio processing and more.&lt;/p&gt;




&lt;h2&gt;What to Consider When Choosing a Video Generation API for No-Code Workflows?&lt;/h2&gt;

&lt;h4&gt;Get the job done&lt;/h4&gt;

&lt;p&gt;Will you be able to generate the videos you require using the API? Does it have all the editing and transcoding features you need to create your content? Can you use your media assets the way you like? Make sure you know what the API cannot do before committing to it.&lt;/p&gt;

&lt;h4&gt;API flexibility&lt;/h4&gt;

&lt;p&gt;You may want to create thumbnails from videos today, but tomorrow you may want to create gifs, trim videos, or merge two videos into one. Will you be able to grow your automation with the API?&lt;/p&gt;

&lt;h4&gt;Scalability and reliability&lt;/h4&gt;

&lt;p&gt;Can the API reliably handle large volumes and grow with your usage?&lt;/p&gt;

&lt;h4&gt;Ease of use&lt;/h4&gt;

&lt;p&gt;How easy it is to use the API and integrate it within your no-code workflow? How well is the API documented? How hard is it to learn the product? &lt;/p&gt;

&lt;h4&gt;Pricing&lt;/h4&gt;

&lt;p&gt;Are the costs easy to understand, predictable and aligned with your usage? Does it make sense when creating bulk videos at scale? How much does it cost to process 1GB of media?&lt;/p&gt;

&lt;h4&gt;API lock-in&lt;/h4&gt;

&lt;p&gt;Related to the previous item: If you find that the API doesn't support a new use case, what will be the costs of switching? How hard will it be to change your workflow to accommodate a different API?&lt;/p&gt;

&lt;h4&gt;Support&lt;/h4&gt;

&lt;p&gt;In case of issues, errors and integration trouble: Is there someone available to talk to? Is the support able to solve your issues in a timely manner?&lt;/p&gt;




&lt;h2&gt;The APIs&lt;/h2&gt;




&lt;h3&gt;Rendi&lt;/h3&gt;

&lt;p&gt;Rendi is a simple API for FFmpeg. Using Rendi is as straightforward as using FFmpeg locally, but except you run FFmpeg online, without having to install anything.&lt;/p&gt;

&lt;p&gt;You can use Rendi either through our simple RESTful HTTP API - or - use our Zapier and Make native integrations to simplify the no-code integration even more.&lt;/p&gt;

&lt;h5&gt;Pros&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Uses the full syntax and abilities of FFmpeg.&lt;/li&gt;
&lt;li&gt;Works not only for video but also for audio and image generation.&lt;/li&gt;
&lt;li&gt;Built for scale and high loads.&lt;/li&gt;
&lt;li&gt;High compute power for fast and efficient processing.&lt;/li&gt;
&lt;li&gt;The commands are all FFmpeg, with no lock-in. You can run these commands on any other installation or server you choose.&lt;/li&gt;
&lt;li&gt;ChatGPT and other LLMs are specifically trained on FFmpeg data and are quite good at constructing FFmpeg commands that can run according to your requirement. &lt;/li&gt;
&lt;li&gt;Simple to integrate with a RESTful HTTP endpoint.&lt;/li&gt;
&lt;li&gt;Native Zapier and Make integrations.&lt;/li&gt;
&lt;li&gt;Built-in media asset storage and delivery: you don't need to deal with serving the output media.&lt;/li&gt;
&lt;li&gt;System status page for monitoring Rendi's past and current availability with uptime of 99.98%.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Cons&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Complicated to set up for those not familiar with FFmpeg.&lt;/li&gt;
&lt;li&gt;No pre-built templates or UI editor to them.&lt;/li&gt;
&lt;li&gt;If you're storing media in Rendi, there is a lock-in because it is difficult to transfer out large sums of files to another CDN (content delivery network).&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Pricing&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;No complicated credit system or limitations on different encodings, resolutions, video length or quality.
*Paid plans start at $59/month, for which you can process up to 400GB of video - with a high compute of 16 vCPU cores.
&lt;b&gt;Cost per 1GB is $0.15&lt;/b&gt;
&lt;/li&gt;
&lt;li&gt;Paid plans start at a 10-minutes processing time cap per command, and can grow as required.&lt;/li&gt;
&lt;li&gt;High quality in-person support for paying subscribers.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;Cloudinary&lt;/h3&gt;

&lt;p&gt;A well-established brand in the space, Cloudinary is a comprehensive media management platform with built-in video transformation features. Cloudinary's strong suit is its CDN capabilities. &lt;/p&gt;

&lt;h5&gt;Pros&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Reliable platform with different product lines.&lt;/li&gt;
&lt;li&gt;Cloudinary is great for transforming and hosting media, making it a solid choice for apps that serve content to many users in various formats.&lt;/li&gt;
&lt;li&gt;Built for scale and high loads.&lt;/li&gt;
&lt;li&gt;Has automated AI features - like auto cropping, image upscaling and more.&lt;/li&gt;
&lt;li&gt;Good and elaborate documentation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Cons&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Video input size cap of 2GB for the Plus paid plan and higher caps for more expensive plans.&lt;/li&gt;
&lt;li&gt;Not built for video generation. It is complicated to combine different media assets or carry out multiple different editing processes on the same asset.&lt;/li&gt;
&lt;li&gt;Since Cloudinary's main selling point is their CDN, you will be using its media storage and distribution features, which amount to a lock-in because it is difficult to transfer out large sums of files to another CDN.&lt;/li&gt;
&lt;li&gt;Hard integration which requires learning Cloudinary's syntax of HTTP get request parameters.&lt;/li&gt;
&lt;li&gt;No pre-built templates or UI editor to create them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Pricing&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;The most complicated credit system of all the tools listed. Credit costs change with encoding, transformation feature, resolution, storage, bandwidth, and special features used.&lt;/li&gt;
&lt;li&gt;Paid plans start at $89/month, which provides 225K transformation credits. These amount to about 75GB of HD H264 encoded video processing.
&lt;b&gt;Cost per 1GB is $1.2&lt;/b&gt;
&lt;/li&gt;
&lt;li&gt;Use can get expensive at scale, especially with bandwidth and transformation overages.&lt;/li&gt;
&lt;li&gt;High quality support for those paying for the higher tier plans.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;Json2Video&lt;/h3&gt;

&lt;p&gt;Json2Video is an API for programmatic video generation. Users can define video content, layout, and style using a JSON format. Then send the JSON as an API request via an HTTP request, using their NodeJS\PHP SDKs or use the native Make integration.&lt;/p&gt;

&lt;h5&gt;Pros&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Dynamically create output videos based on media assets input.&lt;/li&gt;
&lt;li&gt;Simple and intuitive template library.&lt;/li&gt;
&lt;li&gt;Visual editor that simplifies static templates creation.&lt;/li&gt;
&lt;li&gt;Integration with ElevenLabs for voice overs.&lt;/li&gt;
&lt;li&gt;Simple to integrate with a RESTful HTTP endpoint&lt;/li&gt;
&lt;li&gt;Unless you store many different templates, low lock-in, switching providers is simple because the only dependence is on the JSON object construction.&lt;/li&gt;
&lt;li&gt;Native Make integration.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Cons&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Strong limitation on output video length based on plan.&lt;/li&gt;
&lt;li&gt;Poor support for high load and heavy video generation.&lt;/li&gt;
&lt;li&gt;Complicated JSON structure to learn and use.&lt;/li&gt;
&lt;li&gt;Clunky UI. For example, could not use variables in the visual editor.&lt;/li&gt;
&lt;li&gt;Documentation is complicated, and it takes a while to understand the concepts of elements, scenes, movie and the interactions between them. The AI assistant doesn't work.&lt;/li&gt;
&lt;li&gt;No Zapier integration.&lt;/li&gt;
&lt;li&gt;No clear explanation in the documentation on how assets are stored and served. It looks like you need to integrate your own SFTP file system with them.&lt;/li&gt;
&lt;li&gt;No system status reporting to track system availability&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Pricing&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Complicated credit system.&lt;/li&gt;
&lt;li&gt;$50 per month to generate 5 minutes of 4K video, which comes to about 3.5GB video created, and 10 minutes output limit.
&lt;b&gt;Cost per 1GB is $14.3&lt;/b&gt;
&lt;/li&gt;
&lt;li&gt;Has pre-paid plans for consumption based pricing.&lt;/li&gt;
&lt;li&gt;Different support plans based on paid plan.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;Creatomate&lt;/h3&gt;

&lt;p&gt;Customers can define video content, layout, and style using a UI editor or JSON formats, then send an API request to generate the video, either via an HTTP request, using the NodeJS\Python SDKs, or through the native Zapier or Make integration.&lt;/p&gt;

&lt;h5&gt;Pros&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Simple visual editor for static template creation.&lt;/li&gt;
&lt;li&gt;Simple and intuitive template library and documentation.&lt;/li&gt;
&lt;li&gt;Automatic transcription generation&lt;/li&gt;
&lt;li&gt;Creates output videos based on interchanging media assets input.&lt;/li&gt;
&lt;li&gt;Native Make and Zapier integration.&lt;/li&gt;
&lt;li&gt;Simple to integrate with a RESTful HTTP endpoint&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Cons&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Heavily reliant on template creation through the UI, therefore there is lock-in and switching costs for recreating the templates on a different platform.&lt;/li&gt;
&lt;li&gt;Dynamic video generation requires using their JSON format which is complicated to learn and use.&lt;/li&gt;
&lt;li&gt;No built-in media asset management; You must handle storage and delivery separately.&lt;/li&gt;
&lt;li&gt;No system status reporting to track system availability&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Pricing&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Complicated credit system.&lt;/li&gt;
&lt;li&gt;Starts at $41 per month for generating about 1 hour and 6 minutes of 1080P video at 25 FPS, which comes to around 4GB total processed video.
&lt;b&gt;Cost per 1GB is $10.25&lt;/b&gt;
&lt;/li&gt;
&lt;li&gt;Support available to the highest paying plan.&lt;/li&gt;
&lt;/ul&gt;




&lt;h5&gt;Shotstack&lt;/h5&gt;

&lt;p&gt;Shotstack is the most comprehensive of the three APIs for programmatic video generation listed in this post. It offers both a UI editor and JSON format for defining video content, layouts, styles and edits. Capabilities include allowing for AI generation, video editor SDK, different integration options and API endpoints.&lt;/p&gt;

&lt;h5&gt;Pros&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Simple visual editor for static template creation.&lt;/li&gt;
&lt;li&gt;Intuitive template library and documentation.&lt;/li&gt;
&lt;li&gt;Generative AI features with third parties such as - text to speech, text to image, image to video.&lt;/li&gt;
&lt;li&gt;Elaborate storage options and CDN for generated files.&lt;/li&gt;
&lt;li&gt;Built for scale&lt;/li&gt;
&lt;li&gt;Creates output videos based on inter-changing media assets input.&lt;/li&gt;
&lt;li&gt;Has SDKs for NodeJS, Python, and PHP&lt;/li&gt;
&lt;li&gt;Native Make and Zapier integrations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Cons&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Source footage and output video cannot exceed 10GB&lt;/li&gt;
&lt;li&gt;Slow rendering cap of 20 seconds per 1 minute of video.&lt;/li&gt;
&lt;li&gt;No historical data about system status even though promised uptime with 99.9% SLA.&lt;/li&gt;
&lt;li&gt;Complex API structure: takes a long while to go over and understand what the tool can (and cannot) do.&lt;/li&gt;
&lt;li&gt;Using Shotstack's storage features or UI for template editing creates a lock-in for transferring files and templates to a different product later.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Pricing&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Pricing is based on video duration rendered up to 1080p.&lt;/li&gt;
&lt;li&gt;Starter plan at $39/month includes 200 credits which amounts to 200 minutes of video.
&lt;b&gt;Cost per 1GB is $2.3&lt;/b&gt;
&lt;/li&gt;
&lt;li&gt;Different support levels available for various paid tiers.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;How to choose the right video automation API?&lt;/h2&gt;

&lt;p&gt;Each of these tools brings something different to the table. If you need full control and scalability, Rendi’s raw FFmpeg access may be your best bet. For templated workflows and UI-based editing, Shotstack, Json2Video, and Creatomate offer appealing options. If your focus is on going with a large brand and high quality CDN delivery, Cloudinary is worth a look.&lt;/p&gt;

&lt;p&gt;Match the tool to your use case, and be aware that you might need to set a side a few days to test the tools' limits and pick the right one for you.&lt;/p&gt;

</description>
      <category>nocode</category>
      <category>automation</category>
      <category>ffmpeg</category>
      <category>api</category>
    </item>
    <item>
      <title>54 FFmpeg commands for video automation, with explanations</title>
      <dc:creator>Peter Naftaliev</dc:creator>
      <pubDate>Sun, 25 May 2025 16:24:01 +0000</pubDate>
      <link>https://dev.to/pinter/54-ffmpeg-commands-for-video-automation-with-explanations-4pbk</link>
      <guid>https://dev.to/pinter/54-ffmpeg-commands-for-video-automation-with-explanations-4pbk</guid>
      <description>&lt;p&gt;This is a cheatsheet of FFmpeg commands for video automation pipelines.&lt;/p&gt;

&lt;p&gt;Use this as inspiration for your own work, to troubleshoot your FFmpeg commands, or to explore what others are building in automated media apps.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This cheatsheet is an excerpt from: &lt;a href="https://github.com/rendi-api/ffmpeg-cheatsheet" rel="noopener noreferrer"&gt;https://github.com/rendi-api/ffmpeg-cheatsheet&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use this cheatsheet?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use the table of contents, best viewed in github's full view of the MD file, to browse through the main topics covered.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use Ctrl + F to find what you need. All commands, filters and flags are explained throughout the document. If you don't see a specific explanation, it means that it appears somewhere else in this document and you can search for it (and if you don't find it please open an issue and I will take care of it).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;All sample commands can immediately run from your local machine, since they use sample files that are stored online and FFmpeg is able to download them locally.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I have attached the original reference to each command, filter, flag, keyword, and explanation. Use these to dig deeper into FFmpeg, and in general - video formats. Some of the findings are my own, in which case no reference was specified.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There are dropdown arrows used to save on space, you can click on them to get deeper details. The browser is able to search through the text in these hidden sections and reveal them when needed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;To make the most of this cheatsheet, it is best to use it along with your favorite LLM (or MCP server or AI agent).&lt;/strong&gt; A few ways of doing that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Just copy the full text intro your LLM and let the LLM index of all the information found here. Make sure to copy the RAW version of the MD file for best results.&lt;/li&gt;
&lt;li&gt;You can also just refer the LLM to the URL of this file and have it index it.&lt;/li&gt;
&lt;li&gt;If you're interested in a specific command - copy it into the LLM and chat with the LLM to alter this command according to your specific needs&lt;/li&gt;
&lt;li&gt;You should find all the explanations you require for all the commands within this document and the references it provides. Still, you can always copy a command into the chat interface and have the LLM elaborate.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;As &lt;a href="https://www.reddit.com/r/ffmpeg/comments/1kdvimj/comment/mqf5dcz" rel="noopener noreferrer"&gt;someone on reddit said&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I know it burns a tree every time you ask gpt a question, but it beats slogging through 10 year old answers on stackexchange"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  About LLMs and FFmpeg
&lt;/h2&gt;

&lt;p&gt;I used LLMs as much as I could to make the work for this file as easy as possible, still, all commands and explanations have been tested and vetted by me manually. Many of them I have used in the pre-GPT era - hinting at how old I'm getting (🙈)&lt;/p&gt;

&lt;p&gt;LLMs miss out on FFmpeg because it sometimes requires accuracy and attention to fine details that are hard to find online, especially when working with complex filters. I like to use it as a sophisticated search and summarization engine - pointing out specific details and keywords that I then validate online.&lt;/p&gt;

&lt;p&gt;🛠️ - Headlines marked with 🛠️ are ones that were especially hard to find correct solutions or explanations with LLMs, or are too important to trust LLMs with the info, so I did manual research and trial and error.&lt;/p&gt;

&lt;h2&gt;
  
  
  Glossary of common flags\filters
&lt;/h2&gt;

&lt;p&gt;For those looking to optimize their existing FFmpeg commands, skip to the section starting at Command settings&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ffmpeg.org/ffmpeg-filters.html#Filtering-Introduction" rel="noopener noreferrer"&gt;Filtering&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-vf&lt;/code&gt; (also &lt;code&gt;-filter:v&lt;/code&gt;) video filter&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-af&lt;/code&gt; (also &lt;code&gt;-filter:a&lt;/code&gt;) audio filter&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;filter_complex&lt;/code&gt; Complex filter graph - used for general filtering, controlling both audio and video across all streams&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Common filter keywords (you can change the numbers to specify the required index):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;[0]&lt;/code&gt; Select all streams from the first input (0-based index)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[0:v]&lt;/code&gt; Select the video stream from first input&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[1:a]&lt;/code&gt; Select the audio stream from second input&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;0:v:0&lt;/code&gt; From first input, first video stream (0-based index)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;0:a:1&lt;/code&gt; From first input, second audio stream (0-based index)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[name]&lt;/code&gt; Select a named stream, usually used with &lt;code&gt;-filter_complex&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://trac.ffmpeg.org/wiki/Map" rel="noopener noreferrer"&gt;-map [name]&lt;/a&gt; Selecting stream for output&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ffmpeg.org/ffmpeg-all.html#Expression-Evaluation" rel="noopener noreferrer"&gt;Expression evaluations&lt;/a&gt; &lt;code&gt;if&lt;/code&gt; , &lt;code&gt;lte&lt;/code&gt; , &lt;code&gt;gte&lt;/code&gt; and more&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-y&lt;/code&gt; Auto-overwrite output files if existing. Add this flag to the beginning of every FFmpeg command to avoid it asking for confirmation of overwriting&lt;/p&gt;

&lt;h2&gt;
  
  
  Simple editing
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Converting formats
&lt;/h3&gt;

&lt;p&gt;Remux MP4 to MKV:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 &lt;span class="nt"&gt;-c&lt;/span&gt; copy big_buck_bunny_720p_16sec.mkv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-c copy&lt;/code&gt; - Read below&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;MKV and MP4:&lt;/em&gt; Both are video containers and can store H264 and H265 encoded videos and AAC and MP3 encoded audio. The video quality itself is not determined by the container format but rather by the video codec used to compress the video data.&lt;/p&gt;

&lt;p&gt;MKV can contain several streams of video, while MP4 is a more widely supported on different platforms and devices.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Remux MP4 to MOV:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 &lt;span class="nt"&gt;-c&lt;/span&gt; copy big_buck_bunny_720p_16sec.mov
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Encode MP4 to AVI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 big_buck_bunny_720p_16sec.avi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More about video encoding below&lt;/p&gt;

&lt;h3&gt;
  
  
  Resizing and padding
&lt;/h3&gt;

&lt;p&gt;🛠️ Upscale the video to 1080X1920 preserving the original aspect ratio and adding black padding to fill in gaps as needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/popeye_talking.mp4 &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"scale=w=1080:h=1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:color=black,setsar=1:1"&lt;/span&gt; output_resized_pad.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scale details&lt;/p&gt;

&lt;p&gt;&lt;a href="https://trac.ffmpeg.org/wiki/Scaling" rel="noopener noreferrer"&gt;scale=w=1080:h=1920:force_original_aspect_ratio=decrease&lt;/a&gt; resize video to fit inside 1080x1920, will automatically lower output dimensions to be equal or below the specified width and height, while fitting the original aspect ratio of the input. In this case, will down-scale the input to 1080X810, before adding padding.&lt;/p&gt;

&lt;p&gt;If you are unsure about the height (or width) required to keep the original aspect ratio, you can specify &lt;code&gt;scale=w=1080:h=-1&lt;/code&gt; and let FFmpeg pick the correct height, while making sure we keep the original aspect ratio and the maximum width is 1080.&lt;/p&gt;

&lt;p&gt;Specifying -2 &lt;code&gt;scale=w=1080:h=-2&lt;/code&gt; forces to use dimension sizes that are divisible by 2&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Notice that we can't use &lt;code&gt;scale=w=-1:1920&lt;/code&gt; here because it will make FFmpeg pick a width which is larger than 1080, conflicting with the output width we are looking for which is 1080 - resulting in an error.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://trac.ffmpeg.org/wiki/Scaling#fit" rel="noopener noreferrer"&gt;force_original_aspect_ratio:&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&amp;gt; ͏ Achievable with "force_original_aspect_ratio". Of 3 possible values:\&lt;br&gt;
&amp;gt;  ͏ |0| "disable" (default)\&lt;br&gt;
&amp;gt;  ͏ |1| "decrease": auto-decrease output dimensions on need.\&lt;br&gt;
&amp;gt;  ͏ |2| "increase": auto-increase output dimensions on need.&lt;/p&gt;

&lt;p&gt;Pad details&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ffmpeg.org/ffmpeg-filters.html#pad" rel="noopener noreferrer"&gt;pad=1080:1920:(ow-iw)/2:(oh-ih)/2:color=black&lt;/a&gt; Center the resized video and fill the rest with black padding. Values are &lt;code&gt;width:height:x:y&lt;/code&gt; where x:y is the top left corner. Negative values also place the image at the center, so you can use &lt;code&gt;pad=1080:1920:-1:-1:color=black&lt;/code&gt; for a similar effect.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ffmpeg.org/ffmpeg-filters.html#setdar_002c-setsar" rel="noopener noreferrer"&gt;setsar=1:1&lt;/a&gt; Sample aspect ratio - ensures the output pixels scale exactly to 1x1 per pixel. It could also be set to &lt;code&gt;1&lt;/code&gt; or &lt;code&gt;1/1&lt;/code&gt; - these are all the same. In some cases, FFmpeg may set the Sample Aspect Ratio to compensate for ratio change. Expressly state SAR 1:1 to make things work intended.&lt;/p&gt;

&lt;p&gt;Create two scaled videos from the same input video using one FFmpeg command - one horizontal and another vertical. To the vertical video add an overlay\logo to the top:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/popeye_talking.mp4 &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/rendi_banner_white.png &lt;span class="nt"&gt;-filter_complex&lt;/span&gt; &lt;span class="s2"&gt;"[0:v]split=2[s0][s1];[s0]scale=w=1920:h=1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2:color=black,setsar=1:1[out1];[s1]scale=w=720:h=1280:force_original_aspect_ratio=decrease,pad=720:1280:(ow-iw)/2:(oh-ih)/2:color=black,setsar=1:1[s2];[s2][1]overlay=(main_w-overlay_w)/2:(main_w-overlay_w)/5[out2]"&lt;/span&gt; &lt;span class="nt"&gt;-map&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;out1] &lt;span class="nt"&gt;-map&lt;/span&gt; 0:a output_youtube.mp4 &lt;span class="nt"&gt;-map&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;out2] &lt;span class="nt"&gt;-map&lt;/span&gt; 0:a  output_shorts.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two stackoverflow sources of info I constantly use &lt;a href="https://superuser.com/questions/547296/resizing-videos-with-ffmpeg-avconv-to-fit-into-static-sized-player/547406#547406" rel="noopener noreferrer"&gt;Link 1&lt;/a&gt; ; &lt;a href="https://superuser.com/questions/991371/ffmpeg-scale-and-pad" rel="noopener noreferrer"&gt;Link 2&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Trim by time
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/popeye_talking.mp4 &lt;span class="nt"&gt;-ss&lt;/span&gt; 00:00:10 &lt;span class="nt"&gt;-to&lt;/span&gt; 00:00:25 output_trimmed.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are faster ways to trim, but they are less accurate or can create black frames.&lt;/p&gt;

&lt;p&gt;For the advanced explanation see input\output seeking below&lt;/p&gt;

&lt;h2&gt;
  
  
  Audio Processing
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Replace audio in video
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/Neon_Lights_5sec.mp3 &lt;span class="nt"&gt;-map&lt;/span&gt; 0:v &lt;span class="nt"&gt;-map&lt;/span&gt; 1:a  &lt;span class="nt"&gt;-shortest&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;:v copy &lt;span class="nt"&gt;-c&lt;/span&gt;:a aac output_replace_audio.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace the audio in the video with a new audio file&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ffmpeg.org/ffmpeg.html#Advanced-options" rel="noopener noreferrer"&gt;-shortest&lt;/a&gt; Trims the video's end to be as short as the audio. If you want to keep the video length you can remove this flag (and the output will be muted after 5 seconds)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: Above command is unexpected in that it has &lt;code&gt;c:v copy&lt;/code&gt; - it trims in places that are not keyframes without re-encoding so I would have expected to see black frames. But, the output video looks perfect. Also, when trying to explicitly re-encode with &lt;code&gt;-c:v libx264&lt;/code&gt; the output video turned out to be 7 seconds long, longer than the shortest 5 second audio. Searching online I couldn't find an explanation for both these things.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Extract audio from video
&lt;/h3&gt;

&lt;p&gt;Encode MP4 to MP3:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 big_buck_bunny_720p_16sec.mp3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Extract the audio from an MP4 video, downsample it to 16,000 Hz, convert it to mono MP3, also extract the video (muted):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt;  https://storage.rendi.dev/sample/popeye_talking.mp4 &lt;span class="nt"&gt;-ar&lt;/span&gt; 16000 &lt;span class="nt"&gt;-ab&lt;/span&gt; 48k &lt;span class="nt"&gt;-codec&lt;/span&gt;:a libmp3lame &lt;span class="nt"&gt;-ac&lt;/span&gt; 1 output_extracted_audio.mp3 &lt;span class="nt"&gt;-map&lt;/span&gt; 0:v &lt;span class="nt"&gt;-c&lt;/span&gt;:v copy &lt;span class="nt"&gt;-an&lt;/span&gt; out_video_only.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://ffmpeg.org/ffmpeg.html#Audio-Options" rel="noopener noreferrer"&gt;FFmpeg audio options&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-ar&lt;/code&gt; Sample rate 16KHz - the amount of digital audio wave samples per second&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-b:a 48k&lt;/code&gt; (which is the same as &lt;code&gt;-ab&lt;/code&gt;) Bitrate 48KBit/s - which is the amount of data stored per second &lt;a href="https://superuser.com/questions/319542/how-to-specify-audio-and-video-bitrate" rel="noopener noreferrer"&gt;Stackoverflow reference&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-ac 1&lt;/code&gt; audio channels - 1 (mono)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Extract AAC audio from MP4 without encoding it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt;  https://storage.rendi.dev/sample/popeye_talking.mp4 &lt;span class="nt"&gt;-map&lt;/span&gt; 0:a:0 &lt;span class="nt"&gt;-acodec&lt;/span&gt; copy output.aac
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Mix the audio in video
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/Neon_Lights_5sec.mp3 &lt;span class="nt"&gt;-filter_complex&lt;/span&gt; &lt;span class="s2"&gt;"[1:a]volume=0.2[a1];[0:a][a1]amix=inputs=2:duration=shortest"&lt;/span&gt; &lt;span class="nt"&gt;-shortest&lt;/span&gt; &lt;span class="nt"&gt;-map&lt;/span&gt; 0:v &lt;span class="nt"&gt;-c&lt;/span&gt;:v copy &lt;span class="nt"&gt;-c&lt;/span&gt;:a aac output_mix_audio.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mix the audio in the video with a new audio file and lower its volume:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://trac.ffmpeg.org/wiki/Encode/AAC" rel="noopener noreferrer"&gt;AAC Reference&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://trac.ffmpeg.org/wiki/AudioVolume" rel="noopener noreferrer"&gt;[1:a]volume=0.2[a1]&lt;/a&gt; Lowers the volume of the audio file so we could also hear the audio from the video file, &lt;code&gt;[1:a]&lt;/code&gt; means audio from file 1, in a 0-based index. &lt;code&gt;[a1]&lt;/code&gt; marks the changed volume audio so that we could mix it with the video's audio.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ffmpeg.org/ffmpeg-filters.html#amix" rel="noopener noreferrer"&gt;[0:a][a1]amix=inputs=2&lt;/a&gt; Takes the audio from the first stream (the video) and the changed volume audio and mixes them together&lt;/p&gt;

&lt;p&gt;More details&lt;/p&gt;

&lt;p&gt;If you don't want to change volumes, you can just use this filter instead: &lt;code&gt;-filter_complex "[0:a][1:a]amix=inputs=2:duration=shortest"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;:duration=shortest&lt;/code&gt; makes the new audio as short as the shortest audio, the next &lt;code&gt;-shortest&lt;/code&gt; flag is still required because it controls the length of the final output video (and not just its audio)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://superuser.com/questions/801547/ffmpeg-add-audio-but-keep-video-length-the-same-not" rel="noopener noreferrer"&gt;Nice discussion&lt;/a&gt; about cases when video is shorter or longer than audio and you want to align the output video's length accordingly&lt;/p&gt;

&lt;p&gt;&lt;a href="https://trac.ffmpeg.org/ticket/9487" rel="noopener noreferrer"&gt;An open bug around this topic&lt;/a&gt; Using &lt;code&gt;duration:shortest&lt;/code&gt; and &lt;code&gt;-shortest&lt;/code&gt; avoids the implications of the bug.&lt;/p&gt;

&lt;h3&gt;
  
  
  Combine two mp3 tracks
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/Neon_Lights_5sec.mp3 &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/Neon%20Lights.mp3 &lt;span class="nt"&gt;-filter_complex&lt;/span&gt; &lt;span class="s2"&gt;"[0:a]afade=t=out:st=2:d=3[a0];[1:a]afade=t=in:st=0:d=3[a1];[a0][a1]concat=n=2:v=0:a=1"&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;:a libmp3lame &lt;span class="nt"&gt;-q&lt;/span&gt;:a 2 output_gapless_fade.mp3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://ffmpeg.org/ffmpeg-filters.html#afade-1" rel="noopener noreferrer"&gt;[0:a]afade=t=out:st=2:d=3...[1:a]afade=t=in:st=0:d=3&lt;/a&gt; Fade out the first and fade in the second:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First input audio &lt;code&gt;[0:a]&lt;/code&gt; 3-second &lt;code&gt;d=3&lt;/code&gt; fade out &lt;code&gt;t=out&lt;/code&gt; starting from its 2nd second &lt;code&gt;st=2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Second audio &lt;code&gt;[1:a]&lt;/code&gt; 3-second &lt;code&gt;d=3&lt;/code&gt; fade-in &lt;code&gt;t=in&lt;/code&gt; at start of the audio &lt;code&gt;st=0&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://ffmpeg.org/ffmpeg-filters.html#concat" rel="noopener noreferrer"&gt;[a0][a1]concat=n=2:v=0:a=1&lt;/a&gt; Concatenates the two faded audio streams back together to create 1 output audio stream, no video (&lt;code&gt;v=0&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://trac.ffmpeg.org/wiki/Encode/MP3" rel="noopener noreferrer"&gt;-q:a 2&lt;/a&gt; - High quality audio output with an average stereo bitrate of 170-210 KBit/s&lt;/p&gt;

&lt;h3&gt;
  
  
  Crossfade
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/Neon_Lights_5sec.mp3 &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/Neon%20Lights.mp3 &lt;span class="nt"&gt;-filter_complex&lt;/span&gt; &lt;span class="s2"&gt;"[0:0][1:0]acrossfade=d=3:c1=exp:c2=qsin"&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;:a libmp3lame &lt;span class="nt"&gt;-q&lt;/span&gt;:a 2 output.mp3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://ffmpeg.org/ffmpeg-filters.html#acrossfade" rel="noopener noreferrer"&gt;acrossfade=d=3:c1=exp:c2=qsin&lt;/a&gt; 3-second audio crossfade where first track fades out quickly while second track fades in slowly&lt;/p&gt;

&lt;h3&gt;
  
  
  Change audio format
&lt;/h3&gt;

&lt;p&gt;MP3 to WAV pcm_s32le (unsigned 32-bit little-endian) format, mono and 48KHz sample frequency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/Neon%20Lights.mp3 &lt;span class="nt"&gt;-acodec&lt;/span&gt; pcm_s32le &lt;span class="nt"&gt;-ac&lt;/span&gt; 1 &lt;span class="nt"&gt;-ar&lt;/span&gt; 48000 output.wav
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://trac.ffmpeg.org/wiki/audio%20types" rel="noopener noreferrer"&gt;Reference&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Merge the audio from two mp4 files, mix them into mono equally, normalizes the volume, downsample to 16 kHz, encode as MP3 at 64 KBits/s:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/popeye_talking.mp4 &lt;span class="nt"&gt;-filter_complex&lt;/span&gt; &lt;span class="s2"&gt;"[0:a][1:a]amix=inputs=2:duration=longest,pan=mono|c0=.5*c0+.5*c1,dynaudnorm"&lt;/span&gt; &lt;span class="nt"&gt;-ar&lt;/span&gt; 16000 &lt;span class="nt"&gt;-c&lt;/span&gt;:a libmp3lame &lt;span class="nt"&gt;-b&lt;/span&gt;:a 64k merged_audio.mp3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pan=mono|c0=.5*c0+.5*c1&lt;/code&gt; The output channel (c0) is made by blending 50% of the left input (&lt;code&gt;c0&lt;/code&gt;) and 50% of the right input (&lt;code&gt;c1&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dynaudnorm&lt;/code&gt; Applies dynamic audio normalization (smoothens loud/quiet parts)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://trac.ffmpeg.org/wiki/AudioChannelManipulation" rel="noopener noreferrer"&gt;FFmpeg docs about panning and stereo to mono&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced editing
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Change playback speed, without distorting audio
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/popeye_talking.mp4 &lt;span class="nt"&gt;-filter_complex&lt;/span&gt; &lt;span class="s2"&gt;"[0:v]setpts=PTS/1.5[v];[0:a]atempo=1.5[a]"&lt;/span&gt; &lt;span class="nt"&gt;-map&lt;/span&gt; &lt;span class="s2"&gt;"[v]"&lt;/span&gt; &lt;span class="nt"&gt;-map&lt;/span&gt; &lt;span class="s2"&gt;"[a]"&lt;/span&gt; output_sped_up.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://ffmpeg.org/ffmpeg-filters.html#setpts_002c-asetpts" rel="noopener noreferrer"&gt;setpts=PTS/1.5&lt;/a&gt; speeds up video by 1.5x. &lt;code&gt;atempo=1.5&lt;/code&gt; speeds up audio playback rate while preserving pitch&lt;/p&gt;

&lt;h3&gt;
  
  
  Change video frame per second without changing audio speed
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/popeye_talking.mp4 &lt;span class="nt"&gt;-filter&lt;/span&gt;:v &lt;span class="nv"&gt;fps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;60 popeye_fps.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/45462731/using-ffmpeg-to-change-framerate" rel="noopener noreferrer"&gt;Stackoverflow reference&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Jump cuts
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/popeye_talking.mp4 &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"select='between(t,0.0,5.7)+between(t,11.0,18.0)+between(t,19.0,20.0)',setpts=N/FRAME_RATE/TB"&lt;/span&gt; &lt;span class="nt"&gt;-af&lt;/span&gt; &lt;span class="s2"&gt;"aselect='between(t,0.0,5.7)+between(t,11.0,18.0)+between(t,19.0,20.0)',asetpts=N/SR/TB"&lt;/span&gt; popeye_jumpcuts.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Used for making clips shorter, silence removal, removing transitions, etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ffmpeg.org/ffmpeg-filters.html#setpts_002c-asetpts" rel="noopener noreferrer"&gt;setpts=N/FRAME_RATE/TB...asetpts=N/SR/TB&lt;/a&gt; Reset video and audio presentation timestamps according to the trims requested&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;N&lt;/code&gt; The count of consumed frames\audio samples, not including the current frame for audio, starting from 0&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FRAME_RATE&lt;/code&gt; \ &lt;code&gt;SR&lt;/code&gt; Video frame rate and audio sample rate&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TB&lt;/code&gt; The timebase of the input timestamps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/50594412/cut-multiple-parts-of-a-video-with-ffmpeg" rel="noopener noreferrer"&gt;Stackoverflow reference&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🛠️ Video cropping for social media
&lt;/h3&gt;

&lt;p&gt;Crop a 1080X720 video to 720X1080 by cropping chunks of video to 480X720 and upscaling them by 1.5 at specific time frames to create a vertical social media video:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"split=3[1][2][3];[1]trim=0.0:4.5,setpts=PTS-STARTPTS,crop=min(in_w-300&lt;/span&gt;&lt;span class="se"&gt;\,&lt;/span&gt;&lt;span class="s2"&gt;480):min(in_h-0&lt;/span&gt;&lt;span class="se"&gt;\,&lt;/span&gt;&lt;span class="s2"&gt;720):300:0,scale=720:1080,setsar=1:1[1];[2]trim=4.5:8.5,setpts=PTS-STARTPTS,crop=min(in_w-500&lt;/span&gt;&lt;span class="se"&gt;\,&lt;/span&gt;&lt;span class="s2"&gt;480):min(in_h-0&lt;/span&gt;&lt;span class="se"&gt;\,&lt;/span&gt;&lt;span class="s2"&gt;720):500:0,scale=720:1080,setsar=1:1[2];[3]trim=8.5,setpts=PTS-STARTPTS,crop=min(in_w-400&lt;/span&gt;&lt;span class="se"&gt;\,&lt;/span&gt;&lt;span class="s2"&gt;480):min(in_h-0&lt;/span&gt;&lt;span class="se"&gt;\,&lt;/span&gt;&lt;span class="s2"&gt;720):400:0,scale=720:1080,setsar=1:1[3];[1][2][3]concat=n=3:v=1"&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="nt"&gt;-c&lt;/span&gt;:a copy output_cropped.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://ffmpeg.org/ffmpeg-filters.html#split_002c-asplit" rel="noopener noreferrer"&gt;split=3[1][2][3]&lt;/a&gt; Splits the input video into 3 chunks and names them &lt;code&gt;[1]&lt;/code&gt; &lt;code&gt;[2]&lt;/code&gt; &lt;code&gt;[3]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ffmpeg.org/ffmpeg-filters.html#trim" rel="noopener noreferrer"&gt;trim=0.0:4.5&lt;/a&gt; Each crop chunk is a temporary new video starting from the start time and ending in the end time &lt;code&gt;[3]trim=8.5&lt;/code&gt; does not specify an end time, so it will end with the video&lt;/p&gt;

&lt;p&gt;Resetting timestamps with &lt;a href="https://ffmpeg.org/ffmpeg-filters.html#setpts_002c-asetpts" rel="noopener noreferrer"&gt;setpts=PTS-STARTPTS&lt;/a&gt; is required when using trim and concat to make sure that concat works correctly over seemingly separate video streams (the trimmed streams)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ffmpeg.org/ffmpeg-filters.html#crop" rel="noopener noreferrer"&gt;crop=min(in_w-300\,480):min(in_h-0\,720):300:0&lt;/a&gt; The values are &lt;code&gt;width:height:x:y&lt;/code&gt; x,y are the top left corner. The min dimensions ensure FFmpeg won't crop outside the designated size of the output frame, before scaling. The minimum calculations are not required in this scenario, they are there as placeholders in case you will require different dimensions or x,y positioning&lt;/p&gt;

&lt;p&gt;If cropping is outside the boundaries of the frame - the crop will distort the video. In order to handle this, we can use black padding to fill in the gaps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"split=3[1][2][3];[1]trim=0.0:4.5,setpts=PTS-STARTPTS,crop=min(in_w-1200&lt;/span&gt;&lt;span class="se"&gt;\,&lt;/span&gt;&lt;span class="s2"&gt;480):min(in_h-0&lt;/span&gt;&lt;span class="se"&gt;\,&lt;/span&gt;&lt;span class="s2"&gt;720):1200:0,pad=480:720:(ow-iw)/2:(oh-ih)/2:color=black,scale=720:1080,setsar=1:1[1];[2]trim=4.5:8.5,setpts=PTS-STARTPTS,crop=min(in_w-500&lt;/span&gt;&lt;span class="se"&gt;\,&lt;/span&gt;&lt;span class="s2"&gt;480):min(in_h-0&lt;/span&gt;&lt;span class="se"&gt;\,&lt;/span&gt;&lt;span class="s2"&gt;720):500:0,pad=480:720:(ow-iw)/2:(oh-ih)/2:color=black,scale=720:1080,setsar=1:1[2];[3]trim=8.5,setpts=PTS-STARTPTS,crop=min(in_w-400&lt;/span&gt;&lt;span class="se"&gt;\,&lt;/span&gt;&lt;span class="s2"&gt;480):min(in_h-0&lt;/span&gt;&lt;span class="se"&gt;\,&lt;/span&gt;&lt;span class="s2"&gt;720):400:0,pad=480:720:(ow-iw)/2:(oh-ih)/2:color=black,scale=720:1080,setsar=1:1[3];[1][2][3]concat=n=3:v=1"&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="nt"&gt;-c&lt;/span&gt;:a copy output_cropped.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Overlay text on video
&lt;/h3&gt;

&lt;p&gt;Overlay three different text messages on a video, each appearing at a specific time, with a fade-in alpha effect and a semi-transparent background box.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"drawtext=text='Get ready':x=50:y=100:fontsize=80:fontcolor=black:alpha='if(gte(t,1)*lte(t,3),(t-1)/2,1)':box=1:boxcolor=#6bb666@0.6:boxborderw=7:enable='gte(t,1)', drawtext=text='Set':x=50:y=200:fontsize=80:fontcolor=black:alpha='if(gte(t,6)*lte(t,10),(t-6)/4,1)':box=1:boxcolor=#6bb666@0.6:boxborderw=7:enable='gte(t,6)', drawtext=text='BOOM!':x=50:y=300:fontsize=80:fontcolor=black:alpha='if(gte(t,10)*lte(t,15),(t-10)/5,1)':box=1:boxcolor=#6bb666@0.6:boxborderw=7:enable='gte(t,10)'"&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 output_text_overlay.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have a locally stored font file, you can specify it using: &lt;code&gt;fontfile=&amp;lt;path_to_file&amp;gt;&lt;/code&gt;, for example: &lt;code&gt;drawtext=text='Get ready':x=50:y=100:fontsize=80:fontcolor=black:fontfile=arial.ttf&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;drawtext details&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ffmpeg.org/ffmpeg-filters.html#drawtext-1" rel="noopener noreferrer"&gt;drawtext&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Explanation of the "Get ready" overlay &lt;code&gt;drawtext=text='Get ready':x=50:y=100:fontsize=80:fontcolor=black:alpha='if(gte(t,1)*lte(t,3),(t-1)/2,1)':box=1:boxcolor=#6bb666@0.6:boxborderw=7:enable='gte(t,1)'&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://ffmpeg.org/ffmpeg-filters.html#Timeline-editing" rel="noopener noreferrer"&gt;enable='gte(t,1)'&lt;/a&gt; Controls when the overlay is visible - greater than or equal to 1 seconds. &lt;code&gt;*&lt;/code&gt; is the AND operator Display from t = 1s&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;alpha='if(gte(t,1)*lte(t,3),(t-1)/2,1)'&lt;/code&gt; Alpha fades in between t=1 to t=3, at all other times it equals 1 (fully opaque)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;box=1&lt;/code&gt; draws a background behind the text with 7px padding &lt;code&gt;boxborderw=7&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ffmpeg.org/ffmpeg-utils.html#color-syntax" rel="noopener noreferrer"&gt;boxcolor=#6bb666@0.6&lt;/a&gt; — greenish background #6bb666 at 60% opacity.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;x=50:y=100&lt;/code&gt; Top left position of box&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add text overlay to video from a text file and font file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"drawtext=textfile=sample_text.txt:fontfile=Poppins-Regular.ttf:x=50:y=100:fontsize=40:fontcolor=black:alpha='if(gte(t,1)*lte(t,5),t-1,1)':box=1:boxcolor=#6bb666@0.6:boxborderw=7:enable='gte(t,1)'"&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 output_text_font_file.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;FFmpeg does not download the files within &lt;code&gt;textfile=&lt;/code&gt; and &lt;code&gt;fontfile=&lt;/code&gt; , therefore you need to download the file manually from &lt;a href="https://storage.rendi.dev/sample/sample_text.txt" rel="noopener noreferrer"&gt;https://storage.rendi.dev/sample/sample_text.txt&lt;/a&gt; and &lt;a href="https://storage.rendi.dev/sample/Poppins-Regular.ttf" rel="noopener noreferrer"&gt;https://storage.rendi.dev/sample/Poppins-Regular.ttf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is recommended to use textfile instead of specifying the text within the FFmpeg command itself, to avoid issues with special characters that could interfere with the command line syntax.&lt;/p&gt;

&lt;h3&gt;
  
  
  🛠️ Add subtitles to a video
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p.mp4 &lt;span class="nt"&gt;-ss&lt;/span&gt; 00:00 &lt;span class="nt"&gt;-to&lt;/span&gt; 00:40 &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"subtitles=sample_subtitles.srt:fontsdir=.:force_style='FontName=Poppins,FontSize=24,PrimaryColour=&amp;amp;HFFFFFF,OutlineColour=&amp;amp;H4066B66B,Outline=1,BorderStyle=3'"&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264  &lt;span class="nt"&gt;-c&lt;/span&gt;:a copy output_subtitles.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command burns subtitles with a custom font - &lt;code&gt;Poppins&lt;/code&gt;, with custom subtitles style. Notice to use the &lt;code&gt;FontName&lt;/code&gt; (and not the file name) - you can find it when you open the font file. Also, specify the &lt;code&gt;fontsdir&lt;/code&gt; which holds the font file.&lt;/p&gt;

&lt;p&gt;You can download the Poppins font file from &lt;a href="https://storage.rendi.dev/sample/Poppins-Regular.ttf" rel="noopener noreferrer"&gt;https://storage.rendi.dev/sample/Poppins-Regular.ttf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Subtitle details&lt;/p&gt;

&lt;p&gt;Colors are either &lt;code&gt;&amp;amp;amp;HBBGGRR&lt;/code&gt; - blue, green, red or &lt;code&gt;&amp;amp;amp;HAABBGGRR&lt;/code&gt; if you want to add alpha channel (transparency) with FF being 100% transparent and 00 is no transparency.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;PrimaryColour&lt;/code&gt; is the font color&lt;/p&gt;

&lt;p&gt;🛠️ &lt;code&gt;OutlineColour=&amp;amp;amp;H4066B66B,Outline=1,BorderStyle=3&lt;/code&gt; Configures the green background (40/FF in HEXA is 25% opaque) and #6bb666 color in RGB. In order to make the background appear you have to set &lt;code&gt;Outline=1,BorderStyle=3&lt;/code&gt; Stylizing the background is a bit tricky, &lt;a href="https://www.reddit.com/r/ffmpeg/comments/hhytkm/styling_subtitle/" rel="noopener noreferrer"&gt;this reddit thread&lt;/a&gt; has useful info.&lt;/p&gt;

&lt;p&gt;Official FFmpeg documentation: &lt;a href="https://trac.ffmpeg.org/wiki/HowToBurnSubtitlesIntoVideo" rel="noopener noreferrer"&gt;How To Burn Subtitles Into Video&lt;/a&gt; ; &lt;a href="https://ffmpeg.org/ffmpeg-filters.html#subtitles-1" rel="noopener noreferrer"&gt;Subtitles filter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to really customize your subtitles' appearance, the best option is using the ASS subtitles format. &lt;a href="https://hhsprings.bitbucket.io/docs/programming/examples/ffmpeg/subtitle/ass.html" rel="noopener noreferrer"&gt;A good source of info which I use it constantly.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For pixel-perfect subtitle burning with special effects and unique appearances, it is best to create opaque images outside of any subtitle format and burn images on the video with FFmpeg.&lt;/p&gt;

&lt;p&gt;Add a default subtitles srt track to the video and store it in an MKV container, without re-encoding the video, the codec remains H264:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 &lt;span class="nt"&gt;-i&lt;/span&gt; sample_subtitles.srt &lt;span class="nt"&gt;-c&lt;/span&gt; copy &lt;span class="nt"&gt;-c&lt;/span&gt;:s srt &lt;span class="nt"&gt;-disposition&lt;/span&gt;:s:0 default big_buck_bunny_720p_16sec.mkv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-c:s srt&lt;/code&gt; Subtitle format is srt&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ffmpeg.org/ffmpeg.html#Stream-specifiers-1" rel="noopener noreferrer"&gt;-disposition:s:0&lt;/a&gt; default Sets on the default subtitles track&lt;/p&gt;

&lt;p&gt;Extract the subtitles from the mkv file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; big_buck_bunny_720p_16sec.mkv &lt;span class="nt"&gt;-map&lt;/span&gt; 0:s:0 subs.srt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Extract the subtitles from the mkv file&lt;/p&gt;

&lt;h3&gt;
  
  
  Combine media assets
&lt;/h3&gt;

&lt;p&gt;Overlay an image on video - add logo\watermark to video:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/rendi_banner_white_transparent.png &lt;span class="nt"&gt;-filter_complex&lt;/span&gt; &lt;span class="s2"&gt;"overlay=x=(main_w-overlay_w)/8:y=(main_h-overlay_h)/8:enable='gte(t,1)*lte(t,7)'"&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="nt"&gt;-c&lt;/span&gt;:a  output_logo.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above command puts an overlay with a transparent background on top of the video&lt;/p&gt;

&lt;p&gt;&lt;code&gt;x=(main_w-overlay_w)/8:y=(main_h-overlay_h)/8&lt;/code&gt; Positions the overlay's top left corner horizontally at 1/8th of the remaining space from the left and top&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;main_w\main_h&lt;/code&gt; is the width and height of the main video&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;overlay_w\overlay_h&lt;/code&gt; is the width and height of the overlay image&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;enable='gte(t,1)*lte(t,7)'&lt;/code&gt; Controls when the overlay is visible - greater than or equal to 1 seconds and less than or equal to 7 seconds, &lt;code&gt;*&lt;/code&gt; is the AND operator&lt;/p&gt;

&lt;p&gt;🛠 If you want FFmpeg to control the overlay's transparency you can use this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/rendi_banner_white.png &lt;span class="nt"&gt;-filter_complex&lt;/span&gt;  &lt;span class="s2"&gt;"[1:v]format=argb,geq='p(X,Y)':a='0.5*alpha(X,Y)'[v1];[0:v][v1]overlay=x=(main_w-overlay_w)/8:y=(main_h-overlay_h)/8:enable='gte(t,1)*lte(t,7)'"&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="nt"&gt;-c&lt;/span&gt;:a copy output_faded_logo.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;[1:v]format=argb,geq=r='r(X,Y)':a='0.5*alpha(X,Y)'[v1]&lt;/code&gt; Creates the transparent logo&lt;/p&gt;

&lt;p&gt;Details&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;[1:v]&lt;/code&gt; Selects the video stream from the second input (the logo)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;format=argb&lt;/code&gt; Converts the image to ARGB format, so it works with overlay images that don't have an alpha channel&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ffmpeg.org/ffmpeg-filters.html#geq" rel="noopener noreferrer"&gt;geq='p(X,Y)'&lt;/a&gt; defines the color of the pixel of the logo at point X,Y to be the color from the original image. It is required in order to exactly control the transparency of the pixel&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;a='0.5*alpha(X,Y)'&lt;/code&gt; makes the logo 50% transparent by multiplying the alpha channel by 0.5&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[v1]&lt;/code&gt; marks this processed logo as a new video stream&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Put video on top of a background image - creating a video in a new resolution and aspect ratio:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/popeye_talking.mp4 &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/evil-frank.png &lt;span class="nt"&gt;-filter_complex&lt;/span&gt; &lt;span class="s2"&gt;"[1:v][0:v]overlay=(W-w)/2:(H-h)/2"&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="nt"&gt;-c&lt;/span&gt;:a copy output_bg.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;[1:v][0:v]&lt;/code&gt; First puts the image (background) and on top puts the video.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;(W-w)/2:(H-h)/2&lt;/code&gt; centers the video horizontally and vertically on the background image by picking the video's top left corner accordingly. W\H are background width and height, w\h are video width and height, the capital letters belong to the first specified stream &lt;code&gt;[1:v]&lt;/code&gt; and lower case is the second specified stream &lt;code&gt;[0:v]&lt;/code&gt;. Notice that the order is based on &lt;code&gt;[1:v][0:v]&lt;/code&gt; and not the order of the input files.&lt;/p&gt;

&lt;p&gt;Combine intro main and outro to one video and mix with background music:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_5sec_intro.mp4 &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/popeye_talking.mp4 &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_5sec_outro.mp4 &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/Neon%20Lights.mp3 &lt;span class="nt"&gt;-filter_complex&lt;/span&gt; &lt;span class="s2"&gt;"[0:v]fps=30,format=yuv420p,setsar=1[intro_v];[1:v]scale=-2:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2:black,fps=30,format=yuv420p,setsar=1[main_v];[2:v]fps=30,format=yuv420p,setsar=1[outro_v];[0:a]aformat=sample_fmts=fltp:channel_layouts=stereo[intro_a];[1:a]aformat=sample_fmts=fltp:channel_layouts=stereo[main_a];[2:a]aformat=sample_fmts=fltp:channel_layouts=stereo[outro_a];[intro_v][intro_a][main_v][main_a][outro_v][outro_a]concat=n=3:v=1:a=1[combined_video][combined_audio];[3:a]volume=0.1,aformat=sample_fmts=fltp,afade=t=in:ss=0:d=1.5,afade=t=out:st=20:d=2[bgm_faded];[combined_audio][bgm_faded]amix=inputs=2:duration=first:dropout_transition=2[final_audio]"&lt;/span&gt; &lt;span class="nt"&gt;-map&lt;/span&gt; &lt;span class="s2"&gt;"[combined_video]"&lt;/span&gt; &lt;span class="nt"&gt;-map&lt;/span&gt; &lt;span class="s2"&gt;"[final_audio]"&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="nt"&gt;-c&lt;/span&gt;:a aac &lt;span class="nt"&gt;-shortest&lt;/span&gt; intro_main_outro.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;duration=first&lt;/code&gt; The output audio stream duration should be the like the input stream (the combined audio), &lt;code&gt;dropout_transition=2&lt;/code&gt; creates a fade out effect for the shorter audio so that it won't cut off abruptly&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ffmpeg.org/ffmpeg.html#Audio-Options" rel="noopener noreferrer"&gt;aformat=sample_fmts=fltp&lt;/a&gt; Convert audio format to 32-bit float planar (a commonly used format in FFmpeg), couldn't find good simple sources for it online&lt;/p&gt;

&lt;p&gt;🛠️ Stack two videos vertically and keep the audio of the second video:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/popeye_talking.mp4 &lt;span class="nt"&gt;-filter_complex&lt;/span&gt; &lt;span class="s2"&gt;"[0:v]scale=720:-2:force_original_aspect_ratio=decrease,pad=720:640:(ow-iw)/2:(oh-ih)/2:black[top];[1:v]scale=720:-2:force_original_aspect_ratio=decrease,pad=720:640:(ow-iw)/2:(oh-ih)/2:black[bottom];[top][bottom]vstack=inputs=2:shortest=1[v]"&lt;/span&gt; &lt;span class="nt"&gt;-map&lt;/span&gt; &lt;span class="s2"&gt;"[v]"&lt;/span&gt; &lt;span class="nt"&gt;-map&lt;/span&gt; 1:a &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="nt"&gt;-c&lt;/span&gt;:a aac &lt;span class="nt"&gt;-shortest&lt;/span&gt; output_stacked.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://ffmpeg.org/ffmpeg-filters.html#Options-for-filters-with-several-inputs-_0028framesync_0029" rel="noopener noreferrer"&gt;shortest=1&lt;/a&gt; from the two video streams we follow the shortest when vstacking both. &lt;code&gt;-shortest&lt;/code&gt; between the output video and the audio from the second input video we pick the shortest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Asset generation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Image to video
&lt;/h3&gt;

&lt;p&gt;Create a 10 second video from a looping input image and audio file, image fades into view:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-loop&lt;/span&gt; 1 &lt;span class="nt"&gt;-t&lt;/span&gt; 10 &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/bbb-splash.png &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/Neon%20Lights.mp3 &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:-1:-1:color=black,setsar=1,fade=t=in:st=0:d=1,format=yuv420p"&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="nt"&gt;-c&lt;/span&gt;:a aac &lt;span class="nt"&gt;-shortest&lt;/span&gt; output_loop.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Above command runs slowly because it is downloading the image frame for every video frame. To make it run faster, download the png locally and run the command with the local file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-loop 1&lt;/code&gt; Infinitely loop over the input image. &lt;code&gt;-t 10&lt;/code&gt; the duration of the input loop to take is 10 seconds, so even though we infinitely loop the input image, we stop after 10 seconds.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://video.stackexchange.com/questions/12905/repeat-loop-input-video-with-ffmpeg" rel="noopener noreferrer"&gt;Excellent stackoverflow reference about loops - must read&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ffmpeg.org/ffmpeg-filters.html#fade" rel="noopener noreferrer"&gt;fade=t=in:st=0:d=1&lt;/a&gt; 1-second (&lt;code&gt;d=1&lt;/code&gt;) fade-in (&lt;code&gt;t=in&lt;/code&gt;) at start of the video (&lt;code&gt;st=0&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;🛠️ Create a slideshow video of 5 seconds per input image and background audio, fading between images:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-loop&lt;/span&gt; 1 &lt;span class="nt"&gt;-t&lt;/span&gt; 5 &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/rodents.png &lt;span class="nt"&gt;-loop&lt;/span&gt; 1 &lt;span class="nt"&gt;-t&lt;/span&gt; 5 &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/evil-frank.png &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/Neon%20Lights.mp3 &lt;span class="nt"&gt;-filter_complex&lt;/span&gt; &lt;span class="s2"&gt;"[0:v]format=yuv420p,fade=t=in:st=0:d=0.5,setpts=PTS-STARTPTS[v0];[1:v]format=yuv420p,fade=t=out:st=4.5:d=0.5,setpts=PTS-STARTPTS[v1];[v0][v1]xfade=transition=fade:duration=0.5:offset=4.5,format=yuv420p[v]"&lt;/span&gt; &lt;span class="nt"&gt;-map&lt;/span&gt; &lt;span class="s2"&gt;"[v]"&lt;/span&gt; &lt;span class="nt"&gt;-map&lt;/span&gt; 2:a &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="nt"&gt;-c&lt;/span&gt;:a aac &lt;span class="nt"&gt;-shortest&lt;/span&gt; slideshow_with_fade.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The resulting video is 9.5 seconds because there is an overlap of 0.5 second when fading from the first image to the second image. First image is faded in and last image is faded out.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;[0:v]...[v0];[1:v]...[v1];[v0][v1]...[v]&lt;/code&gt; First input video stream &lt;code&gt;[0:v]&lt;/code&gt; is filtered with fade in and its result is marked as &lt;code&gt;v0&lt;/code&gt;, then second input video stream is filtered and its result is marked as &lt;code&gt;v1&lt;/code&gt;, then they are concatenated together with xfade and the output video result is marked as &lt;code&gt;v&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://trac.ffmpeg.org/wiki/Xfade" rel="noopener noreferrer"&gt;xfade=transition=fade:duration=0.5:offset=4.5&lt;/a&gt; Starts fade out transition of the first image at its 4.5 second, which lasts 0.5 second, while adding the second image during the transition.&lt;/p&gt;

&lt;p&gt;🛠️ Create a Ken Burns style video from images:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-loop&lt;/span&gt; 1 &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/rodents.png &lt;span class="nt"&gt;-loop&lt;/span&gt; 1 &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/evil-frank.png &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/Neon%20Lights.mp3 &lt;span class="nt"&gt;-filter_complex&lt;/span&gt; &lt;span class="s2"&gt;"[0:v]scale=8000:-1,zoompan=z='zoom+0.005':x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':d=100:s=1920x1080:fps=25,trim=duration=4,format=yuv420p,setpts=PTS-STARTPTS[v0];[1:v]scale=8000:-1,zoompan=z='if(lte(zoom,1.0),1.5,max(zoom-0.005,1.005))':x=0:y='ih/2-(ih/zoom/2)':d=100:s=1920x1080:fps=25,trim=duration=4,format=yuv420p,setpts=PTS-STARTPTS[v1];[v0][v1]xfade=transition=fade:duration=1:offset=3,format=yuv420p[v]"&lt;/span&gt; &lt;span class="nt"&gt;-map&lt;/span&gt; &lt;span class="s2"&gt;"[v]"&lt;/span&gt; &lt;span class="nt"&gt;-map&lt;/span&gt; 2:a &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="nt"&gt;-c&lt;/span&gt;:a aac &lt;span class="nt"&gt;-shortest&lt;/span&gt; output_kenburns.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Command creates a video from two input images and background audio. Zooms in on the first image's center, plays it for 4 seconds and fade transitions to the next image.&lt;br&gt;
Second image zooms out from its left side while playing it for 4 seconds.&lt;br&gt;
Output is 7 seconds long because of 1 second fade transition between the two image chunks and command shortens the audio to match the video&lt;/p&gt;

&lt;p&gt;&lt;code&gt;z='zoom+0.005'&lt;/code&gt; Every new frame generated adds 0.005 zoom to the previous frame, or, zooms in the previous frame by 1.005&lt;/p&gt;

&lt;p&gt;&lt;code&gt;x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)'&lt;/code&gt; Pan to the center of the frame&lt;/p&gt;

&lt;p&gt;&lt;code&gt;d=100:s=1920x1080:fps=25&lt;/code&gt; specifies that the effect will generate 100 frames (&lt;code&gt;d&lt;/code&gt;), of output resolution &lt;code&gt;s=1920x1080&lt;/code&gt; and 25 frames per second &lt;code&gt;fps&lt;/code&gt; which is 4 seconds effect (100 frames divided by 25 fps)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;scale=8000:-1&lt;/code&gt; Used to first upscale the frame and then zoom on it, this avoids a &lt;a href="https://trac.ffmpeg.org/ticket/4298" rel="noopener noreferrer"&gt;jitteriness bug&lt;/a&gt; which occurs with zoompan filter, at the cost of more compute time for upscaling. &lt;code&gt;-1&lt;/code&gt; means to adjust the height so that aspect ratio will be preserved according to 8000px width. Good reads: &lt;a href="https://superuser.com/a/1112680/431710" rel="noopener noreferrer"&gt;https://superuser.com/a/1112680/431710&lt;/a&gt; , &lt;a href="https://superuser.com/questions/1112617/ffmpeg-smooth-zoompan-with-no-jiggle" rel="noopener noreferrer"&gt;https://superuser.com/questions/1112617/ffmpeg-smooth-zoompan-with-no-jiggle&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ffmpeg.org/ffmpeg-filters.html#zoompan" rel="noopener noreferrer"&gt;zoompan=z='if(lte(zoom,1.0),1.5,max(zoom-0.005,1.005))'&lt;/a&gt; This part zooms out of a zoomed-in starting frame. If the zoom factor is less than 1.0 then we set it to 1.5 - this corresponds to the starting frame. Then the command zooms out by 0.005 at each frame until it reaches a zoom factor of 1.005, giving the zoom-out effect, and then stops changing the zoom - keeping it from resetting the zoom out effect.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;trim=duration=4&lt;/code&gt; It was not possible to specify &lt;code&gt;-t=4&lt;/code&gt; before the input file and keep this image chunk at 4 seconds (like above in create a video from a looping input image). When trying to do that, the first chunk is of a correct length because of &lt;code&gt;xfade&lt;/code&gt; up to 4 seconds, but the second chunk gets repeated so that the total output video matches the audio's length. I tried different ways of solving it, but nothing helped. This is probably due to the zoompan filter which basically eliminates the purpose of &lt;code&gt;-t&lt;/code&gt; by specifying the fps and the frames number without specifying a hard maximum cap.&lt;br&gt;
The only thing that worked is to specify the trim duration after the zoompan.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Ken_Burns_effect" rel="noopener noreferrer"&gt;Ken Burns Effect&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mko.re/blog/ken-burns-ffmpeg/" rel="noopener noreferrer"&gt;Blog post about ken burns and FFmpeg&lt;/a&gt;:&lt;/p&gt;

&lt;h3&gt;
  
  
  Create GIFs
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"select='gt(trunc(t/2),trunc(prev_t/2))',setpts='PTS*0.1',scale=trunc(oh*a/2)*2:320:force_original_aspect_ratio=decrease,pad=trunc(oh*a/2)*2:320:-1:-1"&lt;/span&gt; &lt;span class="nt"&gt;-loop&lt;/span&gt; 0 &lt;span class="nt"&gt;-an&lt;/span&gt; output.gif
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a looping gif from video auto-scaled to 320px width, taking every 2nd frame (&lt;code&gt;lte(n\,1)+gt(trunc(t/2),trunc(prev_t/2))&lt;/code&gt;) and accelerating the playing speed by 10 (&lt;code&gt;setpts='PTS*0.1'&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-loop 0&lt;/code&gt; is the default, and can actually be omitted, stating that the loop is indefinite. To only loops once use &lt;code&gt;-loop 1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://superuser.com/questions/556029/how-do-i-convert-a-video-to-gif-using-ffmpeg-with-reasonable-quality/556031#556031" rel="noopener noreferrer"&gt;Good reference&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Turn video frames into a video compilation
&lt;/h3&gt;

&lt;p&gt;Create a video compilation based on single input video which gets split into parts, with fade effects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/BigBuckBunny_320x180.mp4 &lt;span class="nt"&gt;-filter_complex&lt;/span&gt; &lt;span class="s2"&gt;"[0:v]trim=start=11:end=15,setpts=PTS-STARTPTS,fade=t=in:st=0:d=0.5,fade=t=out:st=3.5:d=0.5[v1];[0:a]atrim=start=11:end=15,asetpts=PTS-STARTPTS,afade=t=in:st=0:d=0.5,afade=t=out:st=3.5:d=0.5[a1];[0:v]trim=start=21:end=25,setpts=PTS-STARTPTS,fade=t=in:st=0:d=0.5,fade=t=out:st=3.5:d=0.5[v2];[0:a]atrim=start=21:end=25,asetpts=PTS-STARTPTS,afade=t=in:st=0:d=0.5,afade=t=out:st=3.5:d=0.5[a2];[v1][a1][v2][a2]concat=n=2:v=1:a=1[outv][outa]"&lt;/span&gt; &lt;span class="nt"&gt;-map&lt;/span&gt; &lt;span class="s2"&gt;"[outv]"&lt;/span&gt; &lt;span class="nt"&gt;-map&lt;/span&gt; &lt;span class="s2"&gt;"[outa]"&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="nt"&gt;-c&lt;/span&gt;:a aac output_fade_in_out.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command takes two segments from the input video (11-15 seconds and 21-25 seconds) applies fade in/out effects to each segment and concatenates both.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;trim=start=X:end=Y&lt;/code&gt; Cuts video to specified time range, &lt;code&gt;atrim&lt;/code&gt; - corresponding for audio&lt;/p&gt;

&lt;p&gt;&lt;code&gt;setpts=PTS-STARTPTS&lt;/code&gt; Resets timestamps to start from 0&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fade=t=in:st=0:d=0.5...fade=t=out:st=3.5:d=0.5&lt;/code&gt; See above in creating a slideshow&lt;/p&gt;

&lt;p&gt;&lt;code&gt;afade&lt;/code&gt; See above in audio processing&lt;/p&gt;

&lt;p&gt;&lt;code&gt;concat=n=2:v=1:a=1&lt;/code&gt; Combines two segments with both video and audio&lt;/p&gt;

&lt;h3&gt;
  
  
  Create thumbnails from video
&lt;/h3&gt;

&lt;p&gt;Create a thumbnail from the frame in second 7:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 &lt;span class="nt"&gt;-ss&lt;/span&gt; 00:00:07 &lt;span class="nt"&gt;-frames&lt;/span&gt;:v 1 output_thumbnail.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://trac.ffmpeg.org/wiki/Create%20a%20thumbnail%20image%20every%20X%20seconds%20of%20the%20video" rel="noopener noreferrer"&gt;Reference&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To control the output image quality use &lt;code&gt;-q:v&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 &lt;span class="nt"&gt;-ss&lt;/span&gt; 00:00:07 &lt;span class="nt"&gt;-frames&lt;/span&gt;:v 1 &lt;span class="nt"&gt;-q&lt;/span&gt;:v 2 output_thumbnail.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Values are from 2 to 31, 2 being the best and 31 being the worst. References: &lt;a href="https://stackoverflow.com/questions/10225403/how-can-i-extract-a-good-quality-jpeg-image-from-a-video-file-with-ffmpeg/10234065#10234065" rel="noopener noreferrer"&gt;Stackoverflow 1&lt;/a&gt; &lt;a href="https://stackoverflow.com/questions/64011346/ffmpeg-quality-conversion-options-video-compression" rel="noopener noreferrer"&gt;Stackoverflow 2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Creates two thumbnails - one from the first frame after second 5 and one from the first frame after second 15:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 &lt;span class="nt"&gt;-filter_complex&lt;/span&gt; &lt;span class="s2"&gt;"[0:v]split=2[first][second];[first]select='gte(t,5)'[thumb1];[second]select='gte(t,15)'[thumb2]"&lt;/span&gt; &lt;span class="nt"&gt;-map&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;thumb1] &lt;span class="nt"&gt;-frames&lt;/span&gt;:v 1 output_thumbnail_1.png &lt;span class="nt"&gt;-map&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;thumb2] &lt;span class="nt"&gt;-frames&lt;/span&gt;:v 1 output_thumbnail_2.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-frames:v 1&lt;/code&gt; Output only 1 video frame&lt;/p&gt;

&lt;p&gt;Create a thumbnail from the first frame of a scene change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"select='gt(scene,0.4)'"&lt;/span&gt; &lt;span class="nt"&gt;-frames&lt;/span&gt;:v 1  &lt;span class="nt"&gt;-q&lt;/span&gt;:v 2 thumbnail_scene.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://www.ffmpeg.org/ffmpeg-filters.html#select_002c-aselect" rel="noopener noreferrer"&gt;gt(scene,0.4)&lt;/a&gt; parameter determines FFmpeg's sensitivity to changes in frame indicating scene change. The value is from 0 to 1, lower values mean FFmpeg will be more sensitive to scene changes and will recognize more scene changes. Recommended values are from 0.3 to 0.5&lt;/p&gt;

&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/35675529/using-ffmpeg-how-to-do-a-scene-change-detection-with-timecode" rel="noopener noreferrer"&gt;Good stackoverflow discussion about detecting scenes with Ffmpeg&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create an image thumbnail from input images
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/bbb-splash.png &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/rodents.png &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/evil-frank.png &lt;span class="nt"&gt;-filter_complex&lt;/span&gt; &lt;span class="s2"&gt;"[1]scale=640:360,pad=648:368:4:4:black[overlay1];[2]scale=640:360,pad=648:368:4:4:black[overlay2];[0][overlay1]overlay=0:main_h-overlay_h[tmp1];[tmp1][overlay2]overlay=main_w-overlay_w:main_h-overlay_h"&lt;/span&gt; &lt;span class="nt"&gt;-frames&lt;/span&gt;:v 1 thumbnail_overlayed.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create a storyboard from a video
&lt;/h3&gt;

&lt;p&gt;All commands below extract frames from video to create different storyboards&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"select='gt(scene,0.4)',scale=640:480,tile=2X2"&lt;/span&gt; &lt;span class="nt"&gt;-frames&lt;/span&gt;:v 1 scene_storyboard.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🛠️ Use &lt;code&gt;tile=2X2&lt;/code&gt; to create a 2X2 storyboard from the scenes in a video. &lt;a href="https://www.ffmpeg.org/ffmpeg-filters.html#Examples-169" rel="noopener noreferrer"&gt;Example from FFmpeg's documentation&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"select='gt(scene,0.4)'"&lt;/span&gt; &lt;span class="nt"&gt;-vsync&lt;/span&gt; 0 scene_storyboard_%03d.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the same storyboard but with separate image files per scene&lt;/p&gt;

&lt;p&gt;🛠️ &lt;a href="https://www.ffmpeg.org/ffmpeg-filters.html#Examples-126" rel="noopener noreferrer"&gt;-vsync 0&lt;/a&gt; drops frames that belong to the same scene so there are no duplication. This parameter is complex to use, &lt;a href="https://superuser.com/a/1073260/431710" rel="noopener noreferrer"&gt;good explanation&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;vsync is fine to use but is deprecated in newer versions of ffmpeg, &lt;code&gt;-fps_mode&lt;/code&gt; is the change &lt;a href="https://superuser.com/questions/1816464/ffmpeg-vsync-deprecated-use-fps-mode" rel="noopener noreferrer"&gt;Reference&lt;/a&gt; &lt;a href="https://ffmpeg.org/ffmpeg.html#:~:text=%2Dfps_mode%5B%3Astream_specifier%5D%20parameter%20(output%2Cper%2Dstream)" rel="noopener noreferrer"&gt;FFmpeg docs&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-skip_frame&lt;/span&gt; nokey &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p.mp4 &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s1"&gt;'scale=640:480,tile=4x4'&lt;/span&gt; &lt;span class="nt"&gt;-an&lt;/span&gt; &lt;span class="nt"&gt;-vsync&lt;/span&gt; 0 keyframes%03d.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create storyboard with several files that are tiled, base the frames the video's keyframes instead of scenes. &lt;a href="https://www.ffmpeg.org/ffmpeg-filters.html#Examples-127" rel="noopener noreferrer"&gt;Example is from FFmpeg's documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-skip_frame nokey&lt;/code&gt; As the text suggests - skips frames that are not key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4  &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"select=not(mod(n&lt;/span&gt;&lt;span class="se"&gt;\,&lt;/span&gt;&lt;span class="s2"&gt;10)),scale=640:480,tile=4x2"&lt;/span&gt;  &lt;span class="nt"&gt;-vsync&lt;/span&gt; 0 tile_4_2_frames_10_%03d.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create 4X2 tile files from every 10th frame of a video. To just create images per frame, remove the &lt;code&gt;,tile4x2&lt;/code&gt; part&lt;/p&gt;

&lt;h2&gt;
  
  
  Command settings
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Generic, simple and optimized FFmpeg command for daily use
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/popeye_talking.mp4 &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"scale=w=1080:h=1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:color=black,setsar=1:1"&lt;/span&gt; &lt;span class="nt"&gt;-crf&lt;/span&gt; 18 &lt;span class="nt"&gt;-preset&lt;/span&gt; veryslow  &lt;span class="nt"&gt;-threads&lt;/span&gt; 0 &lt;span class="nt"&gt;-tune&lt;/span&gt; fastdecode  &lt;span class="nt"&gt;-movflags&lt;/span&gt; +faststart  output_scaled_optimized.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command re-sizes the input video and is good for archiving, streaming (non-live) and playing on many different edge devices. You can usually use the flags in this command for all your FFmpeg commands, unless you have a specific reason not to.&lt;/p&gt;

&lt;p&gt;The parameters in this command have different configuration options. Make sure to read through their FFmpeg references. Let me know if you would like me to elaborate about them here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://trac.ffmpeg.org/wiki/Encode/H.264#Tune" rel="noopener noreferrer"&gt;-tune fastdecode&lt;/a&gt; Encoded output will require less computational power to decode - good for viewing in many different edge devices. &lt;a href="https://superuser.com/questions/564402/explanation-of-x264-tune" rel="noopener noreferrer"&gt;You can use zerolatency for optimization for fast encoding and low latency streaming&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://trac.ffmpeg.org/wiki/Encode/H.264#Preset" rel="noopener noreferrer"&gt;-preset veryslow&lt;/a&gt; Slower encoding, but with a more compressed output keeping the high quality - good when optimize for web-viewing (VOD, archiving, non-live streaming). If your require very fast encoding, at the cost of larger output file use &lt;code&gt;ultrafast&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-threads 0&lt;/code&gt; Specifies how many system threads to use. Optimal is 0 (and is default), usually it is best to just not use this parameter and let FFmpeg optimize. &lt;a href="https://superuser.com/questions/155305/how-many-threads-does-ffmpeg-use-by-default" rel="noopener noreferrer"&gt;But sometimes you want to tweak it, depending on your system and command&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🛠️ Video\Audio encoding, codecs and bitrate
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://ffmpeg.org/ffmpeg.html#Stream-specifiers" rel="noopener noreferrer"&gt;-c -codec&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-c:v&lt;/code&gt; Specifies the video encoder and &lt;code&gt;-c:a&lt;/code&gt; specifies the audio encoder.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-c:a aac&lt;/code&gt; AAC encoded audio. This is also the default for FFmpeg, and a good practice to specify.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://trac.ffmpeg.org/wiki/Encode/MP3" rel="noopener noreferrer"&gt;-c:a libmp3lame&lt;/a&gt; The encoding library for MP3&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-an&lt;/code&gt; Disable audio in the output&lt;/p&gt;




&lt;h4&gt;
  
  
  &lt;a href="https://trac.ffmpeg.org/wiki/Encode/H.264" rel="noopener noreferrer"&gt;-c:v libx264&lt;/a&gt; - H264 (AVC)
&lt;/h4&gt;

&lt;p&gt;Generally FFmpeg will default to H264 when asking for MP4 output, unless you're not using an FFmpeg build with libx264. It's good practice to always specify the codec.&lt;/p&gt;

&lt;p&gt;libx265 - H265 (HEVC), the newer codec, is very similar in behavior and controls. H264 is still the most commonly used.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Apple devices sometimes have issues with FFmpeg generated H265 videos (for example in iOS Airdop), use &lt;code&gt;-vtag hvc1&lt;/code&gt; to solve it. &lt;a href="https://gist.github.com/protrolium/e0dbd4bb0f1a396fcb55#convert-h264-to-h265-to-correct-for-ios-airdrop-error-message" rel="noopener noreferrer"&gt;Thanks!&lt;/a&gt; &lt;a href="https://community.bitmovin.com/t/whats-the-difference-between-hvc1-and-hev1-hevc-codec-tags-for-fmp4/101" rel="noopener noreferrer"&gt;Also related&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx265 &lt;span class="nt"&gt;-vtag&lt;/span&gt; hvc1 &lt;span class="nt"&gt;-c&lt;/span&gt;:a copy output_265.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://trac.ffmpeg.org/wiki/Encode/H.264#Encodingfordumbplayers" rel="noopener noreferrer"&gt;format=yuv420p&lt;/a&gt; H264 YUV planar color format, is used for playback compatibility in most players. Use this flag when transforming images to video and in general when you have playback issues with your output videos, unless you have specific reasons not to.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You may need to use -vf format=yuv420p (or the alias -pix_fmt yuv420p) for your output to work in QuickTime and most other players. These players only support the YUV planar color space with 4:2:0 chroma subsampling for H.264 video. Otherwise, depending on your source, ffmpeg may output to a pixel format that may be incompatible with these players.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Good info about yuv420p in &lt;a href="https://www.reddit.com/r/ffmpeg/comments/1gbv2z5/is_formatyuv420p_mandatory/" rel="noopener noreferrer"&gt;this reddit thread&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-crf&lt;/code&gt; &lt;a href="https://trac.ffmpeg.org/wiki/Encode/H.264#crf" rel="noopener noreferrer"&gt;Constant Rate Factor (CRF)&lt;/a&gt; - It is the default bitrate control option for libx264 and libx265:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Use this rate control mode if you want to keep the best quality and care less about the file size. This is the recommended rate control mode for most uses.&lt;/p&gt;

&lt;p&gt;This method allows the encoder to attempt to achieve a certain output quality for the whole file when output file size is of less importance. This provides maximum compression efficiency with a single pass. By adjusting the so-called quantizer for each frame, it gets the bitrate it needs to keep the requested quality level. The downside is that you can't tell it to get a specific filesize or not go over a specific size or bitrate, which means that this method is not recommended for encoding videos for streaming.&lt;/p&gt;

&lt;p&gt;The range of the CRF scale is 0–51, where 0 is lossless (for 8 bit only, for 10 bit use -qp 0), 23 is the default, and 51 is worst quality possible. A lower value generally leads to higher quality, and a subjectively sane range is 17–28. Consider 17 or 18 to be visually lossless or nearly so; it should look the same or nearly the same as the input but it isn't technically lossless.&lt;br&gt;
The range is exponential, so increasing the CRF value +6 results in roughly half the bitrate / file size, while -6 leads to roughly twice the bitrate.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Common advice is to use &lt;code&gt;-crf 18&lt;/code&gt; for very high quality H264 output, I found that using &lt;code&gt;-crf 10&lt;/code&gt; results in better quality video.&lt;/p&gt;

&lt;p&gt;Use &lt;a href="https://trac.ffmpeg.org/wiki/Encode/H.264#faststartforwebvideo" rel="noopener noreferrer"&gt;-movflags +faststart&lt;/a&gt; to make videos start playing faster online, optimizing for web viewing, by moving metadata to the front of the container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg  &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 &lt;span class="nt"&gt;-c&lt;/span&gt; copy &lt;span class="nt"&gt;-movflags&lt;/span&gt; +faststart big_buck_bunny_720p_16sec_faststart.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://support.google.com/youtube/answer/1722171" rel="noopener noreferrer"&gt;YouTube recommend&lt;/a&gt; uploading MP4 files with faststart to YouTube. They will then re-encode these to VP9.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://superuser.com/questions/856025/any-downsides-to-always-using-the-movflags-faststart-parameter" rel="noopener noreferrer"&gt;Fast start is supported in MP4, M4A and MOV and could take a few seconds to process&lt;/a&gt; I couldn't find an official place that states that faststart works with libx265, but the following command shows that it does work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg  &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx265 &lt;span class="nt"&gt;-c&lt;/span&gt;:a copy &lt;span class="nt"&gt;-movflags&lt;/span&gt; +faststart big_buck_bunny_720p_16sec_h265_faststart.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to make sure that &lt;code&gt;big_buck_bunny_720p_16sec_h265_faststart.mp4&lt;/code&gt; is indeed encoded with moov faststart, run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffprobe &lt;span class="nt"&gt;-v&lt;/span&gt; trace &lt;span class="nt"&gt;-i&lt;/span&gt; your_video.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and check that towards the beginning there is a line that resembles &lt;code&gt;[mov,mp4,m4a,3gp,3g2,mj2 @ 0x...] type:'moov' size:... pos:...&lt;/code&gt;&lt;/p&gt;




&lt;h4&gt;
  
  
  &lt;a href="https://trac.ffmpeg.org/wiki/Encode/VP9" rel="noopener noreferrer"&gt;libvpx-vp9&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;It is the VP9 video encoder for ​WebM, an open, royalty-free media file format. VP9 is owned by google, and most videos on YouTube are encoded with it. It is an encoding designed and optimized for static web hosted video. &lt;code&gt;libvpx-vp9&lt;/code&gt; can save about 20–50% bitrate compared to &lt;code&gt;libx264&lt;/code&gt; (the default H264 encoder), while retaining the same visual quality.&lt;/p&gt;

&lt;p&gt;Constant Quality &lt;code&gt;-crf&lt;/code&gt; encoding in &lt;code&gt;libvpx-vp9&lt;/code&gt; - similar to constant rate factor in &lt;code&gt;libx264&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4 &lt;span class="nt"&gt;-c&lt;/span&gt;:v libvpx-vp9 &lt;span class="nt"&gt;-crf&lt;/span&gt; 15 &lt;span class="nt"&gt;-b&lt;/span&gt;:v 0 &lt;span class="nt"&gt;-c&lt;/span&gt;:a libopus big_buck_bunny_720p_16sec.webm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;To trigger this mode, you must use a combination of &lt;code&gt;-crf&lt;/code&gt; and &lt;code&gt;-b:v 0&lt;/code&gt;. Note that &lt;code&gt;-b:v&lt;/code&gt; MUST be 0. Setting it to anything higher or omitting it entirely will instead invoke the Constrained Quality mode.&lt;/p&gt;

&lt;p&gt;The CRF value can be from 0–63. Lower values mean better quality. Recommended values range from 15–35, with 31 being recommended for 1080p HD video.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;-c:a libopus&lt;/code&gt; The default audio encoder for WebM is libopus, the above command re-encodes the AAC audio in mp4 to opus in webm.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://trac.ffmpeg.org/wiki/Encode/VP9#speed" rel="noopener noreferrer"&gt;CPU, speed and multithread controls for vp9&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;VP9, libx264 and libx265 support 1-pass and 2-pass encodings (you can read about these in their respective references). &lt;a href="https://slhck.info/video/2017/03/01/rate-control.html" rel="noopener noreferrer"&gt;slhck summarized it well:&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To summarize, here's what you should do [which bitrate encoding configuration to use], depending on your use case:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Archival — CRF that gives you the quality you want.&lt;/li&gt;
&lt;li&gt;Streaming — Two-pass CRF or ABR with VBV-constrained bitrate.&lt;/li&gt;
&lt;li&gt;Live Streaming — One-pass CRF or ABR with VBV-constrained bitrate, or CBR if you can waste bits.&lt;/li&gt;
&lt;li&gt;Encoding for Devices — Two-pass ABR, typically.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;slhck probably meant &lt;a href="https://trac.ffmpeg.org/wiki/Encode/VP9#twopass" rel="noopener noreferrer"&gt;two-pass CRF in VP9&lt;/a&gt; for streaming - the first pass lets libvpx-vp9 calculate the desired measures to encode in higher compression in the second pass for reduced file size while keeping quality. This method is more optimized for web hosted videos.&lt;/p&gt;

&lt;p&gt;Good references:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://slhck.info/video/2017/02/24/crf-guide.html" rel="noopener noreferrer"&gt;Another very good reference by slhck about crf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://superuser.com/questions/677576/what-is-crf-used-for-in-ffmpeg" rel="noopener noreferrer"&gt;Stackoverflow CRF in FFmpeg&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.reddit.com/r/compression/comments/vcuory/how_does_crf_compression_work/" rel="noopener noreferrer"&gt;Reddit discussion about CRF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.reddit.com/r/obs/comments/fj6ysq/cqp_vs_cbr_recording/" rel="noopener noreferrer"&gt;Reddit discussion about CRF VS CQP VS CBR and GPU encoding&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.reddit.com/r/obs/comments/1e9b63m/should_i_use_cqp_or_cbr/" rel="noopener noreferrer"&gt;Reddit discussion about CBR and CQP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.reddit.com/r/handbrake/comments/13dckje/is_there_a_way_to_see_what_crf_is_equivalent_to/" rel="noopener noreferrer"&gt;Reddit discussion about CRF and 2-pass&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🛠️ &lt;a href="https://ffmpeg.org/ffmpeg.html#Streamcopy" rel="noopener noreferrer"&gt;-c copy&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;-c copy&lt;/code&gt; whenever possible, it re-muxes the video and audio instead of re-encoding which is compute intensive (especially video re-encoding). &lt;code&gt;-c:v copy&lt;/code&gt; Specifically copies video without re-encoding and &lt;code&gt;-c:a copy&lt;/code&gt; does the same for audio (and is the same as &lt;code&gt;-acodec copy&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Remuxing involves rewrapping streams into a new container without altering them, unlike transcoding, which changes compression and quality. For example - MP4 can be remuxed to MKV and MOV because they are all containers of H264 codec.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When not to use &lt;code&gt;-c copy&lt;/code&gt;?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When applying video filters (scale, overlay, subtitles, trim, fade) or mixing or modifying audio (amix, atempo, volume) - these require re-encoding&lt;/li&gt;
&lt;li&gt;For precise trimming (frame-accurate) -c copy can only cut at keyframes, leading to rough/inaccurate edits.&lt;/li&gt;
&lt;li&gt;Burning subtitles into the video requires re-encoding&lt;/li&gt;
&lt;li&gt;Transcoding between different codecs requires re-encoding&lt;/li&gt;
&lt;li&gt;If you want to compress media&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🛠️ &lt;a href="https://trac.ffmpeg.org/wiki/Seeking" rel="noopener noreferrer"&gt;Input\Output seeking&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Input seeking (&lt;code&gt;-ss&lt;/code&gt; before input):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-ss&lt;/span&gt; 00:00:03 &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4"&lt;/span&gt; &lt;span class="nt"&gt;-frames&lt;/span&gt;:v 1 &lt;span class="s2"&gt;"input_seeking.jpg"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Parses the video by keyframe, making it very fast, but less accurate (in h624 with 25fps there is a keyframe every 10 seconds).&lt;/p&gt;

&lt;p&gt;If you trim the video with input seeking, it resets the timestamps of the video to the trimmed version, so when using filters you need to make sure to adhere to the video times after trim.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4"&lt;/span&gt; &lt;span class="nt"&gt;-ss&lt;/span&gt; 00:00:03 &lt;span class="nt"&gt;-frames&lt;/span&gt;:v 1 &lt;span class="s2"&gt;"input_seeking.jpg"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output seeking (&lt;code&gt;-ss&lt;/code&gt; after input) "decodes but discards input until the timestamps reach position" - it is frame accurate, but can take longer time to process because needs to decode.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🛠️ When trimming, it is advised to use output seeking without &lt;code&gt;-c:v copy&lt;/code&gt;, re-encoding the output video.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The reasons being:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;There is an open bug with trimming with input seeking and &lt;code&gt;-c:v copy&lt;/code&gt;&lt;br&gt;
&lt;a href="https://stackoverflow.com/questions/57450657/ffmpeg-fails-to-trim-beginning-of-clip" rel="noopener noreferrer"&gt;Stackoverflow discussion&lt;/a&gt; -&lt;br&gt;
&lt;a href="https://trac.ffmpeg.org/ticket/8189" rel="noopener noreferrer"&gt;FFmpeg repo bug report&lt;/a&gt; .&lt;br&gt;
Therefore, it is advised to trim with output seeking (with or without &lt;code&gt;-c:v copy&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When trimming with output seeking with &lt;code&gt;-c:v copy&lt;/code&gt; you can see black frames in the output video,&lt;br&gt;
this is due to &lt;code&gt;c:v copy&lt;/code&gt; copying frames that started after a keyframe, but not the keyframe itself,&lt;br&gt;
which misses out on the data required to do the frames. Read more in &lt;a href="https://trac.ffmpeg.org/wiki/Seeking#codec-copy" rel="noopener noreferrer"&gt;FFmpeg's trac documentation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This excerpt from &lt;a href="https://ffmpeg.org/ffmpeg.html#Main-options" rel="noopener noreferrer"&gt;FFmpeg's documentation&lt;/a&gt; sums it all:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When used as an input option, seeks in this input file to position.&lt;br&gt;
Note that in most formats it is not possible to seek exactly, so ffmpeg will seek to the closest seek point before position.&lt;br&gt;
When transcoding and -accurate_seek is enabled (the default), this extra segment between the seek point and position will be decoded and discarded. When doing stream copy or when -noaccurate_seek is used, it will be preserved.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nice answer about this issue in &lt;a href="https://stackoverflow.com/a/18449609/3530894" rel="noopener noreferrer"&gt;Stackoverflow&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The re-encoded output video could be in a different bitrate, so you might need to adjust the output bitrate accordingly (see below).&lt;/p&gt;

&lt;h3&gt;
  
  
  🛠️ Use GPU for acceleration
&lt;/h3&gt;

&lt;p&gt;Transcode video from AVI to H264 (AVC) using Nvidia GPU:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_stereo.avi &lt;span class="nt"&gt;-c&lt;/span&gt;:v h264_nvenc output_gpu_264.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Transcode video from AVI to H265 (HEVC) using Nvidia GPU:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_stereo.avi &lt;span class="nt"&gt;-c&lt;/span&gt;:v hevc_nvenc output_gpu_265.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://trac.ffmpeg.org/wiki/HWAccelIntro#NVENC" rel="noopener noreferrer"&gt;Reference&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Transcode using the Intel GPU - &lt;a href="https://trac.ffmpeg.org/wiki/Hardware/QuickSync" rel="noopener noreferrer"&gt;Quick Sync Video (QSV) encoder&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-init_hw_device&lt;/span&gt; &lt;span class="nv"&gt;qsv&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;hw &lt;span class="nt"&gt;-filter_hw_device&lt;/span&gt; hw &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_stereo.avi &lt;span class="nt"&gt;-c&lt;/span&gt;:v h264_qsv output_gpu_qsv.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More complicated, and less supported, encoding via &lt;a href="https://trac.ffmpeg.org/wiki/Hardware/VAAPI" rel="noopener noreferrer"&gt;AMD GPUs via the Mesa VAAPI driver&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Misc
&lt;/h2&gt;

&lt;h3&gt;
  
  
  FFmpeg Installation
&lt;/h3&gt;

&lt;p&gt;List the formats your FFmpeg build supports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-formats&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;List the codecs your FFmpeg build supports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-codecs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;a href="https://ffmpeg.org/ffprobe.html" rel="noopener noreferrer"&gt;FFprobe&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;It provides structured metadata about media files. Show detailed stream information of a video file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffprobe &lt;span class="nt"&gt;-show_streams&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Closing Remarks
&lt;/h2&gt;

&lt;p&gt;If you have any questions, feedback or other commands you would like to see, write them below.&lt;/p&gt;

</description>
      <category>ffmpeg</category>
      <category>automation</category>
      <category>cheatsheet</category>
      <category>cli</category>
    </item>
  </channel>
</rss>
