<?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: dotnVO</title>
    <description>The latest articles on DEV Community by dotnVO (@dotnvo).</description>
    <link>https://dev.to/dotnvo</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%2F646413%2F5f17632b-3672-4ea5-98de-191e76371c79.jpg</url>
      <title>DEV Community: dotnVO</title>
      <link>https://dev.to/dotnvo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dotnvo"/>
    <language>en</language>
    <item>
      <title>FFMPEG - Trimming and combining MKV files</title>
      <dc:creator>dotnVO</dc:creator>
      <pubDate>Wed, 23 Jun 2021 04:00:00 +0000</pubDate>
      <link>https://dev.to/dotnvo/ffmpeg-trimming-and-combining-mkv-files-30g0</link>
      <guid>https://dev.to/dotnvo/ffmpeg-trimming-and-combining-mkv-files-30g0</guid>
      <description>&lt;p&gt;&lt;a href="https://www.ffmpeg.org/"&gt;FFMPEG&lt;/a&gt; is a really popular open source command line tool. Many free and paid versions of software make use of FFMPEG, whether we know it or not. It's likely you've used software that, under the hood, uses FFMPEG. Essentially, it's a collection of libraries/tools to help modify, process, and manipulate multimedia files.&lt;/p&gt;

&lt;p&gt;A while back, I discovered FFMPEG when I was working on converting a bunch of my media to different containers (MKV to MP4) for my Plex server. I was surprised how easy it was to use. After discovering how useful it was for me, I made a &lt;a href="https://www.youtube.com/watch?v=s9JdI6ivJBg"&gt;tutorial&lt;/a&gt; on how to convert an MKV file to an MP4 file. This was my first 'how to' video and it was fairly well received,  despite the minimal video editing and unprofessional feel. Feel free to like/subscribe, as I'd love to actually start creating more content on YouTube and developing a community.&lt;/p&gt;

&lt;p&gt;I've continued using FFMPEG over the years. Recently I was working on capturing video using OBS, and wanted an easy method to trim and, in some cases, concatenate (combine) videos. This post will cover how to do these two tasks. This post will not cover setting up your system to use FFMPEG. If interested in a 'getting started' tutorial, let me know and I'll set aside some time to write a document.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trimming MKV files
&lt;/h2&gt;

&lt;p&gt;There is a ton of documentation available for this tool, but it can be overwhelming. The basic syntax to trim a file using FFMPEG is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ffmpeg -ss 00:00:00 -i "input.mkv" -to 00:10:00  -c copy  "output.mkv" -avoid_negative_ts 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break down the command in a bit more detail:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-i&lt;/code&gt; stand for 'input', this &lt;em&gt;typically&lt;/em&gt; is followed by a file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"input.mkv"&lt;/code&gt; is the name of the file for your input.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-ss&lt;/code&gt; is the time offset. In this example, it's placed before the -i (input option). This is done intentionally, but this may need to played around with. Doing SS's are forced to split on i-frames, and there's a lot of posts about how to use this in certain scenarios. For example, if you notice you have a couple seconds of audio before your video starts (video freezing) you might need to choose a different configuration or cut the video at the start of an i-frame. You can use &lt;code&gt;ffprobe&lt;/code&gt; or just experiment to try and figure that out.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;00:00:00&lt;/code&gt; This represents our starting time in the file.  There's some documentation regarding the format of &lt;a href="https://ffmpeg.org/ffmpeg-utils.html#Time-duration"&gt;time duration&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-to&lt;/code&gt; this is used to specify time duration. In our example this is placed between two time durations&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;00:10:00&lt;/code&gt; Time duration, since this is after the &lt;code&gt;-to&lt;/code&gt; this is the ending time.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-c copy&lt;/code&gt; specifies the codec to encode. In this example, we're copying the video and audio codecs.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"output.mkv"&lt;/code&gt; specifies the output file&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-avoid_negative_ts 1&lt;/code&gt; This ensures the time base is correct, however I have seen some online forums suggesting this may make it not start on a keyframe.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our example command, this takes whatever file we give it, and outputs only the first 10 seconds of the file. This has a few advantages from using software:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It is &lt;em&gt;fast&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;It can be easily automated with most scripting languages. For example, you could easily use this in conjunction with powershell.&lt;/li&gt;
&lt;li&gt;There is no quality loss.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Combining (Concatenating) MKV Files
&lt;/h2&gt;

&lt;p&gt;FFMPEG offers several ways to combine files, depending on the container/file type. In this example, we are focusing on MKV files. Not all methods FFMPEG provides will work in all scenarios.&lt;/p&gt;

&lt;p&gt;This method (often called the demuxer approach) will involve creating a &lt;code&gt;.txt&lt;/code&gt; to reference our files we want to combine, and make use of &lt;a href="https://ffmpeg.org/ffmpeg-filters.html"&gt;ffmpeg filters&lt;/a&gt;. This is simply to show the diversity of the software; you can reference the files directly as well, though in this example, it would be a tad more complex, as it would require a complex filter, and while there are more complicated methods using filtergraphs, etc., we want to keep it simple. This tutorial assumes you have two videos that are essentially the same encoding, # of streams, etc.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Create a text file, name does not matter, we just need to reference it. It's easiest to place the text file in the same directory as the files we want to combine. In our example below, we'll name the file &lt;code&gt;Example.txt&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt; In the text file, we'll need to add the filenames in this format:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;file 'Example1.mkv'
file 'Example2.mkv'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NOTE: &lt;code&gt;file&lt;/code&gt; is case sensitive!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Run the following FFMPEG command:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ffmpeg -f concat -i Example.txt -c copy output.mkv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we did with our previous example, we'll break down the command into parts&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-f&lt;/code&gt; specifies a filter, short for &lt;code&gt;-filter&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;concat&lt;/code&gt; specifies using the concatenate filter. &lt;a href="https://ffmpeg.org/ffmpeg-filters.html#concat"&gt;Documentation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-i&lt;/code&gt; Same as before, this is the input.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Example.txt&lt;/code&gt; We created this above. This is our &lt;code&gt;input&lt;/code&gt; and ultimately maps out to our actual files.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-c copy&lt;/code&gt; copies all codecs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;output.mkv&lt;/code&gt; specifies the output file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hopefully you enjoyed this quick breakdown; thanks for reading!&lt;/p&gt;

</description>
      <category>ffmpeg</category>
      <category>scripting</category>
      <category>coding</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Using .NET 5 split Method to split strings in PowerShell 7.1+</title>
      <dc:creator>dotnVO</dc:creator>
      <pubDate>Wed, 09 Jun 2021 17:50:49 +0000</pubDate>
      <link>https://dev.to/dotnvo/using-the-split-method-to-split-strings-in-powershell-7-1-net-5-2kci</link>
      <guid>https://dev.to/dotnvo/using-the-split-method-to-split-strings-in-powershell-7-1-net-5-2kci</guid>
      <description>&lt;p&gt;I started using Powershell in version 5, which is built on .NET 4.&lt;/p&gt;

&lt;p&gt;Powershell 7 (well 7.1 and up anyway) is built on .NET 5. 7.1+ has implemented a ton of awesome features. As with any change, &lt;/p&gt;

&lt;p&gt;I use a mixture of .NET methods when I code in Powershell. One method I often use is Split. I was working on a project where I was matching culture to a region that a game supported to automagically identify a default Country Code for my end users. My goal was to get the country from the Display Name in &lt;code&gt;Get-Culture&lt;/code&gt; In PowerShell 5, this might be how I do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-Culture&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Select-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ExpandProperty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;DisplayName&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;English&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;United&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$SplitArray&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Get-Culture&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Select-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ExpandProperty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;DisplayName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"()"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$SplitArray&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;English&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nx"&gt;United&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$SplitArray&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="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;United&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's do the same command in PowerShell 7.1.3:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-Culture&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Select-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ExpandProperty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;DisplayName&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;English&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;United&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$SplitArray&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Get-Culture&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Select-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ExpandProperty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;DisplayName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"()"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$SplitArray&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;English&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;United&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$SplitArray&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="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait, what happened in 7.1.3? The split didn't work, so the last item in the array wasn't returned.&lt;/p&gt;

&lt;p&gt;Let's walk through it. We used the cmdlet &lt;code&gt;Get-Culture&lt;/code&gt; to grab some basic information. When we use the split method on two characters, &lt;code&gt;(&lt;/code&gt; and &lt;code&gt;)&lt;/code&gt;. PowerShell 5 sees we are trying to split a string, but automatically converts it to split on the characters, &lt;code&gt;(&lt;/code&gt; and &lt;code&gt;)&lt;/code&gt;. In .NET 4, the string class only had methods that took characters as parameter types. PowerShell sees this and automagically converts it, to make life a little easier on you. Note there's an implied 'OR' (&lt;code&gt;|&lt;/code&gt;) here as it's an array of characters.&lt;/p&gt;

&lt;p&gt;Why is PowerShell 7 behaving differently? In .NET 5, the string class has some additional parameters that accept strings. PowerShell 7 does not take any automatic action.  To really Illustrate the difference here, I'll split on strings instead of characters using our &lt;code&gt;Get-Culture&lt;/code&gt; from above to get the same output. Note this is an ugly way of doing it but it's for demo purposes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$SplitArray&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(((&lt;/span&gt;&lt;span class="n"&gt;Get-Culture&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Select-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ExpandProperty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;DisplayName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"English ("&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="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;')'&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="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$SplitArray&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;United&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok neat, but that's a little ugly. We're splitting twice. What might be a better way? We can use a character typecast array!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$SplitArray&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;Get-Culture&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Select-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ExpandProperty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;DisplayName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;[]]&lt;/span&gt;&lt;span class="s2"&gt;"()"&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="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$SplitArray&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;United&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>powershell</category>
      <category>scripting</category>
      <category>coding</category>
      <category>dotnet</category>
    </item>
  </channel>
</rss>
