[Live Coding Session] Encrypted HLS with Laravel FFMpeg: Protect your videos with AES-128 Encryption

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everybody thanks for watching again thanks for joining today i'm going to show you uh a new feature of the laravel fmpeg package that i've been working on for a few years now so um as you might know the ffmpeg package is great for converting videos and audio and slideshows and whatever more and we had a feature called hls for about four years and just uh this week we've added encrypted hls so hls is a technique by apple uh they developed it i think around the early ios days and [Music] they probably want wanted to get rid of flash and created a new protocol for streaming so i think it was around time of the ipad when it was available and everybody started migrating to it so what it does it converts one video into multiple videos with different bit rates with different sizes so the video player adapts to the bandwidth of your network so that's great for for video of course so in this example i have a video which i grabbed from the internet it is a video by joseph redfield this one so i grabbed it from the vexels website which is a royalty-free website for videos and photos and i created the fresh laravel application which you can find right here you can find in the in the comments below as well so uh this is the laravel application and it's quite simple actually it only has a a video player which is video.js and it loads the the video that i downloaded so um this is already the converted video i will show you in a minute don't worry so when i start to play the video you will see it doesn't just load one file in the network inspector so uh we've got a bunch of files coming in let me show you in code so in my storage directory i have a folder called uploads and this is the original file red redfield.mp4 which i downloaded from the website and i've got a little console command this one process video upload which converts the video into hls so let's uh let's walk through this this code right here let's see i've got another folder the public folder which contains the output so let's delete it for now and now the video should not work yep of course so what uh what's happening right here we start with a little info line that we are converting the original video so with the ffmpeg package we open this file from the uploads disk so let me show you in the configuration file config file systems and here below the disks i've got my uploads disk which is just a folder in the storage spot but it's not publicly available so it's protected from outside visitors so we open that file from the upload disk we call the export for hls method and then we add two formats so i've got a low format and a high format which are just uh h.264 codecs with different bitrates so the low one is uh kilo bits and the high one is 1000 kilobits per second you can add as many formats as you like you can also add like a mid format or a super high format and what's cool about this package is that you can modify these these exports as well so in this example i've added the low format and i'm also resizing that one so the original video is full hd so 1920 by 1080 and with the low format i'm resizing that to 1280 by 720 and i don't i don't resize the high format so the next line is a progress handler to see uh how far we've come and then we save it to the public disk so what's great about this package is uh that you can save it to different disks but also open it from different disks so this could also be an s3 container or maybe a dropbox or a ftp file system or whatever works for you so you can open it from different disks and save it to different disks so in this case we're saving to public disk because we want it to be publicly available and then we give it a path so in this bar this part here the extension that's quite important it must end with the m3 u8 extension uh and then uh we uh do a little info line done so let's run this command in the in the terminal so here we are by the way this is a fresh level h 8 application you can see that right here if i scroll to the top laravel 8.20.1 i called this comment video upload process so let's run it so art is alias for php artisan let's run it and there it goes so yeah this always takes a while my computer is probably also slower because i am streaming as well don't worry about it so let's go back to code and in the videos folder we're already seeing some progress right here so it creates uh different segments for the different bit rates it's almost ready done so here are the uh files that were generated by the low format here are the files that are generated by high format and hls works with uh with uh playlists so um martin says in the artisan commands have a progress bar helper yeah i know but i think that one needs the total progress right yeah which is which i could use yeah so let's see i don't think i've used that before with progress bar total steps is 100 of course let's see if this works and let's move these into the closure okay i need to read the documentation for this oh yeah you need to give it a collection of something total steps and maybe let's just do this let's undo this should be 100 and then bar advance but i can't say can i do something like oh like i want to set the step all right yep sure progress i've got another keyboard to data so i'm making a lot of typos and then we hit finish let's run it again yeah it seems to work so much better of course oh maybe not what's happening so yeah yeah you're right one for later so uh let's refresh the demo application again and now it works so here you see the the content loaded so this is working all fine what i want to show you is the encryption feature so i'm gonna get rid of these this new bar thing just to make sure i don't break anything so what we can do is call a method that's called with encryption key and you need to give the key so we've also have a little helper method hls exporter generate encryption key so now it's going to encrypt this video with this key so this generates one key for the whole video which is probably fine but there's also another feature that's called with rotating encryption key which other generates the keys so with before i change this if you use this method you need to save the encryption key yourself so let's run it and for now i am going to remove one format to save some time let's run it again yeah so it's a bit faster so let's go back to the public folder so now we have this encryption key which i forgot to save but you get the id uh this is not what i want to show you but so now it it actually just all these segments are encrypted by ffmpeg you don't have to do anything uh for this manually so this is what i wrote in the documentation don't forget to save your key which i did so i'm gonna use the rotation key encryption which needs a callback because it other generates the keys so whenever a key is generated it calls this callback method with the file name and with the content so let's save that to the publix disk as well so storage disk public put file name contents and i'm going to delete the videos folder again to get rid of the old old segments so let's run it and now as you'll see here are the keys that are generated but i forgot to put it in the videos folder of course i forgot so one more time i'm gonna delete the videos folder i'm gonna delete these files as well delete and run it one more time so now it's storing these keys in the videos folder don't need this goodbye so it seems to be done let's refresh the demo application and it still works so if i change the network inspector to all you can see that the keys are downloaded as well they are downloaded automatically by the browser and if you inspect one of the playlists you can see that as well so for every segment it's listing another key so let's see what happens if we delete the keys refresh the page and the video doesn't work anymore so that's actually what we need because we want to limit the accessibility of this video so of course storing these keys to a public folder doesn't make sense so i'm gonna store it to a secret disk so i've added a secret disk as well to my file systems configuration file so let's do that disk secrets let's move this just store it there um yeah run it again here is the new secrets folder and of course when i refresh the page it should not work yeah so someone is asking how these encryption keys work so when you're when ffmpeg encrypts the video or sorry encodes the video from one file into multiple files it encrypts every segment with another key so the encryption happens when you convert the video and then when the browser tries to play that segment it also downloads the associated key so in this playlist which is which is generated automatically it links one key to one segment and you don't have to worry about this so this is all done by ffmpeg and buy the package the decryption is done by the browser or by a video player you can also use something like vlc for playback so that's how this encryption stuff works so back to the browser i'm refreshing again and it doesn't work because it can't find these keys right so how we're going to solve this problem i thought about this too and then i thought it would be great if what if we could deliver these keys to the browser through the laravel application so we can check if the uh user that is authenticated or not is allowed to read these keys so uh let's go into a route file and i'm gonna create a new route and i call this one video playlist and then we want to have a route segments we want that playlist right here and i will call this playlist video.playlist all right and i want the route for [Music] the key as well so i'm gonna update this to key and when somebody wants to retrieve a key or download the key we're just gonna give it them from the storage disk just from this so from the secrets uh we're gonna give them the key let's import that so what about the playlist um i've created a helper for that as well and that one is called dynamic hls playlist so with this class i can open the playlist and i should not forget from disk because we're open it from the public disk and we are opening the playlist from the route so you will see this in a minute and then i have three methods two or three callbacks to implement one is the key resolver so this this callback is gonna give us the key and we need to point it to a url where the player can find that key so that should be this one right we want to update the playlist so all the keys are pointing to this route so let's do that video dot key and then give it the key as a parameter we need to give it the playlist url resolver so what is this this file right here uh without the 0 and the bitrate this is the master playlist or the primary playlist and this one lists all the other playlists so this one is specifically for this bandwidth this resolution this codec so um back when we had two formats like one five thousand and one one thousand uh it actually had this inside it so we need to update these playlists as well and of course this is the current route so video the playlist and give it a playlist and then the last thing we need to do is give it the media itself so those are the the media segments uh this one the ts files so that is i think asset maybe url i'm not sure let's try asset no of course what is it i wrote it in the documentation because i always forget this so let's open the ffmpeg documentation i know it's somewhere around here oh yeah it's storage url right it's this one so of course from the storage disk the public disk and then we give the url to not forgetting it this time videos media so this seems really complex right now i'm gonna show you that it works and then we're gonna do a little walkthrough so let's refresh the page and let's hope i didn't make a mistake i did because it didn't work oh yeah of course i forgot to update the blade file so back to the plate file where are you welcome so instead of referencing to the public to the public folder we're gonna give it the route the one we just created video.playlist and then give it that playlist like i said different keyboard lots of typos today all right let's hit refresh and it still doesn't work we get a 500 error so let's open that unable to load ffmpeg [Music] i've had this error before so i i know why this is so our php cli now knows how to resolve ffmpeg but the php fpm i think the one that runs through that runs through uh nginic doesn't know how to resolve it so we're gonna publish the ffmpeg files the the ffmpeg configuration file this one right here and we need to give the absolute path to ffmpeg and ff probe so let's see where it's located today user local bin let's update it and let's refresh the application but it still doesn't work but we don't get an 200 or a 500 error anymore so uh let's see yeah i know i forgot to return so we got an empty response so this dynamic hls class is responsible which means you can just return this class and here at the bottom it knows how to uh to transform this whole class into a response so let's get back to the web file and refresh one more time now we've got another error so let's see path not found not found it could not find the playlist oh of course just when i said i wouldn't make this mistake again let's refresh it's doing something more but now it can't find so it did find the keys but it did not find the media segment so let's dive into ah i forgot to set the url path right so that's stupid mistake i should do this in the environment file so what's this called too long so let's just copy it let's hit refresh yeah and now it works so now we've got a dynamic playlist let's open uh this one so as we can see it generated links for all these segments maybe i can make this bigger yeah i can oops so it uh yeah it generated urls for all these segments and it also replaced the keys with the absolute path to the key so let's see what happens in the web file now this is the place where you can add some kind of authentication for example you could use the abort board method like a board if auth guest with a 403 so now when we refresh the page it shouldn't work because the encryption key is giving a 403 and now it works again so of course this is where you implement your own logic right here so um let's take a look at this dynamic hls playlist again so let's let's close some things yeah don't save so i'm gonna i'm gonna do one more thing and that's adding the original high format so i can show you what's uh what's happening let's convert one more time should take a little bit longer now so yeah some new keys are generated and we are already seeing this 1000 bitrate file almost ready done so let's dive into this playlist this one is the main playlist the master playlist the primary playlist i don't know the official name i think it's called master playlist so in this playlist all the formats are listed so here we've got our first format which we called low format so it's got a 20 1280 by 720 resolution uh it's got a average bandwidth and it's got a frame rate and codex you don't have to worry about that and this is where it says if you want to play this stream you need this playlist and the same is true for this playlist below which is the one that has a bigger resolution higher bandwidth if the browser browser wants to play this stream it needs this playlist so we've got a master playlist and we've got a playlist for the low bit rate and one for the high bit rate so let's take a look at the low bit rate this low bit bitrate stream is divided into three files which are called segments so this is a first segment second segment third segment and all these segments are listed again in this playlist and by default these segments are 10 seconds but you can change that uh as well i've never had trouble with 10 seconds so i see no reason to update this but yeah so just you know so since we are encrypting all these segments all these segments have a different key right so we've got three segments three keys and you can see the same in the 1000 playlist file the one with high bitrate it's got three segments with three different keys so you just give the browser this file the master playlist and it knows how to figure out which uh which stream to play it it's also adaptive so whenever your network bandwidth um is a throttle down it just selects another stream automatically you don't have to do anything for that it just works um so that's that but the problem with this playlist or i should say with this playlist is that the browser of course can't find these files it doesn't know where to find these encryption keys so what this dynamic oh in this file what this dynamic playlist does is it's opening a playlist like this one and then it's gonna change the path to the key and if you're opening the master playlist it's also gonna change the path to the segment playlist so the first playlist that the browser opens is this one it's the master playlist we're giving it you can see that in the exp inspector as well so this redfield.m3u8 that's the first playlist it's requesting from the from the laravel application and let's refresh it so we have the multiple bitrates yeah so as you can see the only thing that has changed in this master playlist is the path to the segment playlist so instead of just having redfield 0 500 we're having the full path to the playlist url so this browser which is firefox then opens the first playlist which is the redfield0500 which is this playlist so it's not opening this playlist right from this disk but through this route right and as you can see here it also updates a bunch of stuff so in the original file we have the relative path to a key it has updated it to the absolute path to our laravel application and it also updated the url to the uh to the segments so this is probably because i uh ended the app url with the slash it still works so yeah so it updates these these segments as well so that's great so this is updated and this is updated and so it still fetches the segments this stuff right here through the web brow web server not through the laravel application it only serves the playlists and the secrets through the laravel application so whenever the browser wants to play this first segment first it's going to look for the key so it will end up right here requesting that key from the laravel application that's where you can find out do i want to give the browser that key and if you do if you return that key to the browser then it will open a segment which is not through the laravel application but just like i said through the web server so in this case you could use something like a cdn if you really want to and again uh add your own logic right here you don't want to uh if you don't want to this or if you don't want this video to be playable just return a 403 url whatever you like so uh that's it for today um this is stuff i wanted to show you um it's available in ffmpeg 7 or laravel ffmpeg 7.5 which was released just a few days ago and this morning i made a little bug fix for uh for the bit rate because there were some problems with the bit rates in the playlist but that's solved now and you don't have to worry about it again so this also you can read all about this in the documentation with example codes oh yeah and of course yeah just one more one more thing to show you uh let's go back to the comments so now i'm saving this encryption key to the storage but of course i can store it to the database as well or to another another way of storage um i think this is fine maybe but you uh maybe you want to store it in a database i don't know whatever you like so that's that um yeah this is just an optional thing yeah that's it for today so uh thanks again for uh for joining me uh thanks for the comments and uh have a great uh holiday everybody stay safe and i hope to see you soon maybe next year somewhere alright bye you
Info
Channel: Pascal Baljet
Views: 4,497
Rating: undefined out of 5
Keywords: Laravel, PHP, Tailwind CSS, HTML
Id: WlbzWoAcez4
Channel Id: undefined
Length: 39min 46sec (2386 seconds)
Published: Thu Dec 24 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.