use of org.opencastproject.workflow.api.WorkflowOperationException in project opencast by opencast.
the class ConcatWorkflowOperationHandler method getTrackSelectors.
private Map<Integer, Tuple<TrackSelector, Boolean>> getTrackSelectors(WorkflowOperationInstance operation) throws WorkflowOperationException {
Map<Integer, Tuple<TrackSelector, Boolean>> trackSelectors = new HashMap<Integer, Tuple<TrackSelector, Boolean>>();
for (String key : operation.getConfigurationKeys()) {
String tags = null;
String flavor = null;
Boolean mandatory = true;
int number = -1;
if (key.startsWith(SOURCE_TAGS_PREFIX) && !key.endsWith(MANDATORY_SUFFIX)) {
number = NumberUtils.toInt(key.substring(SOURCE_TAGS_PREFIX.length()), -1);
tags = operation.getConfiguration(key);
mandatory = BooleanUtils.toBooleanObject(operation.getConfiguration(SOURCE_TAGS_PREFIX.concat(Integer.toString(number)).concat(MANDATORY_SUFFIX)));
} else if (key.startsWith(SOURCE_FLAVOR_PREFIX) && !key.endsWith(MANDATORY_SUFFIX)) {
number = NumberUtils.toInt(key.substring(SOURCE_FLAVOR_PREFIX.length()), -1);
flavor = operation.getConfiguration(key);
mandatory = BooleanUtils.toBooleanObject(operation.getConfiguration(SOURCE_FLAVOR_PREFIX.concat(Integer.toString(number)).concat(MANDATORY_SUFFIX)));
}
if (number < 0)
continue;
Tuple<TrackSelector, Boolean> selectorTuple = trackSelectors.get(number);
if (selectorTuple == null) {
selectorTuple = Tuple.tuple(new TrackSelector(), BooleanUtils.toBooleanDefaultIfNull(mandatory, false));
} else {
selectorTuple = Tuple.tuple(selectorTuple.getA(), selectorTuple.getB() || BooleanUtils.toBooleanDefaultIfNull(mandatory, false));
}
TrackSelector trackSelector = selectorTuple.getA();
if (StringUtils.isNotBlank(tags)) {
for (String tag : StringUtils.split(tags, ",")) {
trackSelector.addTag(tag);
}
}
if (StringUtils.isNotBlank(flavor)) {
try {
trackSelector.addFlavor(flavor);
} catch (IllegalArgumentException e) {
throw new WorkflowOperationException("Source flavor '" + flavor + "' is malformed");
}
}
trackSelectors.put(number, selectorTuple);
}
return trackSelectors;
}
use of org.opencastproject.workflow.api.WorkflowOperationException in project opencast by opencast.
the class ConcatWorkflowOperationHandler method concat.
private WorkflowOperationResult concat(MediaPackage src, WorkflowOperationInstance operation) throws EncoderException, IOException, NotFoundException, MediaPackageException, WorkflowOperationException {
MediaPackage mediaPackage = (MediaPackage) src.clone();
Map<Integer, Tuple<TrackSelector, Boolean>> trackSelectors = getTrackSelectors(operation);
String outputResolution = StringUtils.trimToNull(operation.getConfiguration(OUTPUT_RESOLUTION));
String outputFrameRate = StringUtils.trimToNull(operation.getConfiguration(OUTPUT_FRAMERATE));
String encodingProfile = StringUtils.trimToNull(operation.getConfiguration(ENCODING_PROFILE));
// Skip the worklow if no source-flavors or tags has been configured
if (trackSelectors.isEmpty()) {
logger.warn("No source-tags or source-flavors has been set.");
return createResult(mediaPackage, Action.SKIP);
}
String targetTagsOption = StringUtils.trimToNull(operation.getConfiguration(TARGET_TAGS));
String targetFlavorOption = StringUtils.trimToNull(operation.getConfiguration(TARGET_FLAVOR));
// Target tags
List<String> targetTags = asList(targetTagsOption);
// Target flavor
if (targetFlavorOption == null)
throw new WorkflowOperationException("Target flavor must be set!");
// Find the encoding profile
if (encodingProfile == null)
throw new WorkflowOperationException("Encoding profile must be set!");
EncodingProfile profile = composerService.getProfile(encodingProfile);
if (profile == null)
throw new WorkflowOperationException("Encoding profile '" + encodingProfile + "' was not found");
// Output resolution
if (outputResolution == null)
throw new WorkflowOperationException("Output resolution must be set!");
Dimension outputDimension = null;
if (outputResolution.startsWith(OUTPUT_PART_PREFIX)) {
if (!trackSelectors.keySet().contains(Integer.parseInt(outputResolution.substring(OUTPUT_PART_PREFIX.length()))))
throw new WorkflowOperationException("Output resolution part not set!");
} else {
try {
String[] outputResolutionArray = StringUtils.split(outputResolution, "x");
if (outputResolutionArray.length != 2) {
throw new WorkflowOperationException("Invalid format of output resolution!");
}
outputDimension = Dimension.dimension(Integer.parseInt(outputResolutionArray[0]), Integer.parseInt(outputResolutionArray[1]));
} catch (WorkflowOperationException e) {
throw e;
} catch (Exception e) {
throw new WorkflowOperationException("Unable to parse output resolution!", e);
}
}
float fps = -1.0f;
if (StringUtils.isNotEmpty(outputFrameRate)) {
if (StringUtils.startsWith(outputFrameRate, OUTPUT_PART_PREFIX)) {
if (!NumberUtils.isNumber(outputFrameRate.substring(OUTPUT_PART_PREFIX.length())) || !trackSelectors.keySet().contains(Integer.parseInt(outputFrameRate.substring(OUTPUT_PART_PREFIX.length())))) {
throw new WorkflowOperationException("Output frame rate part not set or invalid!");
}
} else if (NumberUtils.isNumber(outputFrameRate)) {
fps = NumberUtils.toFloat(outputFrameRate);
} else {
throw new WorkflowOperationException("Unable to parse output frame rate!");
}
}
MediaPackageElementFlavor targetFlavor = null;
try {
targetFlavor = MediaPackageElementFlavor.parseFlavor(targetFlavorOption);
if ("*".equals(targetFlavor.getType()) || "*".equals(targetFlavor.getSubtype()))
throw new WorkflowOperationException("Target flavor must have a type and a subtype, '*' are not allowed!");
} catch (IllegalArgumentException e) {
throw new WorkflowOperationException("Target flavor '" + targetFlavorOption + "' is malformed");
}
List<Track> tracks = new ArrayList<Track>();
for (Entry<Integer, Tuple<TrackSelector, Boolean>> trackSelector : trackSelectors.entrySet()) {
Collection<Track> tracksForSelector = trackSelector.getValue().getA().select(mediaPackage, false);
String currentFlavor = StringUtils.join(trackSelector.getValue().getA().getFlavors());
String currentTag = StringUtils.join(trackSelector.getValue().getA().getTags());
if (tracksForSelector.size() > 1) {
logger.warn("More than one track has been found with flavor '{}' and/or tag '{}' for concat operation, skipping concatenation!", currentFlavor, currentTag);
return createResult(mediaPackage, Action.SKIP);
} else if (tracksForSelector.size() == 0 && trackSelector.getValue().getB()) {
logger.warn("No track has been found with flavor '{}' and/or tag '{}' for concat operation, skipping concatenation!", currentFlavor, currentTag);
return createResult(mediaPackage, Action.SKIP);
} else if (tracksForSelector.size() == 0 && !trackSelector.getValue().getB()) {
logger.info("No track has been found with flavor '{}' and/or tag '{}' for concat operation, skipping track!", currentFlavor, currentTag);
continue;
}
for (Track t : tracksForSelector) {
tracks.add(t);
VideoStream[] videoStreams = TrackSupport.byType(t.getStreams(), VideoStream.class);
if (videoStreams.length == 0) {
logger.info("No video stream available in the track with flavor {}! {}", currentFlavor, t);
return createResult(mediaPackage, Action.SKIP);
}
if (StringUtils.startsWith(outputResolution, OUTPUT_PART_PREFIX) && NumberUtils.isNumber(outputResolution.substring(OUTPUT_PART_PREFIX.length())) && trackSelector.getKey() == Integer.parseInt(outputResolution.substring(OUTPUT_PART_PREFIX.length()))) {
outputDimension = new Dimension(videoStreams[0].getFrameWidth(), videoStreams[0].getFrameHeight());
if (!trackSelector.getValue().getB()) {
logger.warn("Output resolution track {} must be mandatory, skipping concatenation!", outputResolution);
return createResult(mediaPackage, Action.SKIP);
}
}
if (fps <= 0 && StringUtils.startsWith(outputFrameRate, OUTPUT_PART_PREFIX) && NumberUtils.isNumber(outputFrameRate.substring(OUTPUT_PART_PREFIX.length())) && trackSelector.getKey() == Integer.parseInt(outputFrameRate.substring(OUTPUT_PART_PREFIX.length()))) {
fps = videoStreams[0].getFrameRate();
}
}
}
if (tracks.size() == 0) {
logger.warn("No tracks found for concating operation, skipping concatenation!");
return createResult(mediaPackage, Action.SKIP);
} else if (tracks.size() == 1) {
Track track = (Track) tracks.get(0).clone();
track.setIdentifier(null);
addNewTrack(mediaPackage, track, targetTags, targetFlavor);
logger.info("At least two tracks are needed for the concating operation, skipping concatenation!");
return createResult(mediaPackage, Action.SKIP);
}
Job concatJob;
if (fps > 0) {
concatJob = composerService.concat(profile.getIdentifier(), outputDimension, fps, tracks.toArray(new Track[tracks.size()]));
} else {
concatJob = composerService.concat(profile.getIdentifier(), outputDimension, tracks.toArray(new Track[tracks.size()]));
}
// Wait for the jobs to return
if (!waitForStatus(concatJob).isSuccess())
throw new WorkflowOperationException("The concat job did not complete successfully");
if (concatJob.getPayload().length() > 0) {
Track concatTrack = (Track) MediaPackageElementParser.getFromXml(concatJob.getPayload());
concatTrack.setURI(workspace.moveTo(concatTrack.getURI(), mediaPackage.getIdentifier().toString(), concatTrack.getIdentifier(), "concat." + FilenameUtils.getExtension(concatTrack.getURI().toString())));
addNewTrack(mediaPackage, concatTrack, targetTags, targetFlavor);
WorkflowOperationResult result = createResult(mediaPackage, Action.CONTINUE, concatJob.getQueueTime());
logger.debug("Concat operation completed");
return result;
} else {
logger.info("concat operation unsuccessful, no payload returned: {}", concatJob);
return createResult(mediaPackage, Action.SKIP);
}
}
use of org.opencastproject.workflow.api.WorkflowOperationException in project opencast by opencast.
the class VideoSegmenterWorkflowOperationHandler method start.
/**
* {@inheritDoc}
*
* @see org.opencastproject.workflow.api.WorkflowOperationHandler#start(org.opencastproject.workflow.api.WorkflowInstance,
* JobContext)
*/
public WorkflowOperationResult start(final WorkflowInstance workflowInstance, JobContext context) throws WorkflowOperationException {
logger.debug("Running video segmentation on workflow {}", workflowInstance.getId());
WorkflowOperationInstance operation = workflowInstance.getCurrentOperation();
MediaPackage mediaPackage = workflowInstance.getMediaPackage();
// Find movie track to analyze
String trackFlavor = StringUtils.trimToNull(operation.getConfiguration(PROP_ANALYSIS_TRACK_FLAVOR));
List<String> targetTags = asList(operation.getConfiguration(PROP_TARGET_TAGS));
List<Track> candidates = new ArrayList<Track>();
if (trackFlavor != null)
candidates.addAll(Arrays.asList(mediaPackage.getTracks(MediaPackageElementFlavor.parseFlavor(trackFlavor))));
else
candidates.addAll(Arrays.asList(mediaPackage.getTracks(MediaPackageElements.PRESENTATION_SOURCE)));
// Remove unsupported tracks (only those containing video can be segmented)
Iterator<Track> ti = candidates.iterator();
while (ti.hasNext()) {
Track t = ti.next();
if (!t.hasVideo())
ti.remove();
}
// Found one?
if (candidates.size() == 0) {
logger.info("No matching tracks available for video segmentation in workflow {}", workflowInstance);
return createResult(Action.CONTINUE);
}
// More than one left? Let's be pragmatic...
if (candidates.size() > 1) {
logger.info("Found more than one track to segment, choosing the first one ({})", candidates.get(0));
}
Track track = candidates.get(0);
// Segment the media package
Catalog mpeg7Catalog = null;
Job job = null;
try {
job = videosegmenter.segment(track);
if (!waitForStatus(job).isSuccess()) {
throw new WorkflowOperationException("Video segmentation of " + track + " failed");
}
mpeg7Catalog = (Catalog) MediaPackageElementParser.getFromXml(job.getPayload());
mediaPackage.add(mpeg7Catalog);
mpeg7Catalog.setURI(workspace.moveTo(mpeg7Catalog.getURI(), mediaPackage.getIdentifier().toString(), mpeg7Catalog.getIdentifier(), "segments.xml"));
mpeg7Catalog.setReference(new MediaPackageReferenceImpl(track));
// Add target tags
for (String tag : targetTags) {
mpeg7Catalog.addTag(tag);
}
} catch (Exception e) {
throw new WorkflowOperationException(e);
}
logger.debug("Video segmentation completed");
return createResult(mediaPackage, Action.CONTINUE, job.getQueueTime());
}
use of org.opencastproject.workflow.api.WorkflowOperationException in project opencast by opencast.
the class ConfigurablePublishWorkflowOperationHandler method start.
@Override
public WorkflowOperationResult start(WorkflowInstance workflowInstance, JobContext context) throws WorkflowOperationException {
RequireUtil.notNull(workflowInstance, "workflowInstance");
final MediaPackage mp = workflowInstance.getMediaPackage();
final WorkflowOperationInstance op = workflowInstance.getCurrentOperation();
final String channelId = StringUtils.trimToEmpty(op.getConfiguration(CHANNEL_ID_KEY));
if ("".equals(channelId)) {
throw new WorkflowOperationException("Unable to publish this mediapackage as the configuration key " + CHANNEL_ID_KEY + " is missing. Unable to determine where to publish these elements.");
}
final String urlPattern = StringUtils.trimToEmpty(op.getConfiguration(URL_PATTERN));
MimeType mimetype = null;
String mimetypeString = StringUtils.trimToEmpty(op.getConfiguration(MIME_TYPE));
if (!"".equals(mimetypeString)) {
try {
mimetype = MimeTypes.parseMimeType(mimetypeString);
} catch (IllegalArgumentException e) {
throw new WorkflowOperationException("Unable to parse the provided configuration for " + MIME_TYPE, e);
}
}
final boolean withPublishedElements = BooleanUtils.toBoolean(StringUtils.trimToEmpty(op.getConfiguration(WITH_PUBLISHED_ELEMENTS)));
boolean checkAvailability = BooleanUtils.toBoolean(StringUtils.trimToEmpty(op.getConfiguration(CHECK_AVAILABILITY)));
if (getPublications(mp, channelId).size() > 0) {
final String rePublishStrategy = StringUtils.trimToEmpty(op.getConfiguration(STRATEGY));
switch(rePublishStrategy) {
case ("fail"):
// fail is a dummy function for further distribution strategies
fail(mp);
break;
case ("merge"):
// nothing to do here. other publication strategies can be added to this list later on
break;
default:
retract(mp, channelId);
}
}
String mode = StringUtils.trimToEmpty(op.getConfiguration(MODE));
if ("".equals(mode)) {
mode = DEFAULT_MODE;
} else if (!ArrayUtils.contains(KNOWN_MODES, mode)) {
logger.error("Unknown value for configuration key mode: '{}'", mode);
throw new IllegalArgumentException("Unknown value for configuration key mode");
}
final String[] sourceFlavors = StringUtils.split(StringUtils.trimToEmpty(op.getConfiguration(SOURCE_FLAVORS)), ",");
final String[] sourceTags = StringUtils.split(StringUtils.trimToEmpty(op.getConfiguration(SOURCE_TAGS)), ",");
String publicationUUID = UUID.randomUUID().toString();
Publication publication = PublicationImpl.publication(publicationUUID, channelId, null, null);
// Configure the element selector
final SimpleElementSelector selector = new SimpleElementSelector();
for (String flavor : sourceFlavors) {
selector.addFlavor(MediaPackageElementFlavor.parseFlavor(flavor));
}
for (String tag : sourceTags) {
selector.addTag(tag);
}
if (sourceFlavors.length > 0 || sourceTags.length > 0) {
if (!withPublishedElements) {
Set<MediaPackageElement> elements = distribute(selector.select(mp, false), mp, channelId, mode, checkAvailability);
if (elements.size() > 0) {
for (MediaPackageElement element : elements) {
// Make sure the mediapackage is prompted to create a new identifier for this element
element.setIdentifier(null);
PublicationImpl.addElementToPublication(publication, element);
}
} else {
logger.info("No element found for distribution in media package '{}'", mp);
return createResult(mp, Action.CONTINUE);
}
} else {
List<MediaPackageElement> publishedElements = new ArrayList<>();
for (Publication alreadyPublished : mp.getPublications()) {
publishedElements.addAll(Arrays.asList(alreadyPublished.getAttachments()));
publishedElements.addAll(Arrays.asList(alreadyPublished.getCatalogs()));
publishedElements.addAll(Arrays.asList(alreadyPublished.getTracks()));
}
for (MediaPackageElement element : selector.select(publishedElements, false)) {
PublicationImpl.addElementToPublication(publication, element);
}
}
}
if (!"".equals(urlPattern)) {
publication.setURI(populateUrlWithVariables(urlPattern, mp, publicationUUID));
}
if (mimetype != null) {
publication.setMimeType(mimetype);
}
mp.add(publication);
return createResult(mp, Action.CONTINUE);
}
use of org.opencastproject.workflow.api.WorkflowOperationException in project opencast by opencast.
the class ConfigurablePublishWorkflowOperationHandler method populateUrlWithVariables.
/**
* Replace possible variables in the url-pattern configuration for this workflow operation handler.
*
* @param urlPattern
* The operation's template for replacing the variables.
* @param mp
* The {@link MediaPackage} used to get the event / mediapackage id.
* @param pubUUID
* The UUID for the published element.
* @return The URI of the published element with the variables replaced.
* @throws WorkflowOperationException
* Thrown if the URI is malformed after replacing the variables.
*/
public URI populateUrlWithVariables(String urlPattern, MediaPackage mp, String pubUUID) throws WorkflowOperationException {
Map<String, Object> values = new HashMap<>();
values.put(EVENT_ID_TEMPLATE_KEY, mp.getIdentifier().compact());
values.put(PUBLICATION_ID_TEMPLATE_KEY, pubUUID);
String playerPath = securityService.getOrganization().getProperties().get(PLAYER_PROPERTY);
values.put(PLAYER_PATH_TEMPLATE_KEY, playerPath);
values.put(SERIES_ID_TEMPLATE_KEY, StringUtils.trimToEmpty(mp.getSeries()));
String uriWithVariables = DocUtil.processTextTemplate("Replacing Variables in Publish URL", urlPattern, values);
URI publicationURI;
try {
publicationURI = new URI(uriWithVariables);
} catch (URISyntaxException e) {
throw new WorkflowOperationException(String.format("Unable to create URI from template '%s', replacement was: '%s'", urlPattern, uriWithVariables), e);
}
return publicationURI;
}
Aggregations