001/* 002 * (C) Copyright 2006-2012 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl-2.1.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Thomas Roger 016 * Florent Guillaume 017 */ 018package org.nuxeo.ecm.platform.video.service; 019 020import static org.nuxeo.ecm.core.api.CoreSession.ALLOW_VERSION_WRITE; 021 022import java.io.Serializable; 023import java.util.ArrayList; 024import java.util.List; 025import java.util.Map; 026 027import org.apache.commons.logging.Log; 028import org.apache.commons.logging.LogFactory; 029import org.nuxeo.ecm.core.api.DocumentModel; 030import org.nuxeo.ecm.core.api.IdRef; 031import org.nuxeo.ecm.core.event.Event; 032import org.nuxeo.ecm.core.event.EventService; 033import org.nuxeo.ecm.core.event.impl.DocumentEventContext; 034import org.nuxeo.ecm.core.work.AbstractWork; 035import org.nuxeo.ecm.core.work.api.WorkManager; 036import org.nuxeo.ecm.platform.video.TranscodedVideo; 037import org.nuxeo.ecm.platform.video.Video; 038import org.nuxeo.ecm.platform.video.VideoDocument; 039import org.nuxeo.runtime.api.Framework; 040 041/** 042 * Work running a defined video conversion. 043 * 044 * @since 5.6 045 */ 046public class VideoConversionWork extends AbstractWork { 047 048 private static final long serialVersionUID = 1L; 049 050 private static final Log log = LogFactory.getLog(VideoConversionWork.class); 051 052 public static final String CATEGORY_VIDEO_CONVERSION = "videoConversion"; 053 054 public static final String VIDEO_CONVERSIONS_DONE_EVENT = "videoConversionsDone"; 055 056 protected final String conversionName; 057 058 protected static String computeIdPrefix(String repositoryName, String docId) { 059 return repositoryName + ':' + docId + ":videoconv:"; 060 } 061 062 public VideoConversionWork(String repositoryName, String docId, String conversionName) { 063 super(computeIdPrefix(repositoryName, docId) + conversionName); 064 setDocument(repositoryName, docId); 065 this.conversionName = conversionName; 066 } 067 068 @Override 069 public String getCategory() { 070 return CATEGORY_VIDEO_CONVERSION; 071 } 072 073 @Override 074 public String getTitle() { 075 return "Video Conversion " + conversionName; 076 } 077 078 @Override 079 public void work() { 080 setStatus("Extracting"); 081 setProgress(Progress.PROGRESS_INDETERMINATE); 082 083 Video originalVideo = null; 084 try { 085 initSession(); 086 originalVideo = getVideoToConvert(); 087 commitOrRollbackTransaction(); 088 } finally { 089 cleanUp(true, null); 090 } 091 092 if (originalVideo == null) { 093 setStatus("Nothing to process"); 094 return; 095 } 096 097 // Perform the actual conversion 098 VideoService service = Framework.getLocalService(VideoService.class); 099 setStatus("Transcoding"); 100 TranscodedVideo transcodedVideo = service.convert(originalVideo, conversionName); 101 102 // Saving it to the document 103 startTransaction(); 104 setStatus("Saving"); 105 initSession(); 106 DocumentModel doc = session.getDocument(new IdRef(docId)); 107 saveNewTranscodedVideo(doc, transcodedVideo); 108 fireVideoConversionsDoneEvent(doc); 109 setStatus("Done"); 110 } 111 112 protected Video getVideoToConvert() { 113 DocumentModel doc = session.getDocument(new IdRef(docId)); 114 VideoDocument videoDocument = doc.getAdapter(VideoDocument.class); 115 Video video = videoDocument.getVideo(); 116 if (video == null) { 117 log.warn("No original video to transcode for: " + doc); 118 } 119 return video; 120 } 121 122 protected void saveNewTranscodedVideo(DocumentModel doc, TranscodedVideo transcodedVideo) { 123 @SuppressWarnings("unchecked") 124 List<Map<String, Serializable>> transcodedVideos = (List<Map<String, Serializable>>) doc.getPropertyValue("vid:transcodedVideos"); 125 if (transcodedVideos == null) { 126 transcodedVideos = new ArrayList<>(); 127 } 128 transcodedVideos.add(transcodedVideo.toMap()); 129 doc.setPropertyValue("vid:transcodedVideos", (Serializable) transcodedVideos); 130 if (doc.isVersion()) { 131 doc.putContextData(ALLOW_VERSION_WRITE, Boolean.TRUE); 132 } 133 session.saveDocument(doc); 134 } 135 136 /** 137 * Fire a {@code VIDEO_CONVERSIONS_DONE_EVENT} event when no other VideoConversionWork is scheduled for this 138 * document. 139 * 140 * @since 5.8 141 */ 142 protected void fireVideoConversionsDoneEvent(DocumentModel doc) { 143 WorkManager workManager = Framework.getLocalService(WorkManager.class); 144 List<String> workIds = workManager.listWorkIds(CATEGORY_VIDEO_CONVERSION, null); 145 String idPrefix = computeIdPrefix(repositoryName, docId); 146 int worksCount = 0; 147 for (String workId : workIds) { 148 if (workId.startsWith(idPrefix)) { 149 if (++worksCount > 1) { 150 // another work scheduled 151 return; 152 } 153 } 154 } 155 156 DocumentEventContext ctx = new DocumentEventContext(session, session.getPrincipal(), doc); 157 Event event = ctx.newEvent(VIDEO_CONVERSIONS_DONE_EVENT); 158 Framework.getLocalService(EventService.class).fireEvent(event); 159 } 160 161}