Skip to content

Commit 53c7a0a

Browse files
authored
Merge branch 'protonemedia:main' into main
2 parents 29c1a8a + b42162e commit 53c7a0a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+548
-631
lines changed

.github/workflows/run-tests.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,29 @@ jobs:
1515
matrix:
1616
os: [ubuntu-20.04]
1717
php: [8.4, 8.3, 8.2, 8.1]
18-
laravel: ["10.*", "11.*"]
18+
laravel: ['10.*', '11.*', '12.*']
1919
ffmpeg: [5.0, 4.4]
2020
dependency-version: [prefer-lowest, prefer-stable]
2121
include:
2222
- laravel: 10.*
2323
testbench: 8.*
2424
- laravel: 11.*
2525
testbench: 9.*
26+
- laravel: 12.*
27+
testbench: 10.*
2628
exclude:
2729
- laravel: 11.*
2830
php: 8.1
2931
- laravel: 10.*
3032
php: 8.4
33+
- laravel: 12.*
34+
php: 8.1
3135

3236
name: ${{ matrix.os }} - P${{ matrix.php }} - L${{ matrix.laravel }} - FF${{ matrix.ffmpeg }} - ${{ matrix.dependency-version }}
3337

3438
steps:
3539
- name: Checkout code
36-
uses: actions/checkout@v2
40+
uses: actions/checkout@v4
3741

3842
- name: Setup PHP
3943
uses: shivammathur/setup-php@v2
@@ -54,7 +58,7 @@ jobs:
5458
composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-suggest
5559
5660
- name: Cache dependencies
57-
uses: actions/cache@v2
61+
uses: actions/cache@v4
5862
with:
5963
path: ~/.composer/cache/files
6064
key: dependencies-laravel-${{ matrix.laravel }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }}-dep-${{ matrix.dependency-version }}

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -817,7 +817,7 @@ $media = FFMpeg::fromDisk('videos')->open('video.mp4');
817817

818818
// The 'getStreams' method will be called on the underlying Media object since
819819
// it doesn't exists on this object.
820-
$codec = $media->getStreams()->first()->get('codec_name');
820+
$codec = $media->getVideoStream()->get('codec_name');
821821
```
822822

823823
If you want direct access to the underlying object, call the object as a function (invoke):

composer.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,16 @@
2121
],
2222
"require": {
2323
"php": "^8.1|^8.2|^8.3|^8.4",
24-
"illuminate/contracts": "^10.0|^11.0",
24+
"illuminate/contracts": "^10.0|^11.0|^12.0",
2525
"php-ffmpeg/php-ffmpeg": "^1.2",
2626
"ramsey/collection": "^2.0"
2727
},
2828
"require-dev": {
2929
"league/flysystem-memory": "^3.10",
3030
"mockery/mockery": "^1.4.4",
3131
"nesbot/carbon": "^2.66|^3.0",
32-
"orchestra/testbench": "^8.0|^9.0",
33-
"phpunit/phpunit": "^10.4",
32+
"orchestra/testbench": "^8.0|^9.0|^10.0",
33+
"phpunit/phpunit": "^10.4|^11.5.3",
3434
"spatie/image": "^2.2|^3.3",
3535
"spatie/phpunit-snapshot-assertions": "^5.0"
3636
},
@@ -63,4 +63,4 @@
6363
}
6464
}
6565
}
66-
}
66+
}

src/Drivers/InteractsWithFilters.php

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ trait InteractsWithFilters
2222

2323
/**
2424
* Returns an array with the filters applied to the underlying media object.
25-
*
26-
* @return array
2725
*/
2826
public function getFilters(): array
2927
{
@@ -33,8 +31,6 @@ public function getFilters(): array
3331
/**
3432
* Helper method to provide multiple ways to add a filter to the underlying
3533
* media object.
36-
*
37-
* @return self
3834
*/
3935
public function addFilter(): self
4036
{
@@ -77,14 +73,11 @@ public function addFilter(): self
7773
/**
7874
* Calls the callable with a WatermarkFactory instance and
7975
* adds the freshly generated WatermarkFilter.
80-
*
81-
* @param callable $withWatermarkFactory
82-
* @return self
8376
*/
8477
public function addWatermark(callable $withWatermarkFactory): self
8578
{
8679
$withWatermarkFactory(
87-
$watermarkFactory = new WatermarkFactory()
80+
$watermarkFactory = new WatermarkFactory
8881
);
8982

9083
return $this->addFilter($watermarkFactory->get());
@@ -93,11 +86,10 @@ public function addWatermark(callable $withWatermarkFactory): self
9386
/**
9487
* Shortcut for adding a Resize filter.
9588
*
96-
* @param int $width
97-
* @param int $height
98-
* @param string $mode
99-
* @param boolean $forceStandards
100-
* @return self
89+
* @param int $width
90+
* @param int $height
91+
* @param string $mode
92+
* @param bool $forceStandards
10193
*/
10294
public function resize($width, $height, $mode = ResizeFilter::RESIZEMODE_FIT, $forceStandards = true): self
10395
{
@@ -126,8 +118,6 @@ public function addFilterAsComplexFilter($in, $out, ...$arguments): self
126118

127119
/**
128120
* Getter for the pending complex filters.
129-
*
130-
* @return \Illuminate\Support\Collection
131121
*/
132122
public function getPendingComplexFilters(): Collection
133123
{

src/Drivers/InteractsWithMediaStreams.php

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,10 @@ trait InteractsWithMediaStreams
1111
{
1212
/**
1313
* Returns an array with all streams.
14-
*
15-
* @return array
1614
*/
1715
public function getStreams(): array
1816
{
19-
if (!$this->isAdvancedMedia()) {
17+
if (! $this->isAdvancedMedia()) {
2018
return iterator_to_array($this->media->getStreams());
2119
}
2220

@@ -39,7 +37,17 @@ public function getDurationInMiliseconds(): int
3937
$format = $this->getFormat();
4038

4139
if ($format->has('duration')) {
42-
return intval(round($format->get('duration') * 1000));
40+
$duration = $format->get('duration');
41+
42+
if (! blank($duration)) {
43+
return $format->get('duration') * 1000;
44+
}
45+
}
46+
47+
$duration = $this->extractDurationFromStream($this->getVideoStream() ?? $this->getAudioStream());
48+
49+
if ($duration !== null) {
50+
return $duration;
4351
}
4452

4553
throw new UnknownDurationException('Could not determine the duration of the media.');
@@ -69,4 +77,53 @@ public function getVideoStream(): ?Stream
6977
return $stream->isVideo();
7078
});
7179
}
80+
81+
/**
82+
* Extract video duration when it's not a standard property.
83+
*/
84+
public function extractDurationFromStream(Stream $stream): ?int
85+
{
86+
$duration = $this->findDuration($stream->all());
87+
88+
if ($duration === null) {
89+
return null;
90+
}
91+
92+
return $this->formatDuration($duration) * 1000;
93+
}
94+
95+
/**
96+
* Recursively search for the duration key.
97+
*/
98+
public function findDuration(array $array): ?string
99+
{
100+
foreach ($array as $key => $value) {
101+
if (is_array($value)) {
102+
if (! is_null($duration = $this->findDuration($value))) {
103+
return $duration;
104+
}
105+
}
106+
107+
if (strtolower($key) === 'duration') {
108+
return (string) $value;
109+
}
110+
}
111+
112+
return null;
113+
}
114+
115+
/**
116+
* Convert duration string to seconds.
117+
*/
118+
public function formatDuration(string $duration): float
119+
{
120+
$parts = array_map('floatval', explode(':', $duration));
121+
$count = count($parts);
122+
123+
return match ($count) {
124+
2 => $parts[0] * 60 + $parts[1],
125+
3 => $parts[0] * 3600 + $parts[1] * 60 + $parts[2],
126+
default => 0.0,
127+
};
128+
}
72129
}

src/Drivers/PHPFFMpeg.php

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class PHPFFMpeg
4242
private $mediaCollection;
4343

4444
/**
45-
* @var boolean
45+
* @var bool
4646
*/
4747
private $forceAdvanced = false;
4848

@@ -61,8 +61,8 @@ class PHPFFMpeg
6161

6262
public function __construct(FFMpeg $ffmpeg)
6363
{
64-
$this->ffmpeg = $ffmpeg;
65-
$this->pendingComplexFilters = new Collection();
64+
$this->ffmpeg = $ffmpeg;
65+
$this->pendingComplexFilters = new Collection;
6666
}
6767

6868
/**
@@ -114,7 +114,7 @@ public function open(MediaCollection $mediaCollection): self
114114

115115
$this->mediaCollection = $mediaCollection;
116116

117-
if ($mediaCollection->count() === 1 && !$this->forceAdvanced) {
117+
if ($mediaCollection->count() === 1 && ! $this->forceAdvanced) {
118118
$media = Arr::first($mediaCollection->collection());
119119

120120
$this->ffmpeg->setFFProbe(
@@ -147,7 +147,7 @@ public function open(MediaCollection $mediaCollection): self
147147

148148
public function frame(TimeCode $timecode)
149149
{
150-
if (!$this->isVideo()) {
150+
if (! $this->isVideo()) {
151151
throw new Exception('Opened media is not a video file.');
152152
}
153153

@@ -178,8 +178,6 @@ public function openAdvanced(MediaCollection $mediaCollection): self
178178

179179
/**
180180
* Returns the FFMpegDriver of the underlying library.
181-
*
182-
* @return \FFMpeg\Driver\FFMpegDriver
183181
*/
184182
private function getFFMpegDriver(): FFMpegDriver
185183
{
@@ -188,9 +186,6 @@ private function getFFMpegDriver(): FFMpegDriver
188186

189187
/**
190188
* Add a Listener to the underlying library.
191-
*
192-
* @param \Alchemy\BinaryDriver\Listeners\ListenerInterface $listener
193-
* @return self
194189
*/
195190
public function addListener(ListenerInterface $listener): self
196191
{
@@ -201,9 +196,6 @@ public function addListener(ListenerInterface $listener): self
201196

202197
/**
203198
* Remove the Listener from the underlying library.
204-
*
205-
* @param \Alchemy\BinaryDriver\Listeners\ListenerInterface $listener
206-
* @return self
207199
*/
208200
public function removeListener(ListenerInterface $listener): self
209201
{
@@ -214,9 +206,6 @@ public function removeListener(ListenerInterface $listener): self
214206

215207
/**
216208
* Adds a callable to the callbacks array.
217-
*
218-
* @param callable $callback
219-
* @return self
220209
*/
221210
public function beforeSaving(callable $callback): self
222211
{
@@ -227,8 +216,6 @@ public function beforeSaving(callable $callback): self
227216

228217
/**
229218
* Set the callbacks on the Media.
230-
*
231-
* @return self
232219
*/
233220
public function applyBeforeSavingCallbacks(): self
234221
{
@@ -243,10 +230,6 @@ public function applyBeforeSavingCallbacks(): self
243230

244231
/**
245232
* Add an event handler to the underlying library.
246-
*
247-
* @param string $event
248-
* @param callable $callback
249-
* @return self
250233
*/
251234
public function onEvent(string $event, callable $callback): self
252235
{

src/Drivers/UnknownDurationException.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,4 @@
44

55
use Exception;
66

7-
class UnknownDurationException extends Exception
8-
{
9-
}
7+
class UnknownDurationException extends Exception {}

src/Exporters/EncodingException.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public static function decorate(RuntimeException $runtimeException): EncodingExc
1515
$runtimeException->getPrevious()
1616
), function (self $exception) {
1717
if (config('laravel-ffmpeg.set_command_and_error_output_on_exception', true)) {
18-
$exception->message = $exception->getAlchemyException()?->getMessage() ?: "";
18+
$exception->message = $exception->getAlchemyException()?->getMessage() ?: '';
1919
}
2020
});
2121
}

0 commit comments

Comments
 (0)