Search in sources :

Example 1 with VideoSegmenterException

use of org.opencastproject.videosegmenter.api.VideoSegmenterException 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 2 with VideoSegmenterException

use of org.opencastproject.videosegmenter.api.VideoSegmenterException in project opencast by opencast.

the class VideoSegmenterRemoteImpl method segment.

@Override
public Job segment(Track track) throws VideoSegmenterException {
    HttpPost post = new HttpPost();
    try {
        List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
        params.add(new BasicNameValuePair("track", MediaPackageElementParser.getAsXml(track)));
        post.setEntity(new UrlEncodedFormEntity(params));
    } catch (Exception e) {
        throw new VideoSegmenterException(e);
    }
    HttpResponse response = null;
    try {
        response = getResponse(post);
        if (response != null) {
            try {
                Job receipt = JobParser.parseJob(response.getEntity().getContent());
                logger.info("Analyzing {} on a remote analysis server", track);
                return receipt;
            } catch (Exception e) {
                throw new VideoSegmenterException("Unable to analyze element '" + track + "' using a remote analysis service", e);
            }
        }
    } finally {
        closeConnection(response);
    }
    throw new VideoSegmenterException("Unable to analyze element '" + track + "' using a remote analysis service");
}
Also used : 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) VideoSegmenterException(org.opencastproject.videosegmenter.api.VideoSegmenterException) VideoSegmenterException(org.opencastproject.videosegmenter.api.VideoSegmenterException)

Aggregations

VideoSegmenterException (org.opencastproject.videosegmenter.api.VideoSegmenterException)2 File (java.io.File)1 IOException (java.io.IOException)1 URI (java.net.URI)1 URL (java.net.URL)1 ArrayList (java.util.ArrayList)1 LinkedList (java.util.LinkedList)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 Job (org.opencastproject.job.api.Job)1 Catalog (org.opencastproject.mediapackage.Catalog)1 MediaPackageException (org.opencastproject.mediapackage.MediaPackageException)1 MediaLocator (org.opencastproject.metadata.mpeg7.MediaLocator)1 MediaLocatorImpl (org.opencastproject.metadata.mpeg7.MediaLocatorImpl)1 MediaRelTimeImpl (org.opencastproject.metadata.mpeg7.MediaRelTimeImpl)1 MediaTime (org.opencastproject.metadata.mpeg7.MediaTime)1 MediaTimePoint (org.opencastproject.metadata.mpeg7.MediaTimePoint)1 Mpeg7Catalog (org.opencastproject.metadata.mpeg7.Mpeg7Catalog)1