Search in sources :

Example 1 with Video

use of org.opencastproject.metadata.mpeg7.Video in project opencast by opencast.

the class SolrIndexManager method addMpeg7Metadata.

/**
 * Add the mpeg 7 catalog data to the solr document.
 *
 * @param doc
 *          the input document to the solr index
 * @param mpeg7
 *          the mpeg7 catalog
 */
@SuppressWarnings("unchecked")
static void addMpeg7Metadata(SolrInputDocument doc, MediaPackage mediaPackage, Mpeg7Catalog mpeg7) {
    // Check for multimedia content
    if (!mpeg7.multimediaContent().hasNext()) {
        logger.warn("Mpeg-7 doesn't contain  multimedia content");
        return;
    }
    // Get the content duration by looking at the first content track. This
    // of course assumes that all tracks are equally long.
    MultimediaContent<? extends MultimediaContentType> mc = mpeg7.multimediaContent().next();
    MultimediaContentType mct = mc.elements().next();
    MediaTime mediaTime = mct.getMediaTime();
    Schema.setDcExtent(doc, mediaTime.getMediaDuration().getDurationInMilliseconds());
    // Check if the keywords have been filled by (manually) added dublin
    // core data. If not, look for the most relevant fields in mpeg-7.
    SortedSet<TextAnnotation> sortedAnnotations = null;
    if (!"".equals(Schema.getOcKeywords(doc))) {
        sortedAnnotations = new TreeSet<TextAnnotation>(new Comparator<TextAnnotation>() {

            @Override
            public int compare(TextAnnotation a1, TextAnnotation a2) {
                if ((RELEVANCE_BOOST * a1.getRelevance() + a1.getConfidence()) > (RELEVANCE_BOOST * a2.getRelevance() + a2.getConfidence()))
                    return -1;
                else if ((RELEVANCE_BOOST * a1.getRelevance() + a1.getConfidence()) < (RELEVANCE_BOOST * a2.getRelevance() + a2.getConfidence()))
                    return 1;
                return 0;
            }
        });
    }
    // Iterate over the tracks and extract keywords and hints
    Iterator<MultimediaContent<? extends MultimediaContentType>> mmIter = mpeg7.multimediaContent();
    int segmentCount = 0;
    while (mmIter.hasNext()) {
        MultimediaContent<?> multimediaContent = mmIter.next();
        // We need to process visual segments first, due to the way they are handled in the ui.
        for (Iterator<?> iterator = multimediaContent.elements(); iterator.hasNext(); ) {
            MultimediaContentType type = (MultimediaContentType) iterator.next();
            if (!(type instanceof Video) && !(type instanceof AudioVisual))
                continue;
            // for every segment in the current multimedia content track
            Video video = (Video) type;
            Iterator<VideoSegment> vsegments = (Iterator<VideoSegment>) video.getTemporalDecomposition().segments();
            while (vsegments.hasNext()) {
                VideoSegment segment = vsegments.next();
                StringBuffer segmentText = new StringBuffer();
                StringBuffer hintField = new StringBuffer();
                // Collect the video text elements to a segment text
                SpatioTemporalDecomposition spt = segment.getSpatioTemporalDecomposition();
                if (spt != null) {
                    for (VideoText videoText : spt.getVideoText()) {
                        if (segmentText.length() > 0)
                            segmentText.append(" ");
                        segmentText.append(videoText.getText().getText());
                    // TODO: Add hint on bounding box
                    }
                }
                // Add keyword annotations
                Iterator<TextAnnotation> textAnnotations = segment.textAnnotations();
                while (textAnnotations.hasNext()) {
                    TextAnnotation textAnnotation = textAnnotations.next();
                    Iterator<?> kwIter = textAnnotation.keywordAnnotations();
                    while (kwIter.hasNext()) {
                        KeywordAnnotation keywordAnnotation = (KeywordAnnotation) kwIter.next();
                        if (segmentText.length() > 0)
                            segmentText.append(" ");
                        segmentText.append(keywordAnnotation.getKeyword());
                    }
                }
                // Add free text annotations
                Iterator<TextAnnotation> freeIter = segment.textAnnotations();
                if (freeIter.hasNext()) {
                    Iterator<FreeTextAnnotation> freeTextIter = freeIter.next().freeTextAnnotations();
                    while (freeTextIter.hasNext()) {
                        FreeTextAnnotation freeTextAnnotation = freeTextIter.next();
                        if (segmentText.length() > 0)
                            segmentText.append(" ");
                        segmentText.append(freeTextAnnotation.getText());
                    }
                }
                // add segment text to solr document
                Schema.setSegmentText(doc, new DField<String>(segmentText.toString(), Integer.toString(segmentCount)));
                // get the segments time properties
                MediaTimePoint timepoint = segment.getMediaTime().getMediaTimePoint();
                MediaDuration duration = segment.getMediaTime().getMediaDuration();
                // TODO: define a class with hint field constants
                hintField.append("time=" + timepoint.getTimeInMilliseconds() + "\n");
                hintField.append("duration=" + duration.getDurationInMilliseconds() + "\n");
                // Look for preview images. Their characteristics are that they are
                // attached as attachments with a flavor of preview/<something>.
                String time = timepoint.toString();
                for (Attachment slide : mediaPackage.getAttachments(MediaPackageElements.PRESENTATION_SEGMENT_PREVIEW)) {
                    MediaPackageReference ref = slide.getReference();
                    if (ref != null && time.equals(ref.getProperty("time"))) {
                        hintField.append("preview");
                        hintField.append(".");
                        hintField.append(ref.getIdentifier());
                        hintField.append("=");
                        hintField.append(slide.getURI().toString());
                        hintField.append("\n");
                    }
                }
                logger.trace("Adding segment: " + timepoint.toString());
                Schema.setSegmentHint(doc, new DField<String>(hintField.toString(), Integer.toString(segmentCount)));
                // increase segment counter
                segmentCount++;
            }
        }
    }
    // Put the most important keywords into a special solr field
    if (sortedAnnotations != null) {
        Schema.setOcKeywords(doc, importantKeywordsString(sortedAnnotations).toString());
    }
}
Also used : Attachment(org.opencastproject.mediapackage.Attachment) VideoText(org.opencastproject.metadata.mpeg7.VideoText) FreeTextAnnotation(org.opencastproject.metadata.mpeg7.FreeTextAnnotation) Comparator(java.util.Comparator) Iterator(java.util.Iterator) KeywordAnnotation(org.opencastproject.metadata.mpeg7.KeywordAnnotation) TextAnnotation(org.opencastproject.metadata.mpeg7.TextAnnotation) FreeTextAnnotation(org.opencastproject.metadata.mpeg7.FreeTextAnnotation) AudioVisual(org.opencastproject.metadata.mpeg7.AudioVisual) MultimediaContentType(org.opencastproject.metadata.mpeg7.MultimediaContentType) SpatioTemporalDecomposition(org.opencastproject.metadata.mpeg7.SpatioTemporalDecomposition) MediaTimePoint(org.opencastproject.metadata.mpeg7.MediaTimePoint) MediaTimePoint(org.opencastproject.metadata.mpeg7.MediaTimePoint) MediaPackageReference(org.opencastproject.mediapackage.MediaPackageReference) VideoSegment(org.opencastproject.metadata.mpeg7.VideoSegment) Video(org.opencastproject.metadata.mpeg7.Video) MediaTime(org.opencastproject.metadata.mpeg7.MediaTime) MediaDuration(org.opencastproject.metadata.mpeg7.MediaDuration) MultimediaContent(org.opencastproject.metadata.mpeg7.MultimediaContent)

Example 2 with Video

use of org.opencastproject.metadata.mpeg7.Video in project opencast by opencast.

the class SegmentPreviewsWorkflowOperationHandler method createPreviews.

/**
 * Encode tracks from MediaPackage using profiles stored in properties and updates current MediaPackage.
 *
 * @param mediaPackage
 * @param properties
 * @return the operation result containing the updated mediapackage
 * @throws EncoderException
 * @throws ExecutionException
 * @throws InterruptedException
 * @throws IOException
 * @throws NotFoundException
 * @throws WorkflowOperationException
 */
private WorkflowOperationResult createPreviews(final MediaPackage mediaPackage, WorkflowOperationInstance operation) throws EncoderException, InterruptedException, ExecutionException, NotFoundException, MediaPackageException, IOException, WorkflowOperationException {
    long totalTimeInQueue = 0;
    // Read the configuration properties
    String sourceVideoFlavor = StringUtils.trimToNull(operation.getConfiguration("source-flavor"));
    String sourceTags = StringUtils.trimToNull(operation.getConfiguration("source-tags"));
    String targetImageTags = StringUtils.trimToNull(operation.getConfiguration("target-tags"));
    String targetImageFlavor = StringUtils.trimToNull(operation.getConfiguration("target-flavor"));
    String encodingProfileName = StringUtils.trimToNull(operation.getConfiguration("encoding-profile"));
    String referenceFlavor = StringUtils.trimToNull(operation.getConfiguration("reference-flavor"));
    String referenceTags = StringUtils.trimToNull(operation.getConfiguration("reference-tags"));
    // Find the encoding profile
    EncodingProfile profile = composerService.getProfile(encodingProfileName);
    if (profile == null)
        throw new IllegalStateException("Encoding profile '" + encodingProfileName + "' was not found");
    List<String> sourceTagSet = asList(sourceTags);
    // Select the tracks based on the tags and flavors
    Set<Track> videoTrackSet = new HashSet<>();
    for (Track track : mediaPackage.getTracksByTags(sourceTagSet)) {
        if (sourceVideoFlavor == null || (track.getFlavor() != null && sourceVideoFlavor.equals(track.getFlavor().toString()))) {
            if (!track.hasVideo())
                continue;
            videoTrackSet.add(track);
        }
    }
    if (videoTrackSet.size() == 0) {
        logger.debug("Mediapackage {} has no suitable tracks to extract images based on tags {} and flavor {}", mediaPackage, sourceTags, sourceVideoFlavor);
        return createResult(mediaPackage, Action.CONTINUE);
    } else {
        // Determine the tagset for the reference
        List<String> referenceTagSet = asList(referenceTags);
        // Determine the reference master
        for (Track t : videoTrackSet) {
            // Try to load the segments catalog
            MediaPackageReference trackReference = new MediaPackageReferenceImpl(t);
            Catalog[] segmentCatalogs = mediaPackage.getCatalogs(MediaPackageElements.SEGMENTS, trackReference);
            Mpeg7Catalog mpeg7 = null;
            if (segmentCatalogs.length > 0) {
                mpeg7 = loadMpeg7Catalog(segmentCatalogs[0]);
                if (segmentCatalogs.length > 1)
                    logger.warn("More than one segments catalog found for track {}. Resuming with the first one ({})", t, mpeg7);
            } else {
                logger.debug("No segments catalog found for track {}", t);
                continue;
            }
            // Check the catalog's consistency
            if (mpeg7.videoContent() == null || mpeg7.videoContent().next() == null) {
                logger.info("Segments catalog {} contains no video content", mpeg7);
                continue;
            }
            Video videoContent = mpeg7.videoContent().next();
            TemporalDecomposition<? extends Segment> decomposition = videoContent.getTemporalDecomposition();
            // Are there any segments?
            if (decomposition == null || !decomposition.hasSegments()) {
                logger.info("Segments catalog {} contains no video content", mpeg7);
                continue;
            }
            // Is a derived track with the configured reference flavor available?
            MediaPackageElement referenceMaster = getReferenceMaster(mediaPackage, t, referenceFlavor, referenceTagSet);
            // Create the preview images according to the mpeg7 segments
            if (t.hasVideo() && mpeg7 != null) {
                Iterator<? extends Segment> segmentIterator = decomposition.segments();
                List<MediaTimePoint> timePointList = new LinkedList<>();
                while (segmentIterator.hasNext()) {
                    Segment segment = segmentIterator.next();
                    MediaTimePoint tp = segment.getMediaTime().getMediaTimePoint();
                    timePointList.add(tp);
                }
                // convert to time array
                double[] timeArray = new double[timePointList.size()];
                for (int i = 0; i < timePointList.size(); i++) timeArray[i] = (double) timePointList.get(i).getTimeInMilliseconds() / 1000;
                Job job = composerService.image(t, profile.getIdentifier(), timeArray);
                if (!waitForStatus(job).isSuccess()) {
                    throw new WorkflowOperationException("Extracting preview image from " + t + " failed");
                }
                // Get the latest copy
                try {
                    job = serviceRegistry.getJob(job.getId());
                } catch (ServiceRegistryException e) {
                    throw new WorkflowOperationException(e);
                }
                // add this receipt's queue time to the total
                totalTimeInQueue += job.getQueueTime();
                List<? extends MediaPackageElement> composedImages = MediaPackageElementParser.getArrayFromXml(job.getPayload());
                Iterator<MediaTimePoint> it = timePointList.iterator();
                for (MediaPackageElement element : composedImages) {
                    Attachment composedImage = (Attachment) element;
                    if (composedImage == null)
                        throw new IllegalStateException("Unable to compose image");
                    // Add the flavor, either from the operation configuration or from the composer
                    if (targetImageFlavor != null) {
                        composedImage.setFlavor(MediaPackageElementFlavor.parseFlavor(targetImageFlavor));
                        logger.debug("Preview image has flavor '{}'", composedImage.getFlavor());
                    }
                    // Set the mimetype
                    if (profile.getMimeType() != null)
                        composedImage.setMimeType(MimeTypes.parseMimeType(profile.getMimeType()));
                    // Add tags
                    for (String tag : asList(targetImageTags)) {
                        logger.trace("Tagging image with '{}'", tag);
                        composedImage.addTag(tag);
                    }
                    // Refer to the original track including a timestamp
                    MediaPackageReferenceImpl ref = new MediaPackageReferenceImpl(referenceMaster);
                    ref.setProperty("time", it.next().toString());
                    composedImage.setReference(ref);
                    // store new image in the mediaPackage
                    mediaPackage.add(composedImage);
                    String fileName = getFileNameFromElements(t, composedImage);
                    composedImage.setURI(workspace.moveTo(composedImage.getURI(), mediaPackage.getIdentifier().toString(), composedImage.getIdentifier(), fileName));
                }
            }
        }
    }
    return createResult(mediaPackage, Action.CONTINUE, totalTimeInQueue);
}
Also used : Attachment(org.opencastproject.mediapackage.Attachment) Segment(org.opencastproject.metadata.mpeg7.Segment) MediaPackageElement(org.opencastproject.mediapackage.MediaPackageElement) WorkflowOperationException(org.opencastproject.workflow.api.WorkflowOperationException) Job(org.opencastproject.job.api.Job) HashSet(java.util.HashSet) MediaTimePoint(org.opencastproject.metadata.mpeg7.MediaTimePoint) EncodingProfile(org.opencastproject.composer.api.EncodingProfile) Catalog(org.opencastproject.mediapackage.Catalog) Mpeg7Catalog(org.opencastproject.metadata.mpeg7.Mpeg7Catalog) LinkedList(java.util.LinkedList) MediaTimePoint(org.opencastproject.metadata.mpeg7.MediaTimePoint) ServiceRegistryException(org.opencastproject.serviceregistry.api.ServiceRegistryException) Mpeg7Catalog(org.opencastproject.metadata.mpeg7.Mpeg7Catalog) MediaPackageReference(org.opencastproject.mediapackage.MediaPackageReference) Video(org.opencastproject.metadata.mpeg7.Video) MediaPackageReferenceImpl(org.opencastproject.mediapackage.MediaPackageReferenceImpl) Track(org.opencastproject.mediapackage.Track)

Example 3 with Video

use of org.opencastproject.metadata.mpeg7.Video in project opencast by opencast.

the class VideoSegmenterServiceImpl method runSegmentationFFmpeg.

/**
 * Does the actual segmentation with an FFmpeg call, adds the segments to the given videoContent of a catalog and
 * returns a list with the resulting segments
 *
 * @param track the element to analyze
 * @param videoContent the videoContent of the Mpeg7Catalog that the segments should be added to
 * @param mediaFile the file of the track to analyze
 * @param changesThreshold the changesThreshold that is used as option for the FFmpeg call
 * @return a list of the resulting segments
 * @throws IOException
 */
protected LinkedList<Segment> runSegmentationFFmpeg(Track track, Video videoContent, File mediaFile, float changesThreshold) throws IOException {
    String[] command = new String[] { binary, "-nostats", "-i", mediaFile.getAbsolutePath().replaceAll(" ", "\\ "), "-filter:v", "select=gt(scene\\," + changesThreshold + "),showinfo", "-f", "null", "-" };
    String commandline = StringUtils.join(command, " ");
    logger.info("Running {}", commandline);
    ProcessBuilder pbuilder = new ProcessBuilder(command);
    List<String> segmentsStrings = new LinkedList<String>();
    Process process = pbuilder.start();
    BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
    try {
        LineReader lr = new LineReader(reader);
        String line = lr.readLine();
        while (null != line) {
            if (line.startsWith("[Parsed_showinfo")) {
                segmentsStrings.add(line);
            }
            line = lr.readLine();
        }
    } catch (IOException e) {
        logger.error("Error executing ffmpeg: {}", e.getMessage());
    } finally {
        reader.close();
    }
    // [Parsed_showinfo_1 @ 0x157fb40] n:0 pts:12 pts_time:12 pos:227495
    // fmt:rgb24 sar:0/1 s:320x240 i:P iskey:1 type:I checksum:8DF39EA9
    // plane_checksum:[8DF39EA9]
    int segmentcount = 1;
    LinkedList<Segment> segments = new LinkedList<Segment>();
    if (segmentsStrings.size() == 0) {
        Segment s = videoContent.getTemporalDecomposition().createSegment("segment-" + segmentcount);
        s.setMediaTime(new MediaRelTimeImpl(0, track.getDuration()));
        segments.add(s);
    } else {
        long starttime = 0;
        long endtime = 0;
        Pattern pattern = Pattern.compile("pts_time\\:\\d+(\\.\\d+)?");
        for (String seginfo : segmentsStrings) {
            Matcher matcher = pattern.matcher(seginfo);
            String time = "0";
            while (matcher.find()) {
                time = matcher.group().substring(9);
            }
            endtime = (long) (Float.parseFloat(time) * 1000);
            long segmentLength = endtime - starttime;
            if (1000 * stabilityThresholdPrefilter < segmentLength) {
                Segment segment = videoContent.getTemporalDecomposition().createSegment("segment-" + segmentcount);
                segment.setMediaTime(new MediaRelTimeImpl(starttime, endtime - starttime));
                segments.add(segment);
                segmentcount++;
                starttime = endtime;
            }
        }
        // Add last segment
        Segment s = videoContent.getTemporalDecomposition().createSegment("segment-" + segmentcount);
        s.setMediaTime(new MediaRelTimeImpl(endtime, track.getDuration() - endtime));
        segments.add(s);
    }
    logger.info("Segmentation of {} yields {} segments", mediaFile.toURI().toURL(), segments.size());
    return segments;
}
Also used : Pattern(java.util.regex.Pattern) InputStreamReader(java.io.InputStreamReader) Matcher(java.util.regex.Matcher) IOException(java.io.IOException) LinkedList(java.util.LinkedList) MediaTimePoint(org.opencastproject.metadata.mpeg7.MediaTimePoint) Segment(org.opencastproject.metadata.mpeg7.Segment) LineReader(com.google.common.io.LineReader) BufferedReader(java.io.BufferedReader) MediaRelTimeImpl(org.opencastproject.metadata.mpeg7.MediaRelTimeImpl)

Example 4 with Video

use of org.opencastproject.metadata.mpeg7.Video in project opencast by opencast.

the class VideoSegmenterServiceImpl method segment.

/**
 * Starts segmentation on the video track identified by
 * <code>mediapackageId</code> and <code>elementId</code> and returns a
 * receipt containing the final result in the form of anMpeg7Catalog.
 *
 * @param track
 *            the element to analyze
 * @return a receipt containing the resulting mpeg-7 catalog
 * @throws VideoSegmenterException
 */
protected Catalog segment(Job job, Track track) throws VideoSegmenterException, MediaPackageException {
    // implementation
    if (!track.hasVideo()) {
        logger.warn("Element {} is not a video track", track);
        throw new VideoSegmenterException("Element is not a video track");
    }
    try {
        Mpeg7Catalog mpeg7;
        File mediaFile = null;
        URL mediaUrl = null;
        try {
            mediaFile = workspace.get(track.getURI());
            mediaUrl = mediaFile.toURI().toURL();
        } catch (NotFoundException e) {
            throw new VideoSegmenterException("Error finding the video file in the workspace", e);
        } catch (IOException e) {
            throw new VideoSegmenterException("Error reading the video file in the workspace", e);
        }
        if (track.getDuration() == null)
            throw new MediaPackageException("Track " + track + " does not have a duration");
        logger.info("Track {} loaded, duration is {} s", mediaUrl, track.getDuration() / 1000);
        MediaTime contentTime = new MediaRelTimeImpl(0, track.getDuration());
        MediaLocator contentLocator = new MediaLocatorImpl(track.getURI());
        Video videoContent;
        logger.debug("changesThreshold: {}, stabilityThreshold: {}", changesThreshold, stabilityThreshold);
        logger.debug("prefNumber: {}, maxCycles: {}", prefNumber, maxCycles);
        boolean endOptimization = false;
        int cycleCount = 0;
        LinkedList<Segment> segments;
        LinkedList<OptimizationStep> optimizationList = new LinkedList<OptimizationStep>();
        LinkedList<OptimizationStep> unusedResultsList = new LinkedList<OptimizationStep>();
        OptimizationStep stepBest = new OptimizationStep();
        // local copy of changesThreshold, that can safely be changed over optimization iterations
        float changesThresholdLocal = changesThreshold;
        // local copies of prefNumber, absoluteMin and absoluteMax, to make a dependency on track length possible
        int prefNumberLocal = prefNumber;
        int absoluteMaxLocal = absoluteMax;
        int absoluteMinLocal = absoluteMin;
        // absoluteMax and absoluteMin with the duration of the track
        if (durationDependent) {
            double trackDurationInHours = track.getDuration() / 3600000.0;
            prefNumberLocal = (int) Math.round(trackDurationInHours * prefNumberLocal);
            absoluteMaxLocal = (int) Math.round(trackDurationInHours * absoluteMax);
            absoluteMinLocal = (int) Math.round(trackDurationInHours * absoluteMin);
            // make sure prefNumberLocal will never be 0 or negative
            if (prefNumberLocal <= 0) {
                prefNumberLocal = 1;
            }
            logger.info("Numbers of segments are set to be relative to track duration. Therefore for {} the preferred " + "number of segments is {}", mediaUrl, prefNumberLocal);
        }
        logger.info("Starting video segmentation of {}", mediaUrl);
        // to the desired number of segments
        while (!endOptimization) {
            mpeg7 = mpeg7CatalogService.newInstance();
            videoContent = mpeg7.addVideoContent("videosegment", contentTime, contentLocator);
            // run the segmentation with FFmpeg
            segments = runSegmentationFFmpeg(track, videoContent, mediaFile, changesThresholdLocal);
            // calculate errors for "normal" and filtered segmentation
            // and compare them to find better optimization.
            // "normal"
            OptimizationStep currentStep = new OptimizationStep(stabilityThreshold, changesThresholdLocal, segments.size(), prefNumberLocal, mpeg7, segments);
            // filtered
            LinkedList<Segment> segmentsNew = new LinkedList<Segment>();
            OptimizationStep currentStepFiltered = new OptimizationStep(stabilityThreshold, changesThresholdLocal, 0, prefNumberLocal, filterSegmentation(segments, track, segmentsNew, stabilityThreshold * 1000), segments);
            currentStepFiltered.setSegmentNumAndRecalcErrors(segmentsNew.size());
            logger.info("Segmentation yields {} segments after filtering", segmentsNew.size());
            OptimizationStep currentStepBest;
            // - and the filtered segmentation is not already better than the maximum error
            if (currentStep.getErrorAbs() <= currentStepFiltered.getErrorAbs() || (segmentsNew.size() < prefNumberLocal && currentStep.getSegmentNum() > (track.getDuration() / 1000.0f) / (stabilityThreshold / 2) && !(currentStepFiltered.getErrorAbs() <= maxError))) {
                optimizationList.add(currentStep);
                Collections.sort(optimizationList);
                currentStepBest = currentStep;
                unusedResultsList.add(currentStepFiltered);
            } else {
                optimizationList.add(currentStepFiltered);
                Collections.sort(optimizationList);
                currentStepBest = currentStepFiltered;
            }
            cycleCount++;
            logger.debug("errorAbs = {}, error = {}", currentStep.getErrorAbs(), currentStep.getError());
            logger.debug("changesThreshold = {}", changesThresholdLocal);
            logger.debug("cycleCount = {}", cycleCount);
            // end optimization if maximum number of cycles is reached or if the segmentation is good enough
            if (cycleCount >= maxCycles || currentStepBest.getErrorAbs() <= maxError) {
                endOptimization = true;
                if (optimizationList.size() > 0) {
                    if (optimizationList.getFirst().getErrorAbs() <= optimizationList.getLast().getErrorAbs() && optimizationList.getFirst().getError() >= 0) {
                        stepBest = optimizationList.getFirst();
                    } else {
                        stepBest = optimizationList.getLast();
                    }
                }
                // just to be sure, check if one of the unused results was better
                for (OptimizationStep currentUnusedStep : unusedResultsList) {
                    if (currentUnusedStep.getErrorAbs() < stepBest.getErrorAbs()) {
                        stepBest = unusedResultsList.getFirst();
                    }
                }
            // continue optimization, calculate new changes threshold for next iteration of optimization
            } else {
                OptimizationStep first = optimizationList.getFirst();
                OptimizationStep last = optimizationList.getLast();
                // estimate a new changesThreshold based on the one yielding the smallest error
                if (optimizationList.size() == 1 || first.getError() < 0 || last.getError() > 0) {
                    if (currentStepBest.getError() >= 0) {
                        // if the error is smaller or equal to 1, increase changes threshold weighted with the error
                        if (currentStepBest.getError() <= 1) {
                            changesThresholdLocal += changesThresholdLocal * currentStepBest.getError();
                        } else {
                            // to faster reach reasonable segment numbers
                            if (cycleCount <= 1 && currentStep.getSegmentNum() > 2000) {
                                changesThresholdLocal = 0.2f;
                            // if the error is bigger than one, double the changes threshold, because multiplying
                            // with a large error can yield a much too high changes threshold
                            } else {
                                changesThresholdLocal *= 2;
                            }
                        }
                    } else {
                        changesThresholdLocal /= 2;
                    }
                    logger.debug("onesided optimization yields new changesThreshold = {}", changesThresholdLocal);
                // if there are already iterations with positive and negative errors, choose a changesThreshold between those
                } else {
                    // for simplicity a linear relationship between the changesThreshold
                    // and the number of generated segments is assumed and based on that
                    // the expected correct changesThreshold is calculated
                    // the new changesThreshold is calculated by averaging the the mean and the mean weighted with errors
                    // because this seemed to yield better results in several cases
                    float x = (first.getSegmentNum() - prefNumberLocal) / (float) (first.getSegmentNum() - last.getSegmentNum());
                    float newX = ((x + 0.5f) * 0.5f);
                    changesThresholdLocal = first.getChangesThreshold() * (1 - newX) + last.getChangesThreshold() * newX;
                    logger.debug("doublesided optimization yields new changesThreshold = {}", changesThresholdLocal);
                }
            }
        }
        // after optimization of the changes threshold, the minimum duration for a segment
        // (stability threshold) is optimized if the result is still not good enough
        int threshLow = stabilityThreshold * 1000;
        int threshHigh = threshLow + (threshLow / 2);
        LinkedList<Segment> tmpSegments;
        float smallestError = Float.MAX_VALUE;
        int bestI = threshLow;
        segments = stepBest.getSegments();
        // is smaller than the maximum error, the stability threshold will not be optimized
        if (stepBest.getError() <= maxError) {
            threshHigh = stabilityThreshold * 1000;
        }
        for (int i = threshLow; i <= threshHigh; i = i + 1000) {
            tmpSegments = new LinkedList<Segment>();
            filterSegmentation(segments, track, tmpSegments, i);
            float newError = OptimizationStep.calculateErrorAbs(tmpSegments.size(), prefNumberLocal);
            if (newError < smallestError) {
                smallestError = newError;
                bestI = i;
            }
        }
        tmpSegments = new LinkedList<Segment>();
        mpeg7 = filterSegmentation(segments, track, tmpSegments, bestI);
        // for debugging: output of final segmentation after optimization
        logger.debug("result segments:");
        for (int i = 0; i < tmpSegments.size(); i++) {
            int[] tmpLog2 = new int[7];
            tmpLog2[0] = tmpSegments.get(i).getMediaTime().getMediaTimePoint().getHour();
            tmpLog2[1] = tmpSegments.get(i).getMediaTime().getMediaTimePoint().getMinutes();
            tmpLog2[2] = tmpSegments.get(i).getMediaTime().getMediaTimePoint().getSeconds();
            tmpLog2[3] = tmpSegments.get(i).getMediaTime().getMediaDuration().getHours();
            tmpLog2[4] = tmpSegments.get(i).getMediaTime().getMediaDuration().getMinutes();
            tmpLog2[5] = tmpSegments.get(i).getMediaTime().getMediaDuration().getSeconds();
            Object[] tmpLog1 = { tmpLog2[0], tmpLog2[1], tmpLog2[2], tmpLog2[3], tmpLog2[4], tmpLog2[5], tmpLog2[6] };
            tmpLog1[6] = tmpSegments.get(i).getIdentifier();
            logger.debug("s:{}:{}:{}, d:{}:{}:{}, {}", tmpLog1);
        }
        logger.info("Optimized Segmentation yields (after {} iteration" + (cycleCount == 1 ? "" : "s") + ") {} segments", cycleCount, tmpSegments.size());
        // if no reasonable segmentation could be found, instead return a uniform segmentation
        if (tmpSegments.size() < absoluteMinLocal || tmpSegments.size() > absoluteMaxLocal) {
            mpeg7 = uniformSegmentation(track, tmpSegments, prefNumberLocal);
            logger.info("Since no reasonable segmentation could be found, a uniform segmentation was created");
        }
        Catalog mpeg7Catalog = (Catalog) MediaPackageElementBuilderFactory.newInstance().newElementBuilder().newElement(Catalog.TYPE, MediaPackageElements.SEGMENTS);
        URI uri;
        try {
            uri = workspace.putInCollection(COLLECTION_ID, job.getId() + ".xml", mpeg7CatalogService.serialize(mpeg7));
        } catch (IOException e) {
            throw new VideoSegmenterException("Unable to put the mpeg7 catalog into the workspace", e);
        }
        mpeg7Catalog.setURI(uri);
        logger.info("Finished video segmentation of {}", mediaUrl);
        return mpeg7Catalog;
    } catch (Exception e) {
        logger.warn("Error segmenting " + track, e);
        if (e instanceof VideoSegmenterException) {
            throw (VideoSegmenterException) e;
        } else {
            throw new VideoSegmenterException(e);
        }
    }
}
Also used : NotFoundException(org.opencastproject.util.NotFoundException) URI(java.net.URI) URL(java.net.URL) Segment(org.opencastproject.metadata.mpeg7.Segment) MediaLocator(org.opencastproject.metadata.mpeg7.MediaLocator) MediaRelTimeImpl(org.opencastproject.metadata.mpeg7.MediaRelTimeImpl) MediaPackageException(org.opencastproject.mediapackage.MediaPackageException) IOException(java.io.IOException) VideoSegmenterException(org.opencastproject.videosegmenter.api.VideoSegmenterException) MediaTimePoint(org.opencastproject.metadata.mpeg7.MediaTimePoint) LinkedList(java.util.LinkedList) Catalog(org.opencastproject.mediapackage.Catalog) Mpeg7Catalog(org.opencastproject.metadata.mpeg7.Mpeg7Catalog) 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) VideoSegmenterException(org.opencastproject.videosegmenter.api.VideoSegmenterException) Mpeg7Catalog(org.opencastproject.metadata.mpeg7.Mpeg7Catalog) Video(org.opencastproject.metadata.mpeg7.Video) MediaTime(org.opencastproject.metadata.mpeg7.MediaTime) File(java.io.File) MediaLocatorImpl(org.opencastproject.metadata.mpeg7.MediaLocatorImpl)

Example 5 with Video

use of org.opencastproject.metadata.mpeg7.Video in project opencast by opencast.

the class VideoSegmenterTest method testAnalyze.

@Test
public void testAnalyze() throws Exception {
    Job receipt = vsegmenter.segment(track);
    JobBarrier jobBarrier = new JobBarrier(null, serviceRegistry, 1000, receipt);
    jobBarrier.waitForJobs();
    Catalog catalog = (Catalog) MediaPackageElementParser.getFromXml(receipt.getPayload());
    Mpeg7Catalog mpeg7 = new Mpeg7CatalogImpl(catalog.getURI().toURL().openStream());
    // Is there multimedia content in the mpeg7?
    assertTrue("Audiovisual content was expected", mpeg7.hasVideoContent());
    assertNotNull("Audiovisual content expected", mpeg7.multimediaContent().next().elements().hasNext());
    MultimediaContentType contentType = mpeg7.multimediaContent().next().elements().next();
    // Is there at least one segment?
    TemporalDecomposition<? extends Segment> segments = contentType.getTemporalDecomposition();
    Iterator<? extends Segment> si = segments.segments();
    assertTrue(si.hasNext());
    Segment firstSegment = si.next();
    MediaTime firstSegmentMediaTime = firstSegment.getMediaTime();
    long startTime = firstSegmentMediaTime.getMediaTimePoint().getTimeInMilliseconds();
    long duration = firstSegmentMediaTime.getMediaDuration().getDurationInMilliseconds();
    assertEquals("Unexpected start time of first segment", 0, startTime);
    assertEquals("Unexpected duration of first segment", firstSegmentDuration, duration);
    // What about the second one?
    assertTrue("Video is expected to have more than one segment", si.hasNext());
    Segment secondSegment = si.next();
    MediaTime secondSegmentMediaTime = secondSegment.getMediaTime();
    startTime = secondSegmentMediaTime.getMediaTimePoint().getTimeInMilliseconds();
    duration = secondSegmentMediaTime.getMediaDuration().getDurationInMilliseconds();
    assertEquals("Unexpected start time of second segment", firstSegmentDuration, startTime);
    assertEquals("Unexpected duration of second segment", secondSegmentDuration, duration);
    // There should be no third segment
    assertFalse("Found an unexpected third video segment", si.hasNext());
}
Also used : Mpeg7Catalog(org.opencastproject.metadata.mpeg7.Mpeg7Catalog) MediaTime(org.opencastproject.metadata.mpeg7.MediaTime) Mpeg7CatalogImpl(org.opencastproject.metadata.mpeg7.Mpeg7CatalogImpl) Job(org.opencastproject.job.api.Job) JobBarrier(org.opencastproject.job.api.JobBarrier) MultimediaContentType(org.opencastproject.metadata.mpeg7.MultimediaContentType) Catalog(org.opencastproject.mediapackage.Catalog) Mpeg7Catalog(org.opencastproject.metadata.mpeg7.Mpeg7Catalog) Segment(org.opencastproject.metadata.mpeg7.Segment) Test(org.junit.Test)

Aggregations

Mpeg7Catalog (org.opencastproject.metadata.mpeg7.Mpeg7Catalog)10 Video (org.opencastproject.metadata.mpeg7.Video)9 Catalog (org.opencastproject.mediapackage.Catalog)8 MediaTime (org.opencastproject.metadata.mpeg7.MediaTime)8 Segment (org.opencastproject.metadata.mpeg7.Segment)8 IOException (java.io.IOException)7 MediaTimePoint (org.opencastproject.metadata.mpeg7.MediaTimePoint)7 ServiceRegistryException (org.opencastproject.serviceregistry.api.ServiceRegistryException)6 MediaPackageException (org.opencastproject.mediapackage.MediaPackageException)5 MediaRelTimeImpl (org.opencastproject.metadata.mpeg7.MediaRelTimeImpl)5 NotFoundException (org.opencastproject.util.NotFoundException)5 URI (java.net.URI)4 LinkedList (java.util.LinkedList)4 Attachment (org.opencastproject.mediapackage.Attachment)4 MediaLocator (org.opencastproject.metadata.mpeg7.MediaLocator)4 MediaLocatorImpl (org.opencastproject.metadata.mpeg7.MediaLocatorImpl)4 VideoText (org.opencastproject.metadata.mpeg7.VideoText)4 TextAnalyzerException (org.opencastproject.textanalyzer.api.TextAnalyzerException)4 WorkflowOperationException (org.opencastproject.workflow.api.WorkflowOperationException)4 File (java.io.File)3