use of org.opencastproject.workflow.api.WorkflowOperationException in project opencast by opencast.
the class CoverImageWorkflowOperationHandlerBase method start.
@Override
public WorkflowOperationResult start(final WorkflowInstance workflowInstance, JobContext context) throws WorkflowOperationException {
MediaPackage mediaPackage = workflowInstance.getMediaPackage();
WorkflowOperationInstance operation = workflowInstance.getCurrentOperation();
logger.info("Cover Image Workflow started for media package '{}'", mediaPackage.getIdentifier());
// User XML metadata from operation configuration, fallback to default metadata
String xml = operation.getConfiguration(XML_METADATA);
if (xml == null) {
xml = getMetadataXml(mediaPackage);
logger.debug("Metadata was not part of operation configuration, using Dublin Core as fallback");
}
logger.debug("Metadata set to: {}", xml);
String xsl = loadXsl(operation);
logger.debug("XSL for transforming metadata to SVG loaded: {}", xsl);
// Read image dimensions
int width = getIntConfiguration(operation, WIDTH);
logger.debug("Image width set to {}px", width);
int height = getIntConfiguration(operation, HEIGHT);
logger.debug("Image height set to {}px", height);
// Read optional poster image flavor
String posterImgUri = getPosterImageFileUrl(operation.getConfiguration(POSTERIMAGE_URL));
if (posterImgUri == null)
posterImgUri = getPosterImageFileUrl(mediaPackage, operation.getConfiguration(POSTERIMAGE_FLAVOR));
if (posterImgUri == null) {
logger.debug("No optional poster image set");
} else {
logger.debug("Poster image found at '{}'", posterImgUri);
}
// Read target flavor
String targetFlavor = operation.getConfiguration(TARGET_FLAVOR);
if (StringUtils.isBlank(targetFlavor)) {
logger.warn("Required configuration key '{}' is blank", TARGET_FLAVOR);
throw new WorkflowOperationException("Configuration key '" + TARGET_FLAVOR + "' must be set");
}
try {
MediaPackageElementFlavor.parseFlavor(targetFlavor);
} catch (IllegalArgumentException e) {
logger.warn("Given target flavor '{}' is not a valid flavor", targetFlavor);
throw new WorkflowOperationException(e);
}
Job generate;
try {
generate = getCoverImageService().generateCoverImage(xml, xsl, String.valueOf(width), String.valueOf(height), posterImgUri, targetFlavor);
logger.debug("Job for cover image generation created");
if (!waitForStatus(generate).isSuccess()) {
throw new WorkflowOperationException("'Cover image' job did not successfuly end");
}
generate = serviceRegistry.getJob(generate.getId());
Attachment coverImage = (Attachment) MediaPackageElementParser.getFromXml(generate.getPayload());
URI attachmentUri = getWorkspace().moveTo(coverImage.getURI(), mediaPackage.getIdentifier().compact(), UUID.randomUUID().toString(), COVERIMAGE_FILENAME);
coverImage.setURI(attachmentUri);
coverImage.setMimeType(MimeTypes.PNG);
// Add tags
final String targetTags = StringUtils.trimToNull(operation.getConfiguration(TARGET_TAGS));
if (targetTags != null) {
for (String tag : asList(targetTags)) {
logger.trace("Tagging image with '{}'", tag);
if (StringUtils.trimToNull(tag) != null)
coverImage.addTag(tag);
}
}
mediaPackage.add(coverImage);
} catch (MediaPackageException e) {
throw new WorkflowOperationException(e);
} catch (NotFoundException e) {
throw new WorkflowOperationException(e);
} catch (ServiceRegistryException e) {
throw new WorkflowOperationException(e);
} catch (CoverImageException e) {
throw new WorkflowOperationException(e);
} catch (IllegalArgumentException e) {
throw new WorkflowOperationException(e);
} catch (IOException e) {
throw new WorkflowOperationException(e);
}
logger.info("Cover Image Workflow finished successfully for media package '{}' within {}ms", mediaPackage.getIdentifier(), generate.getQueueTime());
return createResult(mediaPackage, Action.CONTINUE, generate.getQueueTime());
}
use of org.opencastproject.workflow.api.WorkflowOperationException in project opencast by opencast.
the class CoverImageWorkflowOperationHandlerBase method getIntConfiguration.
protected int getIntConfiguration(WorkflowOperationInstance operation, String key) throws WorkflowOperationException {
String confString = operation.getConfiguration(key);
int confValue = 0;
if (StringUtils.isBlank(confString))
throw new WorkflowOperationException("Configuration key '" + key + "' must be set");
try {
confValue = Integer.parseInt(confString);
if (confValue < 1)
throw new WorkflowOperationException("Configuration key '" + key + "' must be set to a valid positive integer value");
} catch (NumberFormatException e) {
throw new WorkflowOperationException("Configuration key '" + key + "' must be set to a valid positive integer value");
}
return confValue;
}
use of org.opencastproject.workflow.api.WorkflowOperationException in project opencast by opencast.
the class CompositeWorkflowOperationHandler method composite.
private WorkflowOperationResult composite(MediaPackage src, WorkflowOperationInstance operation) throws EncoderException, IOException, NotFoundException, MediaPackageException, WorkflowOperationException {
MediaPackage mediaPackage = (MediaPackage) src.clone();
CompositeSettings compositeSettings;
try {
compositeSettings = new CompositeSettings(mediaPackage, operation);
} catch (IllegalArgumentException e) {
logger.warn("Unable to parse composite settings because {}", ExceptionUtils.getStackTrace(e));
return createResult(mediaPackage, Action.SKIP);
}
Option<Attachment> watermarkAttachment = Option.<Attachment>none();
Collection<Attachment> watermarkElements = compositeSettings.getWatermarkSelector().select(mediaPackage, false);
if (watermarkElements.size() > 1) {
logger.warn("More than one watermark attachment has been found for compositing, skipping compositing!: {}", watermarkElements);
return createResult(mediaPackage, Action.SKIP);
} else if (watermarkElements.size() == 0 && compositeSettings.getSourceUrlWatermark() != null) {
logger.info("No watermark found from flavor and tags, take watermark from URL {}", compositeSettings.getSourceUrlWatermark());
Attachment urlAttachment = new AttachmentImpl();
urlAttachment.setIdentifier(compositeSettings.getWatermarkIdentifier());
if (compositeSettings.getSourceUrlWatermark().startsWith("http")) {
urlAttachment.setURI(UrlSupport.uri(compositeSettings.getSourceUrlWatermark()));
} else {
InputStream in = null;
try {
in = UrlSupport.url(compositeSettings.getSourceUrlWatermark()).openStream();
URI imageUrl = workspace.putInCollection(COLLECTION, compositeSettings.getWatermarkIdentifier() + "." + FilenameUtils.getExtension(compositeSettings.getSourceUrlWatermark()), in);
urlAttachment.setURI(imageUrl);
} catch (Exception e) {
logger.warn("Unable to read watermark source url {}: {}", compositeSettings.getSourceUrlWatermark(), e);
throw new WorkflowOperationException("Unable to read watermark source url " + compositeSettings.getSourceUrlWatermark(), e);
} finally {
IOUtils.closeQuietly(in);
}
}
watermarkAttachment = Option.option(urlAttachment);
} else if (watermarkElements.size() == 0 && compositeSettings.getSourceUrlWatermark() == null) {
logger.info("No watermark to composite");
} else {
for (Attachment a : watermarkElements) watermarkAttachment = Option.option(a);
}
Collection<Track> upperElements = compositeSettings.getUpperTrackSelector().select(mediaPackage, false);
Collection<Track> lowerElements = compositeSettings.getLowerTrackSelector().select(mediaPackage, false);
// There is only a single track to work with.
if ((upperElements.size() == 1 && lowerElements.size() == 0) || (upperElements.size() == 0 && lowerElements.size() == 1)) {
for (Track t : upperElements) compositeSettings.setSingleTrack(t);
for (Track t : lowerElements) compositeSettings.setSingleTrack(t);
return handleSingleTrack(mediaPackage, operation, compositeSettings, watermarkAttachment);
} else {
// Look for upper elements matching the tags and flavor
if (upperElements.size() > 1) {
logger.warn("More than one upper track has been found for compositing, skipping compositing!: {}", upperElements);
return createResult(mediaPackage, Action.SKIP);
} else if (upperElements.size() == 0) {
logger.warn("No upper track has been found for compositing, skipping compositing!");
return createResult(mediaPackage, Action.SKIP);
}
for (Track t : upperElements) {
compositeSettings.setUpperTrack(t);
}
// Look for lower elements matching the tags and flavor
if (lowerElements.size() > 1) {
logger.warn("More than one lower track has been found for compositing, skipping compositing!: {}", lowerElements);
return createResult(mediaPackage, Action.SKIP);
} else if (lowerElements.size() == 0) {
logger.warn("No lower track has been found for compositing, skipping compositing!");
return createResult(mediaPackage, Action.SKIP);
}
for (Track t : lowerElements) {
compositeSettings.setLowerTrack(t);
}
return handleMultipleTracks(mediaPackage, operation, compositeSettings, watermarkAttachment);
}
}
use of org.opencastproject.workflow.api.WorkflowOperationException in project opencast by opencast.
the class CompositeWorkflowOperationHandler method createWatermarkLaidOutElement.
private Option<LaidOutElement<Attachment>> createWatermarkLaidOutElement(CompositeSettings compositeSettings, Dimension outputDimension, Option<Attachment> watermarkAttachment) throws WorkflowOperationException {
Option<LaidOutElement<Attachment>> watermarkOption = Option.<LaidOutElement<Attachment>>none();
if (watermarkAttachment.isSome() && compositeSettings.getWatermarkLayout().isSome()) {
BufferedImage image;
try {
File watermarkFile = workspace.get(watermarkAttachment.get().getURI());
image = ImageIO.read(watermarkFile);
} catch (Exception e) {
logger.warn("Unable to read the watermark image attachment {}: {}", watermarkAttachment.get().getURI(), e);
throw new WorkflowOperationException("Unable to read the watermark image attachment", e);
}
Dimension imageDimension = Dimension.dimension(image.getWidth(), image.getHeight());
List<Tuple<Dimension, AbsolutePositionLayoutSpec>> watermarkShapes = new ArrayList<Tuple<Dimension, AbsolutePositionLayoutSpec>>();
watermarkShapes.add(0, Tuple.tuple(imageDimension, compositeSettings.getWatermarkLayout().get()));
MultiShapeLayout watermarkLayout = LayoutManager.absoluteMultiShapeLayout(outputDimension, watermarkShapes);
watermarkOption = Option.some(new LaidOutElement<Attachment>(watermarkAttachment.get(), watermarkLayout.getShapes().get(0)));
}
return watermarkOption;
}
use of org.opencastproject.workflow.api.WorkflowOperationException in project opencast by opencast.
the class CompositeWorkflowOperationHandler method handleMultipleTracks.
private WorkflowOperationResult handleMultipleTracks(MediaPackage mediaPackage, WorkflowOperationInstance operation, CompositeSettings compositeSettings, Option<Attachment> watermarkAttachment) throws EncoderException, IOException, NotFoundException, MediaPackageException, WorkflowOperationException {
if (compositeSettings.getMultiSourceLayouts() == null || compositeSettings.getMultiSourceLayouts().size() == 0) {
throw new WorkflowOperationException("Multi video layout must be set! Please verify that you have a " + LAYOUT_MULTIPLE + " or " + LAYOUT + " property in your composite operation in your workflow definition to be able to handle multiple videos");
}
try {
Track upperTrack = compositeSettings.getUpperTrack();
Track lowerTrack = compositeSettings.getLowerTrack();
List<HorizontalCoverageLayoutSpec> layouts = compositeSettings.getMultiSourceLayouts();
VideoStream[] upperVideoStreams = TrackSupport.byType(upperTrack.getStreams(), VideoStream.class);
if (upperVideoStreams.length == 0) {
logger.warn("No video stream available in the upper track! {}", upperTrack);
return createResult(mediaPackage, Action.SKIP);
}
VideoStream[] lowerVideoStreams = TrackSupport.byType(lowerTrack.getStreams(), VideoStream.class);
if (lowerVideoStreams.length == 0) {
logger.warn("No video stream available in the lower track! {}", lowerTrack);
return createResult(mediaPackage, Action.SKIP);
}
// Read the video dimensions from the mediapackage stream information
Dimension upperDimensions = Dimension.dimension(upperVideoStreams[0].getFrameWidth(), upperVideoStreams[0].getFrameHeight());
Dimension lowerDimensions = Dimension.dimension(lowerVideoStreams[0].getFrameWidth(), lowerVideoStreams[0].getFrameHeight());
// Determine dimension of output
Dimension outputDimension = null;
String outputResolutionSource = compositeSettings.getOutputResolutionSource();
if (outputResolutionSource.equals(CompositeSettings.OUTPUT_RESOLUTION_FIXED)) {
outputDimension = compositeSettings.getOutputDimension();
} else if (outputResolutionSource.equals(CompositeSettings.OUTPUT_RESOLUTION_LOWER)) {
outputDimension = lowerDimensions;
} else if (outputResolutionSource.equals(CompositeSettings.OUTPUT_RESOLUTION_UPPER)) {
outputDimension = upperDimensions;
}
// Create the video layout definitions
List<Tuple<Dimension, HorizontalCoverageLayoutSpec>> shapes = new ArrayList<Tuple<Dimension, HorizontalCoverageLayoutSpec>>();
shapes.add(0, Tuple.tuple(lowerDimensions, layouts.get(0)));
shapes.add(1, Tuple.tuple(upperDimensions, layouts.get(1)));
// Calculate the layout
MultiShapeLayout multiShapeLayout = LayoutManager.multiShapeLayout(outputDimension, shapes);
// Create the laid out element for the videos
LaidOutElement<Track> lowerLaidOutElement = new LaidOutElement<Track>(lowerTrack, multiShapeLayout.getShapes().get(0));
LaidOutElement<Track> upperLaidOutElement = new LaidOutElement<Track>(upperTrack, multiShapeLayout.getShapes().get(1));
// Create the optionally laid out element for the watermark
Option<LaidOutElement<Attachment>> watermarkOption = createWatermarkLaidOutElement(compositeSettings, outputDimension, watermarkAttachment);
Job compositeJob = composerService.composite(outputDimension, Option.option(upperLaidOutElement), lowerLaidOutElement, watermarkOption, compositeSettings.getProfile().getIdentifier(), compositeSettings.getOutputBackground());
// Wait for the jobs to return
if (!waitForStatus(compositeJob).isSuccess())
throw new WorkflowOperationException("The composite job did not complete successfully");
if (compositeJob.getPayload().length() > 0) {
Track compoundTrack = (Track) MediaPackageElementParser.getFromXml(compositeJob.getPayload());
compoundTrack.setURI(workspace.moveTo(compoundTrack.getURI(), mediaPackage.getIdentifier().toString(), compoundTrack.getIdentifier(), "composite." + FilenameUtils.getExtension(compoundTrack.getURI().toString())));
// Adjust the target tags
for (String tag : compositeSettings.getTargetTags()) {
logger.trace("Tagging compound track with '{}'", tag);
compoundTrack.addTag(tag);
}
// Adjust the target flavor.
compoundTrack.setFlavor(compositeSettings.getTargetFlavor());
logger.debug("Compound track has flavor '{}'", compoundTrack.getFlavor());
// store new tracks to mediaPackage
mediaPackage.add(compoundTrack);
WorkflowOperationResult result = createResult(mediaPackage, Action.CONTINUE, compositeJob.getQueueTime());
logger.debug("Composite operation completed");
return result;
} else {
logger.info("Composite operation unsuccessful, no payload returned: {}", compositeJob);
return createResult(mediaPackage, Action.SKIP);
}
} finally {
if (compositeSettings.getSourceUrlWatermark() != null)
workspace.deleteFromCollection(COLLECTION, compositeSettings.getWatermarkIdentifier() + "." + FilenameUtils.getExtension(compositeSettings.getSourceUrlWatermark()));
}
}
Aggregations