001/*
002 * (C) Copyright 2006-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 *     Thomas Roger <troger@nuxeo.com>
018 */
019
020package org.nuxeo.ecm.platform.video.convert;
021
022import static org.nuxeo.ecm.platform.video.convert.Constants.INPUT_FILE_PATH_PARAMETER;
023import static org.nuxeo.ecm.platform.video.convert.Constants.OUTPUT_FILE_NAME_PARAMETER;
024import static org.nuxeo.ecm.platform.video.convert.Constants.OUTPUT_FILE_PATH_PARAMETER;
025
026import java.io.File;
027import java.io.IOException;
028import java.io.Serializable;
029import java.nio.file.Files;
030import java.util.ArrayList;
031import java.util.Collections;
032import java.util.HashMap;
033import java.util.List;
034import java.util.Map;
035import java.util.UUID;
036
037import org.apache.commons.io.FileUtils;
038import org.apache.commons.io.FilenameUtils;
039import org.nuxeo.common.utils.Path;
040import org.nuxeo.ecm.core.api.Blob;
041import org.nuxeo.ecm.core.api.blobholder.BlobHolder;
042import org.nuxeo.ecm.core.api.blobholder.SimpleBlobHolderWithProperties;
043import org.nuxeo.ecm.core.convert.api.ConversionException;
044import org.nuxeo.ecm.platform.commandline.executor.api.CmdParameters;
045import org.nuxeo.ecm.platform.convert.plugins.CommandLineBasedConverter;
046import org.nuxeo.ecm.platform.video.VideoInfo;
047import org.nuxeo.ecm.platform.video.tools.VideoTool;
048
049/**
050 * Base class for converters doing video conversions.
051 *
052 * @author <a href="mailto:troger@nuxeo.com">Thomas Roger</a>
053 * @since 5.5
054 */
055public abstract class BaseVideoConversionConverter extends CommandLineBasedConverter {
056
057    protected static final String OUTPUT_TMP_PATH = "converterTmpPath";
058
059    @Override
060    protected Map<String, Blob> getCmdBlobParameters(BlobHolder blobHolder,
061            Map<String, Serializable> stringSerializableMap) {
062        Map<String, Blob> cmdBlobParams = new HashMap<>();
063        cmdBlobParams.put(INPUT_FILE_PATH_PARAMETER, blobHolder.getBlob());
064        return cmdBlobParams;
065    }
066
067    @Override
068    protected Map<String, String> getCmdStringParameters(BlobHolder blobHolder, Map<String, Serializable> parameters) {
069        Map<String, String> cmdStringParams = new HashMap<>();
070
071        String baseDir = getTmpDirectory(parameters);
072        Path tmpPath = new Path(baseDir).append(getTmpDirectoryPrefix() + "_" + UUID.randomUUID());
073
074        File outDir = new File(tmpPath.toString());
075        boolean dirCreated = outDir.mkdir();
076        if (!dirCreated) {
077            throw new ConversionException("Unable to create tmp dir for transformer output: " + outDir);
078        }
079
080        File outFile;
081        try {
082            outFile = File.createTempFile("videoConversion", getVideoExtension(), outDir);
083        } catch (IOException e) {
084            throw new ConversionException("Unable to get Blob for holder", e);
085        }
086        // delete the file as we need only the path for ffmpeg
087        try {
088            Files.delete(outFile.toPath());
089        } catch (IOException e) {
090            throw new ConversionException("Unable to delete the temporary video conversion file.", e);
091        }
092        cmdStringParams.put(OUTPUT_FILE_PATH_PARAMETER, outFile.getAbsolutePath());
093        String baseName = FilenameUtils.getBaseName(blobHolder.getBlob().getFilename());
094        cmdStringParams.put(OUTPUT_FILE_NAME_PARAMETER, baseName + getVideoExtension());
095
096        VideoInfo videoInfo = (VideoInfo) parameters.get("videoInfo");
097        if (videoInfo == null) {
098            return cmdStringParams;
099        }
100
101        long width = videoInfo.getWidth();
102        long height = videoInfo.getHeight();
103        long newHeight = (Long) parameters.get("height");
104
105        long newWidth = width * newHeight / height;
106        if (newWidth % 2 != 0) {
107            newWidth += 1;
108        }
109
110        cmdStringParams.put(OUTPUT_TMP_PATH, outDir.getAbsolutePath());
111        cmdStringParams.put("width", String.valueOf(newWidth));
112        cmdStringParams.put("height", String.valueOf(newHeight));
113        return cmdStringParams;
114    }
115
116    @Override
117    protected BlobHolder buildResult(List<String> cmdOutput, CmdParameters cmdParameters) {
118        String outputPath = cmdParameters.getParameter(OUTPUT_FILE_PATH_PARAMETER);
119        Blob blob = VideoTool.getTemporaryBlob(outputPath, getVideoMimeType());
120        String outFileName = cmdParameters.getParameter(OUTPUT_FILE_NAME_PARAMETER);
121        if (outFileName != null) {
122            blob.setFilename(unquoteValue(outFileName));
123        }
124        List<Blob> blobs = new ArrayList<>(Collections.singletonList(blob));
125        Map<String, Serializable> properties = new HashMap<>();
126        properties.put("cmdOutput", (Serializable) cmdOutput);
127
128        // remove the temp output directory
129        File outDir = new File(cmdParameters.getParameter(OUTPUT_TMP_PATH));
130        FileUtils.deleteQuietly(outDir);
131
132        return new SimpleBlobHolderWithProperties(blobs, properties);
133    }
134
135    /**
136     * @since 5.6
137     */
138    protected String unquoteValue(String value) {
139        if (value.startsWith("\"") && value.endsWith("\"")) {
140            return value.substring(1, value.length() - 1);
141        }
142        return value;
143    }
144
145    /**
146     * Returns the video mime type to use for this converter.
147     */
148    protected abstract String getVideoMimeType();
149
150    /**
151     * Returns the video extension, always prefixed by '.'.
152     */
153    protected abstract String getVideoExtension();
154
155    /**
156     * Returns the temporary directory prefix to use for this converter.
157     */
158    protected abstract String getTmpDirectoryPrefix();
159
160}