--- /dev/null
+<?php
+
+namespace Fluidbook\Tools\Video;
+
+use Cubist\Util\Files\Files;
+use Exception;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Queue\SerializesModels;
+use Spatie\MediaLibrary\MediaCollections\Events\MediaHasBeenAdded;
+use Spatie\MediaLibrary\MediaCollections\Models\Media;
+
+class FluidbookVideoConverterListener implements ShouldQueue
+{
+ use InteractsWithQueue;
+ use SerializesModels;
+
+ public const MEDIA_STATUS_TO_CONVERT = 'status_to_convert';
+ public const MEDIA_STATUS_PROCESSING = 'status_processing';
+ public const MEDIA_STATUS_FAILED = 'status_failed';
+ public const MEDIA_STATUS_READY = 'status_ready';
+ public const MEDIA_VIDEO_EXT = 'mp4';
+
+ /** @var Media */
+ protected $media;
+
+ /**
+ * Create the event listener.
+ *
+ */
+ public function __construct()
+ {
+
+ }
+
+ public function handle(MediaHasBeenAdded $event)
+ {
+ $this->media = $event->media;
+ //prevent any events from media model
+ $this->media->flushEventListeners();
+
+ if ((!$this->isVideo())
+ || $this->media->getCustomProperty('status') !== self::MEDIA_STATUS_TO_CONVERT
+ || strtolower($this->media->extension) === self::MEDIA_VIDEO_EXT || strtolower($this->media->mime_type) == 'video/mp4'
+ ) {
+ $this->media->setCustomProperty('status', self::MEDIA_STATUS_READY);
+ $this->media->setCustomProperty('progress', 100);
+ $this->media->save();
+ return;
+ }
+
+ $this->media->setCustomProperty('status', self::MEDIA_STATUS_PROCESSING);
+ $this->media->save();
+
+ try {
+ $fullPath = $this->media->getPath();
+ $newFileFullPath = pathinfo($fullPath, PATHINFO_DIRNAME)
+ . DIRECTORY_SEPARATOR . pathinfo($fullPath, PATHINFO_FILENAME)
+ . self::MEDIA_VIDEO_EXT;
+
+ if (file_exists($newFileFullPath)) {
+ unlink($newFileFullPath);
+ }
+ self::convert($fullPath, $newFileFullPath);
+
+ if (file_exists($newFileFullPath)) {
+ if (file_exists($fullPath)) {
+ unlink($fullPath);
+ }
+ $this->media->file_name = pathinfo($newFileFullPath, PATHINFO_BASENAME);
+ $this->media->mime_type = Files::getMimeType($newFileFullPath);
+ $this->media->size = filesize($newFileFullPath);
+ $this->media->setCustomProperty('status', self::MEDIA_STATUS_READY);
+ $this->media->setCustomProperty('progress', 100);
+ } else {
+ $this->media->setCustomProperty('status', self::MEDIA_STATUS_FAILED);
+ $this->media->setCustomProperty('error', 'Error while transcoding');
+ }
+ $this->media->save();
+ } catch (Exception $e) {
+ $this->media->setCustomProperty('status', self::MEDIA_STATUS_FAILED);
+ $this->media->setCustomProperty('error', $e->getMessage());
+ $this->media->save();
+ }
+ }
+
+
+ /**
+ * Is media a video?
+ *
+ * @return bool
+ */
+ protected function isVideo()
+ {
+ return str_contains($this->media->mime_type, 'video');
+ }
+
+ public static function convert($input, $dest)
+ {
+ `/usr/bin/ffmpeg -i $input -y -acodec aac -vcodec libx264 -b 384k -ab 64k -mbd 2 -cmp 256 -subcmp 2 -subq 6 -strict experimental -vf scale="640:trunc(320/a)*2" -coder 0 -trellis 0 -bf 0 -refs 5 -flags +loop+mv4 -partitions +parti4x4+parti8x8+partp4x4+partp8x8 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -qmin 10 -qmax 51 -qdiff 4 -ac 2 -ar 44100 -r 13 $dest`;
+ }
+}