Installation:
composer require ac/transcoding
Add to composer.json if not using autoloading:
"autoload": {
"psr-4": {
"App\\": "app/",
"Ac\\Transcoding\\": "vendor/ac/transcoding/src/"
}
}
Run composer dump-autoload.
First Use Case: Transcode an image using FFmpeg (requires FFmpeg installed):
use Ac\Transcoding\Transcoder;
use Ac\Transcoding\Adapter\FFmpegAdapter;
use Ac\Transcoding\Preset\FFmpegPreset;
$transcoder = new Transcoder();
$inputFile = new \Ac\Transcoding\File('path/to/input.mp4');
$outputFile = new \Ac\Transcoding\File('path/to/output.webm');
// Register FFmpeg adapter and preset
$transcoder->registerAdapter('ffmpeg', new FFmpegAdapter());
$transcoder->registerPreset('webm', new FFmpegPreset([
'command' => 'ffmpeg -i {input} -c:v libvpx -b:v 1M {output}',
'input' => ['mp4', 'mov'],
'output' => ['webm']
]));
// Transcode
$transcoder->transcode($inputFile, $outputFile, 'ffmpeg', 'webm');
Where to Look First:
src/Ac/Transcoding/Transcoder.php (core logic).src/Ac/Transcoding/Adapter/ (built-in adapters like FFmpegAdapter, ImageMagickAdapter).src/Ac/Transcoding/Preset/ (preset examples and structure).tests/ (real-world usage patterns).Register Adapters:
$transcoder->registerAdapter('ffmpeg', new FFmpegAdapter());
$transcoder->registerAdapter('imagemagick', new ImageMagickAdapter());
\Ac\Transcoding\Adapter\AbstractAdapter to create custom adapters.Define Presets:
$preset = new FFmpegPreset([
'command' => 'ffmpeg -i {input} -vf "scale=640:480" {output}',
'input' => ['mp4', 'avi'],
'output' => ['mp4']
]);
$transcoder->registerPreset('resize', $preset);
{input} and {output} placeholders for file paths.Transcode Files:
$job = $transcoder->transcode(
$inputFile,
$outputFile,
'ffmpeg', // Adapter name
'resize' // Preset name
);
\Ac\Transcoding\Job object with metadata (success/failure, duration, etc.).Event Handling (Optional):
$transcoder->on('pre', function ($job) {
\Log::info("Starting transcode job: {$job->getInput()->getPathname()}");
});
$transcoder->on('post', function ($job) {
if ($job->isSuccess()) {
\Log::info("Transcode succeeded!");
}
});
pre, post, or error events for hooks.Laravel Service Provider: Bind the transcoder to the container for dependency injection:
$this->app->singleton('transcoder', function ($app) {
$transcoder = new Transcoder();
$transcoder->registerAdapter('ffmpeg', new FFmpegAdapter());
// Register presets...
return $transcoder;
});
Queue Transcoding Jobs: Use Laravel queues to offload transcoding:
$job = (new TranscodeJob($inputFile, $outputFile, 'ffmpeg', 'resize'))
->onQueue('transcodes');
Dynamic Presets: Load presets from a database or config:
$presets = config('transcoding.presets');
foreach ($presets as $name => $config) {
$transcoder->registerPreset($name, new FFmpegPreset($config));
}
File Validation:
Use File class methods to validate before transcoding:
if ($inputFile->isSupported('ffmpeg')) {
$transcoder->transcode(...);
}
Custom Adapters:
Example: Create a CustomAdapter for a proprietary tool:
class CustomAdapter extends AbstractAdapter {
protected $command = 'custom-tool -i {input} -o {output}';
public function getSupportedInputTypes() {
return ['custom'];
}
public function getSupportedOutputTypes() {
return ['converted'];
}
}
Adapter/Preset Registration:
Adapter/Preset not found.$transcoder->registerAdapter('ffmpeg', $adapter); // Must use 'ffmpeg' later
File Path Handling:
$inputFile = new File(storage_path('app/input.mp4'));
Command Placeholders:
{input} or {output} not replaced in commands.FFmpeg/ImageMagick Paths:
ffmpeg/convert not found.$adapter = new FFmpegAdapter(['ffmpeg' => '/usr/local/bin/ffmpeg']);
Concurrent Transcoding:
Enable Verbose Logging:
$transcoder->setLogger(new \Monolog\Logger('transcoding', [
new \Monolog\Handler\StreamHandler(storage_path('logs/transcoding.log'))
]));
Check Job Status:
if (!$job->isSuccess()) {
\Log::error("Transcode failed: " . $job->getError());
}
Validate Presets:
Use Preset::validate() to check config before registering:
if (!$preset->validate()) {
throw new \InvalidArgumentException("Invalid preset config");
}
Preset Inheritance: Extend presets for reuse:
class ResizePreset extends FFmpegPreset {
public function __construct($width, $height) {
parent::__construct([
'command' => 'ffmpeg -i {input} -vf "scale={$width}:{$height}" {output}',
'input' => ['mp4', 'mov'],
'output' => ['mp4']
]);
}
}
Environment-Specific Config:
Use Laravel's config('transcoding') to switch presets/adapters per environment.
Performance:
Job::setTimeout() to avoid hanging.Testing: Mock adapters for unit tests:
$mockAdapter = $this->getMockBuilder(FFmpegAdapter::class)
->disableOriginalConstructor()
->getMock();
$transcoder->registerAdapter('mock', $mockAdapter);
Security:
.php files).Extending Events: Add custom event listeners for notifications or retries:
$transcoder->on('error', function ($job) {
// Send Slack alert or retry logic
});
Legacy PHP Support:
For PHP 5.3+, use trait-based event dispatching if needed (check EventDispatcher class).
How can I help you explore Laravel packages today?