diff --git a/app/config/collections.php b/app/config/collections.php index 379b4e220a..073eb51794 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -4019,23 +4019,12 @@ $collections = [ 'array' => false, 'filters' => [], ], - [ - '$id' => 'output', - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => false, - 'default' => null, - 'array' => false, - 'filters' => [], - ], ], 'indexes' => [ [ '$id' => '_key_profile', 'type' => Database::INDEX_KEY, - 'attributes' => ['output', 'width', 'height', 'videoBitRate', 'audioBitRate' ], + 'attributes' => ['width', 'height', 'videoBitRate', 'audioBitRate' ], 'lengths' => [], 'orders' => [], ], diff --git a/app/config/videos-profiles.php b/app/config/videos-profiles.php index 9ca3e5974c..7215fd0f7e 100644 --- a/app/config/videos-profiles.php +++ b/app/config/videos-profiles.php @@ -8,7 +8,6 @@ return [ 'audioBitRate' => 64, //audio BitRate in Kbps 'width' => 640, //width resolution in px 'height' => 360, //height resolution in px - 'output' => 'hls' ], [ 'name' => '576p', @@ -16,7 +15,6 @@ return [ 'audioBitRate' => 128, 'width' => 1024, 'height' => 576, - 'output' => 'hls' ], [ 'name' => '720p', @@ -24,34 +22,5 @@ return [ 'audioBitRate' => 128, 'width' => 1280, 'height' => 720, - 'output' => 'hls' ], - - [ - - 'name' => '360p', - 'videoBitRate' => 890, //video BitRate in Kbps - 'audioBitRate' => 64, //audio BitRate in Kbps - 'width' => 640, //width resolution in px - 'height' => 360, //height resolution in px - 'output' => 'dash' - ], - [ - 'name' => '576p', - 'videoBitRate' => 2538, - 'audioBitRate' => 128, - 'width' => 1024, - 'height' => 576, - 'output' => 'dash' - ], - [ - 'name' => '720p', - 'videoBitRate' => 3551, - 'audioBitRate' => 128, - 'width' => 1280, - 'height' => 720, - 'output' => 'dash' - ], - - ]; diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index d35d5ea168..40db3706b6 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -177,8 +177,7 @@ App::post('/v1/projects') 'videoBitRate' => $profile['videoBitRate'], 'audioBitRate' => $profile['audioBitRate'], 'width' => $profile['width'], - 'height' => $profile['height'], - 'output' => $profile['output'] + 'height' => $profile['height'] ])); }); } diff --git a/app/controllers/api/videos.php b/app/controllers/api/videos.php index a4caa307d3..b36ea54262 100644 --- a/app/controllers/api/videos.php +++ b/app/controllers/api/videos.php @@ -97,6 +97,83 @@ App::post('/v1/videos') $response->dynamic($video, Response::MODEL_VIDEO); }); +App::get('/v1/videos/:videoId') + ->desc('Get video ') + ->groups(['api', 'videos']) + ->label('scope', 'videos.read') + ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'videos') + ->label('sdk.method', 'get') + ->label('sdk.description', '/docs/references/videos/get-video.md') // TODO: Create markdown + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_VIDEO) + ->param('videoId', '', new UID(), 'Video unique ID.') + ->inject('response') + ->inject('dbForProject') + ->inject('mode') + ->action(function (string $videoId, Response $response, Database $dbForProject, string $mode) { + + $video = Authorization::skip(fn() => $dbForProject->getDocument('videos', $videoId)); + + if ($video->isEmpty()) { + throw new Exception(Exception::VIDEO_NOT_FOUND); + } + + validateFilePermissions($dbForProject, $video['bucketId'], $video['fileId'], $mode); + + $response->dynamic($video, Response::MODEL_VIDEO); + }); + +App::put('/v1/videos/:videoId') + ->desc('Update video') + ->groups(['api', 'videos']) + ->label('scope', 'videos.write') + ->label('audits.event', 'video.update') + ->label('audits.resource', 'video/{request.videoId}') + ->label('sdk.namespace', 'videos') + ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.method', 'update') + ->label('sdk.description', '/docs/references/videos/update.md') // TODO: Create markdown + ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) + ->label('sdk.response.model', Response::MODEL_VIDEO) + ->param('videoId', '', new UID(), 'Video unique ID.') + ->param('bucketId', null, new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).') + ->param('fileId', '', new CustomId(), 'File ID. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->inject('response') + ->inject('project') + ->inject('dbForProject') + ->inject('mode') + ->action(function (string $videoId, $bucketId, $fileId, Response $response, Document $project, Database $dbForProject, string $mode) { + + $video = Authorization::skip(fn() => $dbForProject->getDocument('videos', $videoId)); + + if ($video->isEmpty()) { + throw new Exception(Exception::VIDEO_NOT_FOUND); + } + + validateFilePermissions($dbForProject, $video['bucketId'], $video['fileId'], $mode); + + $file = validateFilePermissions($dbForProject, $bucketId, $fileId, $mode); + $video = Authorization::skip(fn() => + $dbForProject->updateDocument('videos', $videoId, new Document([ + 'bucketId' => $bucketId, + 'fileId' => $file->getId(), + 'size' => $file->getAttribute('sizeOriginal'), + 'duration' => null, + 'width' => null, + 'height' => null, + 'videoCodec' => null, + 'videoBitRate' => null, + 'videoFrameRate' => null, + 'audioCodec' => null, + 'audioBitRate' => null, + 'audioSampleRate' => null, + ]))); + + $response->dynamic($video, Response::MODEL_VIDEO); + }); + App::delete('/v1/videos/:videoId') ->desc('Delete video') ->groups(['api', 'videos']) @@ -137,83 +214,6 @@ App::delete('/v1/videos/:videoId') $response->noContent(); }); -App::put('/v1/videos/:videoId') - ->desc('Update video') - ->groups(['api', 'videos']) - ->label('scope', 'videos.write') - ->label('audits.event', 'video.update') - ->label('audits.resource', 'video/{request.videoId}') - ->label('sdk.namespace', 'videos') - ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) - ->label('sdk.method', 'update') - ->label('sdk.description', '/docs/references/videos/update.md') // TODO: Create markdown - ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) - ->label('sdk.response.model', Response::MODEL_VIDEO) - ->param('videoId', '', new UID(), 'Video unique ID.') - ->param('bucketId', null, new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).') - ->param('fileId', '', new CustomId(), 'File ID. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->inject('response') - ->inject('project') - ->inject('dbForProject') - ->inject('mode') - ->action(function (string $videoId, $bucketId, $fileId, Response $response, Document $project, Database $dbForProject, string $mode) { - - $video = Authorization::skip(fn() => $dbForProject->getDocument('videos', $videoId)); - - if ($video->isEmpty()) { - throw new Exception(Exception::VIDEO_NOT_FOUND); - } - - validateFilePermissions($dbForProject, $video['bucketId'], $video['fileId'], $mode); - - $file = validateFilePermissions($dbForProject, $bucketId, $fileId, $mode); - $video = Authorization::skip(fn() => - $dbForProject->updateDocument('videos', $videoId, new Document([ - 'bucketId' => $bucketId, - 'fileId' => $file->getId(), - 'size' => $file->getAttribute('sizeOriginal'), - 'duration' => null, - 'width' => null, - 'height' => null, - 'videoCodec' => null, - 'videoBitRate' => null, - 'videoFrameRate' => null, - 'audioCodec' => null, - 'audioBitRate' => null, - 'audioSampleRate' => null, - ]))); - - $response->dynamic($video, Response::MODEL_VIDEO); - }); - -App::get('/v1/videos/:videoId') - ->desc('Get video ') - ->groups(['api', 'videos']) - ->label('scope', 'videos.read') - ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) - ->label('sdk.namespace', 'videos') - ->label('sdk.method', 'get') - ->label('sdk.description', '/docs/references/videos/get-video.md') // TODO: Create markdown - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_VIDEO) - ->param('videoId', '', new UID(), 'Video unique ID.') - ->inject('response') - ->inject('dbForProject') - ->inject('mode') - ->action(function (string $videoId, Response $response, Database $dbForProject, string $mode) { - - $video = Authorization::skip(fn() => $dbForProject->getDocument('videos', $videoId)); - - if ($video->isEmpty()) { - throw new Exception(Exception::VIDEO_NOT_FOUND); - } - - validateFilePermissions($dbForProject, $video['bucketId'], $video['fileId'], $mode); - - $response->dynamic($video, Response::MODEL_VIDEO); - }); - App::get('/v1/videos') ->desc('Get video list') ->groups(['api', 'videos']) @@ -299,6 +299,38 @@ App::post('/v1/videos/:videoId/subtitles') $response->dynamic($subtitle, Response::MODEL_SUBTITLE); }); +App::get('/v1/videos/:videoId/subtitles') + ->desc('Get video subtitles') + ->groups(['api', 'videos']) + ->label('scope', 'videos.read') + ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'videos') + ->label('sdk.method', 'getSubtitles') + ->label('sdk.description', '/docs/references/videos/get-subtitles.md') // TODO: Create markdown + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_SUBTITLE_LIST) + ->param('videoId', null, new UID(), 'Video unique ID.') + ->inject('response') + ->inject('dbForProject') + ->action(function ($videoId, Response $response, Database $dbForProject) { + + $query = [ + Query::equal('videoId', [$videoId]), + ]; + + $subtitles = Authorization::skip(fn () => $dbForProject->find('videos_subtitles', $query)); + + if (empty($subtitles)) { + throw new Exception(Exception::VIDEO_SUBTITLE_NOT_FOUND); + } + + $response->dynamic(new Document([ + 'total' => $dbForProject->count('videos_subtitles', $query, APP_LIMIT_COUNT), + 'subtitles' => $subtitles, + ]), Response::MODEL_SUBTITLE_LIST); + }); + App::patch('/v1/videos/:videoId/subtitles/:subtitleId') ->desc('Update video subtitle') ->groups(['api', 'videos']) @@ -383,38 +415,6 @@ App::delete('/v1/videos/:videoId/subtitles/:subtitleId') $response->noContent(); }); -App::get('/v1/videos/:videoId/subtitles') - ->desc('Get video subtitles') - ->groups(['api', 'videos']) - ->label('scope', 'videos.read') - ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) - ->label('sdk.namespace', 'videos') - ->label('sdk.method', 'getSubtitles') - ->label('sdk.description', '/docs/references/videos/get-subtitles.md') // TODO: Create markdown - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_SUBTITLE_LIST) - ->param('videoId', null, new UID(), 'Video unique ID.') - ->inject('response') - ->inject('dbForProject') - ->action(function ($videoId, Response $response, Database $dbForProject) { - - $query = [ - Query::equal('videoId', [$videoId]), - ]; - - $subtitles = Authorization::skip(fn () => $dbForProject->find('videos_subtitles', $query)); - - if (empty($subtitles)) { - throw new Exception(Exception::VIDEO_SUBTITLE_NOT_FOUND); - } - - $response->dynamic(new Document([ - 'total' => $dbForProject->count('videos_subtitles', $query, APP_LIMIT_COUNT), - 'subtitles' => $subtitles, - ]), Response::MODEL_SUBTITLE_LIST); - }); - App::post('/v1/videos/:videoId/rendition') ->alias('/v1/videos/:videoId/rendition', []) ->desc('Create video rendition') @@ -430,12 +430,13 @@ App::post('/v1/videos/:videoId/rendition') ->label('sdk.response.model', Response::MODEL_NONE) ->param('videoId', null, new UID(), 'Video unique ID.') ->param('profileId', '', new CustomId(), 'Profile unique ID.') + ->param('output', '', new WhiteList(['hls', 'dash']), 'output name') ->inject('request') ->inject('response') ->inject('dbForProject') ->inject('project') ->inject('mode') - ->action(action: function (string $videoId, string $profileId, Request $request, Response $response, Database $dbForProject, Document $project, string $mode) { + ->action(action: function (string $videoId, string $profileId, string $output, Request $request, Response $response, Database $dbForProject, Document $project, string $mode) { $video = Authorization::skip(fn() => $dbForProject->getDocument('videos', $videoId)); @@ -452,6 +453,7 @@ App::post('/v1/videos/:videoId/rendition') $transcoder = new Transcoding(); $transcoder + ->setOutput($output) ->setProject($project) ->setVideo($video) ->setProfile($profile) @@ -460,54 +462,6 @@ App::post('/v1/videos/:videoId/rendition') $response->noContent(); }); -App::delete('/v1/videos/:videoId/renditions/:renditionId') - ->desc('Delete video rendition') - ->groups(['api', 'videos']) - ->label('scope', 'videos.write') - ->label('event', 'videos.[videoIdId].renditions.[renditionId].delete') - ->label('audits.event', 'rendition.delete') - ->label('audits.resource', 'video/{request.videoId}/rendition/{request.$id}') - ->label('sdk.namespace', 'videos') - ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) - ->label('sdk.method', 'deleteRendition') - ->label('sdk.description', '/docs/references/videos/delete-rendition.md') // TODO: Create markdown - ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) - ->label('sdk.response.model', Response::MODEL_NONE) - ->param('videoId', '', new UID(), 'Video unique ID.') - ->param('renditionId', '', new UID(), 'Video rendition unique ID.') - ->inject('response') - ->inject('dbForProject') - ->inject('mode') - ->inject('deviceVideos') - ->action(function (string $videoId, string $renditionId, Response $response, Database $dbForProject, string $mode, Device $deviceVideos) { - - $video = Authorization::skip(fn() => $dbForProject->getDocument('videos', $videoId)); - - if ($video->isEmpty()) { - throw new Exception(Exception::VIDEO_NOT_FOUND); - } - - validateFilePermissions($dbForProject, $video['bucketId'], $video['fileId'], $mode); - - $rendition = Authorization::skip(fn() => $dbForProject->getDocument('videos_renditions', $renditionId)); - if ($rendition->isEmpty()) { - throw new Exception(Exception::VIDEO_RENDITION_NOT_FOUND); - } - - $deleted = $dbForProject->deleteDocument('videos_renditions', $renditionId); - - if (!$deleted) { - throw new Exception(Exception::GENERAL_SERVER_ERROR); - } - - Authorization::skip(fn() => $dbForProject->deleteDocument('videos_renditions', $rendition->getId())); - if (!empty($rendition['path'])) { - $deviceVideos->deletePath($rendition['path']); - } - - $response->noContent(); - }); - App::get('/v1/videos/:videoId/renditions/:renditionId') ->desc('Get a single video rendition') ->groups(['api', 'videos']) @@ -581,6 +535,54 @@ App::get('/v1/videos/:videoId/renditions') ]), Response::MODEL_RENDITION_LIST); }); +App::delete('/v1/videos/:videoId/renditions/:renditionId') + ->desc('Delete video rendition') + ->groups(['api', 'videos']) + ->label('scope', 'videos.write') + ->label('event', 'videos.[videoIdId].renditions.[renditionId].delete') + ->label('audits.event', 'rendition.delete') + ->label('audits.resource', 'video/{request.videoId}/rendition/{request.$id}') + ->label('sdk.namespace', 'videos') + ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.method', 'deleteRendition') + ->label('sdk.description', '/docs/references/videos/delete-rendition.md') // TODO: Create markdown + ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) + ->label('sdk.response.model', Response::MODEL_NONE) + ->param('videoId', '', new UID(), 'Video unique ID.') + ->param('renditionId', '', new UID(), 'Video rendition unique ID.') + ->inject('response') + ->inject('dbForProject') + ->inject('mode') + ->inject('deviceVideos') + ->action(function (string $videoId, string $renditionId, Response $response, Database $dbForProject, string $mode, Device $deviceVideos) { + + $video = Authorization::skip(fn() => $dbForProject->getDocument('videos', $videoId)); + + if ($video->isEmpty()) { + throw new Exception(Exception::VIDEO_NOT_FOUND); + } + + validateFilePermissions($dbForProject, $video['bucketId'], $video['fileId'], $mode); + + $rendition = Authorization::skip(fn() => $dbForProject->getDocument('videos_renditions', $renditionId)); + if ($rendition->isEmpty()) { + throw new Exception(Exception::VIDEO_RENDITION_NOT_FOUND); + } + + $deleted = $dbForProject->deleteDocument('videos_renditions', $renditionId); + + if (!$deleted) { + throw new Exception(Exception::GENERAL_SERVER_ERROR); + } + + Authorization::skip(fn() => $dbForProject->deleteDocument('videos_renditions', $rendition->getId())); + if (!empty($rendition['path'])) { + $deviceVideos->deletePath($rendition['path']); + } + + $response->noContent(); + }); + App::get('/v1/videos/:videoId/outputs/:output') ->desc('Get video master renditions manifest') ->groups(['api', 'videos']) @@ -593,7 +595,7 @@ App::get('/v1/videos/:videoId/outputs/:output') ->label('sdk.methodType', 'location') ->label('scope', 'videos.read') ->param('videoId', null, new UID(), 'Video unique ID.') - ->param('output', '', new WhiteList(['hls', 'dash']), 'protocol name') + ->param('output', '', new WhiteList(['hls', 'dash']), 'output name') ->inject('response') ->inject('dbForProject') ->inject('mode') @@ -961,19 +963,17 @@ App::post('/v1/videos/profiles') ->param('audioBitRate', '', new Range(32, 5000), 'Audio profile bit rate in Kbps.') ->param('width', '', new Range(6, 3000), 'Video profile width.') ->param('height', '', new Range(6, 3000), 'Video profile height.') - ->param('output', false, new WhiteList(['hls', 'dash']), 'Video profile output.') ->inject('response') ->inject('dbForProject') - ->action(action: function (string $name, string $videoBitRate, string $audioBitRate, string $width, string $height, string $output, Response $response, Database $dbForProject) { + ->action(action: function (string $name, string $videoBitRate, string $audioBitRate, string $width, string $height, Response $response, Database $dbForProject) { - $profile = Authorization::skip(function () use ($dbForProject, $name, $videoBitRate, $audioBitRate, $width, $height, $output) { + $profile = Authorization::skip(function () use ($dbForProject, $name, $videoBitRate, $audioBitRate, $width, $height) { return $dbForProject->createDocument('videos_profiles', new Document([ 'name' => $name, 'videoBitRate' => (int)$videoBitRate, 'audioBitRate' => (int)$audioBitRate, 'width' => (int)$width, 'height' => (int)$height, - 'output' => $output, ])); }); @@ -1000,10 +1000,9 @@ App::patch('/v1/videos/profiles/:profileId') ->param('audioBitrate', '', new Range(64, 4000), 'Audio profile bit rate in Kbps.') ->param('width', '', new Range(100, 2000), 'Video profile width.') ->param('height', '', new Range(100, 2000), 'Video profile height.') - ->param('output', false, new WhiteList(['hls', 'dash']), 'Video profile output.') ->inject('response') ->inject('dbForProject') - ->action(action: function (string $profileId, string $name, string $videoBitRate, string $audioBitRate, string $width, string $height, string $output, Response $response, Database $dbForProject) { + ->action(action: function (string $profileId, string $name, string $videoBitRate, string $audioBitRate, string $width, string $height, Response $response, Database $dbForProject) { $profile = Authorization::skip(fn() => $dbForProject->getDocument('videos_profiles', $profileId)); if ($profile->isEmpty()) { @@ -1014,8 +1013,8 @@ App::patch('/v1/videos/profiles/:profileId') ->setAttribute('videoBitRate', (int)$videoBitRate) ->setAttribute('audioBitRate', (int)$audioBitRate) ->setAttribute('width', (int)$width) - ->setAttribute('height', (int)$height) - ->setAttribute('output', $output); + ->setAttribute('height', (int)$height); + $profile = Authorization::skip(fn() => $dbForProject->updateDocument('videos_profiles', $profile->getId(), $profile)); diff --git a/app/workers/transcoding.php b/app/workers/transcoding.php index e30cf37431..5fcfa2f0a5 100644 --- a/app/workers/transcoding.php +++ b/app/workers/transcoding.php @@ -1,6 +1,7 @@ database = $this->getProjectDB($this->project->getId()); $this->bucket = $this->database->getDocument('buckets', $this->video->getAttribute('bucketId')); $this->file = $this->database->getDocument('bucket_' . $this->bucket->getInternalId(), $this->video->getAttribute('fileId')); @@ -101,6 +102,11 @@ class TranscodingV1 extends Worker console::error('Storage transfer error'); } + $this->renditionName = $this->profile->getAttribute('width') + . 'X' . $this->profile->getAttribute('height') + . '@' . ($this->profile->getAttribute('videoBitRate') + $this->profile->getAttribute('audioBitRate')); + + /** * FFMpeg init */ @@ -156,10 +162,6 @@ class TranscodingV1 extends Worker $media = $this->ffmpeg->open($inPath); - $this->renditionName = $this->profile->getAttribute('width') - . 'X' . $this->profile->getAttribute('height') - . '@' . ($this->profile->getAttribute('videoBitRate') + $this->profile->getAttribute('audioBitRate')); - $subs = []; $subtitles = $this->database->find('videos_subtitles', [ Query::equal('videoId', [$this->video->getId()]), @@ -198,7 +200,7 @@ class TranscodingV1 extends Worker 'name' => $this->renditionName, 'startedAt' => DateTime::now(), 'status' => self::STATUS_START, - 'output' => $this->profile->getAttribute('output'), + 'output' => $this->args['output'], ])); $this->send($query); $renditionRootPath = $this->getVideoDevice($this->project->getId())->getPath($this->video->getId()) . '/'; @@ -228,17 +230,17 @@ class TranscodingV1 extends Worker } }); - $this->transcode($this->profile->getAttribute('output'), $media, $format, $representation, $subs); + $this->transcode($media, $format, $representation, $subs); unset($media); //exec('/usr/bin/ffmpeg -y -i /usr/src/code/tests/tmp/637f59c88f9ff0fe3b1f/637e1b82aeab8980400e/in/637f59ab5bce0e36d05e.mp4 -c:v libx264 -c:a aac -bf 1 -keyint_min 25 -g 250 -sc_threshold 40 -use_timeline 0 -use_template 0 -seg_duration 10 -hls_playlist 0 -f dash -dn -sn -vf scale=iw:-2:force_original_aspect_ratio=increase,setsar=1:1 -b_strategy 1 -bf 3 -force_key_frames "expr:gte(t,n_forced*2)" -map 0 -s:v:0 1024x576 -b:v:0 2538k -b:a:0 128k -strict -2 -threads 12 /usr/src/code/tests/tmp/637f59c88f9ff0fe3b1f/637e1b82aeab8980400e/out/637f59c88f9ff0fe3b1f.mpd2>&1', $o, $v); //var_dump($o); //var_dump($v); - if ($this->profile->getAttribute('output') === self::OUTPUT_HLS) { + if ($this->args['output'] === self::OUTPUT_HLS) { $streams = $this->getHlsSegmentsUrls($this->outDir . 'master.m3u8'); foreach ($streams as $stream) { - $m3u8 = $this->getSegments(self::OUTPUT_HLS, $this->outDir . $stream['path']); + $m3u8 = $this->getSegments($this->outDir . $stream['path']); if (!empty($m3u8['segments'])) { foreach ($m3u8['segments'] as $segment) { $this->database->createDocument('videos_renditions_segments', new Document([ @@ -255,7 +257,7 @@ class TranscodingV1 extends Worker $query->setAttribute('targetDuration', $m3u8['targetDuration']); } } else { - $mpd = $this->getSegments(self::OUTPUT_DASH, $this->outPath . '.mpd'); + $mpd = $this->getSegments($this->outPath . '.mpd'); if (!empty($mpd['segments'])) { foreach ($mpd['segments'] as $segment) { $this->database->createDocument('videos_renditions_segments', new Document([ @@ -350,14 +352,13 @@ class TranscodingV1 extends Worker } /** - * @param string $output * @param $media Media * @param $format StreamFormat * @param $representation Representation * @param array $subtitles * @return void */ - private function transcode(string $output, Media $media, StreamFormat $format, Representation $representation, array $subtitles): void + private function transcode(Media $media, StreamFormat $format, Representation $representation, array $subtitles): void { $additionalParams = [ @@ -371,7 +372,7 @@ class TranscodingV1 extends Worker $segmentSize = 10; - if ($output === self::OUTPUT_DASH) { + if ($this->args['output'] === self::OUTPUT_DASH) { $media->dash() ->setFormat($format) ->setSegDuration($segmentSize) @@ -397,15 +398,14 @@ class TranscodingV1 extends Worker } /** - * @param string $output * @param string $path * @return array */ - private function getSegments(string $output, string $path): array + private function getSegments(string $path): array { $segments = []; - if ($output === self::OUTPUT_DASH) { + if ($this->args['output'] === self::OUTPUT_DASH) { $metadata = null; $handle = fopen($path, "r"); if ($handle) { diff --git a/src/Appwrite/Event/Transcoding.php b/src/Appwrite/Event/Transcoding.php index ef8b9244a9..7f199701ff 100644 --- a/src/Appwrite/Event/Transcoding.php +++ b/src/Appwrite/Event/Transcoding.php @@ -11,11 +11,37 @@ class Transcoding extends Event protected Document $profile; + protected string $output; + public function __construct() { parent::__construct(Event::TRANSCODING_QUEUE_NAME, Event::TRANSCODING_CLASS_NAME); } + /** + * Sets output. + * + * @param string $output + * @return self + */ + public function setOutput(string $output): self + { + $this->output = $output; + + return $this; + } + + /** + * Returns output. + * + * @return string + */ + public function getOutput(): string + { + return $this->output; + } + + /** * Sets video. * @@ -71,6 +97,7 @@ class Transcoding extends Event public function trigger(): string|bool { return Resque::enqueue($this->queue, $this->class, [ + 'output' => $this->output, 'project' => $this->project, 'user' => $this->user, 'video' => $this->video,