Monthly Archives: January 2020

FFmpeg, The -crf Option, iPhone Videos, and Corporate Networks

I use FFmpeg on a regular basis for video, audio, and image-related editing. It is a command-line tool that goes from very simple to very complicated. I intend to stick with simple today. The point here is you can save 80-90% of the space used by iPhone, GoPro, or Android Video by re-encoding the video with FFmpeg and the -crf option. Keep reading to learn more.

To use FFmpeg, use something like the following.

$ ffmpeg -i input.mp4 output.avi

The above code will convert an mp4 to an avi using inferred settings and won’t change the video’s codec. Side note, if you don’t know what a video format, container, and codecs are and how they relate, pause and read this link: Every Video Format, Codec, and Container Explained.

The problem I have run into is corporate network drives have lots of iPhone videos that have been stored for future reference. The first time I encountered this problem, I was working for ABC Company (to not name names or blame or whatever) and we ran out space on a network drive. We had several hundred engineers that could no longer work because we ran out space. IT could not expand the Network drive because of a limitation. This upset me. I couldn’t believe that this had happened at a large company and no one was doing anything about it. Therefore, I did something about it. I scanned the network to see what was stored on our network drive. The #1 space-consuming filetype was iPhone videos. People had dumped 300GB of iPhone videos onto our network over several years. Therefore I looked for a solution that could re-encode the videos, maintain the format, codec, resolution, framerate, and compatibility but reduce the file size. This is where FFmpeg and the -crf option comes in handy. All you have to do reduce the video size by 80-90% is the use the following code snippet

 ffmpeg -i inputMovie.mov -crf 28 outputVideo.mov

The above code snippet will maintain the format, codec, framerate, resolution, and then adjust the bitrate based on some factors documented better here: CRF Guide (Constant Rate Factor in x264, x265 and libvpx). I usually use a -crf of 28 for my x264 videos which is basically what all iPhone, GoPro, and Android videos are. This is aggressive but the loss of quality is minimal. For instance, a video that was 100MB will be 10MB after re-encoding it with -crf 28 and you can’t tell that I re-encoded the video.

The problem is that the bitrate of an iPhone video is an average of 20,000KB/s or more. Often, you don’t need that high of bitrate and it is overkill. After using -crf of 28, the bitrate will drop to an average of 2000KB/s or so. The bitrate during the video isn’t constant though. The bitrate is variable, you could have a segment of a video that is a bitrate of 10,000KB/s but still have an average 2000KB/s.

The 300GB’s of iPhone movies that I found on the ABC Company network, I re-encoded saving around 270GB. This allowed us to start working again on our Corporate Network drive.

Recently I was at XYZ Company, I did a check for videos on the network. We have 1400GB of videos on that Network drive. I am betting that we can save 1100GB by re-encoding the videos.

Short and Long Name VBA Functions

From time to time I write VBA. One of the things I have needed is what is called the short path. If you ever worked at the command line, it looks like what is shown below. “PROGRA~1” is the short name for “Program Files”.

C:\>dir /x *

 Directory of C:\

01/20/2020  04:09 PM    <DIR>          PROGRA~1     Program Files
01/22/2020  02:05 AM    <DIR>          PROGRA~2     Program Files (x86)
11/24/2019  12:07 AM    <DIR>          SOLIDW~1     SOLIDWORKS Data
11/23/2019  10:26 PM    <DIR>                       Users
01/10/2020  07:41 AM    <DIR>                       Windows
               0 File(s)              0 bytes
              10 Dir(s)  347,556,667,392 bytes free

Short names can be useful when processing file names that are hard to parse. For instance, dumping a file list to a Comma Separated Values file. If one of the paths has a comma, that path will get separated into separate values. One way to deal with this is to just put the path in quotes like this “C:\my path\ with a, comma\folder”. The other way to deal with this just store the short path/name. Usually, when I have used the short name, I have needed it in Excel. Therefore, I have a couple of functions written VBA that I use. They are shown below. One of them returns the short name and the other returns the long name.

Option Explicit
 
' Max length of a long path
Private Const MAX_PATH = 32768
 
' Declarations hooking into Windows API
Private Declare Function GetLongPathNameW Lib "kernel32" (ByVal lpszShortPath As Long, ByVal lpszLongPath As Any, ByVal cchBuffer As Long) As Long
Private Declare Function GetShortPathNameW Lib "kernel32" (ByVal lpszLongPath As Long, ByVal lpszShortPath As Any, ByVal cchBuffer As Long) As Long
 
 
Public Function GetLongPathName(strShortPath As String) As String
    Dim strLongPath As String * MAX_PATH
    Dim lLongPathLength As Long
 
    ' Call WIndows API for long path in Unicode
    lLongPathLength = GetLongPathNameW(StrPtr(strShortPath), strLongPath, MAX_PATH)
 
    ' Handle Any errors before returning
    If lLongPathLength = 0 Then
            GetLongPathName = CVErr(xlErrValue)
    Else
        'Convert string and discard extra characters
        GetLongPathName = Left$(StrConv(strLongPath, vbFromUnicode), lLongPathLength)
    End If
End Function
 
 
Public Function GetShortName(ByVal strLongPath As String) As String
    Dim strShortPath As String * MAX_PATH
    Dim lShortPathLength As Long
 
    ' Call Windows API for short path in Unicode
    ' \\?\ must be prepended because this will allow for paths longer than 260 characters
    lShortPathLength = GetShortPathNameW(StrPtr("\\?\" & strLongPath), strShortPath, MAX_PATH)
 
    ' Handle Any errors before returning
    If lShortPathLength = 0 Then
        GetShortName = CVErr(xlErrValue)
    Else
        'Convert string and discard extra characters
        GetShortName = Mid$(StrConv(strShortPath, vbFromUnicode), 5, lShortPathLength - 4)
    End If
End Function