<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Speakol Engineering]]></title><description><![CDATA[Thoughts, stories and ideas.]]></description><link>https://engineering.speakol.com/</link><image><url>https://engineering.speakol.com/favicon.png</url><title>Speakol Engineering</title><link>https://engineering.speakol.com/</link></image><generator>Ghost 3.2</generator><lastBuildDate>Sat, 28 Feb 2026 20:13:54 GMT</lastBuildDate><atom:link href="https://engineering.speakol.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[A Real-World example of the side effects of abusing database indexes]]></title><description><![CDATA[<p>All of us know that Database Indexes have a significant impact on improving query performance, but not everyone makes sure that the DB uses that index.</p><blockquote>One of the SQL queries that were executed by one of our legacy apps was taking ~40 seconds to run on a MySQL instance.</blockquote>]]></description><link>https://engineering.speakol.com/mysql-query-optimization-story/</link><guid isPermaLink="false">5f311a7267907c00018255fd</guid><category><![CDATA[mysql]]></category><category><![CDATA[database]]></category><dc:creator><![CDATA[Mohamed Al Ashaal]]></dc:creator><pubDate>Wed, 12 Aug 2020 12:29:27 GMT</pubDate><media:content url="https://engineering.speakol.com/content/images/2020/08/MySQL-Logo.wine.png" medium="image"/><content:encoded><![CDATA[<img src="https://engineering.speakol.com/content/images/2020/08/MySQL-Logo.wine.png" alt="A Real-World example of the side effects of abusing database indexes"><p>All of us know that Database Indexes have a significant impact on improving query performance, but not everyone makes sure that the DB uses that index.</p><blockquote>One of the SQL queries that were executed by one of our legacy apps was taking ~40 seconds to run on a MySQL instance.  That query was running on a table that contains more than 100M rows. After investigation, we found that there are many indexes out there that may lead the MySQL planner to make the wrong decision. After removing that redundant/unneeded index(es) we noticed that the query went from ~40 seconds to ~6 seconds.</blockquote><p>Here is an example for the root cause:</p><p>Imagine that we have a table called <code>test</code> contains the following columns <code>(post_id, user_id, status</code>) and filled with ~100M row, and our business logic requires the following queries:</p><!--kg-card-begin: markdown--><ul>
<li><code>SELECT * FROM test where post_id in (10, 30, 50)</code></li>
<li><code>SELECT * FROM test where post_id in (10, 30, 50) and user_id = 283</code></li>
</ul>
<!--kg-card-end: markdown--><p>Unfortunately, some engineers may create two indexes one for <code>post_id</code> and one for <code>user_id</code> but it should be one index covering the two columns.</p><h2 id="lessons-learned">Lessons Learned</h2><ul><li>Duplicate/Redundant Indexes hurts MySQL performance.</li><li>Having one index on multiple columns, ordering these columns from the most used to the least may offer better performance in all CRUD operations than one index per column.</li><li>Premature optimization is the root of all evil.</li><li>Use <code>Explain</code> statement as possible as you can, it helps you to understand what is going under the hood.</li><li>To find unused indexes in your database run the following query <code>select * from sys.schema_unused_indexes</code>.</li><li>To find redundant indexes, <code>select * from sys.schema_redundant_indexes</code>.</li></ul><h2 id="useful-mysql-performance-tools">Useful MySQL Performance Tools</h2><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/major/MySQLTuner-perl"><div class="kg-bookmark-content"><div class="kg-bookmark-title">major/MySQLTuner-perl</div><div class="kg-bookmark-description">MySQLTuner is a script written in Perl that will assist you with your MySQL configuration and make recommendations for increased performance and stability. - major/MySQLTuner-perl</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.githubassets.com/favicons/favicon.svg" alt="A Real-World example of the side effects of abusing database indexes"><span class="kg-bookmark-author">major</span><span class="kg-bookmark-publisher">GitHub</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://avatars3.githubusercontent.com/u/89910?s=400&amp;v=4" alt="A Real-World example of the side effects of abusing database indexes"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.percona.com/software/database-tools/percona-toolkit"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Percona Toolkit</div><div class="kg-bookmark-description">Your enterprise DBAs oversee one of your most valuable assets: the database. They need to plan, design, and deploy new architectures to meet the needs of your applications.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.percona.com/sites/default/files/icon_0.png" alt="A Real-World example of the side effects of abusing database indexes"><span class="kg-bookmark-publisher">Percona</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.percona.com/sites/default/files/styles/thumbnail/public/toolkit-white.png?itok=foI0qmtT" alt="A Real-World example of the side effects of abusing database indexes"></div></a></figure>]]></content:encoded></item><item><title><![CDATA[The Story of an Adaptive Video Ad]]></title><description><![CDATA[Discovering how to make adaptive videos for online streaming.]]></description><link>https://engineering.speakol.com/story-of-a-video-ad/</link><guid isPermaLink="false">5e1458840cea230001ffeddb</guid><category><![CDATA[Engineering]]></category><dc:creator><![CDATA[Hossam Elbery]]></dc:creator><pubDate>Tue, 14 Jan 2020 11:28:39 GMT</pubDate><media:content url="https://engineering.speakol.com/content/images/2020/01/adv.png" medium="image"/><content:encoded><![CDATA[<h3 id="overview">Overview</h3><img src="https://engineering.speakol.com/content/images/2020/01/adv.png" alt="The Story of an Adaptive Video Ad"><p>Speakol is a MENA region-focused content discovery and recommendation platform. Utilizing artificial intelligence &amp; machine learning technologies to understand the intended goals and interests of actual visitors in real-time &amp; featuring native ads to the most relevant audience.</p><p>This ensures that we recommend content and premium native ads where it is most relevant based on consumers'​ profiles.</p><h3 id="challenge">Challenge</h3><p>Until recently, we were only serving Image Ads. and the challenge began when we wanted to add Video Ads to our inventory. The main challenging pints were as follows:</p><ol><li>Response time to show and auto-play video as fast as possible.</li><li>The video must be adaptive, so that we won’t exhaust our users’ bandwidth.</li><li>The streaming service that streams the video.</li><li>Try to keep a minimum bandwidth transfer to minimize the cost of infrastructure.</li></ol><h3 id="baby-steps">Baby steps</h3><p>We started from zero; let's put some limitations on the video file being uploaded (max size: 15mb), save it on an s3 bucket, and serve it directly through our CDN (AWS Cloudfront + Cloudflare).</p><p>Results and observations:</p><ol><li>HTML video element doesn’t stream the file. It downloads the file entirely first and then plays it.</li><li>This works fine on a fast internet connection, but our major audience is on (Slow/Medium) 3G Networks.</li></ol><p>So, we decided to tackle these challenges one by one, and we started by the video size on a slow internet connection.</p><h3 id="compress-resize-video">Compress &amp; Resize Video</h3><p>Our widget that holds the articles and ads boxes, each box has a maximum width of 360px, and we are working with a 16:9 aspect ratio.</p><p>So, we thought why not when the users upload the video file, we use any tool that compresses and resizes it to our desired dimensions and see how much we will get the size to, and serve it directly from CDN.</p><p>Result and observations:</p><ol><li>We used FFmpeg to resize the video file, for example, a video file with the size of 11mb we managed to make it 3mb.</li><li>The response time was faster, of course, from the original file, but still the HTML Video element download the whole file then plays it.</li></ol><blockquote><strong>Conclusion: We need adaptive video streaming.</strong></blockquote><h3 id="rd">R&amp;D</h3><p>We started to search for the best (and cost-effective 😁) solution to serve the video files adaptively.</p><h3 id="test-subject">Test Subject</h3><p>Viewing Video file of 29 seconds duration and 11.5 Mb in size on Slow 3G network.</p><h3 id="cloudflare">Cloudflare</h3><p>We are already using Cloudflare as our outer edge and CDN, and we came across one of their services, which is called <strong>Stream. </strong>Stream simplifies on-demand video streaming by bundling storage, transcoding, distribution, and playback in an easy-to-use solution.<a href="https://www.cloudflare.com/products/cloudflare-stream/"> https://www.cloudflare.com/products/cloudflare-stream/</a></p><p>We thought<strong> Oooooh Yeah!</strong> That’s it, let's use it. The service mainly works as follows:</p><ol><li>Upload your video to s3.</li><li>Give the s3 link to Cloudflare Stream API,  the service downloads it, and do its magic.</li><li>It gives you an ID to use into their HTML Stream Player like the following:</li></ol><pre><code class="language-html">&lt;stream style="width: 360; height: 202.5px;"
src="7a097401f2494b090b44c15c0e7c6891" preload autoplay loop mute&gt;
&lt;/stream&gt;
&lt;script data-cfasync="false" defer type="text/javascript"
        src="https://embed.videodelivery.net/embed/r4xu.fla9.latest.js"&gt;
&lt;/script&gt;</code></pre><p>Here we go, let's test it and see the performance, from now on all our tests are made on Slow 3G networks, fast networks don’t matter.</p><h3 id="results-">Results:</h3><figure class="kg-card kg-image-card"><img src="https://engineering.speakol.com/content/images/2020/01/cf.gif" class="kg-image" alt="The Story of an Adaptive Video Ad"></figure><p><strong>From this video, we can see that:</strong></p><ol><li>It took 16s to start playing the video.</li><li>Cloudflare didn’t adapt the video quality, and it played the same segments in Slow &amp; Fast networks which is (2.5mb) as below</li><li>And from the above video, we can see a considerable lag while playing</li></ol><figure class="kg-card kg-image-card"><img src="https://engineering.speakol.com/content/images/2020/01/image.png" class="kg-image" alt="The Story of an Adaptive Video Ad"></figure><blockquote><strong>Why not do it yourself?!</strong></blockquote><h3 id="what-is-adaptive-http-streaming">What is Adaptive HTTP Streaming?</h3><p>Adaptive Streaming was designed to target this particular problem. The underlying idea is as follows. You encode and store the video content with multiple resolutions. Furthermore, you thinly slice the video into multiple data units, instead of storing the entire video in one big file. Then, when the user plays the video, the stored video strategically uses the network information to provide the user with an optimized streaming service. With this kind of technology, because the file has been encoded with multiple sources, the user is given access to an optimized and selected source for the file, and because the file has been split into numerous chunks, the user can change the quality of the video with relative ease</p><h3 id="server-side-a-k-a-aws-lambda-function-">Server-Side (A.K.A AWS Lambda Function)</h3><p>Each video file must be encoded with supporting resolutions, and since there are multiple files, information regarding each chunk must be provided to the client. The overall flow of adaptive streaming is as follows.</p><ol><li>When uploading the video, the video is sliced into thin segments.</li><li>Each segment is encoded according to the resolution designated by the requirements of the service. During this process, the number of segments increases proportionately to the number of resolutions available.</li><li>A Manifest, a file that contains information on the corresponding media segment and the respective resolution, is provided to the client.</li><li>When the video file is sliced into segments, different tools are used for different Codecs. We used Apple-HLS using FFmpeg.</li></ol><figure class="kg-card kg-image-card"><img src="https://lh6.googleusercontent.com/wLMbuWATk_1Y1EcRTbVDXLWTwyMO60rz13jYjFJPY7SArGaAcHE-A2IqWDTp8O4gK0fj2QWJX58tHIBcYzwOeJZcK3QiaKouhTzNv3mqlqzODGjRbxHlDNdr7JHr4OHRx1GuAdbz" class="kg-image" alt="The Story of an Adaptive Video Ad"></figure><h3 id="client-side">Client-Side</h3><p>The standard for allowing Adaptive Streaming over the web client is the Media Source Extensions (MSE), and it is used to transfer streaming data to the player.</p><ol><li>The client requests the manifest file that contains information regarding segmented data of the video to the server.</li><li>The client parses the manifest file to receive the necessary information, including the resolution and quality, then identifies the path to obtain the corresponding segments (i.e. CDN, URL).</li><li>The client measures the user’s bandwidth, and selects the optimized video quality according to the manifest, and downloads it. (The bandwidth is measured again as the segments are being downloaded.)</li><li>Provides the downloaded segment data to the MSE buffer.</li><li>MSE decodes the data and provides the video object to the player to stream.</li></ol><h3 id="apple-hls-developed-from-apple">Apple-HLS Developed from Apple</h3><ol><li>In spefic browsers, including Safari, HLS could be used directly using the media source from the HTML5 Video.</li><li>Since Safari for mobile does not support MSE, only HLS can be used.</li><li>Media Container Format: mp2ts, mp4 (2016)</li><li>Uses M3U8 for manifests</li></ol><pre><code class="language-javascript">#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:BANDWIDTH=150000,RESOLUTION=256x144
144p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=500000,RESOLUTION=426x240
240p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=640x360
360p.m3u8</code></pre><h3 id="hls-support-for-all-browsers">HLS Support for All Browsers</h3><p>HLS is not supported in all browsers, so we had to use a 3rd party library called <strong>hls.js </strong>to play the video.</p><p><strong>Let’s try it!</strong></p><p>We ran ffmpeg with the following params for three encoding types:</p><pre><code class="language-javascript">var encodeParams = [{'bitrate': '0.15M', 'width': '256',
 'height': '144', 'crf': '40','g': '24',
 'keyint': '24', 'hlstime': '1', 'name': '144p'},
 {'bitrate': '0.5M', 'width': '426',
 'height': '240', 'crf': '20', 'g': '48',
 'keyint': '48', 'hlstime': '2', 'name': '240p'},
 {'bitrate': '0.8M', 'width': '640',
  'height': '360', 'crf': '20', 'g': '48',
  'keyint': '48', 'hlstime': '2', 'name': '360p'}];</code></pre><pre><code class="language-javascript">ffmpeg -y -i in.mp4 -c:v libx264 -b:v 0.15M -ac 1 -c:a aac
    -b:a 24k -vf scale=w=256:h=144 :force_original_aspect_ratio=decrease 
    -field_order progressive -profile:v high -movflags faststart 
    -r 10 -crf 40 -g 24 -keyint_min 24 -sc_threshold 0 
    -hls_time 1 -hls_playlist_type vod 
    -hls_segment_filename 144p_%03d.ts 144p.m3u8 </code></pre><ul><li><strong>-y</strong> force choosing yes for any question from FFmpeg</li><li><strong>-i in.mp4</strong> - set in.mp4 as input file</li><li><strong>-c:v libx264</strong> set video codec to be H264 which is the standard codec of HLS segments</li><li><strong>-b:v 0.15M</strong>  limit video bitrate, these are rendition specific and depends on your content type</li><li><strong>-ac 1 -c:a aac -b:a 24k</strong> - set audio codec to AAC with bitrate of 24k</li><li><strong>-vf "scale=w=256:h=144 :force_original_aspect_ratio=decrease"</strong> - scale video to maximum possible within 256x144 while preserving aspect ratio</li><li><strong>-field-order progressive</strong> – this means to compress the video using a progressive method</li><li><strong>-profile:v high</strong> - set H264 profile to high  - this means support in HD</li><li><strong>-movflags faststart -r 10</strong> - <strong>IMPORTANT</strong>  reorganize the MP4 atoms, so the <strong>moov</strong> atom is at the start for fast start</li><li><strong>-crf 40</strong> - Constant Rate Factor, high-level factor for overall quality</li><li><strong>-g 24 -keyint_min 24</strong> - <strong>IMPORTANT</strong> create keyframe (I-frame) every 24 frames (~1 seconds) - will later affect correct slicing of segments and alignment of renditions</li><li><strong>-sc_threshold 0</strong> - don't create keyframes on scene change - only according to -g</li><li><strong>-hls_time 1</strong> - segment target duration in seconds - the actual length is constrained by keyframes</li><li><strong>-hls_playlist_type vod </strong>- adds the #EXT-X-PLAYLIST-TYPE:VOD tag and keeps all segments in the playlist</li><li><strong>-hls_segment_filename 144p_%03d.ts</strong> - explicitly define segments files names144p.m3u8 - the path of the playlist file - also tells FFmpeg to output HLS (.m3u8)</li></ul><figure class="kg-card kg-image-card"><img src="https://engineering.speakol.com/content/images/2020/01/hls-1.gif" class="kg-image" alt="The Story of an Adaptive Video Ad"></figure><p><strong>From this video, we can see that:</strong></p><ol><li>I took 10s to start playing the video.</li><li>Our solution adapted the video quality in Slow &amp; Fast networks as below</li><li>And from the above video, we can see almost, and there is no lag while playing the video</li></ol><figure class="kg-card kg-image-card"><img src="https://engineering.speakol.com/content/images/2020/01/image-1.png" class="kg-image" alt="The Story of an Adaptive Video Ad"></figure><figure class="kg-card kg-image-card"><img src="https://lh4.googleusercontent.com/YKhVZOi1mybVyW-ORSke-YmLMhpdil3ln9RcXKk1Q4JLG-roTQOJ_5xtqGiLUVw-gCUcDdw5CA8KM3hHSj5STOvXrpeucevoFCkj7rdSpa22MHlYvlVxlAZZwIwPZwzMmQWKEtDu" class="kg-image" alt="The Story of an Adaptive Video Ad"></figure><p>So, we did it, and these numbers are perfect for us. All we have to do now is to tie it all together with our system as an automated process to transcode the video the moment it is uploaded to our service. So, we came up with the following flow.</p><h3 id="flow">Flow</h3><figure class="kg-card kg-image-card"><img src="https://lh6.googleusercontent.com/tEhq2IPRLEErWHBmCv8FCibBjQFsSaWA_xV9923meGhUIwURqQw3bSpsw-yisq39TaIal5SqknTolAisTNta4YeKdA0xfBXHtgu-v1lYu4iWkIzr1W2hmxs2G-TZnQrNoCZfQzMW" class="kg-image" alt="The Story of an Adaptive Video Ad"></figure><h3 id="what-is-all-this-let-s-break-it-down-">What is all this 😅? Let’s break it down:</h3><ol><li>The Advertiser uploads the video file.</li><li>The backend saves the original file to S3 then initiate a job to transcode the file</li><li>The Job executes the Lambda function on the file</li><li>The lambda function downloads the original file from s3 and trans-codes it using FFmpeg then saves it to s3 again</li><li>The backend is notified when the function finishes execution and saves the new video info in the database.</li></ol><h3 id="ffmpeg-on-a-nodejs-serverless-lambda-aws-">FFMPEG on a NodeJS serverless Lambda (AWS)</h3><p>First, a few things everyone should know about node Lambda runtime environment:</p><p>·       They run on Linux x86_64</p><p>·       The directory <strong>/tmp</strong> is the only path writable</p><p>·       To use any 3rd party tool, it must be through a Layer·       To be able to execute and bin file it must be in “nodejs\node_modules”</p><h3 id="ffmpeg-layer">FFMPEG Layer</h3><p>From Layers tab in Lambda Service, we will create a new layer that will contain the FFmpeg bin files</p><figure class="kg-card kg-image-card"><img src="https://lh4.googleusercontent.com/hDwHiuUmdKR5oJL3yhfCk9NmwKISj6HanglkDd05yAmQxsbS01beAqqwPw_h8x9Au7ENDJQs3Yr26K45tYCKw1GSvOmErckYThdylqDcJfoSOrINLRvSV6tVFx7UHQ1nFwjpjd2N" class="kg-image" alt="The Story of an Adaptive Video Ad"></figure><figure class="kg-card kg-image-card"><img src="https://lh5.googleusercontent.com/fcpwnj1GP6hYoYAbbCj6xOH92KVKYIZveHDLu4qIcQnEz76H2XsHmf6dC1mIrf0YrtfbyKSt1WlQkMv6B8k4rafkgH24xAEjLwSItDWTFLHxTtoVfAZkUSmjocZl6wjOuRmcR9Ya" class="kg-image" alt="The Story of an Adaptive Video Ad"></figure><p>FFmpeg files are around 52mb, and the limit upload size in a layer is 10mb, so we will upload it first to S3 and insert the S3 URL while creating the Layer.</p><p><strong>IMPORTANT NOTE: </strong>The zip file must be in this structure: “\<strong>nodejs\node_modules\ffmpeg\*.*</strong>”</p><h3 id="lambda-function">Lambda Function</h3><p>From the functions tab, we will create a new function</p><figure class="kg-card kg-image-card"><img src="https://lh4.googleusercontent.com/sRN-gnoM2kIYoSJ_Tp4hyX9hG2eyXKpFlLYgaG1t_I-SvDtWEyOqb2tOZSda8fiKRFdjvBAu0Xb6hXxw1EG9gqUMnNoE_Pl5IX9QCaXFsYLZRaLPZ6zlZ3VGM9Afo6CliIeZbeet" class="kg-image" alt="The Story of an Adaptive Video Ad"></figure><p>Then choose the layer that we created to be available for our function</p><figure class="kg-card kg-image-card"><img src="https://lh5.googleusercontent.com/r08xMI4sfDa-u7ZHeUrqRSeDh8YuUoBSo79Agt9gKmWoddPOoEtnG8Q4aS-LDzkLjIYirLCoO2Pinjp09-wZeqDw8YDo1MmjpP3PYg9g6ZFvH2nfvqnny7ajygIn8fnW4M2SO0b_" class="kg-image" alt="The Story of an Adaptive Video Ad"></figure><p>Now we can write our code that will execute FFmpeg on the video file, we can find the FFmpeg bin in this path</p><p><strong>“/opt/bin/ffmpeg”.</strong></p><p><strong>IMPORTANT NOTE: </strong>you will not be able to execute the bin from the previous path. You have to copy it to “/tmp” folder first.</p><h3 id="sample-code-will-look-like-this-">Sample code will look like this:</h3><pre><code class="language-javascript">var playlistContent = "#EXTM3U\n#EXT-X-VERSION:3\n";
var encodeParams = [
    { 'bitrate': '0.15M', 'width': '256', 'height': '144', 'crf': '40', 'g': '24', 'keyint': '24', 'hlstime': '1', 'name': '144p' },
    { 'bitrate': '0.5M', 'width': '426', 'height': '240', 'crf': '20', 'g': '48', 'keyint': '48', 'hlstime': '2', 'name': '240p' },
    { 'bitrate': '0.8M', 'width': '640', 'height': '360', 'crf': '20', 'g': '48', 'keyint': '48', 'hlstime': '2', 'name': '360p' }
];
var processing = false;
for (var i = 0; i &lt; encodeParams.length; i++) {
    var currentParam = encodeParams[i];
    var processing = await childProcessPromise.spawn(
        path.join(workdir, "ffmpeg"),
        ['-y', '-i', inputFile, '-c:v', 'libx264', '-b:v', currentParam['bitrate'], '-ac', '1', '-c:a', 'aac', '-b:a', '24k', '-vf',
            'scale=w=' + currentParam['width'] + ':h=' + currentParam['height'] + ':force_original_aspect_ratio=decrease', '-field_order', 'progressive',
            '-profile:v', 'high', '-movflags', 'faststart', '-r', '10', '-crf', currentParam['crf'], '-g', currentParam['g'], '-keyint_min', currentParam['keyint'],
            '-sc_threshold', '0', '-hls_time', currentParam['hlstime'], '-hls_playlist_type', 'vod', '-hls_segment_filename',
            path.join(workdir, currentParam['name'] + '_%03d.ts'), path.join(workdir, currentParam['name'] + '.m3u8')],
        { env: process.env, cwd: workdir }
    );
    playlistContent = playlistContent + "#EXT-X-STREAM-INF:BANDWIDTH=" + parseFloat(currentParam['bitrate'].replace('M', '')) * 1000000
        + ",RESOLUTION=" + currentParam['width'] + "x" + currentParam['height'] + "\n" + currentParam['name'] + ".m3u8\n";
}
await writeFileAsync(path.join(workdir, 'playlist.m3u8'), playlistContent);
if (processing) {
    var createFolder = await s3Util.createFolderS3(inputBucket, uploadkey);
    var files = fs.readdirSync(workdir);
    for (var f = 0; f &lt; files.length; f++) {
        var name = files[f];
        var ext = name.toLowerCase().split('.')[1];
        if (['ts', 'm3u8'].includes(ext)) {
            const filePath = path.join(workdir, name);
            const fileKey = path.join(uploadkey, name);
            await s3Util.uploadFileToS3(inputBucket, fileKey, filePath);
        }
    }
    var stats = fs.statSync(inputFile);
    var fileSizeInBytes = stats["size"];
    return { 'success': true, 'size': fileSizeInBytes, 'path': path.join(uploadkey, 'playlist.m3u8') };
}
</code></pre><hr><h2 id="conclusion-">Conclusion:</h2><p>FFMPEG’s appears to be overwhelming at first glance. When dealing with media there are a ton of things to consider and FFMPEG enables us to fine tune all of these considerations to our liking. </p><p>We’ve easily integrated advanced concepts like encoding modes and segmentation in a basic media file conversion in a simple way to the point of being automated using the AWS Lambda Service.</p><p>There’s definitely more than one way of doing anything in FFMPEG, so if during the course of reading this article you come up with a different way of doing something, please let us know!</p><p>At the end I would like to share some great readings to understand more what is Adaptive streaming and FFMPEG .</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://medium.com/@toastui/implementing-adaptive-http-streaming-using-the-web-e2c12d46a38f"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Implementing Adaptive HTTP Streaming Using the Web</div><div class="kg-bookmark-description">Around the world, people are consuming video contents at a rate that has never been observed before. Flash, once the go-to video player technology on the web, has mostly been replaced by the…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://cdn-images-1.medium.com/fit/c/152/152/1*8I-HPL0bfoIzGied-dzOvA.png" alt="The Story of an Adaptive Video Ad"><span class="kg-bookmark-author">TOAST UI</span><span class="kg-bookmark-publisher">Medium</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://miro.medium.com/max/1037/1*u2xe1XJmSGdtUl2e3UAvOw.png" alt="The Story of an Adaptive Video Ad"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://medium.com/@eyevinntechnology/internet-video-streaming-abr-part-1-b10964849e19"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Internet Video Streaming — ABR part 1</div><div class="kg-bookmark-description">Do you remember the old days when you had to choose between two or three quality levels of an internet video before you could play it? The choice was usually related to the internet connection that…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://cdn-images-1.medium.com/fit/c/152/152/1*8I-HPL0bfoIzGied-dzOvA.png" alt="The Story of an Adaptive Video Ad"><span class="kg-bookmark-author">Eyevinn Technology</span><span class="kg-bookmark-publisher">Medium</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://miro.medium.com/max/579/1*fvw2doXIhDovedOilqsOhw.png" alt="The Story of an Adaptive Video Ad"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://medium.com/@dernis/ffmpeg-tips-tricks-and-and-lessons-learned-a6f3c1187085"><div class="kg-bookmark-content"><div class="kg-bookmark-title">FFMPEG tips, tricks and and lessons learned.</div><div class="kg-bookmark-description">I needed to convert some videos of various encoding types, aspect ratios and resolutions. Like many in this position, I turned to FFMPEG to get the job done. FFMPEG’s appeal is that it can be honed…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://cdn-images-1.medium.com/fit/c/152/152/1*8I-HPL0bfoIzGied-dzOvA.png" alt="The Story of an Adaptive Video Ad"><span class="kg-bookmark-author">Vasily Dernis</span><span class="kg-bookmark-publisher">Medium</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://miro.medium.com/proxy/1*3sela1OADrJr7dJk_CXaEQ.png" alt="The Story of an Adaptive Video Ad"></div></a></figure>]]></content:encoded></item></channel></rss>