Search in sources :

Example 11 with Tuple

use of org.opencastproject.util.data.Tuple 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()));
    }
}
Also used : MultiShapeLayout(org.opencastproject.composer.layout.MultiShapeLayout) VideoStream(org.opencastproject.mediapackage.VideoStream) ArrayList(java.util.ArrayList) Dimension(org.opencastproject.composer.layout.Dimension) WorkflowOperationResult(org.opencastproject.workflow.api.WorkflowOperationResult) WorkflowOperationException(org.opencastproject.workflow.api.WorkflowOperationException) LaidOutElement(org.opencastproject.composer.api.LaidOutElement) HorizontalCoverageLayoutSpec(org.opencastproject.composer.layout.HorizontalCoverageLayoutSpec) Job(org.opencastproject.job.api.Job) Track(org.opencastproject.mediapackage.Track) Tuple(org.opencastproject.util.data.Tuple)

Example 12 with Tuple

use of org.opencastproject.util.data.Tuple 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;
}
Also used : HashMap(java.util.HashMap) TrackSelector(org.opencastproject.mediapackage.selector.TrackSelector) WorkflowOperationException(org.opencastproject.workflow.api.WorkflowOperationException) Tuple(org.opencastproject.util.data.Tuple)

Example 13 with Tuple

use of org.opencastproject.util.data.Tuple 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);
    }
}
Also used : ArrayList(java.util.ArrayList) VideoStream(org.opencastproject.mediapackage.VideoStream) EncodingProfile(org.opencastproject.composer.api.EncodingProfile) Dimension(org.opencastproject.composer.layout.Dimension) MediaPackageElementFlavor(org.opencastproject.mediapackage.MediaPackageElementFlavor) WorkflowOperationException(org.opencastproject.workflow.api.WorkflowOperationException) NotFoundException(org.opencastproject.util.NotFoundException) IOException(java.io.IOException) MediaPackageException(org.opencastproject.mediapackage.MediaPackageException) EncoderException(org.opencastproject.composer.api.EncoderException) WorkflowOperationResult(org.opencastproject.workflow.api.WorkflowOperationResult) MediaPackage(org.opencastproject.mediapackage.MediaPackage) WorkflowOperationException(org.opencastproject.workflow.api.WorkflowOperationException) Job(org.opencastproject.job.api.Job) Tuple(org.opencastproject.util.data.Tuple) Track(org.opencastproject.mediapackage.Track)

Example 14 with Tuple

use of org.opencastproject.util.data.Tuple in project opencast by opencast.

the class ToolsEndpoint method getSegments.

/**
 * Analyzes the media package and tries to get information about segments out of it.
 *
 * @param mediaPackage
 *          the media package
 * @return a list of segments or an empty list if no segments could be found.
 */
private List<Tuple<Long, Long>> getSegments(final MediaPackage mediaPackage) {
    List<Tuple<Long, Long>> segments = new ArrayList<>();
    for (Catalog smilCatalog : mediaPackage.getCatalogs(adminUIConfiguration.getSmilCatalogFlavor())) {
        try {
            Smil smil = smilService.fromXml(workspace.get(smilCatalog.getURI())).getSmil();
            segments = mergeSegments(segments, getSegmentsFromSmil(smil));
        } catch (NotFoundException e) {
            logger.warn("File '{}' could not be loaded by workspace service: {}", smilCatalog.getURI(), getStackTrace(e));
        } catch (IOException e) {
            logger.warn("Reading file '{}' from workspace service failed: {}", smilCatalog.getURI(), getStackTrace(e));
        } catch (SmilException e) {
            logger.warn("Error while parsing SMIL catalog '{}': {}", smilCatalog.getURI(), getStackTrace(e));
        }
    }
    if (!segments.isEmpty())
        return segments;
    // Read from silence detection flavors
    for (Catalog smilCatalog : mediaPackage.getCatalogs(adminUIConfiguration.getSmilSilenceFlavor())) {
        try {
            Smil smil = smilService.fromXml(workspace.get(smilCatalog.getURI())).getSmil();
            segments = mergeSegments(segments, getSegmentsFromSmil(smil));
        } catch (NotFoundException e) {
            logger.warn("File '{}' could not be loaded by workspace service: {}", smilCatalog.getURI(), getStackTrace(e));
        } catch (IOException e) {
            logger.warn("Reading file '{}' from workspace service failed: {}", smilCatalog.getURI(), getStackTrace(e));
        } catch (SmilException e) {
            logger.warn("Error while parsing SMIL catalog '{}': {}", smilCatalog.getURI(), getStackTrace(e));
        }
    }
    // Check for single segment to ignore
    if (segments.size() == 1) {
        Tuple<Long, Long> singleSegment = segments.get(0);
        if (singleSegment.getA() == 0 && singleSegment.getB() >= mediaPackage.getDuration())
            segments.remove(0);
    }
    return segments;
}
Also used : ArrayList(java.util.ArrayList) NotFoundException(org.opencastproject.util.NotFoundException) Smil(org.opencastproject.smil.entity.api.Smil) IOException(java.io.IOException) SmilException(org.opencastproject.smil.api.SmilException) Tuple(org.opencastproject.util.data.Tuple) Catalog(org.opencastproject.mediapackage.Catalog)

Example 15 with Tuple

use of org.opencastproject.util.data.Tuple in project opencast by opencast.

the class ToolsEndpointTest method testEditingInfoParse.

/**
 * Test method for {@link ToolsEndpoint.EditingInfo#parse(JSONObject)}
 */
@Test
public void testEditingInfoParse() throws Exception {
    JSONParser parser = new JSONParser();
    final EditingInfo editingInfo = ToolsEndpoint.EditingInfo.parse((JSONObject) parser.parse(IOUtils.toString(getClass().getResourceAsStream("/tools/POST-editor.json"))));
    final List<Tuple<Long, Long>> segments = editingInfo.getConcatSegments();
    assertEquals(4, segments.size());
    assertTrue(segments.contains(Tuple.tuple(0L, 2449L)));
    assertTrue(segments.contains(Tuple.tuple(4922L, 11284L)));
    assertTrue(segments.contains(Tuple.tuple(14721L, 15963L)));
    assertTrue(segments.contains(Tuple.tuple(15963L, 20132L)));
    final List<String> tracks = editingInfo.getConcatTracks();
    assertEquals(1, tracks.size());
    assertEquals(some("cut-workflow"), editingInfo.getPostProcessingWorkflow());
}
Also used : EditingInfo(org.opencastproject.adminui.endpoint.ToolsEndpoint.EditingInfo) JSONParser(org.json.simple.parser.JSONParser) Tuple(org.opencastproject.util.data.Tuple) Test(org.junit.Test)

Aggregations

Tuple (org.opencastproject.util.data.Tuple)28 ArrayList (java.util.ArrayList)11 Date (java.util.Date)9 MediaPackage (org.opencastproject.mediapackage.MediaPackage)9 NotFoundException (org.opencastproject.util.NotFoundException)8 Test (org.junit.Test)7 IOException (java.io.IOException)6 URI (java.net.URI)6 Job (org.opencastproject.job.api.Job)5 WorkflowOperationException (org.opencastproject.workflow.api.WorkflowOperationException)5 HashMap (java.util.HashMap)4 JSONObject (org.json.simple.JSONObject)4 LaidOutElement (org.opencastproject.composer.api.LaidOutElement)4 Dimension (org.opencastproject.composer.layout.Dimension)4 Catalog (org.opencastproject.mediapackage.Catalog)4 AccessControlList (org.opencastproject.security.api.AccessControlList)4 File (java.io.File)3 InputStream (java.io.InputStream)3 LinkedList (java.util.LinkedList)3 MultiShapeLayout (org.opencastproject.composer.layout.MultiShapeLayout)3