livephoto: multiple trailers in Google (fix #373)
parent
7cedcf70a8
commit
457ac16db1
|
@ -139,6 +139,15 @@ class VideoController extends ApiBase
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return new JSONResponse(['message' => 'Embedded video not found'], Http::STATUS_NOT_FOUND);
|
return new JSONResponse(['message' => 'Embedded video not found'], Http::STATUS_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
} elseif (str_starts_with($liveid, 'self__traileroffset=')) {
|
||||||
|
// Remove prefix
|
||||||
|
$offset = (int) substr($liveid, \strlen('self__traileroffset='));
|
||||||
|
if ($offset <= 0) {
|
||||||
|
return new JSONResponse(['message' => 'Invalid offset'], Http::STATUS_BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read file from offset to end
|
||||||
|
$blob = file_get_contents($path, false, null, $offset);
|
||||||
} else {
|
} else {
|
||||||
// Get stored video file (Apple MOV)
|
// Get stored video file (Apple MOV)
|
||||||
$lp = $this->timelineQuery->getLivePhoto($fileid);
|
$lp = $this->timelineQuery->getLivePhoto($fileid);
|
||||||
|
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace OCA\Memories\Db;
|
namespace OCA\Memories\Db;
|
||||||
|
|
||||||
|
use OCA\Memories\Exif;
|
||||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||||
use OCP\Files\File;
|
use OCP\Files\File;
|
||||||
use OCP\IDBConnection;
|
use OCP\IDBConnection;
|
||||||
|
@ -26,7 +27,7 @@ class LivePhoto
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get liveid from photo part */
|
/** Get liveid from photo part */
|
||||||
public function getLivePhotoId(array &$exif)
|
public function getLivePhotoId(File &$file, array &$exif)
|
||||||
{
|
{
|
||||||
// Apple JPEG (MOV has ContentIdentifier)
|
// Apple JPEG (MOV has ContentIdentifier)
|
||||||
if (\array_key_exists('MediaGroupUUID', $exif)) {
|
if (\array_key_exists('MediaGroupUUID', $exif)) {
|
||||||
|
@ -41,7 +42,36 @@ class LivePhoto
|
||||||
// Google JPEG and Samsung HEIC (Apple?)
|
// Google JPEG and Samsung HEIC (Apple?)
|
||||||
if (\array_key_exists('MotionPhoto', $exif)) {
|
if (\array_key_exists('MotionPhoto', $exif)) {
|
||||||
if ('image/jpeg' === $exif['MIMEType']) {
|
if ('image/jpeg' === $exif['MIMEType']) {
|
||||||
// Google JPEG -- image should hopefully be in trailer
|
// Google Motion Photo JPEG
|
||||||
|
|
||||||
|
// We need to read the DirectoryItemLength key to get the length of the video
|
||||||
|
// These keys are duplicate, one for the image and one for the video
|
||||||
|
// With exiftool -G4, we get the following:
|
||||||
|
//
|
||||||
|
// "Unknown:DirectoryItemSemantic": "Primary"
|
||||||
|
// "Unknown:DirectoryItemLength": 0
|
||||||
|
// "Copy1:DirectoryItemSemantic": "MotionPhoto"
|
||||||
|
// "Copy1:DirectoryItemLength": 3011435 // <-- this is the length of the video
|
||||||
|
//
|
||||||
|
// The video is then located at the end of the file, so we can get the offset.
|
||||||
|
// Match each DirectoryItemSemantic to find MotionPhoto, then get the length.
|
||||||
|
$path = $file->getStorage()->getLocalFile($file->getInternalPath());
|
||||||
|
$extExif = Exif::getExifWithDuplicates($path);
|
||||||
|
|
||||||
|
foreach ($extExif as $key => $value) {
|
||||||
|
if (str_ends_with($key, ':DirectoryItemSemantic')) {
|
||||||
|
if ('MotionPhoto' === $value) {
|
||||||
|
$videoLength = $extExif[str_replace('Semantic', 'Length', $key)];
|
||||||
|
if (\is_int($videoLength) && $videoLength > 0) {
|
||||||
|
$videoOffset = $file->getSize() - $videoLength;
|
||||||
|
|
||||||
|
return 'self__traileroffset='.((string) $videoOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: video should hopefully be in trailer
|
||||||
return 'self__trailer';
|
return 'self__trailer';
|
||||||
}
|
}
|
||||||
if ('image/heic' === $exif['MIMEType']) {
|
if ('image/heic' === $exif['MIMEType']) {
|
||||||
|
|
|
@ -282,6 +282,11 @@ class Exif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getExifWithDuplicates(string $path)
|
||||||
|
{
|
||||||
|
return self::getExifFromLocalPathWithSeparateProc($path, ['-G4']);
|
||||||
|
}
|
||||||
|
|
||||||
/** Get path to exiftool binary */
|
/** Get path to exiftool binary */
|
||||||
private static function getExiftool()
|
private static function getExiftool()
|
||||||
{
|
{
|
||||||
|
@ -407,10 +412,10 @@ class Exif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function getExifFromLocalPathWithSeparateProc(string &$path)
|
private static function getExifFromLocalPathWithSeparateProc(string &$path, array $extraArgs = [])
|
||||||
{
|
{
|
||||||
$pipes = [];
|
$pipes = [];
|
||||||
$proc = proc_open(array_merge(self::getExiftool(), ['-api', 'QuickTimeUTC=1', '-n', '-U', '-json', '--b', $path]), [
|
$proc = proc_open(array_merge(self::getExiftool(), ['-api', 'QuickTimeUTC=1', '-n', '-U', '-json', '--b'], $extraArgs, [$path]), [
|
||||||
1 => ['pipe', 'w'],
|
1 => ['pipe', 'w'],
|
||||||
2 => ['pipe', 'w'],
|
2 => ['pipe', 'w'],
|
||||||
], $pipes);
|
], $pipes);
|
||||||
|
|
Loading…
Reference in New Issue