vendor/pimcore/pimcore/models/Asset/Video.php line 98

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Commercial License (PCL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  *  @license    http://www.pimcore.org/license     GPLv3 and PCL
  13.  */
  14. namespace Pimcore\Model\Asset;
  15. use Pimcore\Event\FrontendEvents;
  16. use Pimcore\File;
  17. use Pimcore\Logger;
  18. use Pimcore\Model;
  19. use Pimcore\Tool;
  20. use Symfony\Component\EventDispatcher\GenericEvent;
  21. /**
  22.  * @method \Pimcore\Model\Asset\Dao getDao()
  23.  */
  24. class Video extends Model\Asset
  25. {
  26.     use Model\Asset\MetaData\EmbeddedMetaDataTrait;
  27.     /**
  28.      * {@inheritdoc}
  29.      */
  30.     protected $type 'video';
  31.     /**
  32.      * {@inheritdoc}
  33.      */
  34.     protected function update($params = [])
  35.     {
  36.         if ($this->getDataChanged()) {
  37.             foreach (['duration''videoWidth''videoHeight'] as $key) {
  38.                 $this->removeCustomSetting($key);
  39.             }
  40.         }
  41.         $this->clearThumbnails();
  42.         parent::update($params);
  43.     }
  44.     /**
  45.      * {@inheritdoc}
  46.      */
  47.     public function clearThumbnails($force false)
  48.     {
  49.         if ($this->getDataChanged() || $force) {
  50.             // clear the thumbnail custom settings
  51.             $this->setCustomSetting('thumbnails'null);
  52.             parent::clearThumbnails($force);
  53.         }
  54.     }
  55.     /**
  56.      * @internal
  57.      *
  58.      * @param string|Video\Thumbnail\Config $config
  59.      *
  60.      * @return Video\Thumbnail\Config|null
  61.      *
  62.      * @throws Model\Exception\NotFoundException
  63.      */
  64.     public function getThumbnailConfig($config)
  65.     {
  66.         $thumbnail null;
  67.         if (is_string($config)) {
  68.             $thumbnail Video\Thumbnail\Config::getByName($config);
  69.             if ($thumbnail === null) {
  70.                 throw new Model\Exception\NotFoundException('Video Thumbnail definition "' $config '" does not exist');
  71.             }
  72.         } elseif ($config instanceof Video\Thumbnail\Config) {
  73.             $thumbnail $config;
  74.         }
  75.         return $thumbnail;
  76.     }
  77.     /**
  78.      * Returns a path to a given thumbnail or an thumbnail configuration
  79.      *
  80.      * @param string|Video\Thumbnail\Config $thumbnailName
  81.      * @param array $onlyFormats
  82.      *
  83.      * @return array|null
  84.      */
  85.     public function getThumbnail($thumbnailName$onlyFormats = [])
  86.     {
  87.         $thumbnail $this->getThumbnailConfig($thumbnailName);
  88.         if ($thumbnail) {
  89.             try {
  90.                 Video\Thumbnail\Processor::process($this$thumbnail$onlyFormats);
  91.                 // check for existing videos
  92.                 $customSetting $this->getCustomSetting('thumbnails');
  93.                 if (is_array($customSetting) && array_key_exists($thumbnail->getName(), $customSetting)) {
  94.                     foreach ($customSetting[$thumbnail->getName()]['formats'] as $pathKey => &$path) {
  95.                         if ($pathKey == 'medias') {
  96.                             foreach ($path as &$format) {
  97.                                 foreach ($format as &$f) {
  98.                                     $f $this->enrichThumbnailPath($f);
  99.                                 }
  100.                             }
  101.                         } else {
  102.                             $path $this->enrichThumbnailPath($path);
  103.                         }
  104.                     }
  105.                     return $customSetting[$thumbnail->getName()];
  106.                 }
  107.             } catch (\Exception $e) {
  108.                 Logger::error("Couldn't create thumbnail of video " $this->getRealFullPath());
  109.                 Logger::error($e);
  110.             }
  111.         }
  112.         return null;
  113.     }
  114.     /**
  115.      * @param string $path
  116.      *
  117.      * @return string
  118.      */
  119.     private function enrichThumbnailPath($path)
  120.     {
  121.         $fullPath rtrim($this->getRealPath(), '/') . $path;
  122.         if (Tool::isFrontend()) {
  123.             $path urlencode_ignore_slash($fullPath);
  124.             $prefix \Pimcore::getContainer()->getParameter('pimcore.config')['assets']['frontend_prefixes']['thumbnail'];
  125.             $path $prefix $path;
  126.         }
  127.         $event = new GenericEvent($this, [
  128.             'filesystemPath' => $fullPath,
  129.             'frontendPath' => $path,
  130.         ]);
  131.         \Pimcore::getEventDispatcher()->dispatch($eventFrontendEvents::ASSET_VIDEO_THUMBNAIL);
  132.         return $event->getArgument('frontendPath');
  133.     }
  134.     /**
  135.      * @param string|array|Image\Thumbnail\Config $thumbnailName
  136.      * @param int|null $timeOffset
  137.      * @param Image|null $imageAsset
  138.      *
  139.      * @return Video\ImageThumbnail
  140.      */
  141.     public function getImageThumbnail($thumbnailName$timeOffset null$imageAsset null)
  142.     {
  143.         if (!\Pimcore\Video::isAvailable()) {
  144.             Logger::error("Couldn't create image-thumbnail of video " $this->getRealFullPath() . ' no video adapter is available');
  145.             return new Video\ImageThumbnail(null); // returns error image
  146.         }
  147.         return new Video\ImageThumbnail($this$thumbnailName$timeOffset$imageAsset);
  148.     }
  149.     /**
  150.      * @internal
  151.      *
  152.      * @param string|null $filePath
  153.      *
  154.      * @return float|null
  155.      *
  156.      * @throws \Exception
  157.      */
  158.     public function getDurationFromBackend(?string $filePath null)
  159.     {
  160.         if (\Pimcore\Video::isAvailable()) {
  161.             if (!$filePath) {
  162.                 $filePath $this->getLocalFile();
  163.             }
  164.             $converter \Pimcore\Video::getInstance();
  165.             $converter->load($filePath, ['asset' => $this]);
  166.             return $converter->getDuration();
  167.         }
  168.         return null;
  169.     }
  170.     /**
  171.      * @internal
  172.      *
  173.      * @return array|null
  174.      *
  175.      * @throws \Exception
  176.      */
  177.     public function getDimensionsFromBackend()
  178.     {
  179.         if (\Pimcore\Video::isAvailable()) {
  180.             $converter \Pimcore\Video::getInstance();
  181.             $converter->load($this->getLocalFile(), ['asset' => $this]);
  182.             return $converter->getDimensions();
  183.         }
  184.         return null;
  185.     }
  186.     /**
  187.      * @return int|null
  188.      */
  189.     public function getDuration()
  190.     {
  191.         $duration $this->getCustomSetting('duration');
  192.         if (!$duration) {
  193.             $duration $this->getDurationFromBackend();
  194.             if ($duration) {
  195.                 $this->setCustomSetting('duration'$duration);
  196.                 Model\Version::disable();
  197.                 $this->save(); // auto save
  198.                 Model\Version::enable();
  199.             }
  200.         }
  201.         return $duration;
  202.     }
  203.     /**
  204.      * @return array|null
  205.      */
  206.     public function getDimensions()
  207.     {
  208.         $dimensions null;
  209.         $width $this->getCustomSetting('videoWidth');
  210.         $height $this->getCustomSetting('videoHeight');
  211.         if (!$width || !$height) {
  212.             $dimensions $this->getDimensionsFromBackend();
  213.             if ($dimensions) {
  214.                 $this->setCustomSetting('videoWidth'$dimensions['width']);
  215.                 $this->setCustomSetting('videoHeight'$dimensions['height']);
  216.                 Model\Version::disable();
  217.                 $this->save(); // auto save
  218.                 Model\Version::enable();
  219.             }
  220.         } else {
  221.             $dimensions = [
  222.                 'width' => $width,
  223.                 'height' => $height,
  224.             ];
  225.         }
  226.         return $dimensions;
  227.     }
  228.     /**
  229.      * @return int|null
  230.      */
  231.     public function getWidth()
  232.     {
  233.         $dimensions $this->getDimensions();
  234.         if ($dimensions) {
  235.             return $dimensions['width'];
  236.         }
  237.         return null;
  238.     }
  239.     /**
  240.      * @return int|null
  241.      */
  242.     public function getHeight()
  243.     {
  244.         $dimensions $this->getDimensions();
  245.         if ($dimensions) {
  246.             return $dimensions['height'];
  247.         }
  248.         return null;
  249.     }
  250.     /**
  251.      * @internal
  252.      *
  253.      * @return array
  254.      */
  255.     public function getSphericalMetaData()
  256.     {
  257.         $data = [];
  258.         if (in_array(File::getFileExtension($this->getFilename()), ['mp4''webm'])) {
  259.             $chunkSize 1024;
  260.             $file_pointer $this->getStream();
  261.             $tag '<rdf:SphericalVideo';
  262.             $tagLength strlen($tag);
  263.             $buffer false;
  264.             // find open tag
  265.             $overlapString '';
  266.             while ($buffer === false && ($chunk fread($file_pointer$chunkSize)) !== false) {
  267.                 if (strlen($chunk) <= $tagLength) {
  268.                     break;
  269.                 }
  270.                 $chunk $overlapString $chunk;
  271.                 if (($position strpos($chunk$tag)) === false) {
  272.                     // if open tag not found, back up just in case the open tag is on the split.
  273.                     $overlapString substr($chunk$tagLength * -1);
  274.                 } else {
  275.                     $buffer substr($chunk$position);
  276.                 }
  277.             }
  278.             if ($buffer !== false) {
  279.                 $tag '</rdf:SphericalVideo>';
  280.                 $tagLength strlen($tag);
  281.                 $offset 0;
  282.                 while (($position strpos($buffer$tag$offset)) === false && ($chunk fread($file_pointer,
  283.                         $chunkSize)) !== false && !empty($chunk)) {
  284.                     $offset strlen($buffer) - $tagLength// subtract the tag size just in case it's split between chunks.
  285.                     $buffer .= $chunk;
  286.                 }
  287.                 if ($position === false) {
  288.                     // this would mean the open tag was found, but the close tag was not.  Maybe file corruption?
  289.                     throw new \RuntimeException('No close tag found.  Possibly corrupted file.');
  290.                 } else {
  291.                     $buffer substr($buffer0$position $tagLength);
  292.                 }
  293.                 $buffer preg_replace('/xmlns[^=]*="[^"]*"/i'''$buffer);
  294.                 $buffer preg_replace('@<(/)?([a-zA-Z]+):([a-zA-Z]+)@''<$1$2____$3'$buffer);
  295.                 $xml = @simplexml_load_string($buffer);
  296.                 $data object2array($xml);
  297.             }
  298.             fclose($file_pointer);
  299.         }
  300.         // remove namespace prefixes if possible
  301.         $resultData = [];
  302.         array_walk($data, function ($value$key) use (&$resultData) {
  303.             $parts explode('____'$key);
  304.             $length count($parts);
  305.             if ($length 1) {
  306.                 $name $parts[$length 1];
  307.                 if (!isset($resultData[$name])) {
  308.                     $key $name;
  309.                 }
  310.             }
  311.             $resultData[$key] = $value;
  312.         });
  313.         return $resultData;
  314.     }
  315. }