From d13527ced549bdea2653ae44c83133f4d306fd4e Mon Sep 17 00:00:00 2001 From: fkiefer <none@none> Date: Thu, 2 Mar 2017 14:19:53 +0100 Subject: [PATCH] OO-2595 Add filter to avoid black video poster suggestions in video/poster config --- .../org/olat/modules/video/VideoManager.java | 11 ++++ .../video/manager/VideoManagerImpl.java | 55 +++++++++++++++++++ .../video/ui/VideoPosterSelectionForm.java | 29 ++++++++-- 3 files changed, 89 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/olat/modules/video/VideoManager.java b/src/main/java/org/olat/modules/video/VideoManager.java index 307cebdaa60..1dd9cf67315 100644 --- a/src/main/java/org/olat/modules/video/VideoManager.java +++ b/src/main/java/org/olat/modules/video/VideoManager.java @@ -463,4 +463,15 @@ public interface VideoManager { */ public boolean hasVideoMetadata(OLATResource videoResource); + /** + * get Frame at given frameNumber in video and save it in the VFSLeaf 'frame' if the image is not mostly black + * + * @param videoResource + * @param frameNumber + * @param duration + * @param frame resource + * @return true if image proposal is mostly black + */ + public abstract boolean getFrameWithFilter(OLATResource videoResource, int frameNumber, long duration, VFSLeaf frame); + } \ No newline at end of file diff --git a/src/main/java/org/olat/modules/video/manager/VideoManagerImpl.java b/src/main/java/org/olat/modules/video/manager/VideoManagerImpl.java index 4599de7e460..f1eef026185 100644 --- a/src/main/java/org/olat/modules/video/manager/VideoManagerImpl.java +++ b/src/main/java/org/olat/modules/video/manager/VideoManagerImpl.java @@ -282,6 +282,61 @@ public class VideoManagerImpl implements VideoManager { return false; } } + + @Override + public boolean getFrameWithFilter(OLATResource videoResource, int frameNumber, long duration, VFSLeaf frame) { + File videoFile = ((LocalFileImpl) getMasterVideoFile(videoResource)).getBasefile(); + BufferedImage bufImg = null; + boolean imgBlack = true; + int countBlack = 0; + try (RandomAccessFile randomAccessFile = new RandomAccessFile(videoFile, "r")) { + OutputStream frameOutputStream = frame.getOutputStream(false); + + FileChannel ch = randomAccessFile.getChannel(); + FileChannelWrapper in = new FileChannelWrapper(ch); + FrameGrab frameGrab = new FrameGrab(in).seekToFrameSloppy(frameNumber); + + bufImg = frameGrab.getFrame(); + + int xmin = bufImg.getMinX(); + int ymin = bufImg.getMinY(); + int xmax = xmin + bufImg.getWidth(); + int ymax = ymin + bufImg.getHeight(); + int pixelCount = bufImg.getWidth() * bufImg.getHeight(); + + for (int x = xmin; x < xmax; x++) { + for (int y = ymin; y < ymax; y++) { + int rgb = bufImg.getRGB(x, y); +// int alpha = (0xff000000 & rgb) >>> 24; + int r = (0x00ff0000 & rgb) >> 16; + int g = (0x0000ff00 & rgb) >> 8; + int b = (0x000000ff & rgb); + if (r < 30 && g < 30 && b < 30) { + countBlack++; + } + } + } + if (countBlack > (int) (0.7F * pixelCount)) { + imgBlack = true; + } else { + imgBlack = false; + ImageIO.write(bufImg, "JPG", frameOutputStream); + } + // avoid endless loop + if (frameNumber > duration) { + imgBlack = false; + } + // close everything to prevent resource leaks + frameOutputStream.close(); + in.close(); + ch.close(); + + return imgBlack; + } catch (Exception | AssertionError e) { + log.error("Could not get frame::" + frameNumber + " for video::" + videoFile.getAbsolutePath(), e); + return false; + } + } /** * get the File of the videoresource diff --git a/src/main/java/org/olat/modules/video/ui/VideoPosterSelectionForm.java b/src/main/java/org/olat/modules/video/ui/VideoPosterSelectionForm.java index 2d1af01e0b9..ecccc5fd634 100644 --- a/src/main/java/org/olat/modules/video/ui/VideoPosterSelectionForm.java +++ b/src/main/java/org/olat/modules/video/ui/VideoPosterSelectionForm.java @@ -87,22 +87,39 @@ public class VideoPosterSelectionForm extends BasicController { } long firstThirdDuration = duration/7; - for (int x = 0; x <= duration; x += firstThirdDuration) { + for (int currentFrame = 0; currentFrame <= duration; currentFrame += firstThirdDuration) { try { - String fileName = FILENAME_PREFIX_PROPOSAL_POSTER + x + FILENAME_POSTFIX_JPG; - VFSLeaf posterProposal = tmpContainer.createChildLeaf(fileName); - videoManager.getFrame(videoResource, x, posterProposal); + String fileName; + boolean imgBlack; + int adjust = 0; + do { + fileName = FILENAME_PREFIX_PROPOSAL_POSTER + (currentFrame+adjust) + FILENAME_POSTFIX_JPG; + VFSLeaf posterProposal = tmpContainer.createChildLeaf(fileName); + imgBlack = videoManager.getFrameWithFilter(videoResource, (currentFrame+adjust), duration, posterProposal); + int step = 24; + if (currentFrame + step <= duration) { + adjust += step; + } else { + adjust -= step; + } + // set lower bound to avoid endless loop + if (currentFrame+adjust < 0) { + // if all poster images are mostly black just take current frame + videoManager.getFrame(videoResource, currentFrame, posterProposal); + break; + } + } while (imgBlack); VideoMediaMapper mediaMapper = new VideoMediaMapper(tmpContainer); String mediaUrl = registerMapper(ureq, mediaMapper); String serverUrl = Settings.createServerURI(); proposalLayout.contextPut("serverUrl", serverUrl); - Link button = LinkFactory.createButton(String.valueOf(x), proposalLayout, this); + Link button = LinkFactory.createButton(String.valueOf(currentFrame), proposalLayout, this); button.setCustomEnabledLinkCSS("o_video_poster_selct"); button.setCustomDisplayText(translate("poster.select")); button.setUserObject(fileName); - generatedPosters.put(mediaUrl + "/" + fileName, String.valueOf(x)); + generatedPosters.put(mediaUrl + "/" + fileName, String.valueOf(currentFrame)); } catch (Exception | AssertionError e) { logError("Error while creating poster images for video::" + videoFile.getAbsolutePath(), e); } -- GitLab