use of org.opencastproject.job.api.Job 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()));
}
}
use of org.opencastproject.job.api.Job in project opencast by opencast.
the class SeriesUpdatedEventHandler method handleEvent.
public void handleEvent(final SeriesItem seriesItem) {
// A series or its ACL has been updated. Find any mediapackages with that series, and update them.
logger.debug("Handling {}", seriesItem);
String seriesId = seriesItem.getSeriesId();
// We must be an administrative user to make this query
final User prevUser = securityService.getUser();
final Organization prevOrg = securityService.getOrganization();
try {
securityService.setUser(SecurityUtil.createSystemUser(systemAccount, prevOrg));
SearchQuery q = new SearchQuery().withSeriesId(seriesId);
SearchResult result = searchService.getForAdministrativeRead(q);
for (SearchResultItem item : result.getItems()) {
MediaPackage mp = item.getMediaPackage();
Organization org = organizationDirectoryService.getOrganization(item.getOrganization());
securityService.setOrganization(org);
// to the distribution channels as well
if (SeriesItem.Type.UpdateAcl.equals(seriesItem.getType())) {
// Build a new XACML file for this mediapackage
Attachment fileRepoCopy = authorizationService.setAcl(mp, AclScope.Series, seriesItem.getAcl()).getB();
// Distribute the updated XACML file
Job distributionJob = distributionService.distribute(CHANNEL_ID, mp, fileRepoCopy.getIdentifier());
JobBarrier barrier = new JobBarrier(null, serviceRegistry, distributionJob);
Result jobResult = barrier.waitForJobs();
if (jobResult.getStatus().get(distributionJob).equals(FINISHED)) {
mp.remove(fileRepoCopy);
mp.add(getFromXml(serviceRegistry.getJob(distributionJob.getId()).getPayload()));
} else {
logger.error("Unable to distribute XACML {}", fileRepoCopy.getIdentifier());
continue;
}
}
// Update the series dublin core
if (SeriesItem.Type.UpdateCatalog.equals(seriesItem.getType())) {
DublinCoreCatalog seriesDublinCore = seriesItem.getMetadata();
mp.setSeriesTitle(seriesDublinCore.getFirst(DublinCore.PROPERTY_TITLE));
// Update the series dublin core
Catalog[] seriesCatalogs = mp.getCatalogs(MediaPackageElements.SERIES);
if (seriesCatalogs.length == 1) {
Catalog c = seriesCatalogs[0];
String filename = FilenameUtils.getName(c.getURI().toString());
URI uri = workspace.put(mp.getIdentifier().toString(), c.getIdentifier(), filename, dublinCoreService.serialize(seriesDublinCore));
c.setURI(uri);
// setting the URI to a new source so the checksum will most like be invalid
c.setChecksum(null);
// Distribute the updated series dc
Job distributionJob = distributionService.distribute(CHANNEL_ID, mp, c.getIdentifier());
JobBarrier barrier = new JobBarrier(null, serviceRegistry, distributionJob);
Result jobResult = barrier.waitForJobs();
if (jobResult.getStatus().get(distributionJob).equals(FINISHED)) {
mp.remove(c);
mp.add(getFromXml(serviceRegistry.getJob(distributionJob.getId()).getPayload()));
} else {
logger.error("Unable to distribute series catalog {}", c.getIdentifier());
continue;
}
}
}
// Remove the series catalog and isPartOf from episode catalog
if (SeriesItem.Type.Delete.equals(seriesItem.getType())) {
mp.setSeries(null);
mp.setSeriesTitle(null);
boolean retractSeriesCatalog = retractSeriesCatalog(mp);
boolean updateEpisodeCatalog = updateEpisodeCatalog(mp);
if (!retractSeriesCatalog || !updateEpisodeCatalog)
continue;
}
// Update the search index with the modified mediapackage
Job searchJob = searchService.add(mp);
JobBarrier barrier = new JobBarrier(null, serviceRegistry, searchJob);
barrier.waitForJobs();
}
} catch (SearchException e) {
logger.warn("Unable to find mediapackages in search: ", e.getMessage());
} catch (UnauthorizedException e) {
logger.warn(e.getMessage());
} catch (MediaPackageException e) {
logger.warn(e.getMessage());
} catch (ServiceRegistryException e) {
logger.warn(e.getMessage());
} catch (NotFoundException e) {
logger.warn(e.getMessage());
} catch (IOException e) {
logger.warn(e.getMessage());
} catch (DistributionException e) {
logger.warn(e.getMessage());
} finally {
securityService.setOrganization(prevOrg);
securityService.setUser(prevUser);
}
}
use of org.opencastproject.job.api.Job in project opencast by opencast.
the class SeriesUpdatedEventHandler method retractSeriesCatalog.
private boolean retractSeriesCatalog(MediaPackage mp) throws DistributionException {
// Retract the series catalog
for (Catalog c : mp.getCatalogs(MediaPackageElements.SERIES)) {
Job retractJob = distributionService.retract(CHANNEL_ID, mp, c.getIdentifier());
JobBarrier barrier = new JobBarrier(null, serviceRegistry, retractJob);
Result jobResult = barrier.waitForJobs();
if (jobResult.getStatus().get(retractJob).equals(FINISHED)) {
mp.remove(c);
} else {
logger.error("Unable to retract series catalog {}", c.getIdentifier());
return false;
}
}
return true;
}
use of org.opencastproject.job.api.Job 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.job.api.Job in project opencast by opencast.
the class EventsLoader method addWorkflowEntry.
private void addWorkflowEntry(MediaPackage mediaPackage) throws Exception {
WorkflowDefinition def = workflowService.getWorkflowDefinitionById("full");
WorkflowInstance workflowInstance = new WorkflowInstanceImpl(def, mediaPackage, null, securityService.getUser(), securityService.getOrganization(), new HashMap<String, String>());
workflowInstance.setState(WorkflowState.SUCCEEDED);
String xml = WorkflowParser.toXml(workflowInstance);
// create job
Job job = serviceRegistry.createJob(WorkflowService.JOB_TYPE, "START_WORKFLOW", null, null, false);
job.setStatus(Status.FINISHED);
job.setPayload(xml);
job = serviceRegistry.updateJob(job);
workflowInstance.setId(job.getId());
workflowService.update(workflowInstance);
}
Aggregations