Skip to content

Commit 914f9c4

Browse files
committed
Upload e Encoding de Videos
1 parent 3755061 commit 914f9c4

File tree

14 files changed

+1310
-4
lines changed

14 files changed

+1310
-4
lines changed

.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,6 @@ AWS_BUCKET=
6363
AWS_USE_PATH_STYLE_ENDPOINT=false
6464

6565
VITE_APP_NAME="${APP_NAME}"
66+
67+
FFMPEG_BINARIES=""
68+
FFPROBE_BINARIES=""
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
3+
namespace App\Http\Controllers\Media;
4+
5+
use App\Http\Controllers\Controller;
6+
use App\Jobs\VideoEncodingJob;
7+
use App\Models\Content;
8+
use Illuminate\Http\Request;
9+
use Illuminate\Http\UploadedFile;
10+
use Pion\Laravel\ChunkUpload\Handler\ContentRangeUploadHandler;
11+
use Pion\Laravel\ChunkUpload\Receiver\FileReceiver;
12+
13+
class VideosController extends Controller
14+
{
15+
public function index(Content $content)
16+
{
17+
return inertia('media/videos/Upload', compact('content'));
18+
}
19+
20+
/**
21+
* Quando realizar a opção de upar algo
22+
* 3 - Expor a rota para receber os chuncks do video upado
23+
*/
24+
public function store(Request $request, Content $content)
25+
{
26+
$video = $content->videos()->create([
27+
'code' => str()->uuid(),
28+
'name' => $request->name,
29+
]);
30+
31+
return $video;
32+
}
33+
34+
public function update(Content $content, $video, Request $request)
35+
{
36+
$video = $content->videos()->findOrFail($video);
37+
38+
$video->update([
39+
'name' => $request->name,
40+
'description' => $request->description
41+
]);
42+
43+
return redirect()->back();
44+
}
45+
46+
public function destroy(Content $content, $video)
47+
{
48+
$video = $content->videos()->findOrFail($video);
49+
$video->delete();
50+
51+
return redirect()->back();
52+
}
53+
54+
public function processChunck(Content $content, $video, Request $request)
55+
{
56+
$receiver = new FileReceiver(
57+
UploadedFile::fake()->createWithContent('file', $request->getContent()),
58+
$request,
59+
ContentRangeUploadHandler::class
60+
);
61+
62+
$save = $receiver->receive();
63+
64+
if($save->isFinished()) {
65+
$video = $content->videos()->findOrFail($video);
66+
67+
$video->update([
68+
'video' => $save->getFile()->storeAs('', str()->uuid(), 'videos')
69+
]);
70+
71+
dispatch(new VideoEncodingJob($video));
72+
}
73+
74+
$save->handler();
75+
}
76+
}

app/Jobs/VideoEncodingJob.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
namespace App\Jobs;
4+
5+
use App\Models\Video;
6+
use FFMpeg\Format\Video\X264;
7+
use Illuminate\Contracts\Queue\ShouldQueue;
8+
use Illuminate\Foundation\Queue\Queueable;
9+
use Illuminate\Support\Facades\Storage;
10+
use ProtoneMedia\LaravelFFMpeg\Support\FFMpeg;
11+
12+
class VideoEncodingJob implements ShouldQueue
13+
{
14+
use Queueable;
15+
16+
/**
17+
* Create a new job instance.
18+
*/
19+
public function __construct(private Video $video)
20+
{
21+
//
22+
}
23+
24+
/**
25+
* Execute the job.
26+
*/
27+
public function handle(): void
28+
{
29+
//Dispararia um evento de inicializacao do encoding
30+
31+
$videoNewName = str_replace(strrchr($this->video->video, '.'), '', $this->video->video) . '.m3u8';
32+
33+
$low = (new X264())->setKiloBitrate(500);
34+
$mid = (new X264())->setKiloBitrate(1500);
35+
$high = (new X264())->setKiloBitrate(3000);
36+
37+
//Fazer o processo referente ao encoding HLS
38+
FFMpeg::fromDisk('videos')
39+
->open($this->video->video)
40+
->exportForHLS()
41+
->addFormat($low)
42+
->addFormat($mid)
43+
->addFormat($high)
44+
->onProgress(function($progress){
45+
//Dispararia um evento via broadcast com as infos do progresso
46+
})
47+
->toDisk('videos_encoded')
48+
->save($this->video->code . '/' . $videoNewName);
49+
50+
Storage::disk('videos')->delete($this->video->video);
51+
52+
$this->video->update([
53+
'video' => $videoNewName,
54+
'is_processed' => true
55+
]);
56+
57+
//Dispararia um evento de finalizacao do encoding
58+
}
59+
}

app/Models/Content.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use App\Traits\Sluggable;
66
use Illuminate\Database\Eloquent\Factories\HasFactory;
77
use Illuminate\Database\Eloquent\Model;
8+
use Illuminate\Database\Eloquent\Relations\HasMany;
89

910
class Content extends Model
1011
{
@@ -21,4 +22,9 @@ protected function casts(): array
2122
'created_at' => 'datetime:d/m/Y H:i'
2223
];
2324
}
25+
26+
public function videos(): HasMany
27+
{
28+
return $this->hasMany(Video::class);
29+
}
2430
}

app/Models/Video.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
namespace App\Models;
4+
5+
use App\Traits\Sluggable;
6+
use Illuminate\Database\Eloquent\Model;
7+
use Illuminate\Database\Eloquent\Relations\BelongsTo;
8+
9+
class Video extends Model
10+
{
11+
use Sluggable;
12+
13+
protected $slugColumnFrom = 'name';
14+
15+
protected $fillable = [
16+
'name','code', 'description', 'thumb',
17+
'video', 'is_processed', 'slug'
18+
];
19+
20+
public function content(): BelongsTo
21+
{
22+
return $this->belongsTo(Content::class);
23+
}
24+
}

composer.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
"laravel/framework": "^12.0",
1616
"laravel/tinker": "^2.10.1",
1717
"laravel/wayfinder": "^0.1.9",
18+
"pbmedia/laravel-ffmpeg": "^8.7",
19+
"pion/laravel-chunk-upload": "^1.5",
1820
"spatie/laravel-sluggable": "^3.7"
1921
},
2022
"require-dev": {

0 commit comments

Comments
 (0)