Skip to content

Commit

Permalink
NXP-29815: add an endpoint to recompute video renditions
Browse files Browse the repository at this point in the history
  • Loading branch information
charlesboidot committed Dec 1, 2020
1 parent fe638f2 commit 930e850
Show file tree
Hide file tree
Showing 110 changed files with 696 additions and 73 deletions.
Expand Up @@ -48,7 +48,9 @@
</dependency>
<dependency>
<groupId>org.nuxeo.ecm.platform</groupId>
<artifactId>nuxeo-platform-video</artifactId>
<artifactId>nuxeo-platform-video-core</artifactId>
<version>11.4-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
Expand Down
@@ -0,0 +1,109 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.nuxeo.ecm.platform</groupId>
<artifactId>nuxeo-platform-video</artifactId>
<version>11.4-SNAPSHOT</version>
</parent>

<artifactId>nuxeo-platform-video-core</artifactId>
<name>Nuxeo Platform Video Core</name>
<description>Nuxeo Platform Video provides video management to Nuxeo Web Platform and RCP. </description>

<dependencies>
<dependency>
<groupId>org.nuxeo.ecm.core</groupId>
<artifactId>nuxeo-core-api</artifactId>
</dependency>
<dependency>
<groupId>org.nuxeo.ecm.core</groupId>
<artifactId>nuxeo-core</artifactId>
</dependency>
<dependency>
<groupId>org.nuxeo.ecm.core</groupId>
<artifactId>nuxeo-core-convert-api</artifactId>
</dependency>
<dependency>
<groupId>org.nuxeo.ecm.core</groupId>
<artifactId>nuxeo-core-convert</artifactId>
</dependency>
<dependency>
<groupId>org.nuxeo.ecm.platform</groupId>
<artifactId>nuxeo-platform-convert</artifactId>
</dependency>
<dependency>
<groupId>org.nuxeo.ecm.platform</groupId>
<artifactId>nuxeo-platform-filemanager</artifactId>
</dependency>
<dependency>
<groupId>org.nuxeo.ecm.platform</groupId>
<artifactId>nuxeo-platform-types</artifactId>
</dependency>
<dependency>
<groupId>org.nuxeo.ecm.core</groupId>
<artifactId>nuxeo-core-mimetype</artifactId>
</dependency>
<dependency>
<groupId>org.nuxeo.ecm.platform</groupId>
<artifactId>nuxeo-platform-imaging-core</artifactId>
</dependency>
<dependency>
<groupId>org.nuxeo.ecm.platform</groupId>
<artifactId>nuxeo-platform-rendition-api</artifactId>
</dependency>
<dependency>
<groupId>org.nuxeo.ecm.automation</groupId>
<artifactId>nuxeo-automation-core</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>

<dependency>
<groupId>org.nuxeo.ecm.core</groupId>
<artifactId>nuxeo-core-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.nuxeo.ecm.platform</groupId>
<artifactId>nuxeo-platform-rendition-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.nuxeo.ecm.platform</groupId>
<artifactId>nuxeo-platform-tag</artifactId>
<scope>test</scope>
</dependency>
<!-- binaries data used by the tests -->
<dependency>
<groupId>org.nuxeo.ecm.platform</groupId>
<artifactId>nuxeo-platform-video-convert-test-data</artifactId>
<version>5.3.2-20100324</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<configuration>
<archive>
<manifestFile>src/test/resources/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

</project>
@@ -0,0 +1,43 @@
/*
* (C) Copyright 2020 Nuxeo (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* Charles Boidot
*/
package org.nuxeo.ecm.platform.video.service;

import static org.nuxeo.ecm.platform.video.service.RecomputeRenditionsAction.PARAM_CONVERSION_NAME;
import static org.nuxeo.ecm.platform.video.service.RecomputeRenditionsAction.PARAM_XPATH;

import java.util.List;

import org.nuxeo.ecm.core.bulk.AbstractBulkActionValidation;
import org.nuxeo.ecm.core.bulk.message.BulkCommand;

/**
* @since 11.4
*/
public class RecomputeRenditionActionValidation extends AbstractBulkActionValidation {
@Override
protected List<String> getParametersToValidate() {
return List.of(PARAM_XPATH, PARAM_CONVERSION_NAME);
}

@Override
protected void validateCommand(BulkCommand command) throws IllegalArgumentException {
String xpath = command.getParam(PARAM_XPATH);
validateXpath(PARAM_XPATH, xpath, command);
}
}
@@ -0,0 +1,179 @@
/*
* (C) Copyright 2020 Nuxeo (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* Charles Boidot
*/
package org.nuxeo.ecm.platform.video.service;

import static org.nuxeo.ecm.core.api.CoreSession.ALLOW_VERSION_WRITE;
import static org.nuxeo.ecm.core.api.versioning.VersioningService.DISABLE_AUTO_CHECKOUT;
import static org.nuxeo.ecm.core.bulk.BulkServiceImpl.STATUS_STREAM;
import static org.nuxeo.ecm.core.bulk.action.SetPropertiesAction.PARAM_DISABLE_AUDIT;
import static org.nuxeo.ecm.platform.picture.listener.PictureViewsGenerationListener.DISABLE_PICTURE_VIEWS_GENERATION_LISTENER;
import static org.nuxeo.lib.stream.computation.AbstractComputation.INPUT_1;
import static org.nuxeo.lib.stream.computation.AbstractComputation.OUTPUT_1;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.nuxeo.ecm.core.api.Blob;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.DocumentNotFoundException;
import org.nuxeo.ecm.core.api.IdRef;
import org.nuxeo.ecm.core.api.model.Property;
import org.nuxeo.ecm.core.bulk.action.computation.AbstractBulkComputation;
import org.nuxeo.ecm.core.bulk.message.BulkCommand;
import org.nuxeo.ecm.core.event.Event;
import org.nuxeo.ecm.core.event.EventService;
import org.nuxeo.ecm.core.event.impl.DocumentEventContext;
import org.nuxeo.ecm.platform.video.TranscodedVideo;
import org.nuxeo.ecm.platform.video.Video;
import org.nuxeo.ecm.platform.video.VideoConstants;
import org.nuxeo.ecm.platform.video.VideoDocument;
import org.nuxeo.ecm.platform.video.adapter.VideoDocumentAdapter;
import org.nuxeo.lib.stream.computation.Topology;
import org.nuxeo.runtime.api.Framework;
import org.nuxeo.runtime.stream.StreamProcessorTopology;

/**
* BAF Computation that fills video renditions for the blob property described
* by the given xpath.
*
* @since 11.4
*/
public class RecomputeRenditionsAction implements StreamProcessorTopology {

private static final Logger log = LogManager.getLogger(RecomputeRenditionsAction.class);

public static final String ACTION_NAME = "recomputeRenditions";

// @since 11.4
public static final String ACTION_FULL_NAME = "bulk/" + ACTION_NAME;

public static final String PARAM_XPATH = "xpath";

public static final String PARAM_CONVERSION_NAME = "conversionName";

@Override
public Topology getTopology(Map<String, String> options) {
return Topology.builder().addComputation(RecomputeRenditionsComputation::new, //
Arrays.asList(INPUT_1 + ":" + ACTION_FULL_NAME, OUTPUT_1 + ":" + STATUS_STREAM)).build();
}

public static class RecomputeRenditionsComputation extends AbstractBulkComputation {

public static final String PICTURE_VIEWS_GENERATION_DONE_EVENT = "pictureViewsGenerationDone";

protected String xpath;

protected String conversionName;

public RecomputeRenditionsComputation() {
super(ACTION_FULL_NAME);
}

@Override
public void startBucket(String bucketKey) {
BulkCommand command = getCurrentCommand();
xpath = command.getParam(PARAM_XPATH);
conversionName = command.getParam(PARAM_CONVERSION_NAME);
}

@Override
protected void compute(CoreSession session, List<String> ids, Map<String, Serializable> properties) {
log.debug("Compute action: {} for doc ids: {}", ACTION_NAME, ids);
for (String docId : ids) {
if (!session.exists(new IdRef(docId))) {
log.debug("Doc id doesn't exist: {}", docId);
continue;
}

DocumentModel workingDocument = session.getDocument(new IdRef(docId));
Property fileProp = workingDocument.getProperty(xpath);
Blob blob = (Blob) fileProp.getValue();
if (blob == null) {
// do nothing
log.debug("No blob for doc: {}", workingDocument);
continue;
}

String title = workingDocument.getTitle();
List<Map<String, Serializable>> transcodedVideos = new ArrayList<>();

try {
VideoDocument videoDoc = workingDocument.getAdapter(VideoDocument.class);
VideoService videoService = Framework.getService(VideoService.class);
Video video = videoDoc.getVideo();

List<String> conversionNames = new ArrayList<>();

if ("*".equals(conversionName)) {
// Recomputing all available renditions
for (VideoConversion conversion : videoService.getAvailableVideoConversions()) {
conversionNames.add(conversion.getName());
}
} else {
// Recomputing wanted renditions
if(conversionName.contains("-")) {
// Recomputing a specific rendition list
String[] conversions = conversionName.split("-");
for (int i = 0; i < conversions.length; i++) {
conversionNames.add(conversions[i]);
}
} else {
// Recomputing a specific rendition
conversionNames.add(conversionName);
}
}
for (String conversion : conversionNames) {
conversionName = conversion;
TranscodedVideo transcodedVideo = videoService.convert(video, conversionName);
transcodedVideos.add(transcodedVideo.toMap());

}
workingDocument.setPropertyValue(VideoConstants.TRANSCODED_VIDEOS_PROPERTY,
(Serializable) transcodedVideos);
session.saveDocument(workingDocument);
} catch (DocumentNotFoundException e) {
// a parent of the document may have been deleted.
continue;
}
if (workingDocument.isVersion()) {
workingDocument.putContextData(ALLOW_VERSION_WRITE, Boolean.TRUE);
}
workingDocument.putContextData("disableNotificationService", Boolean.TRUE);
workingDocument.putContextData(PARAM_DISABLE_AUDIT, Boolean.TRUE);
workingDocument.putContextData(DISABLE_AUTO_CHECKOUT, Boolean.TRUE);
workingDocument.putContextData("", Boolean.TRUE);
session.saveDocument(workingDocument);

DocumentEventContext ctx = new DocumentEventContext(session, session.getPrincipal(), workingDocument);
Event event = ctx.newEvent("");
Framework.getService(EventService.class).fireEvent(event);
}
}

}

}
Expand Up @@ -5,6 +5,7 @@ Bundle-SymbolicName: org.nuxeo.ecm.platform.video
Bundle-Vendor: Nuxeo
Nuxeo-Component: OSGI-INF/adapters-contrib.xml,
OSGI-INF/commandline-contrib.xml,
OSGI-INF/video-bulk-contrib.xml,
OSGI-INF/convert-service-contrib.xml,
OSGI-INF/core-types-contrib.xml,
OSGI-INF/filemanager-importer-contrib.xml,
Expand Down
@@ -0,0 +1,18 @@
<?xml version="1.0"?>
<component name="org.nuxeo.ecm.platform.video.bulk" version="1.0.0">

<require>org.nuxeo.ecm.core.bulk</require>

<extension target="org.nuxeo.ecm.core.bulk" point="actions">
<action name="recomputeRenditions" inputStream="bulk/recomputeRenditions" bucketSize="100" batchSize="50" httpEnabled="true"
validationClass="org.nuxeo.ecm.platform.video.service.RecomputeRenditionActionValidation" />
</extension>

<extension target="org.nuxeo.runtime.stream.service" point="streamProcessor">
<streamProcessor name="recomputeRenditions" class="org.nuxeo.ecm.platform.video.service.RecomputeRenditionsAction"
defaultConcurrency="2" defaultPartitions="2">
<policy name="default" maxRetries="3" delay="1s" maxDelay="10s" continueOnFailure="true" />
</streamProcessor>
</extension>

</component>
@@ -0,0 +1 @@
Bundle-SymbolicName: org.nuxeo.ecm.platform.videos.core.tests

0 comments on commit 930e850

Please sign in to comment.