use of org.opencastproject.mediapackage.track.TrackImpl in project opencast by opencast.
the class WowzaAdaptiveStreamingDistributionService method retractElement.
/**
* Retracts the mediapackage with the given identifier from the distribution channel.
*
* @param channelId
* the channel id
* @param mediapackage
* the mediapackage
* @param elementId
* the element identifier
* @return the retracted element or <code>null</code> if the element was not retracted
*/
protected MediaPackageElement[] retractElement(String channelId, final MediaPackage mediapackage, String elementId) throws DistributionException {
notNull(mediapackage, "mediapackage");
notNull(elementId, "elementId");
notNull(channelId, "channelId");
// Make sure the element exists
final MediaPackageElement element = mediapackage.getElementById(elementId);
if (element == null)
throw new IllegalStateException("No element " + elementId + " found in mediapackage" + mediapackage.getIdentifier());
logger.debug("Start element retraction for element \"{}\" with URI {}", elementId, element.getURI());
ArrayList<MediaPackageElement> retractedElements = new ArrayList<MediaPackageElement>();
// Has this element been distributed?
if (element == null || (!(element instanceof TrackImpl)))
return null;
try {
// Get the distribution path on the disk for this mediapackage element
File elementFile = getDistributionFile(channelId, mediapackage, element);
final File smilFile = getSmilFile(element, mediapackage, channelId);
logger.debug("delete elementFile {}", elementFile);
// or has been removed otherwise
if (elementFile == null || !elementFile.exists()) {
logger.warn("Deleting element file: File does not exist. Perhaps was it already deleted?: {}", elementFile);
retractedElements.add(element);
return retractedElements.toArray(new MediaPackageElement[0]);
} else {
// If a SMIL file is referenced by this element, delete first all the elements within
if (elementFile.equals(smilFile)) {
Document smilXml = getSmilDocument(smilFile);
NodeList videoList = smilXml.getElementsByTagName("video");
for (int i = 0; i < videoList.getLength(); i++) {
if (videoList.item(i) instanceof Element) {
String smilPathStr = ((Element) videoList.item(i)).getAttribute("src");
// Patch the streaming tags
if (smilPathStr.contains("mp4:"))
smilPathStr = smilPathStr.replace("mp4:", "");
if (!smilPathStr.endsWith(".mp4"))
smilPathStr += ".mp4";
elementFile = smilFile.toPath().resolveSibling(smilPathStr).toFile();
deleteElementFile(elementFile);
}
}
if (smilFile.isFile() && !smilFile.delete()) {
logger.warn("The SMIL file {} could not be succesfully deleted. Forcing quite deletion...");
}
} else {
deleteElementFile(elementFile);
}
}
logger.info("Finished rectracting element {} of media package {}", elementId, mediapackage);
retractedElements.add(element);
return retractedElements.toArray(new MediaPackageElement[0]);
} catch (Exception e) {
logger.warn("Error retracting element " + elementId + " of mediapackage " + mediapackage, e);
if (e instanceof DistributionException) {
throw (DistributionException) e;
} else {
throw new DistributionException(e);
}
}
}
use of org.opencastproject.mediapackage.track.TrackImpl in project opencast by opencast.
the class ConfigurablePublishWorkflowOperationHandlerTest method testNormal.
@Test
public void testNormal() throws WorkflowOperationException, URISyntaxException, DistributionException, MediaPackageException {
String channelId = "engage-player";
String attachmentId = "attachment-id";
String catalogId = "catalog-id";
String trackId = "track-id";
Attachment attachment = new AttachmentImpl();
attachment.addTag("engage-download");
attachment.setIdentifier(attachmentId);
attachment.setURI(new URI("http://api.com/attachment"));
Catalog catalog = CatalogImpl.newInstance();
catalog.addTag("engage-download");
catalog.setIdentifier(catalogId);
catalog.setURI(new URI("http://api.com/catalog"));
Track track = new TrackImpl();
track.addTag("engage-streaming");
track.setIdentifier(trackId);
track.setURI(new URI("http://api.com/track"));
Publication publicationtest = new PublicationImpl(trackId, channelId, new URI("http://api.com/publication"), MimeType.mimeType(trackId, trackId));
Track unrelatedTrack = new TrackImpl();
unrelatedTrack.addTag("unrelated");
Capture<MediaPackageElement> capturePublication = Capture.newInstance();
MediaPackage mediapackageClone = EasyMock.createNiceMock(MediaPackage.class);
EasyMock.expect(mediapackageClone.getElements()).andStubReturn(new MediaPackageElement[] { attachment, catalog, track, unrelatedTrack });
EasyMock.expect(mediapackageClone.getIdentifier()).andStubReturn(new IdImpl("mp-id-clone"));
EasyMock.expectLastCall();
EasyMock.replay(mediapackageClone);
MediaPackage mediapackage = EasyMock.createNiceMock(MediaPackage.class);
EasyMock.expect(mediapackage.getElements()).andStubReturn(new MediaPackageElement[] { attachment, catalog, track, unrelatedTrack });
EasyMock.expect(mediapackage.clone()).andStubReturn(mediapackageClone);
EasyMock.expect(mediapackage.getIdentifier()).andStubReturn(new IdImpl("mp-id"));
mediapackage.add(EasyMock.capture(capturePublication));
mediapackage.add(publicationtest);
EasyMock.expect(mediapackage.getPublications()).andStubReturn(new Publication[] { publicationtest });
EasyMock.expectLastCall();
EasyMock.replay(mediapackage);
WorkflowOperationInstance op = EasyMock.createNiceMock(WorkflowOperationInstance.class);
EasyMock.expect(op.getConfiguration(ConfigurablePublishWorkflowOperationHandler.CHANNEL_ID_KEY)).andStubReturn(channelId);
EasyMock.expect(op.getConfiguration(ConfigurablePublishWorkflowOperationHandler.MIME_TYPE)).andStubReturn("text/html");
EasyMock.expect(op.getConfiguration(ConfigurablePublishWorkflowOperationHandler.URL_PATTERN)).andStubReturn("http://api.opencast.org/api/events/${event_id}");
EasyMock.expect(op.getConfiguration(ConfigurablePublishWorkflowOperationHandler.SOURCE_TAGS)).andStubReturn("engage-download,engage-streaming");
EasyMock.expect(op.getConfiguration(ConfigurablePublishWorkflowOperationHandler.CHECK_AVAILABILITY)).andStubReturn("true");
EasyMock.expect(op.getConfiguration(ConfigurablePublishWorkflowOperationHandler.STRATEGY)).andStubReturn("retract");
EasyMock.expect(op.getConfiguration(ConfigurablePublishWorkflowOperationHandler.MODE)).andStubReturn("single");
EasyMock.replay(op);
WorkflowInstance workflowInstance = EasyMock.createNiceMock(WorkflowInstance.class);
EasyMock.expect(workflowInstance.getMediaPackage()).andStubReturn(mediapackage);
EasyMock.expect(workflowInstance.getCurrentOperation()).andStubReturn(op);
EasyMock.replay(workflowInstance);
JobContext jobContext = EasyMock.createNiceMock(JobContext.class);
EasyMock.replay(jobContext);
Job attachmentJob = EasyMock.createNiceMock(Job.class);
EasyMock.expect(attachmentJob.getPayload()).andReturn(MediaPackageElementParser.getAsXml(attachment));
EasyMock.replay(attachmentJob);
Job catalogJob = EasyMock.createNiceMock(Job.class);
EasyMock.expect(catalogJob.getPayload()).andReturn(MediaPackageElementParser.getAsXml(catalog));
EasyMock.replay(catalogJob);
Job trackJob = EasyMock.createNiceMock(Job.class);
EasyMock.expect(trackJob.getPayload()).andReturn(MediaPackageElementParser.getAsXml(track));
EasyMock.replay(trackJob);
Job retractJob = EasyMock.createNiceMock(Job.class);
EasyMock.expect(retractJob.getPayload()).andReturn(MediaPackageElementParser.getAsXml(track));
EasyMock.replay(retractJob);
DownloadDistributionService distributionService = EasyMock.createNiceMock(DownloadDistributionService.class);
// Make sure that all of the elements are distributed.
EasyMock.expect(distributionService.distribute(channelId, mediapackage, attachmentId, true)).andReturn(attachmentJob);
EasyMock.expect(distributionService.distribute(channelId, mediapackage, catalogId, true)).andReturn(catalogJob);
EasyMock.expect(distributionService.distribute(channelId, mediapackage, trackId, true)).andReturn(trackJob);
EasyMock.expect(distributionService.retract(channelId, mediapackage, channelId)).andReturn(retractJob);
EasyMock.replay(distributionService);
SecurityService securityService = EasyMock.createNiceMock(SecurityService.class);
EasyMock.expect(securityService.getOrganization()).andStubReturn(org);
EasyMock.replay(securityService);
ServiceRegistry serviceRegistry = EasyMock.createNiceMock(ServiceRegistry.class);
EasyMock.replay(serviceRegistry);
// Override the waitForStatus method to not block the jobs
ConfigurablePublishWorkflowOperationHandler configurePublish = new ConfigurablePublishWorkflowOperationHandler() {
@Override
protected Result waitForStatus(long timeout, Job... jobs) {
HashMap<Job, Status> map = Stream.mk(jobs).foldl(new HashMap<Job, Status>(), new Fn2<HashMap<Job, Status>, Job, HashMap<Job, Status>>() {
@Override
public HashMap<Job, Status> apply(HashMap<Job, Status> a, Job b) {
a.put(b, Status.FINISHED);
return a;
}
});
return new Result(map);
}
};
configurePublish.setDownloadDistributionService(distributionService);
configurePublish.setSecurityService(securityService);
configurePublish.setServiceRegistry(serviceRegistry);
WorkflowOperationResult result = configurePublish.start(workflowInstance, jobContext);
assertNotNull(result.getMediaPackage());
assertTrue("The publication element has not been added to the mediapackage.", capturePublication.hasCaptured());
assertTrue("Some other type of element has been added to the mediapackage instead of the publication element.", capturePublication.getValue().getElementType().equals(MediaPackageElement.Type.Publication));
Publication publication = (Publication) capturePublication.getValue();
assertEquals(1, publication.getAttachments().length);
assertNotEquals(attachment.getIdentifier(), publication.getAttachments()[0].getIdentifier());
attachment.setIdentifier(publication.getAttachments()[0].getIdentifier());
assertEquals(attachment, publication.getAttachments()[0]);
assertEquals(1, publication.getCatalogs().length);
assertNotEquals(catalog.getIdentifier(), publication.getCatalogs()[0].getIdentifier());
catalog.setIdentifier(publication.getCatalogs()[0].getIdentifier());
assertEquals(catalog, publication.getCatalogs()[0]);
assertEquals(1, publication.getTracks().length);
assertNotEquals(track.getIdentifier(), publication.getTracks()[0].getIdentifier());
track.setIdentifier(publication.getTracks()[0].getIdentifier());
assertEquals(track, publication.getTracks()[0]);
}
use of org.opencastproject.mediapackage.track.TrackImpl in project opencast by opencast.
the class AnalyzeAudioWorkflowOperationHandler method analyze.
private WorkflowOperationResult analyze(MediaPackage src, WorkflowOperationInstance operation) throws SoxException, IOException, NotFoundException, MediaPackageException, WorkflowOperationException, EncoderException {
MediaPackage mediaPackage = (MediaPackage) src.clone();
// Check which tags have been configured
String sourceTagsOption = StringUtils.trimToNull(operation.getConfiguration("source-tags"));
String sourceFlavorOption = StringUtils.trimToNull(operation.getConfiguration("source-flavor"));
String sourceFlavorsOption = StringUtils.trimToNull(operation.getConfiguration("source-flavors"));
boolean forceTranscode = BooleanUtils.toBoolean(operation.getConfiguration("force-transcode"));
AbstractMediaPackageElementSelector<Track> elementSelector = new TrackSelector();
// Make sure either one of tags or flavors are provided
if (StringUtils.isBlank(sourceTagsOption) && StringUtils.isBlank(sourceFlavorOption) && StringUtils.isBlank(sourceFlavorsOption)) {
logger.info("No source tags or flavors have been specified, not matching anything");
return createResult(mediaPackage, Action.CONTINUE);
}
// Select the source flavors
for (String flavor : asList(sourceFlavorsOption)) {
try {
elementSelector.addFlavor(MediaPackageElementFlavor.parseFlavor(flavor));
} catch (IllegalArgumentException e) {
throw new WorkflowOperationException("Source flavor '" + flavor + "' is malformed");
}
}
// Support legacy "source-flavor" option
if (StringUtils.isNotBlank(sourceFlavorOption)) {
String flavor = StringUtils.trim(sourceFlavorOption);
try {
elementSelector.addFlavor(MediaPackageElementFlavor.parseFlavor(flavor));
} catch (IllegalArgumentException e) {
throw new WorkflowOperationException("Source flavor '" + flavor + "' is malformed");
}
}
// Select the source tags
for (String tag : asList(sourceTagsOption)) {
elementSelector.addTag(tag);
}
// Look for elements matching the tag
Collection<Track> elements = elementSelector.select(mediaPackage, false);
// Analyze audio for all tracks found
long totalTimeInQueue = 0;
List<URI> cleanupURIs = new ArrayList<URI>();
Map<Job, Track> analyzeJobs = new HashMap<Job, Track>();
try {
for (Track track : elements) {
TrackImpl audioTrack = (TrackImpl) track;
// Skip video only mismatches
if (!track.hasAudio()) {
logger.info("Skipping audio analysis of '{}', since it contains no audio stream", track);
continue;
} else if (track.hasVideo() || forceTranscode) {
audioTrack = (TrackImpl) extractAudioTrack(track);
audioTrack.setAudio(((TrackImpl) track).getAudio());
cleanupURIs.add(audioTrack.getURI());
}
analyzeJobs.put(soxService.analyze(audioTrack), track);
}
if (analyzeJobs.isEmpty()) {
logger.info("No matching tracks found");
return createResult(mediaPackage, Action.CONTINUE);
}
// Wait for the jobs to return
if (!waitForStatus(analyzeJobs.keySet().toArray(new Job[analyzeJobs.size()])).isSuccess())
throw new WorkflowOperationException("One of the analyze jobs did not complete successfully");
// Process the result
for (Map.Entry<Job, Track> entry : analyzeJobs.entrySet()) {
Job job = entry.getKey();
TrackImpl origTrack = (TrackImpl) entry.getValue();
// add this receipt's queue time to the total
totalTimeInQueue += job.getQueueTime();
if (job.getPayload().length() > 0) {
TrackImpl analyzed = (TrackImpl) MediaPackageElementParser.getFromXml(job.getPayload());
// Set metadata on track
origTrack.setAudio(analyzed.getAudio());
} else {
logger.warn("Analyze audio job {} for track {} has no result!", job, origTrack);
}
}
} finally {
// Clean up temporary audio files from workspace
for (URI uri : cleanupURIs) {
workspace.delete(uri);
}
}
WorkflowOperationResult result = createResult(mediaPackage, Action.CONTINUE, totalTimeInQueue);
logger.debug("Analyze audio operation completed");
return result;
}
use of org.opencastproject.mediapackage.track.TrackImpl in project opencast by opencast.
the class NormalizeAudioWorkflowOperationHandler method normalize.
private WorkflowOperationResult normalize(MediaPackage src, WorkflowOperationInstance operation) throws SoxException, IOException, NotFoundException, MediaPackageException, WorkflowOperationException, EncoderException {
MediaPackage mediaPackage = (MediaPackage) src.clone();
// Check which tags have been configured
String sourceTagsOption = StringUtils.trimToNull(operation.getConfiguration("source-tags"));
String targetTagsOption = StringUtils.trimToNull(operation.getConfiguration("target-tags"));
String sourceFlavorOption = StringUtils.trimToNull(operation.getConfiguration("source-flavor"));
String sourceFlavorsOption = StringUtils.trimToNull(operation.getConfiguration("source-flavors"));
String targetFlavorOption = StringUtils.trimToNull(operation.getConfiguration("target-flavor"));
String targetDecibelString = StringUtils.trimToNull(operation.getConfiguration("target-decibel"));
if (targetDecibelString == null)
throw new IllegalArgumentException("target-decibel must be specified");
boolean forceTranscode = BooleanUtils.toBoolean(operation.getConfiguration("force-transcode"));
Float targetDecibel;
try {
targetDecibel = new Float(targetDecibelString);
} catch (NumberFormatException e1) {
throw new WorkflowOperationException("Unable to parse target-decibel " + targetDecibelString);
}
AbstractMediaPackageElementSelector<Track> elementSelector = new TrackSelector();
// Make sure either one of tags or flavors are provided
if (StringUtils.isBlank(sourceTagsOption) && StringUtils.isBlank(sourceFlavorOption) && StringUtils.isBlank(sourceFlavorsOption)) {
logger.info("No source tags or flavors have been specified, not matching anything");
return createResult(mediaPackage, Action.CONTINUE);
}
// Select the source flavors
for (String flavor : asList(sourceFlavorsOption)) {
try {
elementSelector.addFlavor(MediaPackageElementFlavor.parseFlavor(flavor));
} catch (IllegalArgumentException e) {
throw new WorkflowOperationException("Source flavor '" + flavor + "' is malformed");
}
}
// Support legacy "source-flavor" option
if (StringUtils.isNotBlank(sourceFlavorOption)) {
String flavor = StringUtils.trim(sourceFlavorOption);
try {
elementSelector.addFlavor(MediaPackageElementFlavor.parseFlavor(flavor));
} catch (IllegalArgumentException e) {
throw new WorkflowOperationException("Source flavor '" + flavor + "' is malformed");
}
}
// Select the source tags
for (String tag : asList(sourceTagsOption)) {
elementSelector.addTag(tag);
}
// Target tags
List<String> targetTags = asList(targetTagsOption);
// Target flavor
MediaPackageElementFlavor targetFlavor = null;
if (StringUtils.isNotBlank(targetFlavorOption)) {
try {
targetFlavor = MediaPackageElementFlavor.parseFlavor(targetFlavorOption);
} catch (IllegalArgumentException e) {
throw new WorkflowOperationException("Target flavor '" + targetFlavorOption + "' is malformed");
}
}
// Look for elements matching the tag
Collection<Track> elements = elementSelector.select(mediaPackage, false);
// Encode all tracks found
long totalTimeInQueue = 0;
List<URI> cleanupURIs = new ArrayList<URI>();
Map<Job, Track> normalizeJobs = new HashMap<Job, Track>();
try {
for (Track track : elements) {
TrackImpl audioTrack = (TrackImpl) track;
// Skip video only mismatches
if (!track.hasAudio()) {
logger.info("Skipping audio normalization of '{}', since it contains no audio stream", track);
continue;
} else if (track.hasVideo() || forceTranscode) {
audioTrack = (TrackImpl) extractAudioTrack(track);
audioTrack.setAudio(((TrackImpl) track).getAudio());
cleanupURIs.add(audioTrack.getURI());
}
// Analyze audio track
if (audioTrack.getAudio().size() < 1 || audioTrack.getAudio().get(0).getRmsLevDb() == null) {
logger.info("Audio track {} has no RMS Lev dB metadata, analyze it first", audioTrack);
Job analyzeJob = soxService.analyze(audioTrack);
if (!waitForStatus(analyzeJob).isSuccess())
throw new WorkflowOperationException("Unable to analyze the audio track " + audioTrack);
audioTrack = (TrackImpl) MediaPackageElementParser.getFromXml(analyzeJob.getPayload());
cleanupURIs.add(audioTrack.getURI());
}
normalizeJobs.put(soxService.normalize(audioTrack, targetDecibel), track);
}
if (normalizeJobs.isEmpty()) {
logger.info("No matching tracks found");
return createResult(mediaPackage, Action.CONTINUE);
}
// Wait for the jobs to return
if (!waitForStatus(normalizeJobs.keySet().toArray(new Job[normalizeJobs.size()])).isSuccess())
throw new WorkflowOperationException("One of the normalize jobs did not complete successfully");
// Process the result
for (Map.Entry<Job, Track> entry : normalizeJobs.entrySet()) {
Job job = entry.getKey();
TrackImpl origTrack = (TrackImpl) entry.getValue();
// add this receipt's queue time to the total
totalTimeInQueue += job.getQueueTime();
if (job.getPayload().length() > 0) {
TrackImpl normalizedAudioTrack = (TrackImpl) MediaPackageElementParser.getFromXml(job.getPayload());
TrackImpl resultTrack = normalizedAudioTrack;
if (origTrack.hasVideo() || forceTranscode) {
cleanupURIs.add(normalizedAudioTrack.getURI());
logger.info("Mux normalized audio track {} to video track {}", normalizedAudioTrack, origTrack);
Job muxAudioVideo = composerService.mux(origTrack, normalizedAudioTrack, SOX_AREPLACE_PROFILE);
if (!waitForStatus(muxAudioVideo).isSuccess())
throw new WorkflowOperationException("Muxing normalized audio track " + normalizedAudioTrack + " to video container " + origTrack + " failed");
resultTrack = (TrackImpl) MediaPackageElementParser.getFromXml(muxAudioVideo.getPayload());
// Set metadata on track
extendAudioStream(resultTrack, normalizedAudioTrack);
}
adjustFlavorAndTags(targetTags, targetFlavor, origTrack, resultTrack);
mediaPackage.addDerived(resultTrack, origTrack);
String fileName = getFileNameFromElements(origTrack, resultTrack);
resultTrack.setURI(workspace.moveTo(resultTrack.getURI(), mediaPackage.getIdentifier().toString(), resultTrack.getIdentifier(), fileName));
} else {
logger.warn("Normalize audio job {} for track {} has no result!", job, origTrack);
}
}
} finally {
// Clean up temporary audio and video files from workspace
for (URI uri : cleanupURIs) {
workspace.delete(uri);
}
}
WorkflowOperationResult result = createResult(mediaPackage, Action.CONTINUE, totalTimeInQueue);
logger.debug("Normalize audio operation completed");
return result;
}
use of org.opencastproject.mediapackage.track.TrackImpl in project opencast by opencast.
the class AnalyzeAudioWorkflowOperationHandlerTest method testAudio.
@Test
public void testAudio() throws Exception {
operationInstance.setConfiguration("source-tags", "");
operationInstance.setConfiguration("source-flavor", "*/audio");
operationInstance.setConfiguration("source-flavors", "");
operationInstance.setConfiguration("force-transcode", "false");
WorkflowOperationResult result = operationHandler.start(instance, null);
Assert.assertEquals(Action.CONTINUE, result.getAction());
Assert.assertEquals("Resulting mediapackage has the wrong number of tracks", 3, result.getMediaPackage().getElements().length);
Track[] tracks = result.getMediaPackage().getTracks(new MediaPackageElementFlavor("presentation", "audio"));
Assert.assertEquals("Resulting mediapackage has the wrong number of tracks", 1, tracks.length);
TrackImpl audioVideo = (TrackImpl) tracks[0];
Assert.assertEquals(-20f, audioVideo.getAudio().get(0).getRmsLevDb().floatValue(), 0.001d);
}
Aggregations