Skip to content

Commit

Permalink
Prep 0.7.5
Browse files Browse the repository at this point in the history
  • Loading branch information
belgattitude committed Aug 16, 2018
1 parent 12954f8 commit f404663
Show file tree
Hide file tree
Showing 12 changed files with 147 additions and 38 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## 0.7.5 (2018-08-16)

### Added

- `UnescapedFileInterface` to allow setting outputfile without escaping.
- `PlatformNullFile()` can be set as `$outputFile` in `VideoConvert`.

## 0.7.4 (2018-08-16)

### Added
Expand All @@ -15,7 +22,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

- Added multipass params, example fixed using `VideoConvertParams::withPass()`.


## 0.7.3 (2018-08-15)

### Added
Expand Down
6 changes: 4 additions & 2 deletions docs/video-conversion-service.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ as well as the conversion params.
<?php
$conversionService->convert(
'/path/inputFile.mov',
// Output file will be automatically 'shell' escaped,
'/path/outputFile.mp4',
(new VideoConvertParams())->withVideoCodec('libx264')
);
Expand Down Expand Up @@ -497,8 +498,9 @@ $pass1Params = (new VideoConvertParams())
// PASS 1 Conversion
$this->videoConvert->convert(
'/tmp/input.mov',
// Note the null file here !
(new PlatformNullFile())->getNullFile(),
// In first pass we don't need to output the conversion result
// let's put in /dev/null.
new PlatformNullFile(),
$pass1Params
);

Expand Down
1 change: 1 addition & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ parameters:
# errors when trying to produce them, understand who understand
- tests/unit/Video/Filter/VideoFilterChainTest.php
- tests/unit/Video/Adapter/FFMpegAdapterTest.php
- tests/unit/Video/VideoConverterTest.php
reportUnmatchedIgnoredErrors: true
ignoreErrors:
# With PHPStan 0.10 .... don't like this one so much
Expand Down
13 changes: 10 additions & 3 deletions src/Common/IO/PlatformNullFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use Soluble\MediaTools\Common\Exception\InvalidArgumentException;

class PlatformNullFile
class PlatformNullFile implements UnescapedFileInterface
{
public const PLATFORM_LINUX = 'LINUX';
public const PLATFORM_WIN = 'WINDOWS';
Expand Down Expand Up @@ -48,9 +48,11 @@ public static function getCurrentPlatform(): string
/**
* Return /dev/null on linux/unix/mac or NUL on windows.
*/
public function getNullFile(): string
public function getNullFile(?string $platform = null): string
{
switch ($this->platform) {
$platform = $platform ?? $this->platform;

switch ($platform) {
case self::PLATFORM_WIN:
return 'NUL';
// All others for now
Expand All @@ -59,4 +61,9 @@ public function getNullFile(): string
return '/dev/null';
}
}

public function getFile(): string
{
return $this->getNullFile();
}
}
10 changes: 10 additions & 0 deletions src/Common/IO/UnescapedFileInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Soluble\MediaTools\Common\IO;

interface UnescapedFileInterface
{
public function getFile(): string;
}
8 changes: 4 additions & 4 deletions src/Video/Adapter/ConverterAdapterInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use Soluble\MediaTools\Common\Exception\UnsupportedParamException;
use Soluble\MediaTools\Common\Exception\UnsupportedParamValueException;
use Soluble\MediaTools\Common\IO\PlatformNullFile;
use Soluble\MediaTools\Common\IO\UnescapedFileInterface;
use Soluble\MediaTools\Video\VideoConvertParamsInterface;

interface ConverterAdapterInterface
Expand All @@ -20,9 +20,9 @@ interface ConverterAdapterInterface
public function getMappedConversionParams(VideoConvertParamsInterface $conversionParams): array;

/**
* @param array $arguments
* @param null|string $inputFile
* @param null|string|PlatformNullFile $outputFile
* @param array $arguments
* @param null|string $inputFile
* @param null|string|UnescapedFileInterface $outputFile
*
* @return string
*/
Expand Down
12 changes: 6 additions & 6 deletions src/Video/Adapter/FFMpegAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use Soluble\MediaTools\Common\Exception\InvalidArgumentException;
use Soluble\MediaTools\Common\Exception\UnsupportedParamException;
use Soluble\MediaTools\Common\Exception\UnsupportedParamValueException;
use Soluble\MediaTools\Common\IO\PlatformNullFile;
use Soluble\MediaTools\Common\IO\UnescapedFileInterface;
use Soluble\MediaTools\Video\Config\FFMpegConfigInterface;
use Soluble\MediaTools\Video\VideoConvertParamsInterface;

Expand Down Expand Up @@ -163,9 +163,9 @@ public function getMappedConversionParams(VideoConvertParamsInterface $conversio
}

/**
* @param array<int|string, string> $arguments
* @param string|null $inputFile if <null> will not prepend '-i inputFile' in args
* @param null|string|PlatformNullFile $outputFile
* @param array<int|string, string> $arguments
* @param string|null $inputFile if <null> will not prepend '-i inputFile' in args
* @param null|string|UnescapedFileInterface $outputFile
*
* @throws InvalidArgumentException
*/
Expand All @@ -176,8 +176,8 @@ public function getCliCommand(array $arguments, ?string $inputFile, $outputFile
: '';

$outputArg = '';
if ($outputFile instanceof PlatformNullFile) {
$outputArg = $outputFile->getNullFile();
if ($outputFile instanceof UnescapedFileInterface) {
$outputArg = $outputFile->getFile();
} elseif (is_string($outputFile)) {
$outputArg = sprintf('%s', escapeshellarg($outputFile));
} elseif ($outputFile !== null) {
Expand Down
36 changes: 22 additions & 14 deletions src/Video/VideoConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@
use Psr\Log\LogLevel;
use Psr\Log\NullLogger;
use Soluble\MediaTools\Common\Assert\PathAssertionsTrait;
use Soluble\MediaTools\Common\Exception\FileNotFoundException;
use Soluble\MediaTools\Common\Exception\FileNotReadableException;
use Soluble\MediaTools\Common\Exception\UnsupportedParamException;
use Soluble\MediaTools\Common\Exception\UnsupportedParamValueException;
use Soluble\MediaTools\Common\Exception as CommonException;
use Soluble\MediaTools\Common\IO\UnescapedFileInterface;
use Soluble\MediaTools\Common\Process\ProcessFactory;
use Soluble\MediaTools\Common\Process\ProcessParamsInterface;
use Soluble\MediaTools\Video\Config\FFMpegConfigInterface;
use Soluble\MediaTools\Video\Exception\ConverterExceptionInterface;
use Soluble\MediaTools\Video\Exception\ConverterProcessExceptionInterface;
use Soluble\MediaTools\Video\Exception\InvalidArgumentException;
use Soluble\MediaTools\Video\Exception\InvalidParamReaderException;
use Soluble\MediaTools\Video\Exception\MissingInputFileReaderException;
use Soluble\MediaTools\Video\Exception\ProcessFailedException;
Expand Down Expand Up @@ -48,12 +47,15 @@ public function __construct(FFMpegConfigInterface $ffmpegConfig, ?LoggerInterfac
* to `run()` or `start()` programmatically. Useful if you want to make
* things async...
*
* @param null|string|UnescapedFileInterface $outputFile
*
* @see https://symfony.com/doc/current/components/process.html
*
* @throws UnsupportedParamException
* @throws UnsupportedParamValueException
* @throws CommonException\UnsupportedParamException
* @throws CommonException\UnsupportedParamValueException
* @throws InvalidArgumentException
*/
public function getSymfonyProcess(string $inputFile, string $outputFile, VideoConvertParamsInterface $convertParams, ?ProcessParamsInterface $processParams = null): Process
public function getSymfonyProcess(string $inputFile, $outputFile, VideoConvertParamsInterface $convertParams, ?ProcessParamsInterface $processParams = null): Process
{
$adapter = $this->ffmpegConfig->getAdapter();

Expand All @@ -66,7 +68,12 @@ public function getSymfonyProcess(string $inputFile, string $outputFile, VideoCo
}

$arguments = $adapter->getMappedConversionParams($convertParams);
$ffmpegCmd = $adapter->getCliCommand($arguments, $inputFile, $outputFile);

try {
$ffmpegCmd = $adapter->getCliCommand($arguments, $inputFile, $outputFile);
} catch (CommonException\InvalidArgumentException $e) {
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}

$pp = $processParams ?? $this->ffmpegConfig->getProcessParams();

Expand All @@ -76,8 +83,9 @@ public function getSymfonyProcess(string $inputFile, string $outputFile, VideoCo
/**
* Run a conversion, throw exception on error.
*
* @param callable|null $callback A PHP callback to run whenever there is some
* tmp available on STDOUT or STDERR
* @param null|string|UnescapedFileInterface $outputFile
* @param callable|null $callback A PHP callback to run whenever there is some
* tmp available on STDOUT or STDERR
*
* @throws ConverterExceptionInterface Base exception class for conversion exceptions
* @throws ConverterProcessExceptionInterface Base exception class for process conversion exceptions
Expand All @@ -88,16 +96,16 @@ public function getSymfonyProcess(string $inputFile, string $outputFile, VideoCo
* @throws InvalidParamReaderException
* @throws RuntimeReaderException
*/
public function convert(string $inputFile, string $outputFile, VideoConvertParamsInterface $convertParams, ?callable $callback = null, ?ProcessParamsInterface $processParams = null): void
public function convert(string $inputFile, $outputFile, VideoConvertParamsInterface $convertParams, ?callable $callback = null, ?ProcessParamsInterface $processParams = null): void
{
try {
try {
$this->ensureFileReadable($inputFile);
$process = $this->getSymfonyProcess($inputFile, $outputFile, $convertParams, $processParams);
$process->mustRun($callback);
} catch (FileNotFoundException | FileNotReadableException $e) {
} catch (CommonException\FileNotFoundException | CommonException\FileNotReadableException $e) {
throw new MissingInputFileReaderException($e->getMessage());
} catch (UnsupportedParamValueException | UnsupportedParamException $e) {
} catch (CommonException\UnsupportedParamValueException | CommonException\UnsupportedParamException $e) {
throw new InvalidParamReaderException($e->getMessage());
} catch (SPException\ProcessTimedOutException $e) {
throw new ProcessTimedOutException($e->getProcess(), $e);
Expand All @@ -118,7 +126,7 @@ public function convert(string $inputFile, string $outputFile, VideoConvertParam
__METHOD__,
$e->getMessage(),
$inputFile,
$outputFile
$outputFile instanceof UnescapedFileInterface ? $outputFile->getFile() : $outputFile
)
);
throw $e;
Expand Down
15 changes: 11 additions & 4 deletions src/Video/VideoConverterInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

namespace Soluble\MediaTools\Video;

use Soluble\MediaTools\Common\IO\UnescapedFileInterface;
use Soluble\MediaTools\Common\Process\ProcessParamsInterface;
use Soluble\MediaTools\Video\Exception\ConverterExceptionInterface;
use Soluble\MediaTools\Video\Exception\InvalidArgumentException;
use Symfony\Component\Process\Process;

interface VideoConverterInterface
Expand All @@ -15,17 +17,22 @@ interface VideoConverterInterface
* to `run()` or `start()` programmatically. Useful if you want to make
* things your way...
*
* @param null|string|UnescapedFileInterface $outputFile
*
* @throws InvalidArgumentException
*
* @see https://symfony.com/doc/current/components/process.html
*/
public function getSymfonyProcess(string $inputFile, string $outputFile, VideoConvertParamsInterface $convertParams, ?ProcessParamsInterface $processParams = null): Process;
public function getSymfonyProcess(string $inputFile, $outputFile, VideoConvertParamsInterface $convertParams, ?ProcessParamsInterface $processParams = null): Process;

/**
* Run a conversion, throw exception on error.
*
* @param callable|null $callback A PHP callback to run whenever there is some
* tmp available on STDOUT or STDERR
* @param null|string|UnescapedFileInterface $outputFile
* @param callable|null $callback A PHP callback to run whenever there is some
* tmp available on STDOUT or STDERR
*
* @throws ConverterExceptionInterface When inputFile does not exists
*/
public function convert(string $inputFile, string $outputFile, VideoConvertParamsInterface $convertParams, ?callable $callback = null, ?ProcessParamsInterface $processParams = null): void;
public function convert(string $inputFile, $outputFile, VideoConvertParamsInterface $convertParams, ?callable $callback = null, ?ProcessParamsInterface $processParams = null): void;
}
34 changes: 32 additions & 2 deletions tests/functional/UseCases/VideoConverterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Soluble\MediaTools\Video\Config\FFMpegConfigInterface;
use Soluble\MediaTools\Video\Exception\ConverterExceptionInterface;
use Soluble\MediaTools\Video\Exception\MissingInputFileReaderException;
use Soluble\MediaTools\Video\Exception\ProcessFailedException;
use Soluble\MediaTools\Video\Exception\ProcessTimedOutException;
use Soluble\MediaTools\Video\Filter\YadifVideoFilter;
use Soluble\MediaTools\Video\Process\ProcessParams;
Expand Down Expand Up @@ -156,8 +157,8 @@ public function testConvertVP9MultiPass(): void

$this->videoConvert->convert(
$this->videoFile,
(new PlatformNullFile())->getNullFile(),
$pass1Params
new PlatformNullFile(),
$pass1Params
);

self::assertFileExists($logFile);
Expand All @@ -180,6 +181,35 @@ public function testConvertVP9MultiPass(): void
//unlink($outputFile);
}

public function testConvertWithWrongPassWillError(): void
{
self::expectException(ProcessFailedException::class);
self::expectExceptionMessageRegExp('/Error reading log file(.*)for pass-2 encoding/');

$outputFile = "{$this->outputDir}/testConvertVP9Multipass.webm";

if (file_exists($outputFile)) {
unlink($outputFile);
}

$logFile = tempnam($this->outputDir, 'ffmpeg-passlog');
if ($logFile === false) {
self::markTestIncomplete('Cannot get a temp file');
}

$params = (new VideoConvertParams())
->withPassLogFile($logFile)
->withPass(2)
->withVideoCodec('libvpx-vp9')
->withOutputFormat('webm');

$this->videoConvert->convert(
$this->videoFile,
new PlatformNullFile(),
$params
);
}

public function testConvertMustThrowFileNotFoundException(): void
{
self::expectException(MissingInputFileReaderException::class);
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/Video/VideoConvertParamsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ public function testWithConvertParams(): void

self::assertEquals(
30,
$params1->withConvertParams($params2)
->getParam(VideoConvertParamsInterface::PARAM_TILE_COLUMNS)
$params1->withConvertParams($params2)
->getParam(VideoConvertParamsInterface::PARAM_TILE_COLUMNS)
);
}

Expand Down
38 changes: 38 additions & 0 deletions tests/unit/Video/VideoConverterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@

use MediaToolsTest\Util\ServicesProviderTrait;
use PHPUnit\Framework\TestCase;
use Soluble\MediaTools\Common\IO\UnescapedFileInterface;
use Soluble\MediaTools\Video\Config\FFMpegConfig;
use Soluble\MediaTools\Video\Exception\InvalidArgumentException;
use Soluble\MediaTools\Video\Filter\EmptyVideoFilter;
use Soluble\MediaTools\Video\Filter\Hqdn3DVideoFilter;
use Soluble\MediaTools\Video\Filter\NlmeansVideoFilter;
Expand Down Expand Up @@ -80,6 +82,42 @@ public function testGetSymfonyProcessMustReturnCorrectParams(): void
self::assertContains(' -f webm ', $cmdLine);
self::assertContains(' -ss 0:00:01.0 ', $cmdLine);
self::assertContains(' -frames:v 200 ', $cmdLine);
self::assertContains(escapeshellarg('/path/output'), $cmdLine);
}

public function testGetSymfonyProcessMustThrowExceptionOnWrongOutput(): void
{
self::expectException(InvalidArgumentException::class);
$convertParams = (new VideoConvertParams());

$process = (new VideoConverter(
new FFMpegConfig('ffmpeg')
))->getSymfonyProcess(
__FILE__,
['invalid array'],
$convertParams
);
}

public function testGetSymfonyProcessWithUnescapedFile(): void
{
$convertParams = (new VideoConvertParams());

$process = (new VideoConverter(
new FFMpegConfig('ffmpeg')
))->getSymfonyProcess(
__FILE__,
new class() implements UnescapedFileInterface {
public function getFile(): string
{
return '/a n/un \'escaped/file';
}
},
$convertParams
);

$cmdLine = $process->getCommandLine();
self::assertContains(' /a n/un \'escaped/file', $cmdLine);
}

public function testGetSymfonyProcessMustDefaultToConfigThreads(): void
Expand Down

0 comments on commit f404663

Please sign in to comment.