Search in sources :

Example 1 with TimelinePreviewsException

use of org.opencastproject.timelinepreviews.api.TimelinePreviewsException in project opencast by opencast.

the class TimelinePreviewsServiceImpl method createPreviewsFFmpeg.

/**
 * Executes the FFmpeg command to generate a timeline previews image
 *
 * @param track the track to generate the timeline previews image for
 * @param seconds the length of a segment that one preview image should represent
 * @param width the width of a single preview image
 * @param height the height of a single preview image
 * @param tileX the horizontal number of preview images that are stored in the timeline previews image
 * @param tileY the vertical number of preview images that are stored in the timeline previews image
 * @param duration the duration for which preview images should be generated
 * @return an attachment containing the timeline previews image
 * @throws TimelinePreviewsException
 */
protected Attachment createPreviewsFFmpeg(Track track, double seconds, int width, int height, int tileX, int tileY, double duration) throws TimelinePreviewsException {
    // copy source file into workspace
    File mediaFile;
    try {
        mediaFile = workspace.get(track.getURI());
    } catch (NotFoundException e) {
        throw new TimelinePreviewsException("Error finding the media file in the workspace", e);
    } catch (IOException e) {
        throw new TimelinePreviewsException("Error reading the media file in the workspace", e);
    }
    String imageFilePath = FilenameUtils.removeExtension(mediaFile.getAbsolutePath()) + '_' + UUID.randomUUID() + "_timelinepreviews" + outputFormat;
    int exitCode = 1;
    String[] command = new String[] { binary, "-loglevel", "error", "-t", String.valueOf(duration - seconds / 2.0), "-i", mediaFile.getAbsolutePath(), "-vf", "fps=1/" + seconds + ",scale=" + width + ":" + height + ",tile=" + tileX + "x" + tileY, imageFilePath };
    logger.debug("Start timeline previews ffmpeg process: {}", StringUtils.join(command, " "));
    logger.info("Create timeline preview images file for track '{}' at {}", track.getIdentifier(), imageFilePath);
    ProcessBuilder pbuilder = new ProcessBuilder(command);
    pbuilder.redirectErrorStream(true);
    Process ffmpegProcess = null;
    exitCode = 1;
    BufferedReader errStream = null;
    try {
        ffmpegProcess = pbuilder.start();
        errStream = new BufferedReader(new InputStreamReader(ffmpegProcess.getInputStream()));
        String line = errStream.readLine();
        while (line != null) {
            logger.error("FFmpeg error: " + line);
            line = errStream.readLine();
        }
        exitCode = ffmpegProcess.waitFor();
    } catch (IOException ex) {
        throw new TimelinePreviewsException("Starting ffmpeg process failed", ex);
    } catch (InterruptedException ex) {
        throw new TimelinePreviewsException("Timeline preview creation was unexpectedly interrupted", ex);
    } finally {
        IoSupport.closeQuietly(ffmpegProcess);
        IoSupport.closeQuietly(errStream);
        if (exitCode != 0) {
            try {
                FileUtils.forceDelete(new File(imageFilePath));
            } catch (IOException e) {
            // it is ok, no output file was generated by ffmpeg
            }
        }
    }
    if (exitCode != 0)
        throw new TimelinePreviewsException("Generating timeline preview for track " + track.getIdentifier() + " failed: ffmpeg process exited abnormally with exit code " + exitCode);
    // put timeline previews image into workspace
    FileInputStream timelinepreviewsFileInputStream = null;
    URI previewsFileUri = null;
    try {
        timelinepreviewsFileInputStream = new FileInputStream(imageFilePath);
        previewsFileUri = workspace.putInCollection(COLLECTION_ID, FilenameUtils.getName(imageFilePath), timelinepreviewsFileInputStream);
        logger.info("Copied the created timeline preview images file to the workspace {}", previewsFileUri.toString());
    } catch (FileNotFoundException ex) {
        throw new TimelinePreviewsException(String.format("Timeline previews image file '%s' not found", imageFilePath), ex);
    } catch (IOException ex) {
        throw new TimelinePreviewsException(String.format("Can't write timeline preview images file '%s' to workspace", imageFilePath), ex);
    } catch (IllegalArgumentException ex) {
        throw new TimelinePreviewsException(ex);
    } finally {
        IoSupport.closeQuietly(timelinepreviewsFileInputStream);
        logger.info("Deleted local timeline preview images file at {}", imageFilePath);
        FileUtils.deleteQuietly(new File(imageFilePath));
    }
    // create media package element
    MediaPackageElementBuilder mpElementBuilder = MediaPackageElementBuilderFactory.newInstance().newElementBuilder();
    // it is up to the workflow operation handler to set the attachment flavor
    Attachment timelinepreviewsMpe = (Attachment) mpElementBuilder.elementFromURI(previewsFileUri, MediaPackageElement.Type.Attachment, track.getFlavor());
    // add reference to track
    timelinepreviewsMpe.referTo(track);
    // add additional properties to attachment
    timelinepreviewsMpe.getProperties().put("imageSizeX", String.valueOf(tileX));
    timelinepreviewsMpe.getProperties().put("imageSizeY", String.valueOf(tileY));
    timelinepreviewsMpe.getProperties().put("resolutionX", String.valueOf(resolutionX));
    timelinepreviewsMpe.getProperties().put("resolutionY", String.valueOf(resolutionY));
    // set the flavor and an ID
    timelinepreviewsMpe.setFlavor(track.getFlavor());
    timelinepreviewsMpe.setIdentifier(IdBuilderFactory.newInstance().newIdBuilder().createNew().compact());
    return timelinepreviewsMpe;
}
Also used : TimelinePreviewsException(org.opencastproject.timelinepreviews.api.TimelinePreviewsException) InputStreamReader(java.io.InputStreamReader) FileNotFoundException(java.io.FileNotFoundException) NotFoundException(org.opencastproject.util.NotFoundException) FileNotFoundException(java.io.FileNotFoundException) Attachment(org.opencastproject.mediapackage.Attachment) IOException(java.io.IOException) URI(java.net.URI) FileInputStream(java.io.FileInputStream) MediaPackageElementBuilder(org.opencastproject.mediapackage.MediaPackageElementBuilder) BufferedReader(java.io.BufferedReader) File(java.io.File)

Example 2 with TimelinePreviewsException

use of org.opencastproject.timelinepreviews.api.TimelinePreviewsException in project opencast by opencast.

the class TimelinePreviewsServiceRemote method createTimelinePreviewImages.

/**
 * Takes the given track and returns the job that will create timeline preview images using a remote service.
 *
 * @param sourceTrack the track to create preview images from
 * @param imageCount number of preview images that will be generated
 * @return a job that will create timeline preview images
 * @throws MediaPackageException if the serialization of the given track fails
 * @throws TimelinePreviewsException if the job can't be created for any reason
 */
@Override
public Job createTimelinePreviewImages(Track sourceTrack, int imageCount) throws MediaPackageException, TimelinePreviewsException {
    HttpPost post = new HttpPost("/create");
    try {
        List<BasicNameValuePair> params = new ArrayList<>();
        params.add(new BasicNameValuePair("track", MediaPackageElementParser.getAsXml(sourceTrack)));
        params.add(new BasicNameValuePair("imageCount", Integer.toString(imageCount)));
        post.setEntity(new UrlEncodedFormEntity(params));
    } catch (Exception e) {
        throw new TimelinePreviewsException(e);
    }
    HttpResponse response = null;
    try {
        response = getResponse(post);
        if (response != null) {
            try {
                Job receipt = JobParser.parseJob(response.getEntity().getContent());
                logger.info("Create timeline preview images from {}", sourceTrack);
                return receipt;
            } catch (Exception e) {
                throw new TimelinePreviewsException("Unable to create timeline preview images from " + sourceTrack + " using a remote service", e);
            }
        }
    } finally {
        closeConnection(response);
    }
    throw new TimelinePreviewsException("Unable to create timeline preview images from " + sourceTrack + " using a remote service");
}
Also used : TimelinePreviewsException(org.opencastproject.timelinepreviews.api.TimelinePreviewsException) HttpPost(org.apache.http.client.methods.HttpPost) BasicNameValuePair(org.apache.http.message.BasicNameValuePair) ArrayList(java.util.ArrayList) HttpResponse(org.apache.http.HttpResponse) UrlEncodedFormEntity(org.apache.http.client.entity.UrlEncodedFormEntity) Job(org.opencastproject.job.api.Job) TimelinePreviewsException(org.opencastproject.timelinepreviews.api.TimelinePreviewsException) MediaPackageException(org.opencastproject.mediapackage.MediaPackageException)

Example 3 with TimelinePreviewsException

use of org.opencastproject.timelinepreviews.api.TimelinePreviewsException in project opencast by opencast.

the class TimelinePreviewsWorkflowOperationHandler method start.

/**
 * {@inheritDoc}
 *
 * @see
 * org.opencastproject.workflow.api.WorkflowOperationHandler#start(org.opencastproject.workflow.api.WorkflowInstance,
 * org.opencastproject.job.api.JobContext)
 */
@Override
public WorkflowOperationResult start(WorkflowInstance workflowInstance, JobContext context) throws WorkflowOperationException {
    MediaPackage mediaPackage = workflowInstance.getMediaPackage();
    logger.info("Start timeline previews workflow operation for mediapackage {}", mediaPackage.getIdentifier().compact());
    String sourceFlavorProperty = StringUtils.trimToNull(workflowInstance.getCurrentOperation().getConfiguration(SOURCE_FLAVOR_PROPERTY));
    String sourceTagsProperty = StringUtils.trimToNull(workflowInstance.getCurrentOperation().getConfiguration(SOURCE_TAGS_PROPERTY));
    if (StringUtils.isEmpty(sourceFlavorProperty) && StringUtils.isEmpty(sourceTagsProperty)) {
        throw new WorkflowOperationException(String.format("Required property %s or %s not set", SOURCE_FLAVOR_PROPERTY, SOURCE_TAGS_PROPERTY));
    }
    String targetFlavorProperty = StringUtils.trimToNull(workflowInstance.getCurrentOperation().getConfiguration(TARGET_FLAVOR_PROPERTY));
    if (targetFlavorProperty == null) {
        throw new WorkflowOperationException(String.format("Required property %s not set", TARGET_FLAVOR_PROPERTY));
    }
    String targetTagsProperty = StringUtils.trimToNull(workflowInstance.getCurrentOperation().getConfiguration(TARGET_TAGS_PROPERTY));
    String imageSizeArg = StringUtils.trimToNull(workflowInstance.getCurrentOperation().getConfiguration(IMAGE_SIZE_PROPERTY));
    int imageSize;
    if (imageSizeArg != null) {
        try {
            imageSize = Integer.parseInt(imageSizeArg);
        } catch (NumberFormatException e) {
            imageSize = DEFAULT_IMAGE_SIZE;
            logger.info("No valid integer given for property {}, using default value: {}", IMAGE_SIZE_PROPERTY, DEFAULT_IMAGE_SIZE);
        }
    } else {
        imageSize = DEFAULT_IMAGE_SIZE;
        logger.info("Property {} not set, using default value: {}", IMAGE_SIZE_PROPERTY, DEFAULT_IMAGE_SIZE);
    }
    TrackSelector trackSelector = new TrackSelector();
    for (String flavor : asList(sourceFlavorProperty)) {
        trackSelector.addFlavor(flavor);
    }
    for (String tag : asList(sourceTagsProperty)) {
        trackSelector.addTag(tag);
    }
    Collection<Track> sourceTracks = trackSelector.select(mediaPackage, false);
    if (sourceTracks.isEmpty()) {
        logger.info("No tracks found in mediapackage {} with specified {} {}", mediaPackage.getIdentifier().compact(), SOURCE_FLAVOR_PROPERTY, sourceFlavorProperty);
        createResult(mediaPackage, WorkflowOperationResult.Action.SKIP);
    }
    List<Job> timelinepreviewsJobs = new ArrayList<Job>(sourceTracks.size());
    for (Track sourceTrack : sourceTracks) {
        try {
            // generate timeline preview images
            logger.info("Create timeline previews job for track '{}' in mediapackage '{}'", sourceTrack.getIdentifier(), mediaPackage.getIdentifier().compact());
            Job timelinepreviewsJob = timelinePreviewsService.createTimelinePreviewImages(sourceTrack, imageSize);
            timelinepreviewsJobs.add(timelinepreviewsJob);
        } catch (MediaPackageException | TimelinePreviewsException ex) {
            logger.error("Creating timeline previews job for track '{}' in media package '{}' failed with error {}", sourceTrack.getIdentifier(), mediaPackage.getIdentifier().compact(), ex.getMessage());
        }
    }
    logger.info("Wait for timeline previews jobs for media package {}", mediaPackage.getIdentifier().compact());
    if (!waitForStatus(timelinepreviewsJobs.toArray(new Job[timelinepreviewsJobs.size()])).isSuccess()) {
        cleanupWorkspace(timelinepreviewsJobs);
        throw new WorkflowOperationException(String.format("Timeline previews jobs for media package '%s' have not completed successfully", mediaPackage.getIdentifier().compact()));
    }
    try {
        // copy timeline previews attachments into workspace and add them to the media package
        for (Job job : timelinepreviewsJobs) {
            String jobPayload = job.getPayload();
            if (StringUtils.isNotEmpty(jobPayload)) {
                MediaPackageElement timelinePreviewsMpe = null;
                File timelinePreviewsFile = null;
                try {
                    timelinePreviewsMpe = MediaPackageElementParser.getFromXml(jobPayload);
                    timelinePreviewsFile = workspace.get(timelinePreviewsMpe.getURI());
                } catch (MediaPackageException ex) {
                    // unexpected job payload
                    throw new WorkflowOperationException("Can't parse timeline previews attachment from job " + job.getId());
                } catch (NotFoundException ex) {
                    throw new WorkflowOperationException("Timeline preview images file '" + timelinePreviewsMpe.getURI() + "' not found", ex);
                } catch (IOException ex) {
                    throw new WorkflowOperationException("Can't get workflow image file '" + timelinePreviewsMpe.getURI() + "' from workspace");
                }
                FileInputStream timelinePreviewsInputStream = null;
                logger.info("Put timeline preview images file {} from media package {} to the media package work space", timelinePreviewsMpe.getURI(), mediaPackage.getIdentifier().compact());
                try {
                    timelinePreviewsInputStream = new FileInputStream(timelinePreviewsFile);
                    String fileName = FilenameUtils.getName(timelinePreviewsMpe.getURI().getPath());
                    URI timelinePreviewsWfrUri = workspace.put(mediaPackage.getIdentifier().compact(), timelinePreviewsMpe.getIdentifier(), fileName, timelinePreviewsInputStream);
                    timelinePreviewsMpe.setURI(timelinePreviewsWfrUri);
                } catch (FileNotFoundException ex) {
                    throw new WorkflowOperationException("Timeline preview images file " + timelinePreviewsFile.getPath() + " not found", ex);
                } catch (IOException ex) {
                    throw new WorkflowOperationException("Can't read just created timeline preview images file " + timelinePreviewsFile.getPath(), ex);
                } catch (IllegalArgumentException ex) {
                    throw new WorkflowOperationException(ex);
                } finally {
                    IoSupport.closeQuietly(timelinePreviewsInputStream);
                }
                // set the timeline previews attachment flavor and add it to the mediapackage
                MediaPackageElementFlavor targetFlavor = MediaPackageElementFlavor.parseFlavor(targetFlavorProperty);
                if ("*".equals(targetFlavor.getType())) {
                    targetFlavor = new MediaPackageElementFlavor(timelinePreviewsMpe.getFlavor().getType(), targetFlavor.getSubtype());
                }
                if ("*".equals(targetFlavor.getSubtype())) {
                    targetFlavor = new MediaPackageElementFlavor(targetFlavor.getType(), timelinePreviewsMpe.getFlavor().getSubtype());
                }
                timelinePreviewsMpe.setFlavor(targetFlavor);
                if (!StringUtils.isEmpty(targetTagsProperty)) {
                    for (String tag : asList(targetTagsProperty)) {
                        timelinePreviewsMpe.addTag(tag);
                    }
                }
                mediaPackage.add(timelinePreviewsMpe);
            }
        }
    } finally {
        cleanupWorkspace(timelinepreviewsJobs);
    }
    logger.info("Timeline previews workflow operation for mediapackage {} completed", mediaPackage.getIdentifier().compact());
    return createResult(mediaPackage, WorkflowOperationResult.Action.CONTINUE);
}
Also used : TimelinePreviewsException(org.opencastproject.timelinepreviews.api.TimelinePreviewsException) MediaPackageException(org.opencastproject.mediapackage.MediaPackageException) TrackSelector(org.opencastproject.mediapackage.selector.TrackSelector) ArrayList(java.util.ArrayList) FileNotFoundException(java.io.FileNotFoundException) NotFoundException(org.opencastproject.util.NotFoundException) FileNotFoundException(java.io.FileNotFoundException) IOException(java.io.IOException) URI(java.net.URI) MediaPackageElementFlavor(org.opencastproject.mediapackage.MediaPackageElementFlavor) FileInputStream(java.io.FileInputStream) MediaPackageElement(org.opencastproject.mediapackage.MediaPackageElement) MediaPackage(org.opencastproject.mediapackage.MediaPackage) WorkflowOperationException(org.opencastproject.workflow.api.WorkflowOperationException) Job(org.opencastproject.job.api.Job) File(java.io.File) Track(org.opencastproject.mediapackage.Track)

Example 4 with TimelinePreviewsException

use of org.opencastproject.timelinepreviews.api.TimelinePreviewsException in project opencast by opencast.

the class TimelinePreviewsServiceImpl method generatePreviewImages.

/**
 * Starts generation of timeline preview images for the given video track
 * and returns an attachment containing one image that contains all the
 * timeline preview images.
 *
 * @param job
 * @param track the element to analyze
 * @param imageCount number of preview images that will be generated
 * @return an attachment containing the resulting timeline previews image
 * @throws TimelinePreviewsException
 * @throws org.opencastproject.mediapackage.MediaPackageException
 */
protected Attachment generatePreviewImages(Job job, Track track, int imageCount) throws TimelinePreviewsException, MediaPackageException {
    // Make sure the element can be analyzed using this analysis implementation
    if (!track.hasVideo()) {
        logger.error("Element {} is not a video track", track.getIdentifier());
        throw new TimelinePreviewsException("Element is not a video track");
    }
    try {
        if (track.getDuration() == null)
            throw new MediaPackageException("Track " + track + " does not have a duration");
        double duration = track.getDuration() / 1000.0;
        double seconds = duration / (double) (imageCount);
        seconds = seconds <= 0.0 ? 1.0 : seconds;
        // calculate number of tiles for row and column in tiled image
        int imageSize = (int) Math.ceil(Math.sqrt(imageCount));
        Attachment composedImage = createPreviewsFFmpeg(track, seconds, resolutionX, resolutionY, imageSize, imageSize, duration);
        if (composedImage == null)
            throw new IllegalStateException("Unable to compose image");
        // Set the mimetype
        try {
            composedImage.setMimeType(MimeTypes.parseMimeType(mimetype));
        } catch (IllegalArgumentException e) {
            logger.warn("Invalid mimetype provided for timeline previews image");
            try {
                composedImage.setMimeType(MimeTypes.fromURI(composedImage.getURI()));
            } catch (UnknownFileTypeException ex) {
                logger.warn("No valid mimetype could be found for timeline previews image");
            }
        }
        composedImage.getProperties().put("imageCount", String.valueOf(imageCount));
        return composedImage;
    } catch (Exception e) {
        logger.warn("Error creating timeline preview images for " + track, e);
        if (e instanceof TimelinePreviewsException) {
            throw (TimelinePreviewsException) e;
        } else {
            throw new TimelinePreviewsException(e);
        }
    }
}
Also used : TimelinePreviewsException(org.opencastproject.timelinepreviews.api.TimelinePreviewsException) MediaPackageException(org.opencastproject.mediapackage.MediaPackageException) UnknownFileTypeException(org.opencastproject.util.UnknownFileTypeException) Attachment(org.opencastproject.mediapackage.Attachment) TimelinePreviewsException(org.opencastproject.timelinepreviews.api.TimelinePreviewsException) ConfigurationException(org.osgi.service.cm.ConfigurationException) ServiceRegistryException(org.opencastproject.serviceregistry.api.ServiceRegistryException) NotFoundException(org.opencastproject.util.NotFoundException) IOException(java.io.IOException) MediaPackageException(org.opencastproject.mediapackage.MediaPackageException) FileNotFoundException(java.io.FileNotFoundException) UnknownFileTypeException(org.opencastproject.util.UnknownFileTypeException)

Aggregations

TimelinePreviewsException (org.opencastproject.timelinepreviews.api.TimelinePreviewsException)4 FileNotFoundException (java.io.FileNotFoundException)3 IOException (java.io.IOException)3 MediaPackageException (org.opencastproject.mediapackage.MediaPackageException)3 NotFoundException (org.opencastproject.util.NotFoundException)3 File (java.io.File)2 FileInputStream (java.io.FileInputStream)2 URI (java.net.URI)2 ArrayList (java.util.ArrayList)2 Job (org.opencastproject.job.api.Job)2 Attachment (org.opencastproject.mediapackage.Attachment)2 BufferedReader (java.io.BufferedReader)1 InputStreamReader (java.io.InputStreamReader)1 HttpResponse (org.apache.http.HttpResponse)1 UrlEncodedFormEntity (org.apache.http.client.entity.UrlEncodedFormEntity)1 HttpPost (org.apache.http.client.methods.HttpPost)1 BasicNameValuePair (org.apache.http.message.BasicNameValuePair)1 MediaPackage (org.opencastproject.mediapackage.MediaPackage)1 MediaPackageElement (org.opencastproject.mediapackage.MediaPackageElement)1 MediaPackageElementBuilder (org.opencastproject.mediapackage.MediaPackageElementBuilder)1