Transcoding Videos for Web Streaming with FFmpeg using Laravel Queues
I’ve been working on a project where we were using AWS elastic transcoder for media conversion. Elastic transcoder is a highly scalable solution for media transcoding. However, it charges your per minute for media conversion depending on your region. To reduce operational costs, we decided to shift away from AWS transcoder and use FFmpeg with Laravel for media conversion on our own servers. In this tutorial, I’ll show you how we can use FFmpeg for media conversion and defer processing using Laravel Queues.
Let’s get started by setting up a new project. Create a new Video model, its migration, and controller. We will store uploaded videos information on videos table.
On file upload, we will store video title, original file name, and path of the stored file in the database. After upload, we will dispatch a Job for transcoding it to a web streamable format and update stream_path with the output file path, update converted_for_streaming_at timestamp and set processed to true after FFmpeg is done processing uploaded media file.
1
2
3
4
5
6
7
8
classVideoextendsModel
{
protected$dates=[
'converted_for_streaming_at',
];
protected$guarded=[];
}
In
Video model class, add the
converted_for_streaming_at column to
$dates array so that it should be mutated to dates like
created_at or
updated_at columns.
GET/uploader route will render a form for uploading videos and
POST/upload route will handle the form submission, upload video, create a database record and dispatch an FFmpeg transcoding job.
GET/ index route will render videos view where all uploaded videos will be displayed in native HTML video player.
Also, create a
StoreVideoRequest form request for validating uploader form input.
1
php artisan make:request StoreVideoRequest
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
classStoreVideoRequestextendsFormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
publicfunctionauthorize()
{
returntrue;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
publicfunctionrules()
{
return[
'title'=>'required',
'video'=>'required|file|mimetypes:video/*',
];
}
}
We have a
mimetypes validation rule with
video/* wildcard to only allow video uploads.
Now create a
ConvertVideoForStreaming job which will be dispatched after video is done uploading and a database record is created in
VideoController@store method.
In
handle() method of the dispatched job, we will create a low bitrate X264 format. We will open uploaded file from public disk and add a resize filter to it. Then we will tell
FFmpeg to start transcoding by calling
export() method and output file to public disk in a low bitrate mp4 container format.
Before you go an test it, make sure you have installed Laravel FFmpeg package that we are using in our transcoding job.
1
composer require pbmedia/laravel-ffmpeg
Also, make sure you have ffmpeg binaries installed of your machine. If you’re running Linux, you can easily install it by running following apt install command.
1
sudo apt-getinstall ffmpeg
You must also add
FFmpeg Service Provider and Facade to
app.php.
If you’re running windows, you must add ffmpeg binaries to the system PATH. If you don’t have access to that, you can define these environment variables in your
.env file.
1
2
FFMPEG_BINARIES='PATH_TO_FFMPEG_BINARUES'
FFPROBE_BINARIES='PATH_TO_FFPROBE_BINARIES'
Laravel Queues Configuration
You also need to configure queue connection in your env file. For this tutorial, I’m using database queue connection. Edit
.env file and update
QUEUE_CONNECTION variable to database.
Also run
php artisan queue:table to create database queue table migration and
php artisan migrate to create table. To deal with failed jobs, run
php artisan queue:failed-table to create failed queue jobs migration table and
php artisan migrate to create table.
Running Queue Worker
Before we go and test, run Laravel’s queue worker
1
php artisan queue:work--tries=3--timeout=8600
we have added a
--timeout flag to queue worker. This indicates that don’t want our queue jobs to run longer than 8600 seconds.
Now if you head over to
/uploader route in your application and upload a video file, a database record will be created a transcoding job will be dispatched. You’ll be able to view your dispatched job in the terminal.
Displaying Videos
Create
videos.blade.php file under view directory.
Video is currently being processed and will be available shortly
</div>
@endif
</div>
</div>
@endforeach
</div>
@endSection
We will display an alert for videos that are currently being processed. For processed videos, we will render a video element with transcoded stream_path.
Here’s a demo of what we have done so far.
I have set up a Github repository with example application code. If you run into any issue or have any questions, leave a comment and I will try to help you in any way possible.
Share this post
19 thoughts on “Transcoding Videos for Web Streaming with FFmpeg using Laravel Queues”
Hello! I have some strange problem. I don’t have anything in queue:work.
Its just staying without printing any single line. But the movies are been converted.
I have the same error as other students. I have set up the absolute path but still not working
FFMPEG_BINARIES=’C:/ffmpeg/bin/ffmpeg.exe’ even if l remove the .exe
FFPROBE_BINARIES=’C:/ffmpeg/bin/ffprobe.exe’
Hi Waleed,
Thanks for your sharing, but i’m getting an error when run php artisan vendor:publish –provider=”Pbmedia\LaravelFFMpeg\FFMpegServiceProvider”
Message: Class Pbmedia\LaravelFFMpeg\FFMpegServiceProvider not found.
I install ffmpeg at my applycation root/app so my path is :
FFMPEG_BINARIES=/app/ffmpeg/bin
FFPROBE_BINARIES=/app/ffmpeg/bin
Is there some thing wrong?
I solved this by removing the two lines from the config/app.php and then run the following:
COMPOSER_MEMORY_LIMIT=-1 composer require pbmedia/laravel-ffmpeg
Hi, I’m pretty new in laravel. And when I want to run the server it says the following:
Warning: require(C:\wamp64\www\laravel-stream/vendor/autoload.php): failed to open stream: No such file or directory in C:\wamp64\www\laravel-stream\artisan on line 18
Fatal error: require(): Failed opening required ‘C:\wamp64\www\laravel-stream/vendor/autoload.php’ (include_path=’.;C:\php\pear’) in C:\wamp64\www\laravel-stream\artisan
on line 18
sorry I have error, pls help me
Hello Waleed,
I wanted to repicate your transcoder webservice, unfortunatelly I keep running into the same issue like the guy who posted on your youtuve video.
[2019-04-28 10:18:38][1] Processing: App\Jobs\ConvertVideoForStreaming
[2019-04-28 10:18:38][2] Processing: App\Jobs\ConvertVideoForStreaming
[2019-04-28 10:18:38][3] Processing: App\Jobs\ConvertVideoForStreaming
[2019-04-28 10:18:38][3] Failed: App\Jobs\ConvertVideoForStreaming
I copied the binaries into my web root folder in htdocs/xampp (local webserver)
FFmpeg seems to be installed correctly since it is responding on comands globally with no problems.
The video I am trying to upload and convert is a test.mp4 about 50 MB big
I adjusted the .ENV variable to
FFMPEG_BINARIES=’/FFmpeg’
FFPROBE_BINARIES=’/FFmpeg’
where I put the binaries and I also upgraded them under ENVIRONMENT VARIABLES System Variables in windows.
Let me know if you have any ideas
Cheers
Rainer
What was the exception logged in the failed queues table? You should add the absolute path to
ffmpeg
andffprobe
in your.env
file.I am also getting failed jobs error.Please mention the correct way of declaring “FFMPEG_BINARIES” and “FFPROBE_BINARIES”.
Hello! I have some strange problem. I don’t have anything in queue:work.
Its just staying without printing any single line. But the movies are been converted.
Unable to load FFProbe
I have this type of error
I have the same error as other students. I have set up the absolute path but still not working
FFMPEG_BINARIES=’C:/ffmpeg/bin/ffmpeg.exe’ even if l remove the .exe
FFPROBE_BINARIES=’C:/ffmpeg/bin/ffprobe.exe’
Also, the package doesn’t recognize use FFMpeg;
‘local’,
‘ffmpeg’ => [
‘binaries’ => env(‘FFMPEG_BINARIES’, ‘ffmpeg’),
‘threads’ => 12,
],
‘ffprobe’ => [
‘binaries’ => env(‘FFPROBE_BINARIES’, ‘ffprobe’),
],
‘timeout’ => 3600,
];
in the log file
[2019-12-01 20:58:29] local.INFO: ffprobe running command “C:/ffmpeg/bin/ffprobe.exe” -help -loglevel quiet
[2019-12-01 20:58:30] local.INFO: ffprobe executed command successfully
[2019-12-01 20:58:30] local.INFO: ffprobe running command “C:/ffmpeg/bin/ffprobe.exe” “C:\laragon\www\clone-youtube-application\storage\app\channels/3bf10f3c-59f6-4e9d-94ea-110459ece645/4nQxPhT8ejB724eilbwxrFxHkgwfMV8pKycTWkpE.mp4” -show_streams -print_format json
[2019-12-01 20:58:30] local.ERROR: ffprobe failed to execute command “C:/ffmpeg/bin/ffprobe.exe” “C:\laragon\www\clone-youtube-application\storage\app\channels/3bf10f3c-59f6-4e9d-94ea-110459ece645/4nQxPhT8ejB724eilbwxrFxHkgwfMV8pKycTWkpE.mp4” -show_streams -print_format json
[2019-12-01 20:58:30] local.ERROR: Unable to probe C:\laragon\www\clone-youtube-application\storage\app\channels/3bf10f3c-59f6-4e9d-94ea-110459ece645/4nQxPhT8ejB724eilbwxrFxHkgwfMV8pKycTWkpE.mp4 {“exception”:”[object] (FFMpeg\\Exception\\RuntimeException(code: 0): Unable to probe C:\\laragon\\www\\clone-youtube-application\\storage\\app\\channels/3bf10f3c-59f6-4e9d-94ea-110459ece645/4nQxPhT8ejB724eilbwxrFxHkgwfMV8pKycTWkpE.mp4 at C:\\laragon\\www\\clone-youtube-application\\vendor\\pbmedia\\php-ffmpeg\\src\\FFMpeg\\FFProbe.php:263)
[stacktrace]
i
Which PHP version are you running?
I am running on php 7.37
[2019-12-01 20:58:29] local.INFO: ffprobe running command “C:/ffmpeg/bin/ffprobe.exe” -help -loglevel quiet
[2019-12-01 20:58:30] local.INFO: ffprobe executed command successfully
[2019-12-01 20:58:30] local.INFO: ffprobe running command “C:/ffmpeg/bin/ffprobe.exe” “C:\laragon\www\clone-youtube-application\storage\app\channels/3bf10f3c-59f6-4e9d-94ea-110459ece645/4nQxPhT8ejB724eilbwxrFxHkgwfMV8pKycTWkpE.mp4” -show_streams -print_format json
[2019-12-01 20:58:30] local.ERROR: ffprobe failed to execute command “C:/ffmpeg/bin/ffprobe.exe” “C:\laragon\www\clone-youtube-application\storage\app\channels/3bf10f3c-59f6-4e9d-94ea-110459ece645/4nQxPhT8ejB724eilbwxrFxHkgwfMV8pKycTWkpE.mp4” -show_streams -print_format json
[2019-12-01 20:58:30] local.ERROR: Unable to probe C:\laragon\www\clone-youtube-application\storage\app\channels/3bf10f3c-59f6-4e9d-94ea-110459ece645/4nQxPhT8ejB724eilbwxrFxHkgwfMV8pKycTWkpE.mp4 {“exception”:”[object] (FFMpeg\\Exception\\RuntimeException(code: 0):
I got error how can i fix it? thank you.
message: “Encoding failed”
exception: “FFMpeg\Exception\RuntimeException”
file: “C:\Users\visal\Desktop\project test\ffmpeg_blog\vendor\pbmedia\php-ffmpeg\src\FFMpeg\Media\AbstractVideo.php”
line: 106
hi buddy,
I am using ajax in controller store method , after :
ProcessVideoForStreming::dispatch($video);
return response()->json([message => ‘video under processing’]);
here, return response is not working. It is only working after the job finishes , but I want to
send message first and process the video after it
Hi Waleed,
Thanks for your sharing, but i’m getting an error when run php artisan vendor:publish –provider=”Pbmedia\LaravelFFMpeg\FFMpegServiceProvider”
Message: Class Pbmedia\LaravelFFMpeg\FFMpegServiceProvider not found.
I install ffmpeg at my applycation root/app so my path is :
FFMPEG_BINARIES=/app/ffmpeg/bin
FFPROBE_BINARIES=/app/ffmpeg/bin
Is there some thing wrong?
Hi Cheng,
I have the same issue with FFMpegServiceProvider
In ProviderRepository.php line 208:
Class ‘Pbmedia\LaravelFFMpeg\FFMpegServiceProvider’ not found
I really couldn’t find correct answers or solutions for this problem.
Yes i did one,
comment out that line from app/config.php and after run this two lines:
php artisan cache:clear
php artisan config:clear
and run again your command
I solved this by removing the two lines from the config/app.php and then run the following:
COMPOSER_MEMORY_LIMIT=-1 composer require pbmedia/laravel-ffmpeg
Worked like a charm
Hi, I’m pretty new in laravel. And when I want to run the server it says the following:
Warning: require(C:\wamp64\www\laravel-stream/vendor/autoload.php): failed to open stream: No such file or directory in C:\wamp64\www\laravel-stream\artisan on line 18
Fatal error: require(): Failed opening required ‘C:\wamp64\www\laravel-stream/vendor/autoload.php’ (include_path=’.;C:\php\pear’) in C:\wamp64\www\laravel-stream\artisan
on line 18
What should I do in this situation?
Run
composer install
Hello Waleed,
My jobs get executed correctly, but my videos are just 1 seconds long and gray or very pixely quality and one second long.
Class “Pbmedia\LaravelFFMpeg\FFMpegServiceProvider” not found
My PHP version: 8.0
Laravel Version: 8.67