use of org.opencastproject.smil.entity.media.container.api.SmilMediaContainer in project opencast by opencast.
the class ToolsEndpointTest method setUpClass.
@BeforeClass
public static void setUpClass() throws Exception {
/* Start of Smil mockups */
// Ugly, but strictly the smil APIs
String trackSrc = "http://mh-allinone.localdomain/archive/archive/mediapackage/0f2a2ada-0584-4d4d-a248-111f654aa217/6ec443e7-b097-4470-a618-5e0d848f5252/0/track.mp4";
URL smilUrl = ToolsEndpoint.class.getResource("/tools/smil1.xml");
String smilString = IOUtils.toString(smilUrl);
String trackParamGroupId = "pg-a6d8e576-495f-44c7-8ed7-b5b47c807f0f";
SmilMediaParam param1 = EasyMock.createNiceMock(SmilMediaParam.class);
EasyMock.expect(param1.getName()).andReturn("track-id").anyTimes();
EasyMock.expect(param1.getValue()).andReturn("track-1").anyTimes();
EasyMock.expect(param1.getId()).andReturn("param-e2f41e7d-caba-401b-a03a-e524296cb235").anyTimes();
SmilMediaParam param2 = EasyMock.createNiceMock(SmilMediaParam.class);
EasyMock.expect(param2.getName()).andReturn("track-src").anyTimes();
EasyMock.expect(param2.getValue()).andReturn(trackSrc).anyTimes();
EasyMock.expect(param2.getId()).andReturn("param-1bd5e839-0a74-4310-b1d2-daba07914f79").anyTimes();
SmilMediaParam param3 = EasyMock.createNiceMock(SmilMediaParam.class);
EasyMock.expect(param3.getName()).andReturn("track-flavor").anyTimes();
EasyMock.expect(param3.getValue()).andReturn("presenter/work").anyTimes();
EasyMock.expect(param3.getId()).andReturn("param-1bd5e839-0a74-4310-b1d2-daba07914f79").anyTimes();
EasyMock.replay(param1, param2, param3);
List<SmilMediaParam> params = new ArrayList<>();
params.add(param1);
params.add(param2);
params.add(param3);
SmilMediaParamGroup group1 = EasyMock.createNiceMock(SmilMediaParamGroup.class);
EasyMock.expect(group1.getParams()).andReturn(params).anyTimes();
EasyMock.expect(group1.getId()).andReturn(trackParamGroupId).anyTimes();
EasyMock.replay(group1);
List<SmilMediaParamGroup> paramGroups = new ArrayList<>();
paramGroups.add(group1);
SmilHead head = EasyMock.createNiceMock(SmilHead.class);
EasyMock.expect(head.getParamGroups()).andReturn(paramGroups).anyTimes();
EasyMock.replay(head);
SmilMediaElement object1 = EasyMock.createNiceMock(SmilMediaElement.class);
EasyMock.expect(object1.isContainer()).andReturn(false).anyTimes();
EasyMock.expect(object1.getParamGroup()).andReturn(trackParamGroupId).anyTimes();
EasyMock.expect(object1.getClipBeginMS()).andReturn(0L).anyTimes();
EasyMock.expect(object1.getClipEndMS()).andReturn(2449L).anyTimes();
EasyMock.expect(object1.getSrc()).andReturn(new URI(trackSrc)).anyTimes();
EasyMock.replay(object1);
SmilMediaElement object2 = EasyMock.createNiceMock(SmilMediaElement.class);
EasyMock.expect(object2.isContainer()).andReturn(false).anyTimes();
EasyMock.expect(object2.getParamGroup()).andReturn(trackParamGroupId).anyTimes();
EasyMock.expect(object2.getClipBeginMS()).andReturn(4922L).anyTimes();
EasyMock.expect(object2.getClipEndMS()).andReturn(11284L).anyTimes();
EasyMock.expect(object2.getSrc()).andReturn(new URI(trackSrc)).anyTimes();
EasyMock.replay(object2);
SmilMediaElement object3 = EasyMock.createNiceMock(SmilMediaElement.class);
EasyMock.expect(object3.isContainer()).andReturn(false).anyTimes();
EasyMock.expect(object3.getParamGroup()).andReturn(trackParamGroupId).anyTimes();
EasyMock.expect(object3.getClipBeginMS()).andReturn(14721L).anyTimes();
EasyMock.expect(object3.getClipEndMS()).andReturn(15963L).anyTimes();
EasyMock.expect(object3.getSrc()).andReturn(new URI(trackSrc)).anyTimes();
EasyMock.replay(object3);
SmilMediaElement object4 = EasyMock.createNiceMock(SmilMediaElement.class);
EasyMock.expect(object4.isContainer()).andReturn(false).anyTimes();
EasyMock.expect(object4.getParamGroup()).andReturn(trackParamGroupId).anyTimes();
EasyMock.expect(object4.getClipBeginMS()).andReturn(15963L).anyTimes();
EasyMock.expect(object4.getClipEndMS()).andReturn(20132L).anyTimes();
EasyMock.expect(object4.getSrc()).andReturn(new URI(trackSrc)).anyTimes();
EasyMock.replay(object4);
List<SmilMediaObject> objects1 = new ArrayList<>();
objects1.add(object1);
List<SmilMediaObject> objects2 = new ArrayList<>();
objects2.add(object2);
List<SmilMediaObject> objects3 = new ArrayList<>();
objects3.add(object3);
List<SmilMediaObject> objects4 = new ArrayList<>();
objects4.add(object4);
SmilMediaContainer objectContainer1 = EasyMock.createNiceMock(SmilMediaContainer.class);
EasyMock.expect(objectContainer1.isContainer()).andReturn(true).anyTimes();
EasyMock.expect(objectContainer1.getContainerType()).andReturn(SmilMediaContainer.ContainerType.PAR).anyTimes();
EasyMock.expect(objectContainer1.getElements()).andReturn(objects1).anyTimes();
EasyMock.replay(objectContainer1);
SmilMediaContainer objectContainer2 = EasyMock.createNiceMock(SmilMediaContainer.class);
EasyMock.expect(objectContainer2.isContainer()).andReturn(true).anyTimes();
EasyMock.expect(objectContainer2.getContainerType()).andReturn(SmilMediaContainer.ContainerType.PAR).anyTimes();
EasyMock.expect(objectContainer2.getElements()).andReturn(objects2).anyTimes();
EasyMock.replay(objectContainer2);
SmilMediaContainer objectContainer3 = EasyMock.createNiceMock(SmilMediaContainer.class);
EasyMock.expect(objectContainer3.isContainer()).andReturn(true).anyTimes();
EasyMock.expect(objectContainer3.getContainerType()).andReturn(SmilMediaContainer.ContainerType.PAR).anyTimes();
EasyMock.expect(objectContainer3.getElements()).andReturn(objects3).anyTimes();
EasyMock.replay(objectContainer3);
SmilMediaContainer objectContainer4 = EasyMock.createNiceMock(SmilMediaContainer.class);
EasyMock.expect(objectContainer4.isContainer()).andReturn(true).anyTimes();
EasyMock.expect(objectContainer4.getContainerType()).andReturn(SmilMediaContainer.ContainerType.PAR).anyTimes();
EasyMock.expect(objectContainer4.getElements()).andReturn(objects4).anyTimes();
EasyMock.replay(objectContainer4);
List<SmilMediaObject> containerObjects = new ArrayList<>();
containerObjects.add(objectContainer1);
containerObjects.add(objectContainer2);
containerObjects.add(objectContainer3);
containerObjects.add(objectContainer4);
SmilBody body = EasyMock.createNiceMock(SmilBody.class);
EasyMock.expect(body.getMediaElements()).andReturn(containerObjects).anyTimes();
EasyMock.replay(body);
smil = EasyMock.createNiceMock(Smil.class);
EasyMock.expect(smil.get(trackParamGroupId)).andReturn(group1).anyTimes();
EasyMock.expect(smil.getBody()).andReturn(body).anyTimes();
EasyMock.expect(smil.getHead()).andReturn(head).anyTimes();
EasyMock.expect(smil.toXML()).andReturn(smilString).anyTimes();
EasyMock.expect(smil.getId()).andReturn("s-ec404c2a-5092-4cd4-8717-7b7bbc244656").anyTimes();
EasyMock.replay(smil);
SmilResponse response = EasyMock.createNiceMock(SmilResponse.class);
EasyMock.expect(response.getSmil()).andReturn(smil).anyTimes();
EasyMock.replay(response);
SmilService smilService = EasyMock.createNiceMock(SmilService.class);
EasyMock.expect(smilService.fromXml((String) EasyMock.anyObject())).andReturn(response).anyTimes();
EasyMock.replay(smilService);
/* End of Smil API mockups */
endpoint = new ToolsEndpoint();
endpoint.setSmilService(smilService);
AdminUIConfiguration adminUIConfiguration = new AdminUIConfiguration();
Hashtable<String, String> dictionary = new Hashtable<>();
dictionary.put(AdminUIConfiguration.OPT_PREVIEW_SUBTYPE, "preview");
dictionary.put(AdminUIConfiguration.OPT_WAVEFORM_SUBTYPE, "waveform");
dictionary.put(AdminUIConfiguration.OPT_SMIL_CATALOG_FLAVOR, "smil/cutting");
dictionary.put(AdminUIConfiguration.OPT_SMIL_SILENCE_FLAVOR, "*/silence");
adminUIConfiguration.updated(dictionary);
endpoint.setAdminUIConfiguration(adminUIConfiguration);
}
use of org.opencastproject.smil.entity.media.container.api.SmilMediaContainer in project opencast by opencast.
the class VideoEditorWorkflowOperationHandler method resume.
/**
* {@inheritDoc}
*
* @see org.opencastproject.workflow.api.ResumableWorkflowOperationHandler#resume(org.opencastproject.workflow.api.WorkflowInstance,
* JobContext, java.util.Map)
*/
@Override
public WorkflowOperationResult resume(WorkflowInstance workflowInstance, JobContext context, Map<String, String> properties) throws WorkflowOperationException {
MediaPackage mp = workflowInstance.getMediaPackage();
logger.info("Resume video editor operation for mediapackage {}", mp.getIdentifier().compact());
// Get configuration
WorkflowOperationInstance worflowOperationInstance = workflowInstance.getCurrentOperation();
String sourceTrackFlavorsProperty = StringUtils.trimToNull(worflowOperationInstance.getConfiguration(SOURCE_FLAVORS_PROPERTY));
if (sourceTrackFlavorsProperty == null) {
throw new WorkflowOperationException(format("Required configuration property %s not set.", SOURCE_FLAVORS_PROPERTY));
}
String targetSmilFlavorProperty = StringUtils.trimToNull(worflowOperationInstance.getConfiguration(TARGET_SMIL_FLAVOR_PROPERTY));
if (targetSmilFlavorProperty == null) {
throw new WorkflowOperationException(format("Required configuration property %s not set.", TARGET_SMIL_FLAVOR_PROPERTY));
}
String targetFlavorSybTypeProperty = StringUtils.trimToNull(worflowOperationInstance.getConfiguration(TARGET_FLAVOR_SUBTYPE_PROPERTY));
if (targetFlavorSybTypeProperty == null) {
throw new WorkflowOperationException(format("Required configuration property %s not set.", TARGET_FLAVOR_SUBTYPE_PROPERTY));
}
boolean skipIfNoTrim = BooleanUtils.toBoolean(worflowOperationInstance.getConfiguration(SKIP_NOT_TRIMMED_PROPERTY));
// Get source tracks
TrackSelector trackSelector = new TrackSelector();
for (String flavor : asList(sourceTrackFlavorsProperty)) {
trackSelector.addFlavor(flavor);
}
Collection<Track> sourceTracks = trackSelector.select(mp, false);
if (sourceTracks.isEmpty()) {
throw new WorkflowOperationException(format("No source tracks found in mediapacksge %s with flavors %s.", mp.getIdentifier().compact(), sourceTrackFlavorsProperty));
}
// Get SMIL file
MediaPackageElementFlavor smilTargetFlavor = MediaPackageElementFlavor.parseFlavor(targetSmilFlavorProperty);
Catalog[] smilCatalogs = mp.getCatalogs(smilTargetFlavor);
if (smilCatalogs == null || smilCatalogs.length == 0) {
throw new WorkflowOperationException(format("No SMIL catalog found in mediapackage %s with flavor %s.", mp.getIdentifier().compact(), targetSmilFlavorProperty));
}
File smilFile = null;
Smil smil = null;
try {
smilFile = workspace.get(smilCatalogs[0].getURI());
smil = smilService.fromXml(smilFile).getSmil();
smil = replaceAllTracksWith(smil, sourceTracks.toArray(new Track[sourceTracks.size()]));
InputStream is = null;
try {
is = IOUtils.toInputStream(smil.toXML(), "UTF-8");
// Remove old SMIL
workspace.delete(mp.getIdentifier().compact(), smilCatalogs[0].getIdentifier());
mp.remove(smilCatalogs[0]);
// put modified SMIL into workspace
URI newSmilUri = workspace.put(mp.getIdentifier().compact(), smil.getId(), SMIL_FILE_NAME, is);
Catalog catalog = (Catalog) MediaPackageElementBuilderFactory.newInstance().newElementBuilder().elementFromURI(newSmilUri, MediaPackageElement.Type.Catalog, smilCatalogs[0].getFlavor());
catalog.setIdentifier(smil.getId());
mp.add(catalog);
} catch (Exception ex) {
throw new WorkflowOperationException(ex);
} finally {
IOUtils.closeQuietly(is);
}
} catch (NotFoundException ex) {
throw new WorkflowOperationException(format("Failed to get SMIL catalog %s from mediapackage %s.", smilCatalogs[0].getIdentifier(), mp.getIdentifier().compact()), ex);
} catch (IOException ex) {
throw new WorkflowOperationException(format("Can't open SMIL catalog %s from mediapackage %s.", smilCatalogs[0].getIdentifier(), mp.getIdentifier().compact()), ex);
} catch (SmilException ex) {
throw new WorkflowOperationException(ex);
}
if (skipIfNoTrim) {
// We should not modify the SMIL file as we traverse through its elements, so we make a copy and modify it instead
try {
Smil filteredSmil = smilService.fromXml(smil.toXML()).getSmil();
for (SmilMediaObject element : smil.getBody().getMediaElements()) {
// body should contain par elements
if (element.isContainer()) {
SmilMediaContainer container = (SmilMediaContainer) element;
if (SmilMediaContainer.ContainerType.PAR == container.getContainerType()) {
continue;
}
}
filteredSmil = smilService.removeSmilElement(filteredSmil, element.getId()).getSmil();
}
// one that takes the whole video size
switch(filteredSmil.getBody().getMediaElements().size()) {
case 0:
logger.info("Skipping SMIL job generation for mediapackage '{}', " + "because the SMIL does not define any trimming points", mp.getIdentifier());
return skip(workflowInstance, context);
case 1:
// component represents the whole duration or not, therefore we don't bother to try
if (mp.getDuration() < 0)
break;
SmilMediaContainer parElement = (SmilMediaContainer) filteredSmil.getBody().getMediaElements().get(0);
boolean skip = true;
for (SmilMediaObject elementChild : parElement.getElements()) {
if (!elementChild.isContainer()) {
SmilMediaElement media = (SmilMediaElement) elementChild;
// If they don't represent the whole length, then we break --we have a trimming point
if ((media.getClipBeginMS() != 0) || (media.getClipEndMS() != mp.getDuration())) {
skip = false;
break;
}
}
}
if (skip) {
logger.info("Skipping SMIL job generation for mediapackage '{}', " + "because the trimming points in the SMIL correspond " + "to the beginning and the end of the video", mp.getIdentifier());
return skip(workflowInstance, context);
}
break;
default:
break;
}
} catch (MalformedURLException | SmilException | JAXBException | SAXException e) {
logger.warn("Error parsing input SMIL to determine if it has trimpoints. " + "We will assume it does and go on creating jobs.");
}
}
// Create video edit jobs and run them
List<Job> jobs = null;
try {
logger.info("Create processing jobs for SMIL file: {}", smilCatalogs[0].getIdentifier());
jobs = videoEditorService.processSmil(smil);
if (!waitForStatus(jobs.toArray(new Job[jobs.size()])).isSuccess()) {
throw new WorkflowOperationException(format("Processing SMIL file failed: %s", smilCatalogs[0].getIdentifier()));
}
logger.info("Finished processing of SMIL file: {}", smilCatalogs[0].getIdentifier());
} catch (ProcessFailedException ex) {
throw new WorkflowOperationException(format("Finished processing of SMIL file: %s", smilCatalogs[0].getIdentifier()), ex);
}
// Move edited tracks to work location and set target flavor
Track editedTrack = null;
boolean mpAdded = false;
for (Job job : jobs) {
try {
editedTrack = (Track) MediaPackageElementParser.getFromXml(job.getPayload());
MediaPackageElementFlavor editedTrackFlavor = editedTrack.getFlavor();
editedTrack.setFlavor(new MediaPackageElementFlavor(editedTrackFlavor.getType(), targetFlavorSybTypeProperty));
URI editedTrackNewUri = workspace.moveTo(editedTrack.getURI(), mp.getIdentifier().compact(), editedTrack.getIdentifier(), FilenameUtils.getName(editedTrack.getURI().toString()));
editedTrack.setURI(editedTrackNewUri);
for (Track track : sourceTracks) {
if (track.getFlavor().getType().equals(editedTrackFlavor.getType())) {
mp.addDerived(editedTrack, track);
mpAdded = true;
break;
}
}
if (!mpAdded) {
mp.add(editedTrack);
}
} catch (MediaPackageException ex) {
throw new WorkflowOperationException("Failed to get information about the edited track(s)", ex);
} catch (NotFoundException | IOException | IllegalArgumentException ex) {
throw new WorkflowOperationException("Moving edited track to work location failed.", ex);
} catch (Exception ex) {
throw new WorkflowOperationException(ex);
}
}
logger.info("VideoEdit workflow {} finished", workflowInstance.getId());
return createResult(mp, Action.CONTINUE);
}
use of org.opencastproject.smil.entity.media.container.api.SmilMediaContainer in project opencast by opencast.
the class VideoEditorWorkflowOperationHandler method replaceAllTracksWith.
protected Smil replaceAllTracksWith(Smil smil, Track[] otherTracks) throws SmilException {
SmilResponse smilResponse;
try {
// copy SMIL to work with
smilResponse = smilService.fromXml(smil.toXML());
} catch (Exception ex) {
throw new SmilException("Can not parse SMIL files.");
}
long start;
long end;
// iterate over all elements inside SMIL body
for (SmilMediaObject elem : smil.getBody().getMediaElements()) {
start = -1L;
end = -1L;
// body should contain par elements (container)
if (elem.isContainer()) {
// iterate over all elements in container
for (SmilMediaObject child : ((SmilMediaContainer) elem).getElements()) {
// second depth should contain media elements like audio or video
if (!child.isContainer() && child instanceof SmilMediaElement) {
SmilMediaElement media = (SmilMediaElement) child;
start = media.getClipBeginMS();
end = media.getClipEndMS();
// remove it
smilResponse = smilService.removeSmilElement(smilResponse.getSmil(), media.getId());
}
}
if (start != -1L && end != -1L) {
// add the new tracks inside
smilResponse = smilService.addClips(smilResponse.getSmil(), elem.getId(), otherTracks, start, end - start);
}
} else if (elem instanceof SmilMediaElement) {
throw new SmilException("Media elements inside SMIL body are not supported yet.");
}
}
return smilResponse.getSmil();
}
use of org.opencastproject.smil.entity.media.container.api.SmilMediaContainer in project opencast by opencast.
the class SmilServiceImplTest method testFromXml.
/**
* Test of fromXml methods, of class SmilServiceImpl.
*/
@Test
public void testFromXml() throws Exception {
SmilResponse smilResponse = smilService.fromXml(TEST_SMIL);
assertNotNull(smilResponse.getSmil());
Smil smil = smilResponse.getSmil();
// test head
assertSame(2, smil.getHead().getParamGroups().size());
// test body
assertSame(2, smil.getBody().getMediaElements().size());
assertTrue(smil.getBody().getMediaElements().get(0) instanceof SmilMediaParallelImpl);
assertTrue(smil.getBody().getMediaElements().get(1) instanceof SmilMediaParallelImpl);
SmilMediaContainer par = (SmilMediaContainer) smil.getBody().getMediaElements().get(0);
assertSame(2, par.getElements().size());
assertTrue(par.getElements().get(0) instanceof SmilMediaVideoImpl);
assertTrue(par.getElements().get(1) instanceof SmilMediaAudioImpl);
}
use of org.opencastproject.smil.entity.media.container.api.SmilMediaContainer in project opencast by opencast.
the class SmilServiceImplTest method testAddClipWithParamGroupId.
/**
* passing a previously created paramGroupId
*/
@Test
public void testAddClipWithParamGroupId() throws Exception {
// first, create SMIL with 1 par, 1 video
TrackImpl videoTrack = new TrackImpl();
videoTrack.setIdentifier("presenter-track-1");
videoTrack.setFlavor(new MediaPackageElementFlavor("source", "presenter"));
videoTrack.setURI(new URI("http://hostname/video.mp4"));
videoTrack.addStream(new VideoStreamImpl());
videoTrack.setDuration(1000000000000L);
SmilResponse smilResponse = smilService.createNewSmil();
smilResponse = smilService.addParallel(smilResponse.getSmil());
SmilMediaContainer par = (SmilMediaContainer) smilResponse.getEntity();
// add video track into parallel element
smilResponse = smilService.addClip(smilResponse.getSmil(), par.getId(), videoTrack, 1000L, 1000000L);
SmilMediaObject media = null;
for (SmilObject entity : smilResponse.getEntities()) {
if (entity instanceof SmilMediaObject) {
media = (SmilMediaObject) entity;
break;
}
}
assertNotNull(media);
assertEquals(media.getId(), ((SmilMediaContainer) smilResponse.getSmil().getBody().getMediaElements().get(0)).getElements().get(0).getId());
assertTrue(media instanceof SmilMediaVideoImpl);
assertSame(((SmilMediaElement) media).getMediaType(), SmilMediaElement.MediaType.VIDEO);
// 1000 milliseconds = 1 second
assertEquals(1000L, ((SmilMediaElement) media).getClipBeginMS());
// duration is 1000000 milliseconds = 1000 soconds
// start + duration = 1s + 1000s = 1001s
assertEquals(1001000L, ((SmilMediaElement) media).getClipEndMS());
// get param group id
List<SmilMediaParamGroup> groups = smilResponse.getSmil().getHead().getParamGroups();
assertEquals(1, groups.size());
String paramGroupId = groups.get(0).getId();
// then, create a 2nd par with 1 video with the same param group id
TrackImpl videoTrack2 = new TrackImpl();
videoTrack2.setIdentifier("presenter-track-2");
videoTrack2.setFlavor(new MediaPackageElementFlavor("source2", "presenter"));
videoTrack2.setURI(new URI("http://hostname/video2.mp4"));
videoTrack2.addStream(new VideoStreamImpl());
videoTrack2.setDuration(2000000000000L);
smilResponse = smilService.addParallel(smilResponse.getSmil());
SmilMediaContainer par2 = null;
for (SmilObject entity : smilResponse.getEntities()) {
if (entity instanceof SmilMediaContainer && !entity.getId().equals(par.getId())) {
par2 = (SmilMediaContainer) entity;
break;
}
}
// add video track into parallel element
smilResponse = smilService.addClip(smilResponse.getSmil(), par2.getId(), videoTrack2, 2000L, 2000000L, paramGroupId);
SmilMediaObject media2 = null;
for (SmilObject entity : smilResponse.getEntities()) {
if (entity instanceof SmilMediaObject && !entity.getId().equals(media.getId())) {
media2 = (SmilMediaObject) entity;
break;
}
}
assertNotNull(media2);
SmilMediaElement mediaElement2 = (SmilMediaElement) ((SmilMediaContainer) smilResponse.getSmil().getBody().getMediaElements().get(1)).getElements().get(0);
assertEquals(media2.getId(), mediaElement2.getId());
assertTrue(media2 instanceof SmilMediaVideoImpl);
assertSame(((SmilMediaElement) media2).getMediaType(), SmilMediaElement.MediaType.VIDEO);
// 1000 milliseconds = 1 second
assertEquals(2000L, ((SmilMediaElement) media2).getClipBeginMS());
// duration is 2000000 milliseconds = 2000 seconds
// start + duration = 2s + 2000s = 2002s
assertEquals(2002000L, ((SmilMediaElement) media2).getClipEndMS());
// make sure there's still 1 param group
groups = smilResponse.getSmil().getHead().getParamGroups();
assertEquals(1, groups.size());
// make sure that the media element has the previous param groupo id
assertEquals(paramGroupId, mediaElement2.getParamGroup());
}
Aggregations