This commit is contained in:
shimon
2022-07-26 13:31:34 +03:00
parent 6896ff3999
commit e232f2bbd2
14 changed files with 82 additions and 56 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -8,7 +8,7 @@ return [
'audioBitrate' => 64, //audio bitrate in Kbps
'width' => 640, //width resolution in px
'height' => 360, //height resolution in px
'stream' => 'mpeg-dash'
'stream' => 'dash'
],
[
'name' => '576p',
@@ -16,7 +16,7 @@ return [
'audioBitrate' => 128,
'width' => 1024,
'height' => 576,
'stream' => 'mpeg-dash'
'stream' => 'dash'
],
[
'name' => '720p',
+38 -33
View File
@@ -90,7 +90,7 @@ App::post('/v1/videos/profiles')
->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('stream', false, new WhiteList(['hls', 'mpeg-dash']), 'Video profile stream protocol.')
->param('stream', false, new WhiteList(['hls', 'dash']), 'Video profile stream protocol.')
->inject('response')
->inject('dbForProject')
->action(action: function (string $name, string $videoBitrate, string $audioBitrate, string $width, string $height, string $stream, Response $response, Database $dbForProject) {
@@ -131,7 +131,7 @@ 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('stream', false, new WhiteList(['hls', 'mpeg-dash']), 'Video profile stream protocol.')
->param('stream', false, new WhiteList(['hls', 'dash']), 'Video profile stream protocol.')
->inject('response')
->inject('dbForProject')
->action(action: function (string $profileId, string $name, string $videoBitrate, string $audioBitrate, string $width, string $height, string $stream, Response $response, Database $dbForProject) {
@@ -708,7 +708,7 @@ App::get('/v1/videos/:videoId/streams/:streamId')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('scope', 'files.read')
->param('videoId', null, new UID(), 'Video unique ID.')
->param('streamId', '', new WhiteList(['hls', 'mpeg-dash']), 'stream protocol name')
->param('streamId', '', new WhiteList(['hls', 'dash']), 'stream protocol name')
->inject('response')
->inject('dbForProject')
->inject('mode')
@@ -767,16 +767,16 @@ App::get('/v1/videos/:videoId/streams/:streamId')
$response->setContentType('application/x-mpegurl')->send($template->render(false));
} else {
$adaptations = [];
foreach ($renditions as $rendition) {
foreach ($renditions as $rendition) {
$metadata = $rendition->getAttribute('metadata');
if (!empty($metadata['Period']['AdaptationSet'])) {
foreach ($metadata['Period']['AdaptationSet'] as $set) {
foreach ($metadata['Period']['AdaptationSet'] as $adaptationId => $set) {
$adaption = $set['@attributes'];
$adaption['id'] = $adaptationId;
//$adaption['baseUrl'] = $baseUrl . '/renditions/' . $rendition->getId() . '/' . 'segments/';
$adaption['representation'] = $set['Representation']['@attributes'];
$adaption['representation']['baseUrl'] = $baseUrl . '/renditions/' . $rendition->getId();
$adaption['representation']['SegmentList'] = $set['Representation']['SegmentList']['@attributes'];
$representationId = 0;
$segments = Authorization::skip(fn() => $dbForProject->find('videos_renditions_segments', [
new Query('renditionId', Query::TYPE_EQUAL, [$rendition->getId()]),
@@ -784,11 +784,11 @@ App::get('/v1/videos/:videoId/streams/:streamId')
], 1000, 0, ['representationId'], ['ASC']));
foreach ($segments as $segment) {
if ($segment->getAttribute('isInit') === 1) {
$adaption['representation']['SegmentList']['Initialization'] = $baseUrl . '/renditions/' . $segment->getId() . '/';
if ($segment->getAttribute('isInit')) {
$adaption['representation']['SegmentList']['Initialization'] = $baseUrl . '/renditions/' . $rendition->getId() . '/' . 'segments/' . $segment->getId();
continue;
}
$adaption['representation']['SegmentList']['media'][] = $segment->getId();
$adaption['representation']['SegmentList']['media'][] = $baseUrl . '/renditions/' . $rendition->getId() . '/' . 'segments/' . $segment->getId();
}
$adaptations[] = $adaption;
$representationId++;
@@ -815,7 +815,7 @@ App::get('/v1/videos/:videoId/streams/:streamId/renditions/:renditionId')
// TODO: Response model
->label('scope', 'files.read')
->param('videoId', null, new UID(), 'Video unique ID.')
->param('streamId', '', new WhiteList(['hls', 'mpeg-dash']), 'stream protocol name')
->param('streamId', '', new WhiteList(['hls', 'dash']), 'stream protocol name')
->param('renditionId', '', new UID(), 'Rendition unique ID.')
->inject('response')
->inject('dbForProject')
@@ -845,26 +845,26 @@ App::get('/v1/videos/:videoId/streams/:streamId/renditions/:renditionId')
throw new Exception('Rendition not found', 404, Exception::VIDEO_RENDITION_NOT_FOUND);
}
$segments = Authorization::skip(fn () => $dbForProject->find('videos_renditions_segments', [
new Query('renditionId', Query::TYPE_EQUAL, [$renditionId]),
], 4000, 0, [], ['ASC']));
$segments = Authorization::skip(fn() => $dbForProject->find('videos_renditions_segments', [
new Query('renditionId', Query::TYPE_EQUAL, [$renditionId]),
], 4000));
if (empty($segments)) {
throw new Exception('Rendition segments not found', 404, Exception::VIDEO_RENDITION_SEGMENT_NOT_FOUND);
}
$paramsSegments = [];
$paramsSegments = [];
foreach ($segments as $segment) {
$paramsSegments[] = [
'duration' => $segment->getAttribute('duration'),
'url' => 'http://127.0.0.1/v1/videos/' . $videoId . '/streams/' . $streamId . '/renditions/' . $renditionId . '/segments/' . $segment->getId() ,
];
'duration' => $segment->getAttribute('duration'),
'url' => 'http://127.0.0.1/v1/videos/' . $videoId . '/streams/' . $streamId . '/renditions/' . $renditionId . '/segments/' . $segment->getId(),
];
}
$template = new View(__DIR__ . '/../../views/videos/hls.phtml');
$template->setParam('targetDuration', $rendition->getAttribute('targetDuration'));
$template->setParam('paramsSegments', $paramsSegments);
$response->setContentType('application/x-mpegurl')->send($template->render(false));
$template = new View(__DIR__ . '/../../views/videos/hls.phtml');
$template->setParam('targetDuration', $rendition->getAttribute('targetDuration'));
$template->setParam('paramsSegments', $paramsSegments);
$response->setContentType('application/x-mpegurl')->send($template->render(false));
});
@@ -880,15 +880,15 @@ App::get('/v1/videos/:videoId/streams/:streamId/renditions/:renditionId/segments
// TODO: Response model
->label('scope', 'files.read')
->param('videoId', null, new UID(), 'Video unique ID.')
->param('streamId', '', new WhiteList(['hls', 'mpeg-dash']), 'stream protocol name')
->param('streamId', '', new WhiteList(['hls', 'dash']), 'stream protocol name')
->param('renditionId', '', new UID(), 'Rendition unique ID.')
->param('segmentId', '', new UID(), 'Segment unique ID.')
->inject('response')
->inject('dbForProject')
->inject('videosDevice')
->inject('deviceVideos')
->inject('mode')
->inject('user')
->action(function (string $videoId, string $streamId, string $renditionId, string $segmentId, Response $response, Database $dbForProject, Device $videosDevice, string $mode, Document $user) {
->action(function (string $videoId, string $streamId, string $renditionId, string $segmentId, Response $response, Database $dbForProject, Device $deviceVideos, string $mode, Document $user) {
$video = Authorization::skip(fn() => $dbForProject->findOne('videos', [
new Query('_uid', Query::TYPE_EQUAL, [$videoId])
@@ -919,8 +919,13 @@ App::get('/v1/videos/:videoId/streams/:streamId/renditions/:renditionId/segments
throw new Exception('Rendition segments not found', 404, Exception::VIDEO_RENDITION_SEGMENT_NOT_FOUND);
}
$output = $videosDevice->read($segment->getAttribute('path') . $segment->getAttribute('fileName'));
$response->setContentType('video/MP2T')->send($output);
$output = $deviceVideos->read($segment->getAttribute('path') . $segment->getAttribute('fileName'));
if ($streamId === 'hls') {
$response->setContentType('video/MP2T')->send($output);
} else {
$response->setContentType('video/iso.segment')->send($output);
}
});
@@ -936,7 +941,7 @@ App::get('/v1/videos/:videoId/streams/:streamId/subtitles/:subtitleId')
// TODO: Response model
->label('scope', 'files.read')
->param('videoId', null, new UID(), 'Video unique ID.')
->param('streamId', '', new WhiteList(['hls', 'mpeg-dash']), 'stream protocol name')
->param('streamId', '', new WhiteList(['hls', 'dash']), 'stream protocol name')
->param('subtitleId', '', new UID(), 'Subtitle unique ID.')
->inject('response')
->inject('dbForProject')
@@ -998,15 +1003,15 @@ App::get('/v1/videos/:videoId/streams/:streamId/subtitles/:subtitleId/segments/:
// TODO: Response model
->label('scope', 'files.read')
->param('videoId', null, new UID(), 'Video unique ID.')
->param('streamId', '', new WhiteList(['hls', 'mpeg-dash']), 'stream protocol name')
->param('streamId', '', new WhiteList(['hls', 'dash']), 'stream protocol name')
->param('subtitleId', '', new UID(), 'Subtitle unique ID.')
->param('segmentId', '', new UID(), 'Segment unique ID.')
->inject('response')
->inject('dbForProject')
->inject('videosDevice')
->inject('deviceVideos')
->inject('mode')
->inject('user')
->action(function (string $videoId, string $streamId, string $subtitleId, string $segmentId, Response $response, Database $dbForProject, Device $videosDevice, string $mode, Document $user) {
->action(function (string $videoId, string $streamId, string $subtitleId, string $segmentId, Response $response, Database $dbForProject, Device $deviceVideos, string $mode, Document $user) {
$video = Authorization::skip(fn() => $dbForProject->findOne('videos', [
new Query('_uid', Query::TYPE_EQUAL, [$videoId])
@@ -1034,6 +1039,6 @@ App::get('/v1/videos/:videoId/streams/:streamId/subtitles/:subtitleId/segments/:
throw new Exception('Subtitle segments not found', 404, Exception::VIDEO_SUBTITLE_SEGMENT_NOT_FOUND);
}
$output = $videosDevice->read($segment->getAttribute('path') . $segment->getAttribute('fileName'));
$output = $deviceVideos->read($segment->getAttribute('path') . $segment->getAttribute('fileName'));
$response->setContentType('text/vtt')->send($output);
});
+4
View File
@@ -916,6 +916,10 @@ App::setResource('deviceFiles', function ($project) {
return getDevice(APP_STORAGE_UPLOADS . '/app-' . $project->getId());
}, ['project']);
App::setResource('deviceVideos', function ($project) {
return getDevice(APP_STORAGE_VIDEOS . '/app-' . $project->getId());
}, ['project']);
App::setResource('deviceFunctions', function ($project) {
return getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId());
}, ['project']);
+10 -6
View File
@@ -6,16 +6,20 @@
<ServiceDescription id="0"></ServiceDescription>
<Period id="0" start="PT0.0S">
<?php foreach ($this->getParam('params', []) as $param): ?>
<AdaptationSet
<?php if (isset($param['id'])):?> id="<?php echo $param['id']; ?>"<?php endif;?><?php if (isset($param['contentType'])): ?> contentType="<?php echo $param['contentType']; ?>"<?php endif;?><?php if (isset($param['startWithSAP'])): ?> startWithSAP="<?php echo $param['startWithSAP']; ?>"<?php endif;?><?php if (isset($param['segmentAlignment'])): ?> segmentAlignment="<?php echo $param['segmentAlignment']; ?>"<?php endif;?><?php if (isset($param['bitstreamSwitching'])): ?> bitstreamSwitching="<?php echo $param['bitstreamSwitching']; ?>"<?php endif;?><?php if (isset($param['frameRate'])): ?> frameRate="<?php echo $param['frameRate']; ?>"<?php endif;?><?php if (isset($param['maxWidth'])): ?> maxWidth="<?php echo $param['maxWidth']; ?>"<?php endif;?><?php if (isset($param['par'])): ?> par="<?php echo $param['par']; ?>"<?php endif;?><?php if (isset($param['lang'])): ?> lang="<?php echo $param['lang']; ?>"<?php endif;?>>
<Representation<?php if (isset($param['representation']['id'])):?> id="<?php echo $param['representation']['id']; ?>"<?php endif;?><?php if (isset($param['representation']['mimeType'])):?> mimeType="<?php echo $param['representation']['mimeType']; ?>"<?php endif;?><?php if (isset($param['representation']['codecs'])):?> codecs="<?php echo $param['representation']['codecs']; ?>"<?php endif;?><?php if (isset($param['representation']['width'])):?> width="<?php echo $param['representation']['width']; ?>"<?php endif;?><?php if (isset($param['representation']['height'])):?> height="<?php echo $param['representation']['height']; ?>"<?php endif;?><?php if (isset($param['representation']['sar'])):?> sar="<?php echo $param['representation']['sar']; ?>"<?php endif;?><?php if (isset($param['representation']['audioSamplingRate'])):?> audioSamplingRate="<?php echo $param['representation']['audioSamplingRate']; ?>"<?php endif;?>>
<BaseURL><?php if (isset($param['baseUrl'])): echo $param['baseUrl']; endif;?></BaseURL>
<AdaptationSet <?php if (isset($param['id'])):?> id="<?php echo $param['id']; ?>"<?php endif;?><?php if (isset($param['contentType'])): ?> contentType="<?php echo $param['contentType']; ?>"<?php endif;?><?php if (isset($param['startWithSAP'])): ?> startWithSAP="<?php echo $param['startWithSAP']; ?>"<?php endif;?><?php if (isset($param['segmentAlignment'])): ?> segmentAlignment="<?php echo $param['segmentAlignment']; ?>"<?php endif;?><?php if (isset($param['bitstreamSwitching'])): ?> bitstreamSwitching="<?php echo $param['bitstreamSwitching']; ?>"<?php endif;?><?php if (isset($param['frameRate'])): ?> frameRate="<?php echo $param['frameRate']; ?>"<?php endif;?><?php if (isset($param['maxWidth'])): ?> maxWidth="<?php echo $param['maxWidth']; ?>"<?php endif;?><?php if (isset($param['par'])): ?> par="<?php echo $param['par']; ?>"<?php endif;?><?php if (isset($param['lang'])): ?> lang="<?php echo $param['lang']; ?>"<?php endif;?>>
<Representation <?php if (isset($param['representation']['id'])):?> id="<?php echo $param['representation']['id']; ?>"<?php endif;?><?php if (isset($param['representation']['mimeType'])):?> mimeType="<?php echo $param['representation']['mimeType']; ?>"<?php endif;?><?php if (isset($param['representation']['codecs'])):?> codecs="<?php echo $param['representation']['codecs']; ?>"<?php endif;?><?php if (isset($param['representation']['width'])):?> width="<?php echo $param['representation']['width']; ?>"<?php endif;?><?php if (isset($param['representation']['height'])):?> height="<?php echo $param['representation']['height']; ?>"<?php endif;?><?php if (isset($param['representation']['sar'])):?> sar="<?php echo $param['representation']['sar']; ?>"<?php endif;?><?php if (isset($param['representation']['audioSamplingRate'])):?> audioSamplingRate="<?php echo $param['representation']['audioSamplingRate']; ?>"<?php endif;?>>
<?php if ($param['contentType'] === 'audio'):?>
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2" />
<?php endif;?>
<Initialization sourceURL="<?php if (isset($param['representation']['SegmentList']['Initialization'])):?><?php echo $param['representation']['SegmentList']['Initialization']; ?><?php endif;?>"/>
<?php foreach ($param['representation']['SegmentList']['media'] as $segment): ?>
<SegmentURL media="<?php if (isset($segment)):?><?php echo $segment; ?><?php endif;?>"/>
<?php endforeach; ?>
<?php if (isset($param['representation']['SegmentList']['media'])):?>
<?php foreach ($param['representation']['SegmentList']['media'] as $segment): ?>
<SegmentURL media="<?php if (isset($segment)):?><?php echo $segment; ?><?php endif;?>"/>
<?php endforeach; ?>
<?php endif;?>
</Representation>
</AdaptationSet>
<?php endforeach; ?>
+3 -4
View File
@@ -36,7 +36,7 @@ class TranscodingV1 extends Worker
const STATUS_ERROR = 'error';
const STREAM_HLS = 'hls';
const STREAM_MPEG_DASH = 'mpeg-dash';
const STREAM_MPEG_DASH = 'dash';
const BASE_URL_ENDPOINT = 'http://127.0.0.1/v1/videos';
@@ -246,7 +246,7 @@ class TranscodingV1 extends Worker
Authorization::skip(function () use ($segment, $project, $query) {
return $this->database->createDocument('videos_renditions_segments', new Document([
'renditionId' => $query->getId(),
'type' => 0,
'representationId' => 0,
'fileName' => $segment['fileName'],
'path' => $this->getVideoDevice($project->getId())->getPath($this->args['videoId']) . '/' . $this->getRenditionName() . '/',
'duration' => $segment['duration'],
@@ -374,7 +374,7 @@ class TranscodingV1 extends Worker
$segmentSize = 10;
if ($stream === 'mpeg-dash') {
if ($stream === 'dash') {
$dash = $video->dash()
->setFormat($format)
->setSegDuration($segmentSize)
@@ -430,7 +430,6 @@ class TranscodingV1 extends Worker
];
}
}
var_dump($segments);
fclose($handle);
}
+1 -1
View File
@@ -80,7 +80,7 @@
}
],
"require-dev": {
"appwrite/sdk-generator": "0.18.8",
"appwrite/sdk-generator": "0.19.6",
"phpunit/phpunit": "9.5.20",
"swoole/ide-helper": "4.8.9",
"textalk/websocket": "1.5.7"
@@ -51,7 +51,7 @@ class VideoProfile extends Model
'type' => self::TYPE_STRING,
'description' => 'http video stream type.',
'default' => null,
'example' => 'mpeg-dash',
'example' => 'dash',
])
;
}
@@ -331,7 +331,7 @@ class VideoCustomServerTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals($renditionId, $response['body']['$id']);
var_dump($response);
//var_dump($response['body']);
return [
'renditionId' => $renditionId,
@@ -384,7 +384,7 @@ class VideoCustomServerTest extends Scope
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
var_dump($response['body']);
//var_dump($response['body']);
preg_match_all('#\b/videos[^,\s()<>]+(?:\([\w\d]+\)|([^,[:punct:]\s]|/))#', $response['body'], $match);
@@ -415,6 +415,20 @@ class VideoCustomServerTest extends Scope
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
var_dump($response);
var_dump($response['body']);
}
public function testBla(){
$response = $this->client->call(Client::METHOD_GET, '/videos/62dfaeb69c97ea81c58c/streams/dash/renditions/62dfaeb83bc30e827719/segments/62dfaed714324026902c', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
var_dump($response['body']);
}
}