/**
  * Sorts the optimized media files based on the provided priority options
  *
  * Example:
  *
  *   optimized media files: [1.ogv, 2.mp4, 3.webm, 4.mp4, 5.wmv]
  *              priorities: [video/mp4, video/webm]
  *            appendOthers: true
  *           property name: mime_type
  *                  result: [2.mp4, 3.webm, 1.ogv, 4.mp4, 5.wmv]
  *
  * @param  \WIRO\Html5mediaelements\Domain\Model\Media  $media         media record
  * @param  array                                        $priorities    array of values for $propertyName that
  *                                                                     define the priority of the media files
  * @param  boolean                                      $appendOthers  append duplicate priority media files or files that don't
  *                                                                     match a priority to the result array as well
  *                                                                     (in their original order after the media files with priorities)
  * @param  string                                       $propertyName  file property based on which priority should be measured
  * @return array                                                       sorted array of media files
  */
 protected function prioritizeMedia(\WIRO\Html5mediaelements\Domain\Model\Media $media, array $priorities, $appendOthers = true, $propertyName = 'mime_type')
 {
     // Reserve spots for prioritized formats
     $orderedMedia = array_fill(0, count($priorities), NULL);
     $priorityFormats = array_flip(array_unique($priorities));
     foreach ($media->getOptimizedMedia() as $optimizedMedia) {
         $optimizedFile = $optimizedMedia->getOptimizedFile();
         if (!$optimizedFile) {
             continue;
         }
         $property = $optimizedFile->getOriginalResource()->getProperty($propertyName);
         // Check if format should be prioritized
         if (isset($priorityFormats[$property]) && !isset($orderedMedia[$priorityFormats[$property]])) {
             // Prioritized format: Put into reserved spot
             $orderedMedia[$priorityFormats[$property]] = $optimizedFile;
         } else {
             if ($appendOthers) {
                 // Append others
                 $orderedMedia[] = $optimizedFile;
             }
         }
     }
     // Remove empty spots, use sequenced indexes
     return array_values(array_filter($orderedMedia));
 }
 /**
  * Converts source media to configured media formats and references them
  *
  * @param  \WIRO\Html5mediaelements\Domain\Model\Media $media   media record
  * @param  array                                       $config  conversion configuration for media formats
  * @return void
  */
 protected function convertMedia(Media $media, array $config)
 {
     // Create a local file for processing
     $originalFile = $media->getSourceFile()->getOriginalResource()->getOriginalFile();
     $localFile = $originalFile->getForLocalProcessing(FALSE);
     // Prepare for conversion
     if ($media->isAudio()) {
         $source = new \PHPVideoToolkit\Audio($localFile);
     } else {
         $source = new \PHPVideoToolkit\Video($localFile);
     }
     $multiOutput = new \PHPVideoToolkit\MultiOutput();
     $outputContext = array();
     foreach ($config as $formatName => $formatConfig) {
         // Skip files without audio and video
         if ($media->isAudio() && !$formatConfig['audio']['enabled'] || $media->isVideo() && !$formatConfig['audio']['enabled'] && !$formatConfig['video']['enabled']) {
             continue;
         }
         // Generate video file name
         $fileName = $this->generateFilename($originalFile, $formatConfig['filename']);
         $filePath = $this->tempPathFiles . $fileName;
         // Store information about conversion input
         $outputContext[] = array('format' => $formatName, 'path' => $filePath, 'name' => $fileName);
         // Configure output format
         $fallbackFormat = $media->isAudio() ? 'AudioFormat' : 'VideoFormat';
         $className = '\\PHPVideoToolkit\\' . $fallbackFormat . '_' . ucfirst($formatConfig['format']);
         if ($formatConfig['format'] && class_exists($className)) {
             $format = new $className();
         } else {
             $format = \PHPVideoToolkit\Format::getFormatFor($filePath, null, $fallbackFormat);
         }
         // Set format options from configuration
         if ($formatConfig['audio']['enabled']) {
             if ($formatConfig['audio']['codec']) {
                 $format->setAudioCodec($formatConfig['audio']['codec']);
             }
             if ($formatConfig['audio']['bitrate']) {
                 $format->setAudioBitrate((double) $formatConfig['audio']['bitrate']);
             }
             if ($formatConfig['audio']['quality']) {
                 $format->setAudioQuality((double) $formatConfig['audio']['quality']);
             }
             if ($formatConfig['audio']['sampleFrequency']) {
                 $format->setAudioSampleFrequency((int) $formatConfig['audio']['sampleFrequency']);
             }
             if ($formatConfig['audio']['channels']) {
                 $format->setAudioChannels((int) $formatConfig['audio']['channels']);
             }
             if ($formatConfig['audio']['volume']) {
                 $format->setVolume((int) $formatConfig['audio']['volume']);
             }
         } else {
             $format->disableAudio();
         }
         if ($media->isVideo()) {
             if ($formatConfig['video']['enabled']) {
                 if ($formatConfig['video']['codec']) {
                     $format->setVideoCodec($formatConfig['video']['codec']);
                 }
                 if ($formatConfig['video']['width'] && $formatConfig['video']['height']) {
                     $format->setVideoDimensions($formatConfig['video']['width'], $formatConfig['video']['height'], true);
                 }
                 if ($formatConfig['video']['aspectRatio']) {
                     $format->setVideoAspectRatio($formatConfig['video']['aspectRatio'], true);
                 }
                 if ($formatConfig['video']['frameRate']) {
                     $format->setVideoFrameRate((double) $formatConfig['video']['frameRate']);
                 }
                 if ($formatConfig['video']['maxFrames']) {
                     $format->setVideoMaxFrames($formatConfig['video']['maxFrames']);
                 }
                 if ($formatConfig['video']['bitrate']) {
                     $format->setVideoBitrate($formatConfig['video']['bitrate']);
                 }
                 if ($formatConfig['video']['pixelFormat']) {
                     $format->setVideoPixelFormat($formatConfig['video']['pixelFormat']);
                 }
                 if ($formatConfig['video']['quality']) {
                     $format->setVideoQuality((double) $formatConfig['video']['quality']);
                 }
                 if ($formatConfig['video']['h264']['preset']) {
                     $format->setH264Preset($formatConfig['video']['h264']['preset']);
                 }
                 if ($formatConfig['video']['h264']['tune']) {
                     $format->setH264Tune($formatConfig['video']['h264']['tune']);
                 }
                 if ($formatConfig['video']['h264']['profile']) {
                     $format->setH264Profile($formatConfig['video']['h264']['profile']);
                 }
             } else {
                 $format->disableVideo();
             }
         }
         // Add to conversion command
         $multiOutput->addOutput($filePath, $format);
     }
     if (empty($outputContext)) {
         return;
     }
     // TODO make asynchronous
     $process = $source->save($multiOutput, null, \PHPVideoToolkit\Media::OVERWRITE_UNIQUE);
     /*
     // Start conversion
     $progressHandler = new \PHPVideoToolkit\ProgressHandlerNative(null);
     $process = $source->saveNonBlocking($multiOutput, null, \PHPVideoToolkit\Media::OVERWRITE_UNIQUE, $progressHandler);
     
     \TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($progressHandler, 'SP');
     return;
     
     // Wait for files being converted
     $lastStatus = null;
     while ($progressHandler->completed !== true) {
     	$probe = $progressHandler->probe(true);
     	if ($probe['status'] !== $lastStatus) {
     		//echo $probe['status'] . PHP_EOL;
     		$lastStatus = $probe['status'];
     	}
     
     	sleep(0.5);
     }
     */
     // Get converted files
     $outputFiles = $process->getAllOutput();
     foreach ($outputContext as $i => $fileOptions) {
         // Add converted file to FAL
         $file = $originalFile->getParentFolder()->addFile($outputFiles[$i], $fileOptions['name'], 'changeName');
         // TODO check for permission of user (_cli_scheduler)
         // Set dimension metadata of converted file
         $this->setFileMetadata($file);
         // Create new optimized media record
         $mediaOptimized = $this->objectManager->get('WIRO\\Html5mediaelements\\Domain\\Model\\MediaOptimized');
         $mediaOptimized->setPid($media->getPid());
         $mediaOptimized->setType($media->isAudio() ? MediaOptimized::TYPE_AUDIO : MediaOptimized::TYPE_VIDEO);
         $mediaOptimized->setFormat($fileOptions['format']);
         // Add reference to media record
         $media->addOptimizedMedium($mediaOptimized);
         $this->mediaRepository->update($media);
         $this->persistenceManager->persistAll();
         // Add reference to converted file
         $this->addFileReference('tx_html5mediaelements_domain_model_mediaoptimized', 'optimized_file', $mediaOptimized, $file);
     }
     // Set converted flag in media record
     $media->setIsConverted(true);
     $this->mediaRepository->update($media);
 }