1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.opencastproject.workflow.handler.crop;
22
23 import org.opencastproject.crop.api.CropException;
24 import org.opencastproject.crop.api.CropService;
25 import org.opencastproject.job.api.Job;
26 import org.opencastproject.job.api.JobContext;
27 import org.opencastproject.mediapackage.MediaPackage;
28 import org.opencastproject.mediapackage.MediaPackageElementFlavor;
29 import org.opencastproject.mediapackage.MediaPackageElementParser;
30 import org.opencastproject.mediapackage.MediaPackageException;
31 import org.opencastproject.mediapackage.Track;
32 import org.opencastproject.mediapackage.identifier.IdImpl;
33 import org.opencastproject.serviceregistry.api.ServiceRegistry;
34 import org.opencastproject.util.NotFoundException;
35 import org.opencastproject.workflow.api.AbstractWorkflowOperationHandler;
36 import org.opencastproject.workflow.api.ConfiguredTagsAndFlavors;
37 import org.opencastproject.workflow.api.WorkflowInstance;
38 import org.opencastproject.workflow.api.WorkflowOperationException;
39 import org.opencastproject.workflow.api.WorkflowOperationHandler;
40 import org.opencastproject.workflow.api.WorkflowOperationInstance;
41 import org.opencastproject.workflow.api.WorkflowOperationResult;
42 import org.opencastproject.workspace.api.Workspace;
43
44 import org.osgi.service.component.annotations.Component;
45 import org.osgi.service.component.annotations.Reference;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 import java.io.IOException;
50 import java.util.ArrayList;
51 import java.util.Arrays;
52 import java.util.HashMap;
53 import java.util.List;
54 import java.util.Map;
55
56
57
58
59 @Component(
60 immediate = true,
61 service = WorkflowOperationHandler.class,
62 property = {
63 "service.description=Videosegmentation Workflow Operation Handler",
64 "workflow.operation=crop-video"
65 }
66 )
67 public class CropWorkflowOperationHandler extends AbstractWorkflowOperationHandler {
68
69
70 private static final Logger logger = LoggerFactory.getLogger(CropWorkflowOperationHandler.class);
71
72
73 private static final String PROP_SOURCE_FLAVOR = "source-flavor";
74
75 private static final String PROP_TARGET_FLAVOR = "target-flavor";
76
77
78 private static final String PROP_TARGET_TAGS = "target-tags";
79
80
81 private CropService cropService = null;
82
83
84 private Workspace workspace = null;
85
86
87
88
89
90
91
92 @Override
93 public WorkflowOperationResult start(WorkflowInstance workflowInstance, JobContext jobContext)
94 throws WorkflowOperationException {
95
96 WorkflowOperationInstance operation = workflowInstance.getCurrentOperation();
97 MediaPackage mediaPackage = workflowInstance.getMediaPackage();
98
99 logger.info("Start cropping workflow operation for mediapackage {}", mediaPackage.getIdentifier().toString());
100
101
102 ConfiguredTagsAndFlavors tagsAndFlavors = getTagsAndFlavors(workflowInstance,
103 Configuration.none, Configuration.one, Configuration.many, Configuration.many);
104 List<String> targetTags = tagsAndFlavors.getTargetTags();
105 List<MediaPackageElementFlavor> targetFlavorOption = tagsAndFlavors.getTargetFlavors();
106
107 MediaPackageElementFlavor targetFlavor = null;
108 if (!targetFlavorOption.isEmpty()) {
109 targetFlavor = targetFlavorOption.get(0);
110 }
111 MediaPackageElementFlavor trackFlavor = tagsAndFlavors.getSingleSrcFlavor();
112
113 List<Track> candidates = new ArrayList<>();
114 candidates.addAll(Arrays.asList(mediaPackage.getTracks(trackFlavor)));
115 candidates.removeIf(t -> !t.hasVideo());
116
117 if (candidates.size() == 0) {
118 logger.info("No matching tracks available for cropping in workflow {}", workflowInstance);
119 return createResult(WorkflowOperationResult.Action.CONTINUE);
120 } else if (candidates.size() > 1) {
121 logger.info("Found more than one track to crop");
122 }
123
124
125 Map<Job, Track> jobs = new HashMap<Job, Track>();
126 for (Track candidate : candidates) {
127 try {
128 jobs.put(cropService.crop(candidate), candidate);
129 } catch (MediaPackageException | CropException e) {
130 throw new WorkflowOperationException("Failed starting crop job", e);
131 }
132 }
133
134
135 if (!waitForStatus(jobs.keySet().toArray(new Job[0])).isSuccess()) {
136 throw new WorkflowOperationException("Crop operation failed");
137 }
138
139 long totalTimeInQueue = 0;
140
141
142 for (Map.Entry<Job, Track> entry : jobs.entrySet()) {
143 Job job = entry.getKey();
144 Track track = entry.getValue();
145
146 Track croppedTrack;
147 try {
148 croppedTrack = (Track) MediaPackageElementParser.getFromXml(job.getPayload());
149 } catch (MediaPackageException e) {
150 throw new WorkflowOperationException(String.format("Crop service yielded invalid track: %s", job.getPayload()));
151 }
152
153
154 croppedTrack.setIdentifier(IdImpl.fromUUID().toString());
155
156
157 try {
158 String filename = "cropped_" + croppedTrack.getURI().toString();
159 croppedTrack.setURI(workspace
160 .moveTo(croppedTrack.getURI(), mediaPackage.getIdentifier().toString(), croppedTrack.getIdentifier(),
161 filename));
162 } catch (NotFoundException | IOException e) {
163 throw new WorkflowOperationException(
164 String.format("Could not move %s to media package %s", croppedTrack.getURI(),
165 mediaPackage.getIdentifier()));
166 }
167
168
169 targetTags.forEach(croppedTrack::addTag);
170 croppedTrack.setFlavor(targetFlavor);
171
172
173 mediaPackage.addDerived(croppedTrack, track);
174
175 totalTimeInQueue += job.getQueueTime() == null ? 0 : job.getQueueTime();
176 }
177 logger.info("Video cropping completed");
178 return createResult(mediaPackage, WorkflowOperationResult.Action.CONTINUE, totalTimeInQueue);
179 }
180
181
182
183
184
185
186
187
188 @Reference
189 protected void setCropService(CropService cropService) {
190 this.cropService = cropService;
191 }
192
193
194
195
196
197
198
199
200 @Reference
201 protected void setWorkspace(Workspace workspace) {
202 this.workspace = workspace;
203 }
204
205 @Reference
206 @Override
207 public void setServiceRegistry(ServiceRegistry serviceRegistry) {
208 super.setServiceRegistry(serviceRegistry);
209 }
210
211 }