What will it take to convert one input file into multiple output formats in one configuration?

A use case would be to prepare HTML5 video files - ogg, mp4 and flv formats from one source file, or prepare different resolutions in same format or a mix of both resolutions and formats.

Current Media Mover API seems to have the file change with execution of each step and it is fed to the input of subsequent step, so if I chain like this:

  1. Select
  2. Convert
  3. Store
  4. Convert
  5. Store

Then step 3 will operate on output of step 2. If step 2 reduces resolution, step 3 will produce degraded quality of the output if it needs for example to upsample.

The solution is seemingly to do select again in step 3:

  1. Select
  2. Convert
  3. Store
  4. Select
  5. Convert
  6. Store

But this has problems - what if select #3 outputs multiple files (as select steps are designed to do that)? I think the API won't handle it properly.

Comments

arthurf’s picture

For now I would avoid trying to do this with one configuration. If you stop the step at #3 and then create a new configuration that selects files from the first configuration I think you can solve the issue.

iva2k’s picture

Ok, that is quite straightforward. The only shortcoming of separate configurations I can think of is placing the variants of the video into one field. I want the field to hold N variants, and I want to clear the field once, upon source update. A single configuration can have a "clear the field" command in step 2. If I split it into N configurations, where the "clear the field" command should be?

If it is in each configuration's step 2, then they will fight over and each will erase files from all the other configurations that ran before it.

If it is in neither of the configurations, a change in the source will not reset the output field.

I'm basing this on assumption that order of running the configurations can not be set. If the order is always the same and predetermined, AND is reset to the start every time when the source field is changed, then it is not an issue. But I think there is no mechanism to restart from beginning the auto-run configurations in cron.

I think a better solution would be to add a meta step that simply makes its output file uri taken from the first source (it is file->source_uri). Thinking further, a "source_fid" field would be also needed in the {media_mover_files} table and file object.

arthurf’s picture

I'm not quite sure I understand you about the field clearing. What I think you're asking for is creating derivatives of a source file where the container (field) of that file is the same as the storage of the derivatives- basically your source and your target are the same. This can be handled if you handle selection by checking your source URI against the media_mover_files source_uri columns. You could also filter the file selection by file extension. This would prevent the race condition. Using order of configurations isn't a way to go- there is no guaranteed order because items are generally processed by a queue worker. As far as the source_fid - the fid column in media_mover_files is this.

Personally I like to use a source specific field and a derivatives specific field but if you're not in a position to do that I think you'd need to tweak things a bit.

As far as the possibility of creating a derivative for each step instead of using multiple configurations- you'd probably need a "use source file" option on all transformation steps (ie: mm_ffmpeg), use media_mover_api_file_create_derivative() to create a first class derivative. We'd also need a state that marks a derivative as finished.

If you can filter your selection process based on file extension and source_uri/uri columns that's probably the easiest way. Otherwise it starts opening up some questions that we might want to start looking hard at media_derivatives

iva2k’s picture

>Personally I like to use a source specific field and a derivatives specific field ...
Yes, I meant exactly the same.

The challenge is that conversion step (ff_mpeg video conversion) does not provide derivatives in a single step - it spits out one file at a time as it has only one set of settings.

To reiterate:
Clearing the field has nothing to do with selection. I want to basically have a set of derivatives put into a single field (which is different from the source). From non-chaining limitation I have to create a separate configuration for each derivative, then put them all into one output field. Hence the race condition on who's clearing the old derivatives from that output field before putting all new derivatives. Think from "user changes a file on the source field" workflow perspective -> it will kick off all configurations based on this field. How do these configurations manage 1. remove all old derivatives and then 2. put all new derivatives?

Here's a flow chart:

User saves node with source video field -> mm_fields selects the file
-> ff_mpeg runs conversion to format A -> mm_fields stores the result to output field position [0]
-> ff_mpeg runs conversion to format B -> mm_fields stores the result to output field position [1]
-> ff_mpeg runs conversion to format C -> mm_fields stores the result to output field position [2]

Now user edits and saves the same node with new video in the source video field -> mm_fields selects the file
-> ff_mpeg runs conversion to format A -> mm_fields stores the result to output field position [3]
-> ff_mpeg runs conversion to format B -> mm_fields stores the result to output field position [4]
-> ff_mpeg runs conversion to format C -> mm_fields stores the result to output field position [5]

Question - which step can remove output field position [0], [1] and [2]? ffmpeg steps A, B, C are not guaranteed to run in the same order.

I hope that explains it better.

iva2k’s picture

To allow chain conversions I've added source_fid column to {media_mover_files} - it stays unchanged after the file is initially selected and allows resetting fid property. Then I added code saving source_fid in a couple of places and added a small step definition as follows:

/**
 * Implements hook_media_mover().
 */
function MYMODULE_media_mover() {
  $items = array();
  $items['MYMODULE_restart_from_source'] = array(
    'description' => t('Utility: Restart from Source'),
    'callback' => 'media_mover_api_restart_from_source',
  );
  return $items;
}

/**
 * Media Mover API - Step callback - Restart from Source file.
 * A helper step that allows to chain multiple conversions from the same source file.
 */
function MYMODULE_restart_from_source($step, $file) {
  $file->uri = $file->source_uri;
  $file->fid = empty($file->source_fid) ? FALSE : $file->source_fid;

  // return the file URI
  return $file->uri;
}

Here's a patch that does all that.

Using this chained processing I created a single configuration that takes one video file from a source field and generates 4 derivatives in one target file field for "Video for Everybody" type display (there is no limit - just use the new Restart from source step before each conversion). I further use patched MediaElement module #1933280: Medialement module should support formatting for Mediaelement.js "Video for Everybody" to create one player for that field. Works perfectly on iOS and major desktop browsers.

iva2k’s picture

Status: Active » Needs review
StatusFileSize
new5.52 KB

Sorry, clicked "svae" too soon. Here's the patch for #5.

Status: Needs review » Needs work

The last submitted patch, media_mover_chain_conversions-1928786-5.patch, failed testing.

iva2k’s picture

Status: Needs work » Needs review

To reiterate again the need for a single chained configuration - the output field is regenerated with all new derivatives if the source field changes by having the configuration reset the output field contents when first derivative is saved. Without this capability there is no way to guarantee that only latest derivatives are stored in the output field.

arthurf’s picture

Status: Needs review » Closed (fixed)

I committed this in somewhat modified form:
* I created a directory for all the functionality that I think should be moved into the core module (mm_dir, mm_compress, etc). This is now in there.
* I added a test for this new step.
* I added an update function since I changed the name of the action that you specified

arthurf’s picture

Issue summary: View changes

update