Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

3x: Allow homarus to use faststart #170

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Homarus/config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ parameters:
app.formats.defaults:
mimetype: video/mp4
format: mp4
app.tempDirectory: /tmp/

services:
# default configuration for services in *this* file
Expand All @@ -50,4 +51,5 @@ services:
$formats: '%app.formats.valid%'
$defaults: '%app.formats.defaults%'
$executable: '%app.executable%'
$tempDirectory: '%app.tempDirectory%'
tags: ['controller.service_arguments']
67 changes: 51 additions & 16 deletions Homarus/src/Controller/HomarusController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;

/**
* Class HomarusController
*
* @param $log
*
* @package Islandora\Homarus\Controller
*/
class HomarusController
Expand Down Expand Up @@ -48,6 +49,13 @@ class HomarusController
*/
private $executable;

/**
* The temp directory.
*
* @var string
*/
private $tempDirectory;

/**
* Controller constructor.
*
Expand All @@ -59,6 +67,8 @@ class HomarusController
* The default mimetype and format.
* @param string $executable
* The path to the programs executable.
* @param string $tempDirectory
* The temporary directory path.
* @param \Psr\Log\LoggerInterface $log
* The logger.
*/
Expand All @@ -67,18 +77,21 @@ public function __construct(
array $formats,
array $defaults,
string $executable,
string $tempDirectory,
LoggerInterface $log
) {
$this->cmd = $cmd;
$this->formats = $formats;
$this->defaults = $defaults;
$this->executable = $executable;
$this->tempDirectory = $tempDirectory;
$this->log = $log;
}

/**
* @param \Symfony\Component\HttpFoundation\Request $request
* @return \Symfony\Component\HttpFoundation\Response|\Symfony\Component\HttpFoundation\StreamedResponse
*
* @return \Symfony\Component\HttpFoundation\Response|\Symfony\Component\HttpFoundation\BinaryFileResponse
*/
public function convert(Request $request)
{
Expand All @@ -97,15 +110,18 @@ public function convert(Request $request)

// Find the format
$content_types = $request->getAcceptableContentTypes();
list($content_type, $format) = $this->getFfmpegFormat($content_types);
[$content_type, $format] = $this->getFfmpegFormat($content_types);

$cmd_params = "";
if ($format == "mp4") {
$cmd_params = " -vcodec libx264 -preset medium -acodec aac " .
"-strict -2 -ab 128k -ac 2 -async 1 -movflags " .
"frag_keyframe+empty_moov ";
"faststart -y";
}

$temp_file_path = $this->tempDirectory . basename($source) . "." . $format;
$this->log->debug('Tempfile: ' . $temp_file_path);

// Arguments to ffmpeg command are sent as a custom header.
$args = $request->headers->get('X-Islandora-Args');

Expand All @@ -125,24 +141,16 @@ public function convert(Request $request)
$this->log->debug("X-Islandora-Args:", ['args' => $args]);
$token = $request->headers->get('Authorization');
$headers = "'Authorization: $token'";
$cmd_string = "$this->executable -headers $headers -i $source $args $cmd_params -f $format -";
$cmd_string = "$this->executable -headers $headers -i $source $args $cmd_params -f $format $temp_file_path";
$this->log->debug('Ffmpeg Command:', ['cmd' => $cmd_string]);

// Return response.
try {
return new StreamedResponse(
$this->cmd->execute($cmd_string, $source),
200,
['Content-Type' => $content_type]
);
} catch (\RuntimeException $e) {
$this->log->error("RuntimeException:", ['exception' => $e]);
return new Response($e->getMessage(), 500);
}
return $this->generateDerivativeResponse($cmd_string, $source, $temp_file_path, $content_type);
}

/**
* Filters through an array of acceptable content-types and returns a FFmpeg format.
* Filters through an array of acceptable content-types and returns a
* FFmpeg format.
*
* @param array $content_types
* The Accept content-types.
Expand All @@ -167,6 +175,33 @@ private function getFfmpegFormat(array $content_types): array
return [$this->defaults["mimetype"], $this->defaults["format"]];
}

/**
* @param string $cmd_string
* @param string $source
* @param string $path
* @param string $content_type
*
* @return \Symfony\Component\HttpFoundation\Response|\Symfony\Component\HttpFoundation\BinaryFileResponse
*/
public function generateDerivativeResponse(
string $cmd_string,
string $source,
string $path,
string $content_type
) {
try {
$this->cmd->execute($cmd_string, $source);
return (new BinaryFileResponse(
$path,
200,
['Content-Type' => $content_type]
))->deleteFileAfterSend(true);
} catch (\RuntimeException $e) {
$this->log->error("RuntimeException:", ['exception' => $e]);
return new Response($e->getMessage(), 500);
}
}

/**
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse
*/
Expand Down
23 changes: 20 additions & 3 deletions Homarus/tests/HomarusControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Prophecy\PhpUnit\ProphecyTrait;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\Request;

/**
Expand Down Expand Up @@ -39,6 +40,8 @@ public function setUp(): void
[ 'mimetype' => 'video/x-msvideo', 'format' => 'avi'],
[ 'mimetype' => 'video/ogg', 'format' => 'ogg'],
];

$this->tempDirectory = '/../public/static/';
}

/**
Expand Down Expand Up @@ -72,6 +75,7 @@ public function testErrorReturns500()
$this->formats,
$this->defaults,
'convert',
$this->tempDirectory,
$this->prophesize(Logger::class)->reveal()
);

Expand Down Expand Up @@ -210,13 +214,26 @@ private function getDefaultController()
$mock_service = $prophecy->reveal();

// Create a controller.
$controller = new HomarusController(
$controller = $this->getMockBuilder(HomarusController::class)
->onlyMethods(['generateDerivativeResponse'])
->setConstructorArgs([
$mock_service,
$this->formats,
$this->defaults,
'convert',
$this->prophesize(Logger::class)->reveal()
);
$this->tempDirectory,
$this->prophesize(Logger::class)->reveal(),
])
->getMock();

$controller->method('generateDerivativeResponse')
->will($this->returnCallback(function ($cmd_string, $source, $path, $content_type) {
return new BinaryFileResponse(
__DIR__ . "/fixtures/foo.mp4",
200,
['Content-Type' => $content_type]
);
}));
return $controller;
}

Expand Down
Empty file added Homarus/tests/fixtures/foo.mp4
Empty file.