<?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: Sebastian Marin</title>
    <description>The latest articles on DEV Community by Sebastian Marin (@sebmarin88).</description>
    <link>https://dev.to/sebmarin88</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%2F1087749%2Fc276c89f-03e1-437b-9b24-81b5be71e461.jpg</url>
      <title>DEV Community: Sebastian Marin</title>
      <link>https://dev.to/sebmarin88</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sebmarin88"/>
    <language>en</language>
    <item>
      <title>The ultimate guide to online video (codecs, containers and more)</title>
      <dc:creator>Sebastian Marin</dc:creator>
      <pubDate>Tue, 13 Jun 2023 15:53:35 +0000</pubDate>
      <link>https://dev.to/api_video/the-ultimate-guide-to-online-video-codecs-containers-and-more-i26</link>
      <guid>https://dev.to/api_video/the-ultimate-guide-to-online-video-codecs-containers-and-more-i26</guid>
      <description>&lt;p&gt;Video is one of the most popular forms of media today, with billions of hours of video content being watched every day. But have you ever wondered how all of this video content is compressed and decompressed? Or what the difference is between a codec and a container? Understanding these concepts is crucial for anyone who works with video, whether you’re a content creator, marketer, or just someone who enjoys watching videos online. In this article, we’ll take a deep dive into the world of video formats, codecs, and containers. We’ll explore the most popular codecs used today, such as H.264, H.265, and VP9, and discuss how they work to compress and decompress video files. We’ll also examine some of the most popular video formats used today, such as MP4, AVI, and MOV. By the end of this article, you’ll have a better understanding of how video files work and why it’s important to understand these concepts.&lt;/p&gt;

&lt;p&gt;With the rise of video-sharing platforms like YouTube, Vimeo, and TikTok, more and more people are uploading videos to the internet every day. Understanding codecs and compression is essential for creating high-quality videos that can be easily shared and viewed on different devices and platforms. Similarly, understanding container formats is important for ensuring that your videos are compatible with different software applications and operating systems.&lt;/p&gt;

&lt;p&gt;By using the right codecs and container formats, you can create videos that are optimized for different use cases. For example, if you’re creating a video for streaming over the internet, you’ll want to use a codec that provides good compression while maintaining high-quality video playback. On the other hand, if you’re creating a video for archival purposes, you may want to use a codec that provides lossless compression to preserve the original quality of the video.&lt;/p&gt;

&lt;p&gt;Now that we’ve established the importance of codecs and containers in digital video, let’s dive a little deeper into video encoding and the different types of codecs that are commonly used.&lt;/p&gt;

&lt;p&gt;Encoding is the process of exporting digital video into a format and specification suitable for playback by a user. Each video file contains two elements: codecs and containers. Codecs are compression-decompression algorithms that compress the video data to reduce its size and decompress it for playback. Containers are file formats that hold the compressed video data along with other information such as audio tracks, subtitles, and metadata.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UfjwHBNn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/umd2r19vpy1zv0itn7vg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UfjwHBNn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/umd2r19vpy1zv0itn7vg.png" alt="Illustration of file format metaphor" width="745" height="332"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Imagine a shipping container filled with packages of many types. In this analogy, the shipping container is the container format, and the codec is the tool that creates the packages and places them in the container. The container format determines how the compressed video data is stored and organized within the file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deep dive into compression-decompression algorithms
&lt;/h2&gt;

&lt;p&gt;Codecs compress and decompress video data by using complex algorithms that analyze the video data and remove any unnecessary information while preserving the quality of the video. During the compression process, the codec analyzes the video data and identifies areas that can be compressed without affecting the overall quality of the video. The codec then discards this information and stores only the essential data required to recreate the video.&lt;/p&gt;

&lt;p&gt;When decompressing the video data, the codec reverses this process by analyzing the compressed data and recreating the original video data by filling in any missing information. This process is done in real-time during playback, allowing you to watch high-quality videos without having to wait for them to fully download.&lt;/p&gt;

&lt;p&gt;There are two main types of codecs: lossy and lossless. Lossy codecs use compression algorithms that discard some of the original video data to reduce the file size. Lossless codecs, on the other hand, use compression algorithms that preserve all of the original video data while still reducing the file size.&lt;/p&gt;

&lt;p&gt;There are many different lossy video codecs available today, each with its own strengths and weaknesses. Some of the most popular codecs include H.264, H.265 (also known as HEVC), VP9, and AV1. H.264 is currently the most widely used codec and is supported by most devices and platforms. It provides good compression while maintaining high-quality video playback. &lt;/p&gt;

&lt;p&gt;Let's take H.264 as an example and explain how its algorithms actually work:&lt;/p&gt;

&lt;p&gt;H.264 uses a &lt;strong&gt;block-oriented motion compensation&lt;/strong&gt; algorithm. This means that it divides each frame into small blocks called &lt;strong&gt;macroblocks&lt;/strong&gt; and then predicts the movement of these blocks in the next frame. By predicting the movement of these blocks, H.264 can compress the video data more efficiently.&lt;/p&gt;

&lt;p&gt;In a little more detail:&lt;/p&gt;

&lt;p&gt;The entropy coding algorithm used in H.264 is called &lt;strong&gt;CABAC (Context-adaptive binary arithmetic coding).&lt;/strong&gt; CABAC is used to compress the video data by encoding the symbols that represent the video frames. The symbols are typically pixel values or motion vectors that describe how the pixels move from one frame to another. CABAC uses adaptive probability estimation to adjust the probabilities of symbols based on the context in which they appear. This means that as more data is compressed, CABAC can adjust its probabilities to better reflect the actual distribution of symbols in the data stream. This allows CABAC to achieve better compression than other entropy coding algorithms that use fixed probabilities. &lt;/p&gt;

&lt;p&gt;The same process occurs in reverse when decoding an H.264 video.&lt;/p&gt;

&lt;p&gt;H.265 is a newer lossy codec that provides even better compression than H.264 but requires more processing power to decode. VP9 is an open-source codec developed by Google that provides high-quality video playback while using less bandwidth than other codecs. AV1 is a newer codec that provides even better compression than VP9 but is not yet widely supported by devices and platforms.&lt;/p&gt;

&lt;p&gt;Lossless codecs on the other hand retain all of the original data after decompression. However, lossless video codecs like ProRes codecs can’t compress videos low enough for live web streaming. In contrast, a lossy codec will compress a file by permanently getting rid of data—especially data that is redundant.&lt;/p&gt;

&lt;p&gt;Lossless compression is also used in cases where it is important that the original and the decompressed data be identical, or where deviations from the original data would be unfavorable like in the production stage of videos and movies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Video formats: not just .mp4
&lt;/h2&gt;

&lt;p&gt;Video formats are more than just a file’s extension, like the .mp4 in Video.mp4. They include a whole package of files that make up the video stream, audio stream, and any metadata included with the file. All of this data is read by a video player to stream video content for playback.&lt;/p&gt;

&lt;p&gt;The video stream includes the data necessary for motion video playback, while the audio stream includes any data related to sound. Metadata is any data outside of audio and sound, including bitrate, resolution, subtitles, device type, and date of creation.&lt;/p&gt;

&lt;p&gt;In addition to standard metadata fields, MP4 files can also contain Extensible Metadata Platform (XMP) metadata. XMP metadata is a standard for embedding metadata in digital files that was developed by Adobe Systems. It allows you to add custom metadata fields to your video files that can be used to store additional information about the video.&lt;/p&gt;

&lt;p&gt;Some examples of XMP metadata fields that can be added to MP4 files include camera settings, location data, and copyright information. This information can be useful for video production and editing. For example, if you are working on a video project that includes footage from multiple cameras, you can use XMP metadata to keep track of which camera was used for each shot.&lt;/p&gt;

&lt;p&gt;There are many different video formats available, each with its own advantages and disadvantages. Some of the most common video formats include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;MP4&lt;/strong&gt;: This is a popular format that is widely supported by most devices and platforms. It uses the H.264 codec for video compression and can store both audio and video data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AVI&lt;/strong&gt;: This format is widely used on Windows-based systems. It uses a variety of codecs for video compression, including DivX and XviD.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WMV&lt;/strong&gt;: This format was developed by Microsoft and is commonly used for streaming video on the web. It uses the Windows Media Video codec for compression.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MOV&lt;/strong&gt;: This format was developed by Apple and is commonly used on Mac-based systems. It uses the H.264 and ProRes codecs for video compression and can store both audio and video data.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Choosing the right video format depends on your specific needs. If you want a format that is widely supported by most devices and platforms, then MP4 is a good choice. If you are working on a Windows-based system, then AVI might be a better choice. If you are streaming video on the web, then WMV might be the best option.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bit depth and rate…
&lt;/h2&gt;

&lt;p&gt;In video files, &lt;strong&gt;bit depth&lt;/strong&gt; and &lt;strong&gt;color depth&lt;/strong&gt; are two different concepts that are often confused with each other. &lt;strong&gt;Bit depth&lt;/strong&gt; refers to the number of bits used to represent each pixel in an image or video file. The higher the bit depth, the more colors can be represented in an image or video file. &lt;strong&gt;Color depth&lt;/strong&gt;, on the other hand, refers to the number of colors that can be displayed in an image or video file. It is measured in bits per pixel (bpp).&lt;/p&gt;

&lt;p&gt;For example, if a video file has a bit depth of 8 bits and a color depth of 24 bpp, it means that each pixel in the video file is represented by 8 bits and can display up to 16.7 million colors.&lt;/p&gt;

&lt;p&gt;In summary, bit depth refers to the number of bits used to represent each pixel in an image or video file, while color depth refers to the number of colors that can be displayed in an image or video file.&lt;/p&gt;

&lt;p&gt;Now on to &lt;strong&gt;Bitrate. It&lt;/strong&gt; is the rate at which bits are processed or computed over time. The higher the bitrate, the more data there is, which generally means a higher-quality video file. When choosing a bitrate it is important to consider the device your videos will be played on. High bitrate file streams need lots of processing power to encode, and a fast internet connection to download for playback. There are two main types of bitrate: &lt;strong&gt;CBR (constant bitrate)&lt;/strong&gt; and &lt;strong&gt;VBR (variable bitrate)&lt;/strong&gt;. Bitrates directly affect the file size and quality of your video. The higher the bitrate, the better the quality of your video, but also the larger the file size.&lt;/p&gt;

&lt;p&gt;For example, if you have a video with a bitrate of 10 Mbps (megabits per second), it means that 10 million bits are transmitted every second.&lt;/p&gt;

&lt;p&gt;A useful application for your new understanding of bitrate is making sure all your future videos uploaded to a specific platform meet the requirements for minimum and maximum bitrate. This is important when using programs such as Adobe's Premiere Pro or Apple's final cut pro to obtain the best results when exporting.&lt;/p&gt;

&lt;p&gt;Here is a brief guide on the bitrates required for optimal streaming performance on Instagram, TikTok, and YouTube:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Instagram&lt;/strong&gt;: Instagram recommends a bitrate of 3-5 Mbps for optimal streaming performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TikTok&lt;/strong&gt;: TikTok recommends a bitrate of 2.5-3.5 Mbps for optimal streaming performance and a maximum of 8.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;YouTube&lt;/strong&gt;: YouTube recommends a bitrate of 8 Mbps for 1080p video at 30 frames per second (fps) and 12 Mbps for 1080p video at 60 fps and a maximum of 50 at 1080p 60fps or 68 Mbps at 4K.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Please note that these are general recommendations and the actual bitrate required may vary depending on the video content and other factors.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Playback Techniques for Video and Livestreaming&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;When on the viewing end of the video streaming pipeline there are a few things to take into account: &lt;/p&gt;

&lt;p&gt;Video playback and livestreaming are two different methods of viewing video content. Video playback refers to the process of downloading a video file and playing it back on your device. This is the traditional method of watching videos online. Livestreaming, on the other hand, refers to the process of broadcasting live video content over the internet in real time. This allows viewers to watch events as they happen.&lt;/p&gt;

&lt;p&gt;There are several formats available for live streaming. One popular format that supports adaptive bitrate (ABR) is HTTP Live Streaming (HLS). HLS or HTTP Live Streaming is a popular format that uses adaptive bitrate streaming techniques to enable high-quality streaming with small HTTP-based file segments. The key to this format’s popularity is the use of HTTP, which is the universal language protocol for the Internet. This allows for reduced infrastructure costs, greater reach, and simple HTML5 player implementation.&lt;/p&gt;

&lt;p&gt;Another popular format is Real-Time Messaging Protocol (RTMP), which is a proprietary protocol developed by Adobe Systems for streaming audio, video, and data over the internet between a server and a client.&lt;/p&gt;

&lt;p&gt;A great feature of the HLS format is the M3U8 file descriptor. This file allows the client or device to automatically select the best quality stream at any time to prevent playback buffering regardless of bandwidth or CPU power. This means that if your internet connection slows down or speeds up, the stream will automatically adjust to ensure that you have a smooth viewing experience.&lt;/p&gt;

&lt;p&gt;Wow, it turns out that the ultimate guide to video is a bit more complex than anticipated 😅🙃.&lt;/p&gt;

&lt;p&gt;Congratulations on understanding all the nuances of digital video! It’s no small feat to have a good grasp of such a complex topic. You should be proud of yourself!&lt;/p&gt;

&lt;p&gt;If you’re looking for a way to simplify your video hosting, encoding, transcoding, and streaming pipeline, I recommend using &lt;a href="http://api.video"&gt;api.video&lt;/a&gt;. This platform makes it easy to manage your online video needs. Upload your videos, encode them into multiple formats and resolutions, and stream them to your viewers all from one place. Plus, &lt;a href="http://api.video"&gt;api.video&lt;/a&gt; offers a variety of features such as analytics and security options to help you get the most out of your video content.&lt;/p&gt;

&lt;p&gt;Whether you’re a seasoned video professional or just starting out, &lt;a href="http://api.video"&gt;api.video&lt;/a&gt; is the perfect solution for simplifying your video workflow.&lt;/p&gt;

</description>
      <category>onlinevideo</category>
      <category>codec</category>
      <category>beginners</category>
      <category>web</category>
    </item>
    <item>
      <title>Unleashing the power of python and FFMPEG: Extracting and stitching video frames with ease</title>
      <dc:creator>Sebastian Marin</dc:creator>
      <pubDate>Thu, 25 May 2023 15:44:56 +0000</pubDate>
      <link>https://dev.to/api_video/unleashing-the-power-of-python-and-ffmpeg-extracting-and-stitching-video-frames-with-ease-2ded</link>
      <guid>https://dev.to/api_video/unleashing-the-power-of-python-and-ffmpeg-extracting-and-stitching-video-frames-with-ease-2ded</guid>
      <description>&lt;h3&gt;
  
  
  TL;DR:
&lt;/h3&gt;

&lt;p&gt;Learn how to harness the capabilities of Python and the FFMPEG library to effortlessly extract frames from a video at regular intervals. Explore the step-by-step process, from leveraging the &lt;strong&gt;&lt;code&gt;ffmpeg-python&lt;/code&gt;&lt;/strong&gt; module to extracting frames, and discover how to seamlessly stitch them back together into a dynamic video sequence. Unleash your creativity by automating video skimming and programmatically creating video trailers with just a few lines of code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Unlocking New Possibilities
&lt;/h3&gt;

&lt;p&gt;Have you ever wondered how you can extract frames from a video at regular intervals using Python and FFMPEG? Well, wonder no more! In this article, I will delve into the exciting world of video processing and show you how to effortlessly extract a list of frames from a video file. This powerful technique not only enables you to perform a quick skim of the video but also opens up a world of possibilities, such as creating a captivating trailer for your video programmatically.&lt;/p&gt;

&lt;p&gt;By utilising the robust capabilities of Python and the versatile FFMPEG library, you can automate the extraction process and obtain frames evenly spaced throughout the video duration. Whether you're a video enthusiast looking to explore the content of a lengthy recording or a content creator aiming to generate engaging teasers, this technique will undoubtedly come in handy.&lt;/p&gt;

&lt;p&gt;Once you've extracted the frames, you might be wondering, "What can I do with them?" Well, the possibilities are endless! You can reassemble the frames back into a condensed video, allowing you to create a visually stunning trailer that captures the essence of the original footage. Imagine the convenience of automating this process instead of manually sifting through hours of video content to find the most compelling moments. With Python and FFMPEG, you have the power to programmatically curate a captivating preview, saving you time and effort.&lt;/p&gt;

&lt;p&gt;In this article, we'll guide you through the step-by-step process of extracting frames from a video using Python and FFMPEG. I'll cover the necessary installations and setup, dive into the code implementation, and explore additional customisation options to suit your specific needs. So, whether you're a beginner seeking to expand your Python skills or an experienced developer looking for an efficient video processing solution, this tutorial is tailored just for you.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Extract Images From Your Video&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To extract images from your video, we will utilize the powerful &lt;strong&gt;&lt;code&gt;ffmpeg-python&lt;/code&gt;&lt;/strong&gt; module. This module provides a convenient Python interface to interact with the FFMPEG library, enabling us to perform various video processing tasks with ease.&lt;/p&gt;

&lt;p&gt;To get started, you need to ensure that &lt;strong&gt;&lt;code&gt;ffmpeg-python&lt;/code&gt;&lt;/strong&gt; is installed in your Python environment. If it's not installed yet, you can easily install it by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;ffmpeg&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once &lt;strong&gt;&lt;code&gt;ffmpeg-python&lt;/code&gt;&lt;/strong&gt; is installed, let's explore the process of extracting images from a video at specific intervals, as illustrated in the code snippet below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;ffmpeg&lt;/span&gt;

&lt;span class="n"&gt;YOUR_FILE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'sample-mov-file.mov'&lt;/span&gt;
&lt;span class="n"&gt;probe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ffmpeg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;probe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;YOUR_FILE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;probe&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'streams'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;'duration'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;probe&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'streams'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;'width'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Set how many spots you want to extract a video from.
&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;

&lt;span class="n"&gt;intervals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;parts&lt;/span&gt;
&lt;span class="n"&gt;intervals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intervals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;interval_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;intervals&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;intervals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;interval_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;ffmpeg&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;YOUR_FILE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'scale'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Image'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;'.jpg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vframes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Let's break down the code snippet step by step:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Firstly, import the &lt;strong&gt;&lt;code&gt;ffmpeg&lt;/code&gt;&lt;/strong&gt; module, which provides the necessary video processing capabilities.&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;&lt;code&gt;YOUR_FILE&lt;/code&gt;&lt;/strong&gt; variable, specify the name of the video file from which you want to extract images. Ensure that the video file is located in the same folder as the code sample.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;&lt;code&gt;ffmpeg.probe&lt;/code&gt;&lt;/strong&gt; function is utilized to retrieve essential information about the video. By accessing properties like &lt;strong&gt;&lt;code&gt;'duration'&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;'width'&lt;/code&gt;&lt;/strong&gt; from the probe, we can determine the video's duration and width.&lt;/li&gt;
&lt;li&gt;Define the &lt;strong&gt;&lt;code&gt;parts&lt;/code&gt;&lt;/strong&gt; variable to represent the desired number of intervals from which you want to extract images.&lt;/li&gt;
&lt;li&gt;Calculate the &lt;strong&gt;&lt;code&gt;intervals&lt;/code&gt;&lt;/strong&gt; value by dividing the video's duration by the number of parts and converting it to an integer.&lt;/li&gt;
&lt;li&gt;Create the &lt;strong&gt;&lt;code&gt;interval_list&lt;/code&gt;&lt;/strong&gt; using list comprehension, generating tuples that specify the start and end time for each interval.&lt;/li&gt;
&lt;li&gt;Iterate over each interval in the &lt;strong&gt;&lt;code&gt;interval_list&lt;/code&gt;&lt;/strong&gt; using a loop.&lt;/li&gt;
&lt;li&gt;Within the loop, utilize the &lt;strong&gt;&lt;code&gt;ffmpeg.input&lt;/code&gt;&lt;/strong&gt; function to specify the input file, with the &lt;strong&gt;&lt;code&gt;ss&lt;/code&gt;&lt;/strong&gt; parameter set to the end time of the current interval (&lt;strong&gt;&lt;code&gt;item[1]&lt;/code&gt;&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;Apply the &lt;strong&gt;&lt;code&gt;.filter&lt;/code&gt;&lt;/strong&gt; method to scale the output image, ensuring the width remains consistent while automatically adjusting the height to maintain the aspect ratio.&lt;/li&gt;
&lt;li&gt;Use the &lt;strong&gt;&lt;code&gt;.output&lt;/code&gt;&lt;/strong&gt; method to define the output file name for the extracted frame. In this example, the format &lt;strong&gt;&lt;code&gt;'Image' + str(i) + '.jpg'&lt;/code&gt;&lt;/strong&gt; is employed, where &lt;strong&gt;&lt;code&gt;i&lt;/code&gt;&lt;/strong&gt; represents the index of the image.&lt;/li&gt;
&lt;li&gt;Finally, execute the extraction process by calling &lt;strong&gt;&lt;code&gt;.run()&lt;/code&gt;&lt;/strong&gt;. The loop will iterate to the next interval accordingly.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To assemble the extracted images back into a video sequence, consider the following code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;ffmpeg&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ffmpeg&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Image%d.jpg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;framerate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'output.mp4'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code snippet compiles the sequence of extracted frames named &lt;strong&gt;&lt;code&gt;'Image%d.jpg'&lt;/code&gt;&lt;/strong&gt;, where &lt;strong&gt;&lt;code&gt;%d&lt;/code&gt;&lt;/strong&gt; represents the frame number. It then creates a new video file named &lt;strong&gt;&lt;code&gt;'output.mp4'&lt;/code&gt;&lt;/strong&gt; with a frame rate of 1 frame per second, effectively assembling the extracted images into a video sequence.&lt;/p&gt;

&lt;p&gt;Now that you have the code snippet at your disposal, you can start extracting frames from your videos programmatically. Experiment with different frame rates and explore the exciting possibilities of using these extracted frames to create engaging visual content, such as video trailers or quick skims of your videos.&lt;/p&gt;

&lt;p&gt;Get ready to unlock the potential of video frame extraction with Python and FFMPEG. Discover the magic of transforming videos into dynamic visual experiences that leave a lasting impression on your audience.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Mastering the Art of Seamless Large File Uploads with JavaScript</title>
      <dc:creator>Sebastian Marin</dc:creator>
      <pubDate>Tue, 23 May 2023 15:57:37 +0000</pubDate>
      <link>https://dev.to/sebmarin88/mastering-the-art-of-seamless-large-file-uploads-with-javascript-3pl5</link>
      <guid>https://dev.to/sebmarin88/mastering-the-art-of-seamless-large-file-uploads-with-javascript-3pl5</guid>
      <description>&lt;h2&gt;
  
  
  TLDR
&lt;/h2&gt;

&lt;p&gt;This article shows you how to upload large files to api.video using JavaScript and the File API and the Blob API. You will learn how to split the file into segments, upload them with a token and a header, and show the progress and the URL to the user. You can find the code on &lt;strong&gt;&lt;a href="https://github.com/apivideo/blobUpload" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/strong&gt;, and use a library to simplify the upload.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Uploading large files to remote servers can be a challenge for developers. Whether it’s presentations, PDFs, files, or videos, we often encounter errors and frustrations when our files exceed the server’s limit. But what if we could avoid these errors with just a few lines of JavaScript? In this article, we will show you how to do just that.&lt;/p&gt;

&lt;p&gt;api.video enables developers to build, scale and operate video in their own apps and platforms in minutes, with just a few lines of code. The service handles the end-to-end workflow, from video ingestion to worldwide video delivery. You can &lt;strong&gt;&lt;a href="https://dashboard.api.video/register" rel="noopener noreferrer"&gt;test it for free&lt;/a&gt;&lt;/strong&gt; right away and start building.&lt;/p&gt;

&lt;p&gt;One of the most common errors with large uploads is &lt;strong&gt;HTTP 413: Request Entity too Large.&lt;/strong&gt; This means the server has a fixed size limit for accepting files, and anything larger than that will be rejected. You might think that the solution is to increase the server limit, but that’s not always feasible or desirable. For example, if you raise the limit to 2GB for videos, you might end up with huge images that take up too much space.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05iwm4x2u5n0h07s9k7y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05iwm4x2u5n0h07s9k7y.png" alt="413 Cat"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another problem with large uploads is that they can fail midway and force you to start over. How annoying is it when your upload fails at 95% completion? To avoid this, we need a way to resume the upload from where it left off.&lt;/p&gt;

&lt;h2&gt;
  
  
  Segments/Chunks
&lt;/h2&gt;

&lt;p&gt;You probably know that streaming videos from api.video, Netflix or YouTube involves breaking down large video files into smaller segments that are transmitted over the internet. Then the player on your device stitches the video segments back together to play them in the correct order. But did you know that you can do the same thing with your large file uploads? You can split the large file into smaller segments and upload each one separately, without your users noticing anything!&lt;/p&gt;

&lt;p&gt;This is possible thanks to the File API and the Blob API that are built into JavaScript and supported by all major browsers:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcg3g6vq3i9swa2y8fsl6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcg3g6vq3i9swa2y8fsl6.png" alt="Blob URLs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These APIs allow us to take a large file from our user, and use the browser locally to divide it into smaller segments, without affecting the user experience!&lt;/p&gt;

&lt;p&gt;In this article, we will show you how to use this technique to upload a large video to api.video.&lt;/p&gt;

&lt;p&gt;You can find the code for this example on &lt;strong&gt;&lt;a href="https://github.com/apivideo/blobUpload" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/strong&gt;, so feel free to clone the repo and run it locally.&lt;/p&gt;

&lt;p&gt;To create your own uploader like this, you’ll need a free &lt;a href="https://dashboard.api.video/" rel="noopener noreferrer"&gt;&lt;strong&gt;api.video account&lt;/strong&gt;&lt;/a&gt;. You’ll also need a &lt;strong&gt;&lt;a href="https://docs.api.video/reference/get_upload-tokens" rel="noopener noreferrer"&gt;delegated upload token&lt;/a&gt;&lt;/strong&gt;, which is a public upload key that lets anyone upload videos into your api.video account. You can create one using CURL and a terminal window in just 3 steps.&lt;/p&gt;

&lt;p&gt;We recommend that you set a TTL (time to live) on your token, so that it expires as soon as the video is uploaded.&lt;/p&gt;

&lt;p&gt;Once you have your token, you’re ready to start uploading large files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Markup
&lt;/h2&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

Add a video here:
    &amp;lt;br&amp;gt;
    &amp;lt;input type="file" id="video-url-example"&amp;gt;
    &amp;lt;br&amp;gt;



    &amp;lt;br&amp;gt;
    &amp;lt;div id="video-information" style="width: 50%"&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div id="chunk-information" style="width: 50%"&amp;gt;&amp;lt;/div&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;There is an input field for a video file, and then there are 2 divs where we will output information as the video uploads.&lt;/p&gt;

&lt;p&gt;Next on the page is the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; section - and here's where the heavy lifting will occur.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;script&amp;gt;
      const input = document.querySelector('#video-url-example');
      const url ="https://sandbox.api.video/upload?token=to1R5LOYV0091XN3GQva27OS";
      var chunkCounter;
      //break into 5 MB chunks fat minimum
      const chunkSize = 6000000;
      var videoId = "";
      var playerUrl = "";


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;First, we need to define some JavaScript variables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;input: the file input interface specified in the HTML.&lt;/li&gt;
&lt;li&gt;url: the delegated upload url to api.video. The token in the code above (and on Github) points to a sandbox instance, so videos will be watermarked and removed automatically after 24-72 hours. If you’ve created your own token, replace the URL parameter ‘to1R5LOYV0091XN3GQva27OS’ with your token.&lt;/li&gt;
&lt;li&gt;chunkCounter: the number of chunks that we will create from the file. • chunkSize: the size of each chunk in bytes. We set it to 6,000,000, which is slightly above the 5 MB minimum. For production, we can increase this to 100MB or more.&lt;/li&gt;
&lt;li&gt;videoId: the delegated upload will assign a videoId on the api.video service. This is used for subsequent uploads to identify the segments, ensuring that the video is properly reassembled on the server.&lt;/li&gt;
&lt;li&gt;playerUrl: this will store the playback URL for the api.video player after the upload is complete.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, we create an EventListener on the input - when a file is added, split up the file and begin the upload process:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

 input.addEventListener('change', () =&amp;gt; {
        const file = input.files[0];
           //get the file name to name the file.  If we do not name the file, the upload will be called 'blob'
           const filename = input.files[0].name;
        var numberofChunks = Math.ceil(file.size/chunkSize);
        document.getElementById("video-information").innerHTML = "There will be " + numberofChunks + " chunks uploaded."
        var start =0;
        var chunkEnd = start + chunkSize;
        //upload the first chunk to get the videoId
        createChunk(videoId, start);



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We assign the uploaded file to a variable called ‘file’. To calculate the number of chunks to upload, we divide the file size by the chunk size. We round up the number, because any ‘remainder’ smaller than 6M bytes will be the last chunk to be uploaded. We display this number on the page for the user to see. (This is just for demonstration purposes, your users might not be interested in this information in a real product).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgu1sx4sj5eyhsjeyf89p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgu1sx4sj5eyhsjeyf89p.png" alt="Sliced Cat"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Slicing up the file
&lt;/h2&gt;

&lt;p&gt;The function createChunk splits the file into smaller pieces.&lt;/p&gt;

&lt;p&gt;Then, we start to slice the file into chunks. You might think we should use &lt;code&gt;chunkSize -1&lt;/code&gt; as the last byte of the chunk we create, since the file starts from zero. But that’s not the case. We use chunkSize as it is, because it represents&lt;/p&gt;

&lt;p&gt;the index of the first byte that is excluded from the new Blob (i.e. the byte at this index is not part of the chunk).&lt;/p&gt;

&lt;p&gt;So, we need to use &lt;code&gt;chunkSize&lt;/code&gt; as it is, because it marks the boundary between the new Blob and the rest of the file.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

function createChunk(videoId, start, end){
            chunkCounter++;
            console.log("created chunk: ", chunkCounter);
            chunkEnd = Math.min(start + chunkSize , file.size );
            const chunk = file.slice(start, chunkEnd);
            console.log("i created a chunk of video" + start + "-" + chunkEnd + "minus 1    ");
            const chunkForm = new FormData();
            if(videoId.length &amp;gt;0){
                //we have a videoId
                chunkForm.append('videoId', videoId);
                console.log("added videoId");

            }
            chunkForm.append('file', chunk, filename);
            console.log("added file");


            //created the chunk, now upload iit
            uploadChunk(chunkForm, start, chunkEnd);
        }


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In the createChunk function, we increment the chunkCounter to keep track of which chunk we are uploading, and we calculate the end of the chunk (remember that the last chunk will be smaller than chunkSize, and it will go until the end of the file).&lt;/p&gt;

&lt;p&gt;In the first chunk uploaded, we include the filename to name the file (otherwise, the file will be called ‘blob.’&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual slice command
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;file.slice&lt;/code&gt; cuts the video into a ‘chunk’ for upload. This is how we divide the file into smaller pieces!&lt;/p&gt;

&lt;p&gt;We then create a form to upload the video segment to the API. The API returns a videoId after the first segment is uploaded, and we need to include this videoId in the following segments (so that the backend knows which video to append the segment to).&lt;/p&gt;

&lt;p&gt;On the first upload, the videoId is empty, so we don’t need it. We add the chunk to the form, and then we call the uploadChunk function to send this file to api.video. On the next uploads, the form will have both the videoId and the video segment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Uploading the chunk
&lt;/h2&gt;

&lt;p&gt;Let's walk through the uploadChunk function:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

    function uploadChunk(chunkForm, start, chunkEnd){
            var oReq = new XMLHttpRequest();
            oReq.upload.addEventListener("progress", updateProgress);   
            oReq.open("POST", url, true);
            var blobEnd = chunkEnd-1;
            var contentRange = "bytes "+ start+"-"+ blobEnd+"/"+file.size;
            oReq.setRequestHeader("Content-Range",contentRange);
            console.log("Content-Range", contentRange);


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We kick off the upload by creating a &lt;code&gt;XMLHttpRequest&lt;/code&gt; to handle the upload. We add a listener so we can track the upload progress.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a byterange header
&lt;/h2&gt;

&lt;p&gt;When doing a partial upload, you need to inform the server which ‘part’ of the file you are sending - we use the byterange header for this.&lt;/p&gt;

&lt;p&gt;We attach a header to this request with the byterange of the chunk being uploaded.&lt;/p&gt;

&lt;p&gt;Note that in this case, the end of the byterange should be the last byte of the chunk, so this value is one byte less than the slice command we used to cut the chunk.&lt;/p&gt;

&lt;p&gt;The header will look something like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Content-Range: bytes 0-999999/4582884&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Upload progress updates
&lt;/h2&gt;

&lt;p&gt;While the video chunk is uploading, we can show the upload progress on the page, so our user knows that everything is working fine. We created the progress listener at the start of the uploadChunk function. Now we can define what it does:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

            &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateProgress&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lengthComputable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
                &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;percentComplete&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loaded&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;oEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;totalPercentComplete&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;chunkCounter&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;numberofChunks&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;percentComplete&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;numberofChunks&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;chunk-information&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Chunk # &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;chunkCounter&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; is &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;percentComplete&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;% uploaded. Total uploaded: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;totalPercentComplete&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="c1"&gt;//  console.log (percentComplete);&lt;/span&gt;
                &lt;span class="c1"&gt;// ...&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;not computable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="c1"&gt;// Unable to compute progress information since the total size is unknown&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;First, we do some math to calculate the progress. For each chunk we can get the percentage uploaded (&lt;code&gt;percentComplete&lt;/code&gt;). This is a fun value for the demo, but not very useful for real users.&lt;/p&gt;

&lt;p&gt;What our users want is the &lt;code&gt;totalPercentComplete&lt;/code&gt;, which is the sum of the existing chunks uploaded plus the amount currently being uploaded.&lt;/p&gt;

&lt;p&gt;For this demo, we display all these values in the ‘chunk-information’ div on the page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffifbd8gc6vx2k49xjimc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffifbd8gc6vx2k49xjimc.png" alt="chunk information diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chunk upload complete
&lt;/h2&gt;

&lt;p&gt;Once a chunk is fully uploaded, we run the following code (in the onload event).&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="nx"&gt;oReq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                           &lt;span class="c1"&gt;// Uploaded.&lt;/span&gt;
                            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;uploaded chunk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
                            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;oReq.response&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;oReq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oReq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                            &lt;span class="nx"&gt;videoId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;videoId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                            &lt;span class="c1"&gt;//playerUrl = resp.assets.player;&lt;/span&gt;
                            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;videoId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;videoId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                            &lt;span class="c1"&gt;//now we have the video ID - loop through and add the remaining chunks&lt;/span&gt;
                            &lt;span class="c1"&gt;//we start one chunk in, as we have uploaded the first one.&lt;/span&gt;
                            &lt;span class="c1"&gt;//next chunk starts at + chunkSize from start&lt;/span&gt;
                            &lt;span class="nx"&gt;start&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;chunkSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
                            &lt;span class="c1"&gt;//if start is smaller than file size - we have more to still upload&lt;/span&gt;
                            &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
                                &lt;span class="c1"&gt;//create the new chunk&lt;/span&gt;
                                &lt;span class="nf"&gt;createChunk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;videoId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                            &lt;span class="p"&gt;}&lt;/span&gt;
                            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                                &lt;span class="c1"&gt;//the video is fully uploaded. there will now be a url in the response&lt;/span&gt;
                                &lt;span class="nx"&gt;playerUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;player&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                                &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;all uploaded! Watch here: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;playerUrl&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
                                &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;video-information&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;all uploaded! Watch the video &amp;lt;a href=&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;'&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;playerUrl&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;' target=&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;'_blank&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;'&amp;gt;here&amp;lt;/a&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
                            &lt;span class="p"&gt;}&lt;/span&gt;

              &lt;span class="p"&gt;};&lt;/span&gt;
              &lt;span class="nx"&gt;oReq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunkForm&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;When the file segment is uploaded, the API returns a JSON response with the videoId. We store this in the videoId variable, so we can include it in the next uploads.&lt;/p&gt;

&lt;p&gt;To upload the next chunk, we increase the bytrange start variable by the chunkSize. If we have not reached the end of the file, we call the createChunk function with the videoId and the start. This will recursively upload each subsequent piece of the large file, until we reach the end of the file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Upload complete
&lt;/h3&gt;

&lt;p&gt;When &lt;code&gt;start &amp;gt; file.size&lt;/code&gt;, we know that the file has been completely uploaded to the server, and our work is done! In this example, we know that the server can accept 5 MB files, so we split the video into many smaller segments to fit under the server size limit.&lt;/p&gt;

&lt;p&gt;When the last segment is uploaded, the api.video response contains the full video response (similar to the get video endpoint). This response includes the player URL that is used to play the video. We save this in the &lt;code&gt;playerUrl&lt;/code&gt; variable, and add a link on the page so that the user can watch their video. And that’s it!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fexk2isr4lewjuxqjw77n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fexk2isr4lewjuxqjw77n.png" alt="Chunk upload complete"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, we have shown you how to upload large files to api.video using JavaScript and the File API and the Blob API. We have explained how to split the file into smaller segments and upload them separately, using the byterange header and the delegated upload token. We have also demonstrated how to show the upload progress and the playback URL to the user. We hope you found this article useful and informative. If you have any questions or feedback, please let me know in the comments below. Happy uploading!&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
