Search in sources :

Example 16 with EncoderException

use of org.opencastproject.composer.api.EncoderException 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);
    }
}
Also used : InputStream(java.io.InputStream) Attachment(org.opencastproject.mediapackage.Attachment) URI(java.net.URI) WorkflowOperationException(org.opencastproject.workflow.api.WorkflowOperationException) MediaPackageException(org.opencastproject.mediapackage.MediaPackageException) NotFoundException(org.opencastproject.util.NotFoundException) IOException(java.io.IOException) EncoderException(org.opencastproject.composer.api.EncoderException) MediaPackage(org.opencastproject.mediapackage.MediaPackage) WorkflowOperationException(org.opencastproject.workflow.api.WorkflowOperationException) AttachmentImpl(org.opencastproject.mediapackage.attachment.AttachmentImpl) Track(org.opencastproject.mediapackage.Track)

Example 17 with EncoderException

use of org.opencastproject.composer.api.EncoderException 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 18 with EncoderException

use of org.opencastproject.composer.api.EncoderException in project opencast by opencast.

the class ComposerServiceImpl method parallelEncode.

/**
 * {@inheritDoc}
 *
 * @see org.opencastproject.composer.api.ComposerService#encode(org.opencastproject.mediapackage.Track,
 *      java.lang.String)
 */
@Override
public Job parallelEncode(Track sourceTrack, String profileId) throws EncoderException, MediaPackageException {
    try {
        final EncodingProfile profile = profileScanner.getProfile(profileId);
        logger.info("Starting parallel encode with profile {} with job load {}", profileId, df.format(profile.getJobLoad()));
        return serviceRegistry.createJob(JOB_TYPE, Operation.ParallelEncode.toString(), Arrays.asList(profileId, MediaPackageElementParser.getAsXml(sourceTrack)), profile.getJobLoad());
    } catch (ServiceRegistryException e) {
        throw new EncoderException("Unable to create a job", e);
    }
}
Also used : EncoderException(org.opencastproject.composer.api.EncoderException) EncodingProfile(org.opencastproject.composer.api.EncodingProfile) ServiceRegistryException(org.opencastproject.serviceregistry.api.ServiceRegistryException)

Example 19 with EncoderException

use of org.opencastproject.composer.api.EncoderException in project opencast by opencast.

the class ComposerServiceImpl method parallelEncode.

/**
 * Encodes audio and video track to a file. If both an audio and a video track are given, they are muxed together into
 * one movie container.
 *
 * @param job
 *          Job in which context the encoding is done
 * @param mediaTrack
 *          Source track
 * @param profileId
 *          the encoding profile
 * @return the encoded track or none if the operation does not return a track. This may happen for example when doing
 *         two pass encodings where the first pass only creates metadata for the second one
 * @throws EncoderException
 *           if encoding fails
 */
private List<Track> parallelEncode(Job job, Track mediaTrack, String profileId) throws EncoderException, MediaPackageException {
    if (job == null) {
        throw new EncoderException("The Job parameter must not be null");
    }
    // Get the tracks and make sure they exist
    final File mediaFile = loadTrackIntoWorkspace(job, "source", mediaTrack);
    // Create the engine
    final EncodingProfile profile = getProfile(profileId);
    final EncoderEngine encoderEngine = getEncoderEngine();
    // List of encoded tracks
    LinkedList<Track> encodedTracks = new LinkedList<>();
    // Do the work
    int i = 0;
    Map<String, File> source = new HashMap<>();
    source.put("video", mediaFile);
    List<File> outputFiles = encoderEngine.process(source, profile, null);
    activeEncoder.remove(encoderEngine);
    for (File encodingOutput : outputFiles) {
        // Put the file in the workspace
        URI returnURL;
        final String targetTrackId = idBuilder.createNew().toString();
        try (InputStream in = new FileInputStream(encodingOutput)) {
            returnURL = workspace.putInCollection(COLLECTION, job.getId() + "-" + i + "." + FilenameUtils.getExtension(encodingOutput.getAbsolutePath()), in);
            logger.info("Copied the encoded file to the workspace at {}", returnURL);
            if (encodingOutput.delete()) {
                logger.info("Deleted the local copy of the encoded file at {}", encodingOutput.getAbsolutePath());
            } else {
                logger.warn("Unable to delete the encoding output at {}", encodingOutput);
            }
        } catch (Exception e) {
            throw new EncoderException("Unable to put the encoded file into the workspace", e);
        }
        // Have the encoded track inspected and return the result
        Job inspectionJob = inspect(job, returnURL);
        Track inspectedTrack = (Track) MediaPackageElementParser.getFromXml(inspectionJob.getPayload());
        inspectedTrack.setIdentifier(targetTrackId);
        List<String> tags = profile.getTags();
        for (String tag : tags) {
            if (encodingOutput.getName().endsWith(profile.getSuffix(tag)))
                inspectedTrack.addTag(tag);
        }
        encodedTracks.add(inspectedTrack);
        i++;
    }
    return encodedTracks;
}
Also used : HashMap(java.util.HashMap) FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) EncodingProfile(org.opencastproject.composer.api.EncodingProfile) URI(java.net.URI) LinkedList(java.util.LinkedList) FileInputStream(java.io.FileInputStream) ServiceRegistryException(org.opencastproject.serviceregistry.api.ServiceRegistryException) MediaInspectionException(org.opencastproject.inspection.api.MediaInspectionException) MediaPackageException(org.opencastproject.mediapackage.MediaPackageException) NotFoundException(org.opencastproject.util.NotFoundException) IOException(java.io.IOException) EncoderException(org.opencastproject.composer.api.EncoderException) EncoderException(org.opencastproject.composer.api.EncoderException) Job(org.opencastproject.job.api.Job) File(java.io.File) Track(org.opencastproject.mediapackage.Track)

Example 20 with EncoderException

use of org.opencastproject.composer.api.EncoderException in project opencast by opencast.

the class ComposerServiceImpl method trim.

/**
 * Trims the given track using the encoding profile <code>profileId</code> and the given starting point and duration
 * in miliseconds.
 *
 * @param job
 *          the associated job
 * @param sourceTrack
 *          the source track
 * @param profileId
 *          the encoding profile identifier
 * @param start
 *          the trimming in-point in millis
 * @param duration
 *          the trimming duration in millis
 * @return the trimmed track or none if the operation does not return a track. This may happen for example when doing
 *         two pass encodings where the first pass only creates metadata for the second one
 * @throws EncoderException
 *           if trimming fails
 */
private Option<Track> trim(Job job, Track sourceTrack, String profileId, long start, long duration) throws EncoderException {
    String targetTrackId = idBuilder.createNew().toString();
    // Get the track and make sure it exists
    final File trackFile = loadTrackIntoWorkspace(job, "source", sourceTrack);
    // Get the encoding profile
    final EncodingProfile profile = getProfile(job, profileId);
    // Create the engine
    final EncoderEngine encoderEngine = getEncoderEngine();
    File output;
    try {
        output = encoderEngine.trim(trackFile, profile, start, duration, null);
    } catch (EncoderException e) {
        Map<String, String> params = new HashMap<>();
        params.put("track", sourceTrack.getURI().toString());
        params.put("profile", profile.getIdentifier());
        params.put("start", Long.toString(start));
        params.put("duration", Long.toString(duration));
        incident().recordFailure(job, TRIMMING_FAILED, e, params, detailsFor(e, encoderEngine));
        throw e;
    } finally {
        activeEncoder.remove(encoderEngine);
    }
    // trim did not return a file
    if (!output.exists() || output.length() == 0)
        return none();
    // Put the file in the workspace
    URI workspaceURI = putToCollection(job, output, "trimmed file");
    // Have the encoded track inspected and return the result
    Job inspectionJob = inspect(job, workspaceURI);
    try {
        Track inspectedTrack = (Track) MediaPackageElementParser.getFromXml(inspectionJob.getPayload());
        inspectedTrack.setIdentifier(targetTrackId);
        return some(inspectedTrack);
    } catch (MediaPackageException e) {
        throw new EncoderException(e);
    }
}
Also used : EncoderException(org.opencastproject.composer.api.EncoderException) MediaPackageException(org.opencastproject.mediapackage.MediaPackageException) EncodingProfile(org.opencastproject.composer.api.EncodingProfile) Job(org.opencastproject.job.api.Job) File(java.io.File) Map(java.util.Map) HashMap(java.util.HashMap) URI(java.net.URI) Track(org.opencastproject.mediapackage.Track)

Aggregations

EncoderException (org.opencastproject.composer.api.EncoderException)41 Job (org.opencastproject.job.api.Job)26 IOException (java.io.IOException)19 ArrayList (java.util.ArrayList)19 MediaPackageException (org.opencastproject.mediapackage.MediaPackageException)19 EncodingProfile (org.opencastproject.composer.api.EncodingProfile)16 URI (java.net.URI)12 HashMap (java.util.HashMap)12 Track (org.opencastproject.mediapackage.Track)12 File (java.io.File)11 NotFoundException (org.opencastproject.util.NotFoundException)11 HttpResponse (org.apache.http.HttpResponse)10 UrlEncodedFormEntity (org.apache.http.client.entity.UrlEncodedFormEntity)10 HttpPost (org.apache.http.client.methods.HttpPost)10 BasicNameValuePair (org.apache.http.message.BasicNameValuePair)10 ServiceRegistryException (org.opencastproject.serviceregistry.api.ServiceRegistryException)10 Map (java.util.Map)9 MediaPackageElement (org.opencastproject.mediapackage.MediaPackageElement)7 LinkedList (java.util.LinkedList)6 POST (javax.ws.rs.POST)6