001/* 002 * (C) Copyright 2016 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Ricardo Dias 018 */ 019package org.nuxeo.ecm.platform.video.tools.service; 020 021import org.apache.commons.logging.Log; 022import org.apache.commons.logging.LogFactory; 023import org.nuxeo.ecm.core.api.Blob; 024import org.nuxeo.ecm.core.api.NuxeoException; 025import org.nuxeo.ecm.core.api.blobholder.BlobHolder; 026import org.nuxeo.ecm.core.api.blobholder.SimpleBlobHolder; 027import org.nuxeo.ecm.platform.commandline.executor.api.CmdParameters; 028import org.nuxeo.ecm.platform.commandline.executor.api.CommandAvailability; 029import org.nuxeo.ecm.platform.commandline.executor.api.CommandLineExecutorService; 030import org.nuxeo.ecm.platform.commandline.executor.api.CommandNotAvailable; 031import org.nuxeo.ecm.platform.commandline.executor.api.ExecResult; 032import org.nuxeo.ecm.platform.video.tools.VideoClosedCaptionsExtractor; 033import org.nuxeo.ecm.platform.video.tools.VideoConcat; 034import org.nuxeo.ecm.platform.video.tools.VideoSlicer; 035import org.nuxeo.ecm.platform.video.tools.VideoTool; 036import org.nuxeo.ecm.platform.video.tools.VideoToolsService; 037import org.nuxeo.ecm.platform.video.tools.VideoWatermarker; 038import org.nuxeo.runtime.api.Framework; 039import org.nuxeo.runtime.model.ComponentContext; 040import org.nuxeo.runtime.model.DefaultComponent; 041 042import java.util.HashMap; 043import java.util.List; 044import java.util.Map; 045 046/** 047 * The {@link VideoToolsService} default implementation for handling video blobs. It provides extension points for 048 * handling video operations, such as concat, slice, watermark and extract closed captions. 049 * 050 * @since 8.4 051 */ 052public class VideoToolsServiceImpl extends DefaultComponent implements VideoToolsService { 053 054 protected static final Log log = LogFactory.getLog(VideoToolsServiceImpl.class); 055 056 protected Map<String, Class> videoTools; 057 058 @Override 059 public void activate(ComponentContext context) { 060 super.activate(context); 061 062 videoTools = new HashMap<>(); 063 videoTools.put(VideoWatermarker.NAME, VideoWatermarker.class); 064 videoTools.put(VideoSlicer.NAME, VideoSlicer.class); 065 videoTools.put(VideoConcat.NAME, VideoConcat.class); 066 videoTools.put(VideoClosedCaptionsExtractor.NAME, VideoClosedCaptionsExtractor.class); 067 } 068 069 @Override 070 public Blob extractClosedCaptions(Blob video, String outputFormat, String startAt, String endAt) { 071 Map<String, Object> parameters = new HashMap<>(); 072 parameters.put(VideoClosedCaptionsExtractor.OUTPUT_FORMAT_PARAM, outputFormat); 073 parameters.put(VideoClosedCaptionsExtractor.START_AT_PARAM, startAt); 074 parameters.put(VideoClosedCaptionsExtractor.END_AT_PARAM, endAt); 075 076 BlobHolder result = execute(VideoClosedCaptionsExtractor.NAME, new SimpleBlobHolder(video), parameters); 077 return result.getBlob(); 078 } 079 080 @Override 081 public Blob concat(List<Blob> videos) { 082 BlobHolder blobHolder = execute(VideoConcat.NAME, new SimpleBlobHolder(videos), null); 083 return blobHolder.getBlob(); 084 } 085 086 @Override 087 public List<Blob> slice(Blob video, String startAt, String duration, boolean encode) { 088 Map<String, Object> parameters = new HashMap<>(); 089 parameters.put(VideoSlicer.DURATION_PARAM, duration); 090 parameters.put(VideoSlicer.START_AT_PARAM, startAt); 091 parameters.put(VideoSlicer.ENCODE_PARAM, encode); 092 093 BlobHolder result = execute(VideoSlicer.NAME, new SimpleBlobHolder(video), parameters); 094 return result.getBlobs(); 095 } 096 097 @Override 098 public Blob watermark(Blob video, Blob picture, String x, String y) { 099 Map<String, Object> parameters = new HashMap<>(); 100 parameters.put(VideoWatermarker.WATERMARK_PARAM, picture); 101 parameters.put(VideoWatermarker.WATERMARK_X_POSITION_PARAM, x); 102 parameters.put(VideoWatermarker.WATERMARK_Y_POSITION_PARAM, y); 103 104 BlobHolder result = execute(VideoWatermarker.NAME, new SimpleBlobHolder(video), parameters); 105 return result.getBlob(); 106 } 107 108 /** 109 * Executes the video tool with the provided parameters. 110 * @param toolName 111 * @param blobHolder 112 * @param parameters 113 * @return 114 */ 115 private BlobHolder execute(String toolName, BlobHolder blobHolder, Map<String, Object> parameters) { 116 BlobHolder result = null; 117 118 if (!isToolAvailable(toolName)) { 119 return result; 120 } 121 try { 122 // initialize the tool and set up the parameters 123 VideoTool tool = (VideoTool) videoTools.get(toolName).newInstance(); 124 Map<String, String> params = tool.setupParameters(blobHolder, parameters); 125 CmdParameters cmdParams = setupCmdParameters(params); 126 String commandLineName = tool.getCommandLineName(); 127 128 CommandLineExecutorService cles = Framework.getService(CommandLineExecutorService.class); 129 ExecResult clResult = cles.execCommand(commandLineName, cmdParams); 130 tool.cleanupInputs(params); 131 // Get the result, and first, handle errors. 132 if (clResult.getError() != null) { 133 throw new NuxeoException("Failed to execute the command <" + commandLineName + ">", 134 clResult.getError()); 135 } 136 137 if (!clResult.isSuccessful()) { 138 throw new NuxeoException("Failed to execute the command <" + commandLineName + ">. Final command [ " 139 + clResult.getCommandLine() + " ] returned with error " + clResult.getReturnCode()); 140 } 141 result = tool.buildResult(blobHolder.getBlob().getMimeType(), params); 142 } catch (CommandNotAvailable e) { 143 throw new NuxeoException("The video tool command is not available.", e); 144 } catch (InstantiationException e) { 145 throw new NuxeoException("The video tool is not available.", e); 146 } catch (IllegalAccessException e) { 147 throw new NuxeoException("The video tool is not available.", e); 148 } 149 return result; 150 } 151 152 public boolean isToolAvailable(String toolName) { 153 String commandLine; 154 try { 155 VideoTool tool = (VideoTool) videoTools.get(toolName).newInstance(); 156 commandLine = tool.getCommandLineName(); 157 } catch (InstantiationException e) { 158 throw new NuxeoException("The video tool is not available.", e); 159 } catch (IllegalAccessException e) { 160 throw new NuxeoException("The video tool is not available.", e); 161 } 162 CommandAvailability ca = Framework.getService(CommandLineExecutorService.class) 163 .getCommandAvailability(commandLine); 164 return ca.isAvailable(); 165 } 166 167 protected CmdParameters setupCmdParameters(Map<String, String> parameters) { 168 CmdParameters cmdParameters = new CmdParameters(); 169 for (String param: parameters.keySet()) { 170 cmdParameters.addNamedParameter(param, parameters.get(param)); 171 } 172 return cmdParameters; 173 } 174 175}