001/* 002 * (C) Copyright 2006-2012 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 018 * Florent Guillaume 019 */ 020package org.nuxeo.ecm.platform.video.service; 021 022import static org.nuxeo.ecm.core.api.CoreSession.ALLOW_VERSION_WRITE; 023 024import java.io.Serializable; 025import java.util.ArrayList; 026import java.util.List; 027import java.util.Map; 028 029import org.apache.commons.logging.Log; 030import org.apache.commons.logging.LogFactory; 031import org.nuxeo.ecm.core.api.DocumentModel; 032import org.nuxeo.ecm.core.api.IdRef; 033import org.nuxeo.ecm.core.event.Event; 034import org.nuxeo.ecm.core.event.EventService; 035import org.nuxeo.ecm.core.event.impl.DocumentEventContext; 036import org.nuxeo.ecm.core.work.AbstractWork; 037import org.nuxeo.ecm.core.work.api.WorkManager; 038import org.nuxeo.ecm.platform.video.TranscodedVideo; 039import org.nuxeo.ecm.platform.video.Video; 040import org.nuxeo.ecm.platform.video.VideoDocument; 041import org.nuxeo.runtime.api.Framework; 042 043/** 044 * Work running a defined video conversion. 045 * 046 * @since 5.6 047 */ 048public class VideoConversionWork extends AbstractWork { 049 050 private static final long serialVersionUID = 1L; 051 052 private static final Log log = LogFactory.getLog(VideoConversionWork.class); 053 054 public static final String CATEGORY_VIDEO_CONVERSION = "videoConversion"; 055 056 public static final String VIDEO_CONVERSIONS_DONE_EVENT = "videoConversionsDone"; 057 058 protected final String conversionName; 059 060 protected static String computeIdPrefix(String repositoryName, String docId) { 061 return repositoryName + ':' + docId + ":videoconv:"; 062 } 063 064 public VideoConversionWork(String repositoryName, String docId, String conversionName) { 065 super(computeIdPrefix(repositoryName, docId) + conversionName); 066 setDocument(repositoryName, docId); 067 this.conversionName = conversionName; 068 } 069 070 @Override 071 public String getCategory() { 072 return CATEGORY_VIDEO_CONVERSION; 073 } 074 075 @Override 076 public String getTitle() { 077 return "Video Conversion " + conversionName; 078 } 079 080 @Override 081 public void work() { 082 setStatus("Extracting"); 083 setProgress(Progress.PROGRESS_INDETERMINATE); 084 085 Video originalVideo = null; 086 try { 087 openSystemSession(); 088 originalVideo = getVideoToConvert(); 089 commitOrRollbackTransaction(); 090 } finally { 091 cleanUp(true, null); 092 } 093 094 if (originalVideo == null) { 095 setStatus("Nothing to process"); 096 return; 097 } 098 099 // Perform the actual conversion 100 VideoService service = Framework.getService(VideoService.class); 101 setStatus("Transcoding"); 102 TranscodedVideo transcodedVideo = service.convert(originalVideo, conversionName); 103 104 // Saving it to the document 105 startTransaction(); 106 setStatus("Saving"); 107 openSystemSession(); 108 DocumentModel doc = session.getDocument(new IdRef(docId)); 109 saveNewTranscodedVideo(doc, transcodedVideo); 110 fireVideoConversionsDoneEvent(doc); 111 setStatus("Done"); 112 } 113 114 protected Video getVideoToConvert() { 115 DocumentModel doc = session.getDocument(new IdRef(docId)); 116 VideoDocument videoDocument = doc.getAdapter(VideoDocument.class); 117 Video video = videoDocument.getVideo(); 118 if (video == null) { 119 log.warn("No original video to transcode for: " + doc); 120 } 121 return video; 122 } 123 124 protected void saveNewTranscodedVideo(DocumentModel doc, TranscodedVideo transcodedVideo) { 125 @SuppressWarnings("unchecked") 126 List<Map<String, Serializable>> transcodedVideos = (List<Map<String, Serializable>>) doc.getPropertyValue("vid:transcodedVideos"); 127 if (transcodedVideos == null) { 128 transcodedVideos = new ArrayList<>(); 129 } 130 transcodedVideos.add(transcodedVideo.toMap()); 131 doc.setPropertyValue("vid:transcodedVideos", (Serializable) transcodedVideos); 132 if (doc.isVersion()) { 133 doc.putContextData(ALLOW_VERSION_WRITE, Boolean.TRUE); 134 } 135 session.saveDocument(doc); 136 } 137 138 /** 139 * Fire a {@code VIDEO_CONVERSIONS_DONE_EVENT} event when no other VideoConversionWork is scheduled for this 140 * document. 141 * 142 * @since 5.8 143 */ 144 protected void fireVideoConversionsDoneEvent(DocumentModel doc) { 145 WorkManager workManager = Framework.getService(WorkManager.class); 146 List<String> workIds = workManager.listWorkIds(CATEGORY_VIDEO_CONVERSION, null); 147 String idPrefix = computeIdPrefix(repositoryName, docId); 148 int worksCount = 0; 149 for (String workId : workIds) { 150 if (workId.startsWith(idPrefix)) { 151 if (++worksCount > 1) { 152 // another work scheduled 153 return; 154 } 155 } 156 } 157 158 DocumentEventContext ctx = new DocumentEventContext(session, session.getPrincipal(), doc); 159 Event event = ctx.newEvent(VIDEO_CONVERSIONS_DONE_EVENT); 160 Framework.getService(EventService.class).fireEvent(event); 161 } 162 163}