use of org.opencastproject.mediapackage.MediaPackageElementFlavor in project opencast by opencast.
the class IndexServiceImpl method updateEventAssets.
@Override
public String updateEventAssets(MediaPackage mp, HttpServletRequest request) throws IndexServiceException {
JSONObject metadataJson = null;
// regex for form field name matching an attachment or a catalog
// The first sub items identifies if the file is an attachment or catalog
// The second is the item flavor
// Example form field names: "catalog/captions/timedtext" and "attachment/captions/vtt"
// The prefix of field name for attachment and catalog
// The metadata is expected to contain a workflow definition id and
// asset metadata mapped to the asset field id.
List<String> assetList = new LinkedList<String>();
// 1. save assets with temporary flavors
try {
if (!ServletFileUpload.isMultipartContent(request)) {
throw new IllegalArgumentException("No multipart content");
}
for (FileItemIterator iter = new ServletFileUpload().getItemIterator(request); iter.hasNext(); ) {
FileItemStream item = iter.next();
String fieldName = item.getFieldName();
if (item.isFormField()) {
if ("metadata".equals(fieldName)) {
String metadata = Streams.asString(item.openStream());
try {
metadataJson = (JSONObject) parser.parse(metadata);
} catch (Exception e) {
logger.warn("Unable to parse metadata {}", metadata);
throw new IllegalArgumentException("Unable to parse metadata");
}
}
} else {
if (item.getFieldName().toLowerCase().matches(attachmentRegex)) {
assetList.add(item.getFieldName());
// Add attachment with field name as temporary flavor
mp = ingestService.addAttachment(item.openStream(), item.getName(), new MediaPackageElementFlavor(item.getFieldName(), "*"), mp);
} else if (item.getFieldName().toLowerCase().matches(catalogRegex)) {
assetList.add(item.getFieldName());
// Add catalog with field name as temporary flavor
mp = ingestService.addCatalog(item.openStream(), item.getName(), new MediaPackageElementFlavor(item.getFieldName(), "*"), mp);
} else {
logger.warn("Unknown field name found {}", item.getFieldName());
}
}
}
// and correct the temporary flavor to the new flavor.
try {
JSONArray assetMetadata = (JSONArray) ((JSONObject) metadataJson.get("assets")).get("options");
if (assetMetadata != null) {
mp = updateMpAssetFlavor(assetList, mp, assetMetadata, isOverwriteExistingAsset);
} else {
logger.warn("The asset option mapping parameter was not found");
throw new IndexServiceException("The asset option mapping parameter was not found");
}
} catch (Exception e) {
// Assuming a parse error versus a file error and logging the error type
logger.warn("Unable to process asset metadata {}", metadataJson.get("assets"), e);
throw new IllegalArgumentException("Unable to parse metadata", e);
}
return startAddAssetWorkflow(metadataJson, mp);
} catch (Exception e) {
logger.error("Unable to create event: {}", getStackTrace(e));
throw new IndexServiceException(e.getMessage());
}
}
use of org.opencastproject.mediapackage.MediaPackageElementFlavor in project opencast by opencast.
the class AssetManagerUpdatedEventHandler method handleEvent.
public void handleEvent(final SeriesItem seriesItem) {
// A series or its ACL has been updated. Find any mediapackages with that series, and update them.
logger.debug("Handling {}", seriesItem);
String seriesId = seriesItem.getSeriesId();
// We must be an administrative user to make this query
final User prevUser = securityService.getUser();
final Organization prevOrg = securityService.getOrganization();
try {
securityService.setUser(SecurityUtil.createSystemUser(systemAccount, prevOrg));
final AQueryBuilder q = assetManager.createQuery();
final AResult result = q.select(q.snapshot()).where(q.seriesId().eq(seriesId).and(q.version().isLatest())).run();
for (Snapshot snapshot : enrich(result).getSnapshots()) {
final String orgId = snapshot.getOrganizationId();
final Organization organization = organizationDirectoryService.getOrganization(orgId);
if (organization == null) {
logger.warn("Skipping update of episode {} since organization {} is unknown", snapshot.getMediaPackage().getIdentifier().compact(), orgId);
continue;
}
securityService.setOrganization(organization);
MediaPackage mp = snapshot.getMediaPackage();
// Update the series XACML file
if (SeriesItem.Type.UpdateAcl.equals(seriesItem.getType())) {
// Build a new XACML file for this mediapackage
authorizationService.setAcl(mp, AclScope.Series, seriesItem.getAcl());
}
// Update the series dublin core or extended metadata
if (SeriesItem.Type.UpdateCatalog.equals(seriesItem.getType()) || SeriesItem.Type.UpdateElement.equals(seriesItem.getType())) {
DublinCoreCatalog seriesDublinCore = null;
MediaPackageElementFlavor catalogType = null;
if (SeriesItem.Type.UpdateCatalog.equals(seriesItem.getType())) {
seriesDublinCore = seriesItem.getMetadata();
mp.setSeriesTitle(seriesDublinCore.getFirst(DublinCore.PROPERTY_TITLE));
catalogType = MediaPackageElements.SERIES;
} else {
seriesDublinCore = seriesItem.getExtendedMetadata();
catalogType = MediaPackageElementFlavor.flavor(seriesItem.getElementType(), "series");
}
// Update the series dublin core
Catalog[] seriesCatalogs = mp.getCatalogs(catalogType);
if (seriesCatalogs.length == 1) {
Catalog c = seriesCatalogs[0];
String filename = FilenameUtils.getName(c.getURI().toString());
URI uri = workspace.put(mp.getIdentifier().toString(), c.getIdentifier(), filename, dublinCoreService.serialize(seriesDublinCore));
c.setURI(uri);
// setting the URI to a new source so the checksum will most like be invalid
c.setChecksum(null);
}
}
// Remove the series catalogs and isPartOf from episode catalog
if (SeriesItem.Type.Delete.equals(seriesItem.getType())) {
mp.setSeries(null);
mp.setSeriesTitle(null);
for (Catalog seriesCatalog : mp.getCatalogs(MediaPackageElements.SERIES)) {
mp.remove(seriesCatalog);
}
authorizationService.removeAcl(mp, AclScope.Series);
for (Catalog episodeCatalog : mp.getCatalogs(MediaPackageElements.EPISODE)) {
DublinCoreCatalog episodeDublinCore = DublinCoreUtil.loadDublinCore(workspace, episodeCatalog);
episodeDublinCore.remove(DublinCore.PROPERTY_IS_PART_OF);
String filename = FilenameUtils.getName(episodeCatalog.getURI().toString());
URI uri = workspace.put(mp.getIdentifier().toString(), episodeCatalog.getIdentifier(), filename, dublinCoreService.serialize(episodeDublinCore));
episodeCatalog.setURI(uri);
// setting the URI to a new source so the checksum will most like be invalid
episodeCatalog.setChecksum(null);
}
// here we don't know the series extended metadata types,
// we assume that all series catalog flavors have a fixed subtype: series
MediaPackageElementFlavor seriesFlavor = MediaPackageElementFlavor.flavor("*", "series");
for (Catalog catalog : mp.getCatalogs()) {
if (catalog.getFlavor().matches(seriesFlavor))
mp.remove(catalog);
}
}
try {
// Update the asset manager with the modified mediapackage
assetManager.takeSnapshot(snapshot.getOwner(), mp);
} catch (AssetManagerException e) {
logger.error("Error updating mediapackage {}", mp.getIdentifier().compact(), e);
}
}
} catch (NotFoundException e) {
logger.warn(e.getMessage());
} catch (IOException e) {
logger.warn(e.getMessage());
} finally {
securityService.setOrganization(prevOrg);
securityService.setUser(prevUser);
}
}
use of org.opencastproject.mediapackage.MediaPackageElementFlavor in project opencast by opencast.
the class PrepareAVWorkflowOperationHandler method findAudioTrack.
/**
* Finds a suitable audio track from the mediapackage by scanning a source flavor sequence
*
* @param videoTrack
* the video track
* @param mediaPackage
* the mediapackage
* @param audioMuxingSourceFlavors
* sequence of source flavors where an audio track should be searched for
* @return the found audio track
*/
private Track findAudioTrack(Track videoTrack, MediaPackage mediaPackage, String audioMuxingSourceFlavors) {
if (audioMuxingSourceFlavors != null) {
String type;
String subtype;
for (String flavorStr : audioMuxingSourceFlavors.split("[\\s,]")) {
if (!flavorStr.isEmpty()) {
MediaPackageElementFlavor flavor = null;
try {
flavor = MediaPackageElementFlavor.parseFlavor(flavorStr);
} catch (IllegalArgumentException e) {
logger.error("The parameter {} contains an invalid flavor: {}", OPT_AUDIO_MUXING_SOURCE_FLAVORS, flavorStr);
throw e;
}
type = (QUESTION_MARK.equals(flavor.getType())) ? videoTrack.getFlavor().getType() : flavor.getType();
subtype = (QUESTION_MARK.equals(flavor.getSubtype())) ? videoTrack.getFlavor().getSubtype() : flavor.getSubtype();
// Recreate the (possibly) modified flavor
flavor = new MediaPackageElementFlavor(type, subtype);
for (Track track : mediaPackage.getTracks(flavor)) {
if (track.hasAudio()) {
logger.info("Audio muxing found audio source {} with flavor {}", track, track.getFlavor());
return track;
}
}
}
}
}
return null;
}
use of org.opencastproject.mediapackage.MediaPackageElementFlavor in project opencast by opencast.
the class PrepareAVWorkflowOperationHandler method mux.
/**
* Merges audio and video track of the selected flavor and adds it to the media package. If there is nothing to mux, a
* new track with the target flavor is created (pointing to the original url).
*
* @param src
* The source media package
* @param operation
* the mux workflow operation
* @return the operation result containing the updated mediapackage
* @throws EncoderException
* if encoding fails
* @throws IOException
* if read/write operations from and to the workspace fail
* @throws NotFoundException
* if the workspace does not contain the requested element
*/
private WorkflowOperationResult mux(MediaPackage src, WorkflowOperationInstance operation) throws EncoderException, WorkflowOperationException, NotFoundException, MediaPackageException, IOException {
MediaPackage mediaPackage = (MediaPackage) src.clone();
// Read the configuration properties
String sourceFlavorName = StringUtils.trimToNull(operation.getConfiguration("source-flavor"));
String targetTrackTags = StringUtils.trimToNull(operation.getConfiguration("target-tags"));
String targetTrackFlavorName = StringUtils.trimToNull(operation.getConfiguration("target-flavor"));
String muxEncodingProfileName = StringUtils.trimToNull(operation.getConfiguration("mux-encoding-profile"));
String audioVideoEncodingProfileName = StringUtils.trimToNull(operation.getConfiguration("audio-video-encoding-profile"));
String videoOnlyEncodingProfileName = StringUtils.trimToNull(operation.getConfiguration("video-encoding-profile"));
String audioOnlyEncodingProfileName = StringUtils.trimToNull(operation.getConfiguration("audio-encoding-profile"));
String[] targetTags = StringUtils.split(targetTrackTags, ",");
List<String> removeTags = new ArrayList<String>();
List<String> addTags = new ArrayList<String>();
List<String> overrideTags = new ArrayList<String>();
if (targetTags != null) {
for (String tag : targetTags) {
if (tag.startsWith(MINUS)) {
removeTags.add(tag);
} else if (tag.startsWith(PLUS)) {
addTags.add(tag);
} else {
overrideTags.add(tag);
}
}
}
// Make sure the source flavor is properly set
if (sourceFlavorName == null)
throw new IllegalStateException("Source flavor must be specified");
MediaPackageElementFlavor sourceFlavor = MediaPackageElementFlavor.parseFlavor(sourceFlavorName);
// Make sure the target flavor is properly set
if (targetTrackFlavorName == null)
throw new IllegalStateException("Target flavor must be specified");
MediaPackageElementFlavor targetFlavor = MediaPackageElementFlavor.parseFlavor(targetTrackFlavorName);
// Reencode when there is no need for muxing?
boolean rewrite = true;
if (StringUtils.trimToNull(operation.getConfiguration(OPT_REWRITE)) != null) {
rewrite = Boolean.parseBoolean(operation.getConfiguration(OPT_REWRITE));
}
String audioMuxingSourceFlavors = StringUtils.trimToNull(operation.getConfiguration(OPT_AUDIO_MUXING_SOURCE_FLAVORS));
// Select those tracks that have matching flavors
Track[] tracks = mediaPackage.getTracks(sourceFlavor);
Track audioTrack = null;
Track videoTrack = null;
switch(tracks.length) {
case 0:
logger.info("No audio/video tracks with flavor '{}' found to prepare", sourceFlavor);
return createResult(mediaPackage, Action.CONTINUE);
case 1:
videoTrack = tracks[0];
if (!tracks[0].hasAudio() && tracks[0].hasVideo() && (audioMuxingSourceFlavors != null)) {
audioTrack = findAudioTrack(tracks[0], mediaPackage, audioMuxingSourceFlavors);
} else {
audioTrack = tracks[0];
}
break;
case 2:
for (Track track : tracks) {
if (track.hasAudio() && !track.hasVideo()) {
audioTrack = track;
} else if (!track.hasAudio() && track.hasVideo()) {
videoTrack = track;
} else {
throw new WorkflowOperationException("Multiple tracks with competing audio/video streams and flavor '" + sourceFlavor + "' found");
}
}
break;
default:
logger.error("More than two tracks with flavor {} found. No idea what we should be doing", sourceFlavor);
throw new WorkflowOperationException("More than two tracks with flavor '" + sourceFlavor + "' found");
}
Job job = null;
Track composedTrack = null;
// Make sure we have a matching combination
if (audioTrack == null && videoTrack != null) {
if (rewrite) {
logger.info("Encoding video only track {} to work version", videoTrack);
if (videoOnlyEncodingProfileName == null)
videoOnlyEncodingProfileName = PREPARE_VONLY_PROFILE;
// Find the encoding profile to make sure the given profile exists
EncodingProfile profile = composerService.getProfile(videoOnlyEncodingProfileName);
if (profile == null)
throw new IllegalStateException("Encoding profile '" + videoOnlyEncodingProfileName + "' was not found");
composedTrack = prepare(videoTrack, mediaPackage, videoOnlyEncodingProfileName);
} else {
composedTrack = (Track) videoTrack.clone();
composedTrack.setIdentifier(null);
mediaPackage.add(composedTrack);
}
} else if (videoTrack == null && audioTrack != null) {
if (rewrite) {
logger.info("Encoding audio only track {} to work version", audioTrack);
if (audioOnlyEncodingProfileName == null)
audioOnlyEncodingProfileName = PREPARE_AONLY_PROFILE;
// Find the encoding profile to make sure the given profile exists
EncodingProfile profile = composerService.getProfile(audioOnlyEncodingProfileName);
if (profile == null)
throw new IllegalStateException("Encoding profile '" + audioOnlyEncodingProfileName + "' was not found");
composedTrack = prepare(audioTrack, mediaPackage, audioOnlyEncodingProfileName);
} else {
composedTrack = (Track) audioTrack.clone();
composedTrack.setIdentifier(null);
mediaPackage.add(composedTrack);
}
} else if (audioTrack == videoTrack) {
if (rewrite) {
logger.info("Encoding audiovisual track {} to work version", videoTrack);
if (audioVideoEncodingProfileName == null)
audioVideoEncodingProfileName = PREPARE_AV_PROFILE;
// Find the encoding profile to make sure the given profile exists
EncodingProfile profile = composerService.getProfile(audioVideoEncodingProfileName);
if (profile == null)
throw new IllegalStateException("Encoding profile '" + audioVideoEncodingProfileName + "' was not found");
composedTrack = prepare(videoTrack, mediaPackage, audioVideoEncodingProfileName);
} else {
composedTrack = (Track) videoTrack.clone();
composedTrack.setIdentifier(null);
mediaPackage.add(composedTrack);
}
} else {
logger.info("Muxing audio and video only track {} to work version", videoTrack);
if (audioTrack.hasVideo()) {
logger.info("Stripping audio from track {}", audioTrack);
audioTrack = prepare(audioTrack, null, PREPARE_AONLY_PROFILE);
}
if (muxEncodingProfileName == null)
muxEncodingProfileName = MUX_AV_PROFILE;
// Find the encoding profile
EncodingProfile profile = composerService.getProfile(muxEncodingProfileName);
if (profile == null)
throw new IllegalStateException("Encoding profile '" + muxEncodingProfileName + "' was not found");
job = composerService.mux(videoTrack, audioTrack, profile.getIdentifier());
if (!waitForStatus(job).isSuccess()) {
throw new WorkflowOperationException("Muxing video track " + videoTrack + " and audio track " + audioTrack + " failed");
}
composedTrack = (Track) MediaPackageElementParser.getFromXml(job.getPayload());
mediaPackage.add(composedTrack);
String fileName = getFileNameFromElements(videoTrack, composedTrack);
composedTrack.setURI(workspace.moveTo(composedTrack.getURI(), mediaPackage.getIdentifier().toString(), composedTrack.getIdentifier(), fileName));
}
long timeInQueue = 0;
if (job != null) {
// add this receipt's queue time to the total
timeInQueue = job.getQueueTime();
}
// Update the track's flavor
composedTrack.setFlavor(targetFlavor);
logger.debug("Composed track has flavor '{}'", composedTrack.getFlavor());
// Add the target tags
if (overrideTags.size() > 0) {
composedTrack.clearTags();
for (String tag : overrideTags) {
logger.trace("Tagging composed track with '{}'", tag);
composedTrack.addTag(tag);
}
} else {
for (String tag : removeTags) {
logger.trace("Remove tagging '{}' from composed track", tag);
composedTrack.removeTag(tag.substring(MINUS.length()));
}
for (String tag : addTags) {
logger.trace("Add tagging '{}' to composed track", tag);
composedTrack.addTag(tag.substring(PLUS.length()));
}
}
return createResult(mediaPackage, Action.CONTINUE, timeInQueue);
}
use of org.opencastproject.mediapackage.MediaPackageElementFlavor in project opencast by opencast.
the class CoverImageWorkflowOperationHandlerBase method getPosterImageFileUrl.
protected String getPosterImageFileUrl(MediaPackage mediaPackage, String posterimageFlavor) throws WorkflowOperationException {
if (posterimageFlavor == null) {
logger.debug("Optional configuration key '{}' not set", POSTERIMAGE_FLAVOR);
return null;
}
MediaPackageElementFlavor flavor;
try {
flavor = MediaPackageElementFlavor.parseFlavor(posterimageFlavor);
} catch (IllegalArgumentException e) {
logger.warn("'{}' is not a valid flavor", posterimageFlavor);
throw new WorkflowOperationException(e);
}
Attachment[] atts = mediaPackage.getAttachments(flavor);
if (atts.length > 1) {
logger.warn("More than one attachment with the flavor '{}' found in media package '{}'", posterimageFlavor, mediaPackage.getIdentifier());
throw new WorkflowOperationException("More than one attachment with the flavor'" + posterimageFlavor + "' found.");
} else if (atts.length == 0) {
logger.warn("No attachment with the flavor '{}' found in media package '{}'", posterimageFlavor, mediaPackage.getIdentifier());
return null;
}
try {
return getWorkspace().get(atts[0].getURI()).getAbsolutePath();
} catch (NotFoundException e) {
throw new WorkflowOperationException(e);
} catch (IOException e) {
throw new WorkflowOperationException(e);
}
}
Aggregations