Giter Site home page Giter Site logo

nystudio107 / craft-transcoder Goto Github PK

View Code? Open in Web Editor NEW
43.0 4.0 12.0 3.8 MB

Transcode video & audio files to various formats, and provide video thumbnails

Home Page: https://nystudio107.com/plugins/transcoder

License: Other

PHP 89.47% JavaScript 0.30% CSS 1.79% Vue 0.94% Twig 3.64% Dockerfile 0.16% Makefile 1.14% TypeScript 2.56%
craftcms craft-plugin craft3 ffmpeg transcoder

craft-transcoder's Introduction

Scrutinizer Code Quality Code Coverage Build Status Code Intelligence Status

Transcoder plugin for Craft CMS 4.x

Transcode video & audio files to various formats, and provide video thumbnails

Screenshot

Note: The license fee for this plugin is $59.00 via the Craft Plugin Store.

Requirements

This plugin requires Craft CMS 4.0.0 or later.

Installation

To install Transcoder, follow these steps:

  1. Open your terminal and go to your Craft project:

     cd /path/to/project
    
  2. Then tell Composer to load the plugin:

     composer require nystudio107/craft-transcoder
    
  3. Install the plugin via ./craft install/plugin transcoder via the CLI, or in the Control Panel, go to Settings → Plugins and click the “Install” button for Transcoder.

You can also install Transcoder via the Plugin Store in the Craft Control Panel.

Transcoder works on Craft 4.x.

You will also need ffmpeg installed for Transcoder to work. On Ubuntu 16.04, you can do just:

sudo apt-get update
sudo apt-get install ffmpeg

To install ffmpeg on Centos 6/7, you can follow the guide How to Install FFmpeg on CentOS

If you have managed hosting, contact your sysadmin to get ffmpeg installed.

Documentation

Click here -> Transcoder Documentation

Transcoder Roadmap

Some things to do, and ideas for potential features:

Brought to you by nystudio107

craft-transcoder's People

Contributors

arifje avatar khalwat avatar peirix avatar urbantrout avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

craft-transcoder's Issues

[FR] GraphQL Support

I can't find anything in the documentation:
Can this plugin be used to include transcoded video url fields via GraphQL directly for an asset?

Server error generated when getFileInfo returns no data

When ffprobe can't run for some reason or there's no valid file data returned, getFileInfo() generates an server error which is not catched correctly:

screenshot 2018-10-26 at 09 40 28

Edit: for now I resolved it with:

{% set videoData = (craft.transcoder.getFileInfo(video, true)) ? craft.transcoder.getFileInfo(video, true) : false %}

But I don't know if this is the best way.

Can't get Admin CP Thumbnails generating/showing

Howdy!

Got ffmpeg and ffprobe installed. I actually am able to generate a thumbnail but I only see 2 generated in the @webroot/transcoder/thumbnail/ directory and I can't figure out how to trigger the generation. The 2 generated thumbnails also are not showing as thumbnails in the CP Assets section. Just a file icon that says .mp4.

So, a couple of questions:

  1. Is there a consistent way to trigger thumbnail generation?
  2. Can I trigger thumbnail generation for all video assets in the asset index?
  3. How do I get the thumbnails to show up and replace the file icon in the Admin CP Assets section?

Thanks!

timeInSecs of 20 seems to be the only value that works

Question

I'm testing Transcoder on a page that has five videos with

	{% set transVideoThumbUrl = craft.transcoder.getVideoThumbnailUrl(videoURL, {
	    "width": 550,
	    "height": 367,
	    "timeInSecs": 20,
	})%}

Only two of the five videos were showing images and I found that some are less than 20 seconds in length. But if I change timeInSecs to anything other than 20, I get no thumbnails for any of the videos.

I've tried values from 1 up to 30, but 20 is the only one that works. Not sure how to proceed in terms of troubleshooting this issue.

Transcoder produces an error when using environment variables for the asset volume file system path

If your asset volume "file system path" is set to an environment variable, transcoder's getAssetPath function will return an error with the message "the input value is not a valid URL". If the "file system path" is changed to use the @webroot alias or an absolute path, all functions work as expected and thumbnails will be produced and videos transcoded.

I prefer to use environment variables where possible, however I've had to change a website I'm working on to use @webroot for the time being to enable Transcoder to work.

  • Craft version: 3.4.8
  • PHP version: 7.3
  • Transcoder version: 1.2.10

Thumbnails stopped working in the CP

We've upgraded to Craft 4 a few weeks ago, and the CP isn't showing thumbnails from uploaded videos anymore. Found this in the logs:

2022-11-09 12:09:32 [web.ERROR] [nystudio107\transcoder\services\Transcode::getAssetPath] the input value is not a valid URL. {"memory":79278192}

Also, but probably not related, this on:

2022-11-09 12:09:32 [web.WARNING] [craft\elements\Asset::_dimensions] Asset 179746 is missing its width or height {"memory":79284104}

My guess this is Craft checking dimensions on an asset (type video), which should't happen.

Doesn't work :(

Nothing works :( Testing this locally. I'm hosting my assets on S3, the plugin is installed and paid for, and ffmpeg is installed at /usr/local/bin/ffmpeg. The error messages varies a bit, either it just outputs "unkown" when I'm trying to transform a video, or

  {% set fileInfo = craft.transcoder.getFileInfo(video, true) %}
  <h4>{{ fileInfo }}</h4>

gives me "Array to string conversion" (sometimes). Am I missing something?

Craft 5 Support

Do you have plans for updating this plugin for Craft 5? Thanks!

How to prevent encoded files are deleted when clearing cache?

While developing our new website I noticed encoded videos where missing after a while, but I didn't understand why. Turns out that clearing the cache also deletes ALL encoded files (images/videos).

How can I prevent these files are getting deleted? In our case it's - very - important that these files stay alive. We can't take the risk that a admin clears all cache and forgets to uncheck transcoder files manually...

Thanks!

[FR] Queue transcoding

Is it possible to queue the transcoding of video's? If we currently upload more than 1 video the ffmpeg process gets killed because the server runs out of memory.

How to: prevent new encoding after parameters/preferences change (bitrate)

As it appears, the filenames of the encoded videos are based on the SUFFIX_MAP parameters, which contains parameters like bitrate, height, width etc. In our case this is far from ideal, because when you change the bitrate, it won't match any of the encoded videos anymore and it has to be encoded again.

I'll try to explain why this is bad for us; we upload 15-20 videos on a daily base. We have thousands of videos. If we make a change to the bitrate preferences we don't want to loose all encoded videos, nor do we want to encode all these (thousands) of videos again. We just want to encode new videos we upload according to these new preferences. Videos that are already encoded should be preserved and not encoded again.

Is it possible to realise this?

AWS Elemental MediaConvert integration

I have a client needing transcoding in Craft - they're storing all of their assets on S3. This doesn't work with AWS Elemental MediaConvert, does it?

Trying to find a way to work with S3 and transcode assets there and not on the main server.

Feature request: encoding process via queue

When encoding multiple gif files to mp4, the template triggers all these ffmpeg processes at the same time. This results in 40 to 50 ffmpeg processes (in our case), which results in a smoking server and ffmpeg errors.

It would be awesome if we could prevent this, maybe by using the queue for these jobs? Then we could set a delay on these jobs so we create a spread.

[FR] Feature request: add watermark to video

Sorry for the feature-request-spamming, got another idea for this great addon. We could definately use a watermark function! :-)

I used to have a script that added a watermark on top left, right or bottom left/right, and used different images for different video dimensions, so the size of the watermark was also in ratio with the size of the video.

So, it you let users upload these images, define the path and position in config (or as parameters!) it should be easy to implement. I'm sure you know how this all works, but here's a part of the code/idea. Maybe it will help you.

/ -----------------------------------------------
// video specs 
// -----------------------------------------------

$height = $video_data['height'];         
$width = $video_data['width'];   

// -----------------------------------------------
// determine logo dimension 
// -----------------------------------------------

$logo_1080 = '/path/to/logo_1080.png';
// etc.

if ($width >= 1900) {
    $logo_argument = $logo_1080;
} elseif ($width >= 1100 ) {
    $logo_argument = $logo_720;
} elseif ($width >= 800 ) {             
    $logo_argument = $logo_480;
} elseif ($width >= 600 ) {
    $logo_argument = $logo_360; 
} elseif ($width >= 350 || $width <= 380) { 
    $logo_argument = $logo_240;                       
    
// ----------------------------------------------
// logo offset                  
// ----------------------------------------------

$position = ' ';        

// increase offset for bigger videos (preseve offset ratio)

if($logo_offset_x > 0) {

    if ($width >= 1900) $logo_offset_x *= 5; // 1080p
    elseif ($width >= 1100 ) $logo_offset_x *= 3.5; // 720p
    elseif ($width >= 800 ) $logo_offset_x *= 2.5; // 480p
    elseif ($width >= 600 ) $logo_offset_x *= 2; // 360p
    elseif ($width >= 350 || $width <= 380) $logo_offset_x *=1; // 240p
}

if($logo_offset_y > 0) {       
    if ($width >= 1900) $logo_offset_y *= 5; // 1080p
    elseif ($width >= 1100 ) $logo_offset_y *= 3.5; // 720p
    elseif ($width >= 800 ) $logo_offset_y *= 2.5; // 480p
    elseif ($width >= 600 ) $logo_offset_y *= 2; // 360p
    elseif ($width >= 350 || $width <= 380) $logo_offset_y *=1; // 240p
}

$debug_string .= "[INFO] logo offset: " . $logo_offset_x . "/" . $logo_offset_y . "\n";

// ----------------------------------------------
// logo position
// ----------------------------------------------

$position = ' ';

switch($logo_position) {
    
    case 'top_left':
        $position = 'overlay=' . $logo_offset_x . ':' . $logo_offset_y;
    break;
    
    case 'top_right':       
        $position = 'overlay=main_w-overlay_w-' . $logo_offset_x . ':' . $logo_offset_y;
    break;
    
    case 'bottom_left': 
        $position = 'overlay=' . $logo_offset_x . ':main_h-overlay_h-' . $logo_offset_y;
    break;
    
    case 'bottom_right':
        $position = 'overlay=main_w-overlay_w-' . $logo_offset_x . ':main_h-overlay_h-' . $logo_offset_y;
    break;
    
    case 'center_middle':
        $position = 'overlay=main_w/2-overlay_w/2:main_h/2-overlay_h/2';
    break;
    
    default: 
        $position = 'overlay=main_w-overlay_w-' . $logo_offset_x . ':' . $logo_offset_y;
}   


// $position string is then added to the ffmpeg encode string / command
// example;  [watermark]; [in] [watermark] ' . $position . '

Cheers!

Need information before I commit to this plugin

@khalwat, before I move forward with this plugin I just need to check off a few boxes regarding functionality. I read through the documentation, but I may not completely understand the plugin (I apologize in advance for stupid questions):

  1. Can I use this plugin to convert an uploaded mp4 to my other HTML5 video fallbacks -- webm and ogg? If yes, can the other formats be converted all at once with a single mp4 upload?
  2. My videos are currently uploaded and stored in an Amazon S3 bucket. If I upload an mp4, can the conversions be stored in the same S3 bucket?

The bottom line is that I need a convenient way to get those HTML5 video fallbacks. For my clients, I'd like to avoid hosting with YT or Vimeo and instead host videos on S3. I want to make it easy for clients to upload a single video knowing that it will function across various browsers.

Add possibility to check for encoded videos via CURL/HTTP instead of local paths

Currently all functions that are checking if an encoded version of the video/gif/audio exists, are looking for a local path, like "/content/video/encoded/video.mp4". While that might work fine when your data is on the same server, this is not te case when your content is hosted on a remote server or CDN.

In our case that path is pointing to a NFS share and NFS shares are a risk due to connection issues. Also, we have multiple backends (web) and we need to create a NFS share on each of these clients to keep this plugin working and detecting the encoded files. When the NFS server doesn't respond, all webservers freeze.

A better approach to my opinion would be to do this check with a simple CURL/HTTP request. I dirty hacked our version to test it, and it seem to work fine;

   public function getVideoUrl(string|Asset $filePath, array $videoOptions, bool $generate = true, array $encodingOptions = []): string
    {
        $result = '';
        $settings = Transcoder::$plugin->getSettings();
        $subfolder = '';
        $devMode = Craft::$app->config->getGeneral()->devMode;
         
        // Sub folder check
        if (is_object($filePath) && ($filePath instanceof Asset) && $settings['createSubfolders']) {          
            $subfolder = $filePath->folderPath;
        } else {        
            // Grab segment from URL
            $segments = explode("/", $filePath);
            $subfolder = $segments[count($segments)-2] . '/';
        }
        
        // Video options
        $videoOptions = $this->coalesceOptions('defaultVideoOptions', $videoOptions);
    
        // Get the video encoder presets to use
        $videoEncoders = $settings['videoEncoders'];
        $thisEncoder = $videoEncoders[$videoOptions['videoEncoder']];
        $videoOptions['fileSuffix'] = $thisEncoder['fileSuffix'];
                    
        // Destination video file
        $destVideoFile = $this->getFilename($filePath, $videoOptions);
                   
        // Generate video 
        if($generate) {
  
            // Encoded video URL
            $url = $settings['transcoderUrls']['video'] . $subfolder ?? $settings['transcoderUrls']['default'];
            $encodedUrl = Craft::parseEnv($url) . $destVideoFile;                    
          
            // Remote url is passed, check if it exists
            if (!is_object($filePath) && filter_var($filePath, FILTER_VALIDATE_URL)) {
                                
                // curl request
                $ch = curl_init($encodedUrl);
                curl_setopt($ch, CURLOPT_NOBODY, true);
                curl_exec($ch);
                $retcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                curl_close($ch);

                if($retcode=="200") {
                    return $encodedUrl;                      
                }         
            } 

         ....

        // Don't generate the video, check for existing encoded video, show original if there's not an encoded video            
        } else {
  
            // Encoded video URL
            $url = $settings['transcoderUrls']['video'] . $subfolder ?? $settings['transcoderUrls']['default'];
            $encodedUrl = Craft::parseEnv($url) . $destVideoFile;
            
            // Validator  
            $validator = new UrlValidator();
            $error = '';
                        
            if ($validator->validate($encodedUrl, $error)) {
    
                // curl request
                $ch = curl_init($encodedUrl);
                curl_setopt($ch, CURLOPT_NOBODY, true);
                curl_exec($ch);
                $retcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                curl_close($ch);
                                
                if($retcode=="200") {
                                        
                    $result = $encodedUrl;
                                        
                } else {
                    
                    if($devMode) {
                        echo "<div class='uk-alert'>";
                        echo "<div class='uk-padding-small'>Can't find remote encoded URL:<br><br>$encodedUrl <br><br>Showing original video asset</div>";
                        echo "</div>";                        
                    }
                    
                    $result = "";
                }
            }
        }

Would be awesome if this could be integrated as an option/setting preference.

Undefined index: subtitle

Random video upload caused this error, probably got something to do with the encoding type/meta data;

screenshot 2019-02-11 at 12 18 26

WebM generates an empty video file, H264 works as expected.

Describe the bug

I'm using the transcoder plugin inside of a custom Craft module.

The plugin produces an empty video file when I transcode a video using the default WebM config.
However, if I use the default h264 config, the plugin works as expected.

Here is a cut-down version of the module:

public function actionIndex()
{
	$id = Craft::$app->request->get('id');

	if (!$id) {
		throw new \Exception('ID parameter is required.');
	}

	$asset = Asset::find()->id($id)->one();

	if (!$asset) {
		throw new \Exception("Asset matching ID '{$id}' not found.");
	}

	$transcoder = Craft::$app->plugins->getPlugin('transcoder');

	if (!$transcoder || !($transcoder instanceof Transcoder)) {
		throw new \Exception('Transcoder plugin not found.');
	}

	$url = $transcoder->transcode->getVideoUrl($asset, [
		'videoEncoder' => 'webm',
	]);

	return $this->asJson([
		'src' => $url,
	]);
}

If I manually run FFMPEG inside the ddev container, the video is transcoded to WebM as expected, so I don't believe FFMPEG is the issue.

Expected behaviour

A WebM version of the video asset is to be generated.

Versions

  • DDEV version: 1.22.7
  • PHP: 8.2.15
  • Plugin version: 4.0.1
  • Craft version: 4.7.4
  • FFMPEG version: 4.3.6

[FR] Possibility to store asset data in database?

Hi,

During the development of our new website we noticed a huge slowdown/lag in case of multiple videos on a page. Not only during initial encoding, but also everytime getFileInfo() is fired, which we use for grabbing dimensions.

Two thoughts;

  1. can we push the encoding part to the background, so the page will still be loaded instead or timing out eventually?
  2. is it possible to store file info (dimensions, filesize etc.) in the database, so we don't have to read the files/assets from our CDN.

Thanks in advance!

Nothing Works (transVideoUrl, "auto-generated" video thumbnails, progress URLs, etc.)

Hello,

I followed the installation instructions for the server installation, paid for the plugin, and copied the syntax exactly, however, I cannot get ANYTHING to work.

My syntax is as follows:

`{% for video in block.file_asset %}

Progress URL: {{ progressUrl }}

{% endfor %}`

The videos are stored in an S3 volume, and i can get the links to work regular just fine by using {{ video.getUrl() }} so I know the assets are working. The thumbnails in the asset manager are also not showing up, as described as an automatic process in the plugin description...

The Craft installation is on Ubuntu 18-04 running PHP 7.1 and managed through Server Pilot.
This is for a high-end video production company, so this feature is very important. The source videos are already in .MP4 format, but eventually will need to convert .MOV files into .MP4 if this plugin truly does work.

Any suggestions? Where do I go from here?

Suggestion: Reduce the 'timeInSecs' default for thumbnail options to prevent CP thumbnail errors

Currently the timeInSecs config option within defaultThumbnailOptions is set to 10 seconds. If a video is uploaded which is less than 10 seconds, thumbnails will fail to generate automatically in the CP unless the setting is explicitly changed by the user in their transcoder config file. A more failsafe default might be 1 second.

One recent site I was working on involved only sub-10 second videos intended to autoplay and loop in the browser alongside images. I couldn't work out why they were failing and always returning an internal server error in the console when in the CP. I discovered that it was due to the 10 second default causing ffmpeg to return an error (not an issue within templates as I was setting the timeInSecs in the options).

Other users may stumble on this like I did, and may just think it's not working altogether, so updating the default might help that.

How to access transcoder on API level

Not a bug, but more a request for example; I want to access the Transcoder methods from another plugin (Elements API) and I don't know how.

I tried to access services:

$transcoderService = \nystudio107\transcoder\Transcoder::$plugin->getInstance();
$transcoderService->Transcode->getVideoUrl();

But no luck.

Thanks in advance!

Videos not loading

Question

Hello,
My videos do not seem to be transcoding. The progress url outputs this.
,"duration":"unknown","time":0,"progress":"unknown","message":"encoding GIF, can't determine duration"}

What can cause this? It seems like the transcoding isn't starting at all. ffmpeg has been installed via Plesk. The log file shows nothing strange on first glance

Thank you,

[FR] - AWS S3 Storage

Is there an easy way of setting an S3 Volume as the transcoderPaths? I assume I could then set transcoderUrls to then use a CloudFront URL if this functionality is there.

Transcoder doesn't create thumbs of videos in portrait orientation

Describe the bug

As the title says, Transcoder doesn't create thumbs of videos in portrait orientation using the code below:

{% set videoURL = "#{imageServerUrl}/reviews/#{productUrl}/#{sampleMoviesDir}/#{row.ReviewSampleMovieFileName}" %}
{% set transVideoThumbUrl = craft.transcoder.getVideoThumbnailUrl(videoURL, {
    "width": 550,
    "height": 367,
    "timeInSecs": 2,
})%}

<img src="{{transVideoThumbUrl}}">

Videos in landscape orientation are fine. I can provide a link to a page that demonstrates the problem but would prefer to share the link privately.

Versions

  • Plugin version: 1.2.14
  • Craft version: 3.5.19.1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.