├── .gitignore ├── .travis.yml ├── LICENSE.md ├── README.md ├── composer.json ├── phpunit.xml ├── src ├── ElastcoderAWS.php ├── ElastcoderServiceProvider.php └── config.php ├── tests └── ElastcoderTest.php └── videos └── guida.mp4 /.gitignore: -------------------------------------------------------------------------------- 1 | composer.phar 2 | composer.lock 3 | coverage.xml 4 | .DS_Store 5 | Thumbs.db 6 | /vendor 7 | /.idea 8 | 9 | phpunit.local.xml 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.5 5 | - 5.6 6 | 7 | before_script: 8 | - travis_retry composer self-update 9 | - travis_retry composer install --prefer-source --no-interaction --dev 10 | 11 | script: 12 | - vendor/bin/phpunit 13 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 : Nicolás Bistolfi (nbistolfi@gmail.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Elastcoder 2 | 3 | [![Build Status](https://travis-ci.org/dumpk/elastcoder.svg?branch=master)](https://travis-ci.org/dumpk/elastcoder) 4 | [![Latest Stable Version](https://img.shields.io/packagist/v/dumpk/elastcoder.svg)](https://packagist.org/packages/dumpk/elastcoder) 5 | [![Author](https://img.shields.io/badge/author-%40nicolasbistolfi-blue.svg)](https://twitter.com/nicolasbistolfi) 6 | 7 | AWS Elastic Transcoder integration for Laravel. This is a simple wrapper if you don't want to go too deep with the [AWS SDK for PHP 3.x](http://docs.aws.amazon.com/aws-sdk-php/v3/api/index.html)!. 8 | 9 | ## Installation 10 | 11 | Require this package with composer: 12 | 13 | ``` 14 | composer require dumpk/elastcoder 15 | ``` 16 | Add the service provider to your config/app.php file: 17 | ``` 18 | Dumpk\Elastcoder\ElastcoderServiceProvider::class 19 | ``` 20 | Publish config file by running : 21 | ``` 22 | php artisan vendor:publish --tag=elastcoder 23 | ``` 24 | 25 | Add this variables to your .env with your Amazon credentials 26 | 27 | ``` 28 | AWS_ACCESS_KEY_ID={AMAZONACCESSKEY} 29 | AWS_SECRET_ACCESS_KEY={SECRETAMAZONSOMETHINGLONG} 30 | AWS_REGION={YOURREGION} 31 | ``` 32 | 33 | ## Usage 34 | 35 | Add the ElastcoderAWS class to your class header 36 | ```php 37 | use Dumpk\Elastcoder\ElastcoderAWS; 38 | ``` 39 | 40 | Now you just need to instance your class 41 | 42 | ```php 43 | $elastcoder = new ElastcoderAWS(); 44 | ``` 45 | 46 | You'll need to have your video uploaded to S3 before using this library, so that means that you already have the key for the file you want to encode. 47 | The configuration has to look like: 48 | 49 | ```php 50 | 51 | $config = [ 52 | 'PresetId' => '432423-dsda', 53 | 'width' => 1920, 54 | 'height' => 1080, 55 | 'aspect' => '16:9', 56 | 'ext' => 'mp4', 57 | 'PipelineId' => '343244232-n2fuqq4', 58 | 'Watermarks' => [[ 59 | 'PresetWatermarkId' => 'BottomRight', 60 | 'InputKey' => '1080.png', 61 | ]], 62 | 'TimeSpan' => [ 63 | 'StartTime' => '0.4', 64 | 'Duration' => '5.3' 65 | ], 66 | ] 67 | 68 | ``` 69 | 70 | There's an example file you can throw in on your config folder in dumpk/elastcoder/example/elastcoder.php remember to change the values for the pipeline and presetId you want and you have configured on your AWS account. 71 | 72 | So now you can call the transcoding function: 73 | 74 | ```php 75 | $job = $elastcoder->transcodeVideo($asset->key, $destinationKey, $config, $thumbPattern); 76 | 77 | ``` 78 | You can also transcode audio files like so : 79 | ``` 80 | $job = $elastcoder->transcodeAudio($inputfile,$uotputfile,$artwork) 81 | ``` 82 | 83 | This will return a job with an array, where you can find the "Id" of the Job, you'll need to check the job for completeness to know if your video is ready. Buy you already know that, so for your convienience you can use: 84 | 85 | ```php 86 | $job = $elastcoder->getJob($job["Id"]); 87 | 88 | ``` 89 | And check if $job['Status'] == 'complete' 90 | 91 | Also you can change the ACL of your file, because you might want to give access to everyone to see your amazing video, so: 92 | ```php 93 | $elastcoder->setPublicObject($key, $bucket); 94 | 95 | ``` 96 | 97 | If you want to be more specific about that and have different types of permissions, you can use: 98 | ```php 99 | $elastcoder->setObjectACL($key, $bucket, $acl); 100 | 101 | ``` 102 | $acl can be a string with this values => private|public-read|public-read-write|authenticated-read|bucket-owner-read|bucket-owner-full-control 103 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dumpk/elastcoder", 3 | "description": "AWS Elastic Transcoder Service Integration", 4 | "keywords": ["laravel", "aws", "transcoder", "amazon elastic transcoder"], 5 | "homepage": "http://github.com/dumpk/elastcoder", 6 | "license": "MIT", 7 | "require": { 8 | "aws/aws-sdk-php" : "~3.0", 9 | "dumpk/esetres": "0.9" 10 | }, 11 | "require-dev": { 12 | "phpunit/phpunit": "~4.0", 13 | "phpspec/phpspec": "~2.1", 14 | "laravel/laravel": "~5.1" 15 | }, 16 | "authors": [ 17 | { 18 | "name": "Nicolás Bistolfi", 19 | "email": "nbistolfi@gmail.com" 20 | } 21 | ], 22 | "autoload": { 23 | "psr-4": { 24 | "Dumpk\\Elastcoder\\": "src/" 25 | } 26 | }, 27 | "minimum-stability": "dev" 28 | } 29 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | tests/ 15 | 16 | 17 | 18 | 19 | src/ 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/ElastcoderAWS.php: -------------------------------------------------------------------------------- 1 | etc = new ElasticTranscoderClient($this->_getConfig()); 16 | } 17 | 18 | private function _getConfig() 19 | { 20 | $config = array( 21 | 'version' => 'latest', 22 | 'key' => env('AWS_ACCESS_KEY_ID', ''), 23 | 'secret' => env('AWS_SECRET_ACCESS_KEY', ''), 24 | 'region' => env('AWS_REGION', ''), 25 | 'timeout' => 3, 26 | ); 27 | 28 | return $config; 29 | } 30 | 31 | public function listJobs($PipelineId, $page = null) 32 | { 33 | return $this->etc->listJobsByPipeline([ 34 | 'Ascending' => 'false', 35 | 'PageToken' => $page, 36 | 'PipelineId' => $PipelineId, // REQUIRED 37 | ]); 38 | } 39 | 40 | public function transcodeVideo($inputKey, $destinationKey, $config, $thumbPattern = null) 41 | { 42 | $presetId = $config['PresetId']; 43 | $pipelineId = $config['PipelineId']; 44 | $watermarks = null; 45 | 46 | $input = array( 47 | 'Key' => $inputKey, 48 | ); 49 | 50 | if (isset($config['TimeSpan'])) { 51 | $input['TimeSpan'] = $config['TimeSpan']; 52 | } 53 | 54 | $output = array( 55 | 'Key' => $destinationKey, 56 | 'PresetId' => $presetId, 57 | ); 58 | 59 | if ($thumbPattern) { 60 | $output['ThumbnailPattern'] = $thumbPattern; 61 | } 62 | if (isset($config['Watermarks'])) { 63 | $output['Watermarks'] = $config['Watermarks']; 64 | } 65 | 66 | $job_config = array( 67 | 'PipelineId' => $pipelineId, 68 | 'Input' => $input, 69 | 'Output' => $output, 70 | ); 71 | 72 | $result = $this->etc->createJob($job_config); 73 | 74 | return $result['Job']; 75 | } 76 | 77 | 78 | /** 79 | * Transcode Audio files 80 | * @param $inputFile 81 | * @param $outputFile 82 | * @param $artwork 83 | * @return mixed 84 | */ 85 | public function transcodeAudio($inputFile, $outputFile, $artwork = '') 86 | { 87 | 88 | 89 | $input = [ 90 | 'Key' => $inputFile, 91 | //for clipping audio file 92 | 'TimeSpan' => [ 93 | 'StartTime' => config('elascoder.audio.StartTime'), 94 | 'Duration' => config('elastcoder.audio.Duration') 95 | ] 96 | ]; 97 | 98 | $output = [ 99 | 'Key' => $outputFile, //name of your transcoded file 100 | 'PresetId' => config('elastcoder.audio.PresetId'), 101 | ]; 102 | 103 | $albumArt = [ 104 | 'AlbumArtMerge' => config('elastcoder.audio.AlbumArtMerge'), 105 | 'AlbumArtArtwork' =>[ 106 | 'AlbumArtInputKey' => $artwork, //image you want to use as album art 107 | 'AlbumArtMaxWidth' => config('elastcoder.audio.AlbumArtMaxWidth'), 108 | 'AlbumArtMaxHeight' => config('elastcoder.audio.AlbumArtMaxHeight'), 109 | 'AlbumArtSizingPolicy' => config('elastcoder.audio.AlbumArtSizingPolicy') 110 | ] 111 | ]; 112 | 113 | $job = [ 114 | 'PipelineId' => config('elastcoder.audio.PipelineId'), 115 | 'Input' => $input, 116 | 'Output' => $output, 117 | 'AlbumArt' => $albumArt 118 | ]; 119 | 120 | $result = $this->etc->createJob($job); 121 | 122 | return $result['Job']; 123 | } 124 | 125 | public function getJob($job_id) 126 | { 127 | $result = $this->etc->readJob(array('Id' => $job_id)); 128 | if (isset($result['Job'])) { 129 | return $result['Job']; 130 | } else { 131 | return; 132 | } 133 | } 134 | 135 | /** 136 | * @deprecated 137 | */ 138 | public function uploadFile($localPath, $key, $bucket, $acl = 'public-read', $metadata = array(), $cache = 'max-age=3600', $extraOptions = array()) { 139 | 140 | return EsetresAWS::uploadFile($localPath, $key, $bucket, $acl, $metadata, $cache, $extraOptions); 141 | } 142 | 143 | /** 144 | * @deprecated 145 | */ 146 | public function getObject($key, $bucket) 147 | { 148 | return EsetresAWS::getObject($key, $bucket); 149 | } 150 | 151 | /** 152 | * @deprecated 153 | */ 154 | public function deleteObject($key, $bucket) 155 | { 156 | return EsetresAWS::deleteObject($key, $bucket); 157 | } 158 | 159 | /** 160 | * @deprecated 161 | */ 162 | public function objectExists($key, $bucket) 163 | { 164 | return EsetresAWS::objectExists($key, $bucket); 165 | } 166 | 167 | /** 168 | * @deprecated 169 | */ 170 | public function setPublicObject($key, $bucket) 171 | { 172 | return EsetresAWS::setPublicObject($key, $bucket); 173 | } 174 | 175 | /** 176 | * @deprecated 177 | */ 178 | public function setObjectACL($key, $bucket, $acl = 'public-read') 179 | { 180 | return EsetresAWS::setObjectACL($key, $bucket, $acl); 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /src/ElastcoderServiceProvider.php: -------------------------------------------------------------------------------- 1 | publishes([ 15 | __DIR__.'/config.php' => config_path('elastcoder.php'), 16 | ],'elastcoder'); 17 | } 18 | 19 | public function register() 20 | { 21 | // 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /src/config.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'example' => [ 6 | 'type' => 1, 7 | 'PresetId' => '', 8 | 'width' => 1920, 9 | 'height' => 1080, 10 | 'aspect' => '16:9', 11 | 'ext' => 'mp4', 12 | 'PipelineId' => '1434059450461-nfuqq4', 13 | 'Watermarks' => [[ 14 | 'PresetWatermarkId' => 'BottomRight', 15 | 'InputKey' => '1080.png', 16 | ]], 17 | 'TimeSpan' => [ //added for clips functionality (this is an example) 18 | 'StartTime' => '0.4', 19 | 'Duration' => '5.3' 20 | ], 21 | ], 22 | ], 23 | 24 | /* 25 | |-------------------------------------------------------------------------- 26 | | Configuration for audio transcoding 27 | |-------------------------------------------------------------------------- 28 | */ 29 | 'audio' =>[ 30 | 'PipelineId' => '', 31 | 'PresetId' => '', 32 | 'StartTime'=> '', //leave empty if you don't intend clipping |HH:mm:ss.SSS 33 | 'Duration'=> '',//leave empty if you don't intend clipping | HH:mm:ss.SSS 34 | 'container'=> 'mp3', 35 | 'OutputKeyPrefix' => '', 36 | 'AlbumArtMerge' =>'Fallback', //Replace|Prepend|Append|Fallback 37 | 'AlbumArtMaxWidth' =>'', 38 | 'AlbumArtMaxHeight' => '', 39 | 'AlbumArtSizingPolicy' => '', //AlbumArtSizingPolicy":"Fit|Fill|Stretch|Keep|ShrinkToFit|ShrinkToFill 40 | 'AlbumArtFormat' => '',//jpg|png 41 | 42 | ] 43 | 44 | ]; 45 | -------------------------------------------------------------------------------- /tests/ElastcoderTest.php: -------------------------------------------------------------------------------- 1 | listJobs(getenv('PIPELINE_ID')); 16 | $this->assertTrue(is_array($list['Jobs'])); 17 | foreach($list['Jobs'] as $job) { 18 | $this->_checkJobStructure($job); 19 | }*/ 20 | $destination_key = time().'-'.getenv('DESTINATION_KEY'); 21 | // if ($elastcoder->objectExists(getenv('KEY'), getenv('BUCKET'))) { 22 | // $elastcoder->deleteObject(getenv('KEY'), getenv('BUCKET')); 23 | // } 24 | if ($elastcoder->objectExists($destination_key, getenv('DESTINATION_BUCKET'))) { 25 | $elastcoder->deleteObject($destination_key, getenv('DESTINATION_BUCKET')); 26 | } 27 | $uploadResult = $elastcoder->uploadFile(getenv('LOCAL_FILE'), getenv('KEY'), getenv('BUCKET')); 28 | 29 | $this->assertTrue(isset($uploadResult['ObjectURL']), 'Upload file object URL result'); 30 | $objectURL = $uploadResult['ObjectURL']; 31 | $config = [ 32 | 'type' => 3, 33 | 'PresetId' => getenv('PRESET_ID'), 34 | 'width' => 1280, 35 | 'height' => 720, 36 | 'aspect' => '16:9', 37 | 'ext' => 'mp4', 38 | 'PipelineId' => getenv('PIPELINE_ID'), 39 | ]; 40 | $job = $elastcoder->transcodeVideo(getenv('KEY'), $destination_key, $config); 41 | $this->_checkJobStructure($job); 42 | $count = 0; 43 | do { 44 | sleep(5); 45 | $job = $elastcoder->getJob($job['Id']); 46 | $count++; 47 | } while($job['Status'] == 'Submitted' || $count < 5); 48 | $jobOK = FALSE; 49 | if (strtolower($job['Status']) == 'complete') { 50 | $elastcoder->setPublicObject($destination_key, getenv('DESTINATION_BUCKET')); 51 | $jobOK = TRUE; 52 | } 53 | $this->assertTrue($jobOK, 'Transcoding job completed'); 54 | $object = $elastcoder->getObject($destination_key, getenv('DESTINATION_BUCKET')); 55 | echo $object['@metadata']['effectiveUri']; 56 | } 57 | 58 | private function _checkJobStructure($job) { 59 | $this->assertTrue(isset($job['Id'])); 60 | $this->assertTrue(is_array($job['Output'])); 61 | $this->assertTrue(is_array($job['Outputs'])); 62 | $this->assertTrue(is_array($job['Input'])); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /videos/guida.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dumpk/elastcoder/bf94dc3f3e940f1d4359fa130edb9be0a8f7ea8e/videos/guida.mp4 --------------------------------------------------------------------------------