001
014
015 package com.liferay.portlet.documentlibrary.util;
016
017 import com.liferay.portal.kernel.exception.SystemException;
018 import com.liferay.portal.kernel.log.Log;
019 import com.liferay.portal.kernel.log.LogFactoryUtil;
020 import com.liferay.portal.kernel.messaging.DestinationNames;
021 import com.liferay.portal.kernel.messaging.MessageBusUtil;
022 import com.liferay.portal.kernel.repository.model.FileVersion;
023 import com.liferay.portal.kernel.util.FileUtil;
024 import com.liferay.portal.kernel.util.PropsKeys;
025 import com.liferay.portal.kernel.util.SetUtil;
026 import com.liferay.portal.kernel.util.StringBundler;
027 import com.liferay.portal.kernel.util.StringPool;
028 import com.liferay.portal.repository.liferayrepository.model.LiferayFileVersion;
029 import com.liferay.portal.util.PrefsPropsUtil;
030 import com.liferay.portal.util.PropsValues;
031 import com.liferay.portlet.documentlibrary.NoSuchFileEntryException;
032 import com.liferay.portlet.documentlibrary.store.DLStoreUtil;
033
034 import java.io.File;
035 import java.io.InputStream;
036
037 import java.util.List;
038 import java.util.Set;
039 import java.util.Vector;
040
041
046 public class VideoProcessor extends DefaultPreviewableProcessor {
047
048 public static final String PREVIEW_TYPE = "flv";
049
050 public static final String THUMBNAIL_TYPE = "jpg";
051
052 public static void generateVideo(FileVersion fileVersion)
053 throws Exception {
054
055 _instance._generateVideo(fileVersion);
056 }
057
058 public static DLProcessor getInstance() {
059 return _instance;
060 }
061
062 public static InputStream getPreviewAsStream(FileVersion fileVersion)
063 throws Exception {
064
065 return _instance.doGetPreviewAsStream(fileVersion);
066 }
067
068 public static long getPreviewFileSize(FileVersion fileVersion)
069 throws Exception {
070
071 return _instance.doGetPreviewFileSize(fileVersion);
072 }
073
074 public static InputStream getThumbnailAsStream(FileVersion fileVersion)
075 throws Exception {
076
077 return _instance.doGetThumbnailAsStream(fileVersion);
078 }
079
080 public static long getThumbnailFileSize(FileVersion fileVersion)
081 throws Exception {
082
083 return _instance.doGetThumbnailFileSize(fileVersion);
084 }
085
086 public static Set<String> getVideoMimeTypes() {
087 return _videoMimeTypes;
088 }
089
090 public static boolean hasVideo(FileVersion fileVersion) {
091 boolean hasVideo = false;
092
093 try {
094 hasVideo = _instance._hasVideo(fileVersion);
095
096 if (!hasVideo && _instance.isSupported(fileVersion)) {
097 _instance._queueGeneration(fileVersion);
098 }
099 }
100 catch (Exception e) {
101 _log.error(e, e);
102 }
103
104 return hasVideo;
105 }
106
107 public VideoProcessor() {
108 FileUtil.mkdirs(PREVIEW_TMP_PATH);
109 FileUtil.mkdirs(THUMBNAIL_TMP_PATH);
110 }
111
112 public boolean isSupported(String mimeType) {
113 return _videoMimeTypes.contains(mimeType);
114 }
115
116 public void trigger(FileVersion fileVersion) {
117 _instance._queueGeneration(fileVersion);
118 }
119
120 @Override
121 protected String getPreviewType() {
122 return PREVIEW_TYPE;
123 }
124
125 @Override
126 protected String getThumbnailType() {
127 return THUMBNAIL_TYPE;
128 }
129
130 private void _generateThumbnailXuggler(
131 FileVersion fileVersion, File file, int height, int width)
132 throws Exception {
133
134 String tempFileId = DLUtil.getTempFileId(
135 fileVersion.getFileEntryId(), fileVersion.getVersion());
136
137 File thumbnailTempFile = getThumbnailTempFile(tempFileId);
138
139 try {
140 try {
141 LiferayVideoThumbnailConverter liferayVideoThumbnailConverter =
142 new LiferayVideoThumbnailConverter(
143 file.getCanonicalPath(), thumbnailTempFile,
144 THUMBNAIL_TYPE, height, width, _THUMBNAIL_PERCENTAGE);
145
146 liferayVideoThumbnailConverter.convert();
147 }
148 catch (Exception e) {
149 _log.error(e, e);
150 }
151
152 addFileToStore(
153 fileVersion.getCompanyId(), THUMBNAIL_PATH,
154 getThumbnailFilePath(fileVersion), thumbnailTempFile);
155 }
156 catch (Exception e) {
157 throw new SystemException(e);
158 }
159 finally {
160 FileUtil.delete(thumbnailTempFile);
161 }
162
163 if (_log.isInfoEnabled()) {
164 _log.info(
165 "Xuggler generated a thumbnail for " +
166 fileVersion.getFileVersionId());
167 }
168 }
169
170 private void _generateVideo(FileVersion fileVersion) throws Exception {
171 String tempFileId = DLUtil.getTempFileId(
172 fileVersion.getFileEntryId(), fileVersion.getVersion());
173
174 File videoTempFile = _getVideoTempFile(
175 tempFileId, fileVersion.getExtension());
176 File previewTempFile = getPreviewTempFile(tempFileId);
177
178 try {
179 if (!PrefsPropsUtil.getBoolean(
180 PropsKeys.XUGGLER_ENABLED, PropsValues.XUGGLER_ENABLED) ||
181 _hasVideo(fileVersion)) {
182
183 return;
184 }
185
186 File file = null;
187
188 if (_isGeneratePreview(fileVersion) ||
189 _isGenerateThumbnail(fileVersion)) {
190
191 if (fileVersion instanceof LiferayFileVersion) {
192 try {
193 LiferayFileVersion liferayFileVersion =
194 (LiferayFileVersion)fileVersion;
195
196 file = liferayFileVersion.getFile(false);
197 }
198 catch (UnsupportedOperationException uoe) {
199 }
200 }
201
202 if (file == null) {
203 InputStream inputStream = fileVersion.getContentStream(
204 false);
205
206 FileUtil.write(videoTempFile, inputStream);
207
208 file = videoTempFile;
209 }
210 }
211
212 if (_isGeneratePreview(fileVersion)) {
213 try {
214 _generateVideoXuggler(
215 fileVersion, file, previewTempFile,
216 PropsValues.DL_FILE_ENTRY_PREVIEW_VIDEO_HEIGHT,
217 PropsValues.DL_FILE_ENTRY_PREVIEW_VIDEO_WIDTH);
218 }
219 catch (Exception e) {
220 _log.error(e, e);
221 }
222 }
223
224 if (_isGenerateThumbnail(fileVersion)) {
225 try {
226 _generateThumbnailXuggler(
227 fileVersion, file,
228 PropsValues.DL_FILE_ENTRY_PREVIEW_VIDEO_HEIGHT,
229 PropsValues.DL_FILE_ENTRY_PREVIEW_VIDEO_WIDTH);
230 }
231 catch (Exception e) {
232 _log.error(e, e);
233 }
234 }
235 }
236 catch (NoSuchFileEntryException nsfee) {
237 }
238 finally {
239 _fileVersionIds.remove(fileVersion.getFileVersionId());
240
241 FileUtil.delete(previewTempFile);
242 FileUtil.delete(videoTempFile);
243 }
244 }
245
246 private void _generateVideoXuggler(
247 FileVersion fileVersion, File srcFile, File destFile, int height,
248 int width)
249 throws Exception {
250
251 try {
252 LiferayVideoConverter liferayVideoConverter =
253 new LiferayVideoConverter(
254 srcFile.getCanonicalPath(), destFile.getCanonicalPath(),
255 height, width, _SAMPLE_RATE);
256
257 liferayVideoConverter.convert();
258 }
259 catch (Exception e) {
260 _log.error(e, e);
261 }
262
263 addFileToStore(
264 fileVersion.getCompanyId(), PREVIEW_PATH,
265 getPreviewFilePath(fileVersion), destFile);
266
267 if (_log.isInfoEnabled()) {
268 _log.info(
269 "Xuggler generated a preview video for " +
270 fileVersion.getFileVersionId());
271 }
272 }
273
274 private File _getVideoTempFile(String tempFileId, String targetExtension) {
275 String videoTempFilePath = _getVideoTempFilePath(
276 tempFileId, targetExtension);
277
278 return new File(videoTempFilePath);
279 }
280
281 private String _getVideoTempFilePath(
282 String tempFileId, String targetExtension) {
283
284 StringBundler sb = new StringBundler(5);
285
286 sb.append(PREVIEW_TMP_PATH);
287 sb.append(tempFileId);
288
289 if (PREVIEW_TYPE.equals(targetExtension)) {
290 sb.append("_tmp");
291 }
292
293 sb.append(StringPool.PERIOD);
294 sb.append(targetExtension);
295
296 return sb.toString();
297 }
298
299 private boolean _hasVideo(FileVersion fileVersion) throws Exception {
300 if (!isSupported(fileVersion)) {
301 return false;
302 }
303
304 boolean previewExists = DLStoreUtil.hasFile(
305 fileVersion.getCompanyId(), REPOSITORY_ID,
306 getPreviewFilePath(fileVersion));
307 boolean thumbnailExists = DLStoreUtil.hasFile(
308 fileVersion.getCompanyId(), REPOSITORY_ID,
309 getThumbnailFilePath(fileVersion));
310
311 if (PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED &&
312 PropsValues.DL_FILE_ENTRY_THUMBNAIL_ENABLED) {
313
314 if (previewExists && thumbnailExists) {
315 return true;
316 }
317 }
318 else if (PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED && previewExists) {
319 return true;
320 }
321 else if (PropsValues.DL_FILE_ENTRY_THUMBNAIL_ENABLED &&
322 thumbnailExists) {
323
324 return true;
325 }
326
327 return false;
328 }
329
330 private boolean _isGeneratePreview(FileVersion fileVersion)
331 throws Exception {
332
333 String previewFilePath = getPreviewFilePath(fileVersion);
334
335 if (PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED &&
336 !DLStoreUtil.hasFile(
337 fileVersion.getCompanyId(), REPOSITORY_ID, previewFilePath)) {
338
339 return true;
340 }
341 else {
342 return false;
343 }
344 }
345
346 private boolean _isGenerateThumbnail(FileVersion fileVersion)
347 throws Exception {
348
349 String thumbnailFilePath = getThumbnailFilePath(fileVersion);
350
351 if (PropsValues.DL_FILE_ENTRY_THUMBNAIL_ENABLED &&
352 !DLStoreUtil.hasFile(
353 fileVersion.getCompanyId(), REPOSITORY_ID, thumbnailFilePath)) {
354
355 return true;
356 }
357 else {
358 return false;
359 }
360 }
361
362 private void _queueGeneration(FileVersion fileVersion) {
363 if (_fileVersionIds.contains(fileVersion.getFileVersionId()) ||
364 !isSupported(fileVersion)) {
365
366 return;
367 }
368
369 _fileVersionIds.add(fileVersion.getFileVersionId());
370
371 MessageBusUtil.sendMessage(
372 DestinationNames.DOCUMENT_LIBRARY_VIDEO_PROCESSOR, fileVersion);
373 }
374
375 private static int _SAMPLE_RATE = 44100;
376
377 private static int _THUMBNAIL_PERCENTAGE =
378 PropsValues.DL_FILE_ENTRY_THUMBNAIL_VIDEO_FRAME_PERCENTAGE;
379
380 private static Log _log = LogFactoryUtil.getLog(VideoProcessor.class);
381
382 private static VideoProcessor _instance = new VideoProcessor();
383
384 private static List<Long> _fileVersionIds = new Vector<Long>();
385 private static Set<String> _videoMimeTypes = SetUtil.fromArray(
386 PropsValues.DL_FILE_ENTRY_PREVIEW_VIDEO_MIME_TYPES);
387
388 }