use of org.opencastproject.mediapackage.MediaPackageException in project opencast by opencast.
the class VideoEditorServiceImpl method processSmil.
/**
* Splice segments given by smil document for the given track to the new one.
*
* @param job
* processing job
* @param smil
* smil document with media segments description
* @param trackParamGroupId
* @return processed track
* @throws ProcessFailedException
* if an error occured
*/
protected Track processSmil(Job job, Smil smil, String trackParamGroupId) throws ProcessFailedException {
SmilMediaParamGroup trackParamGroup;
ArrayList<String> inputfile = new ArrayList<>();
ArrayList<VideoClip> videoclips = new ArrayList<>();
try {
trackParamGroup = (SmilMediaParamGroup) smil.get(trackParamGroupId);
} catch (SmilException ex) {
// can't be thrown, because we found the Id in processSmil(Smil)
throw new ProcessFailedException("Smil does not contain a paramGroup element with Id " + trackParamGroupId);
}
MediaPackageElementFlavor sourceTrackFlavor = null;
String sourceTrackUri = null;
// get source track metadata
for (SmilMediaParam param : trackParamGroup.getParams()) {
if (SmilMediaParam.PARAM_NAME_TRACK_SRC.equals(param.getName())) {
sourceTrackUri = param.getValue();
} else if (SmilMediaParam.PARAM_NAME_TRACK_FLAVOR.equals(param.getName())) {
sourceTrackFlavor = MediaPackageElementFlavor.parseFlavor(param.getValue());
}
}
File sourceFile;
try {
sourceFile = workspace.get(new URI(sourceTrackUri));
} catch (IOException ex) {
throw new ProcessFailedException("Can't read " + sourceTrackUri);
} catch (NotFoundException ex) {
throw new ProcessFailedException("Workspace does not contain a track " + sourceTrackUri);
} catch (URISyntaxException ex) {
throw new ProcessFailedException("Source URI " + sourceTrackUri + " is not valid.");
}
// inspect input file to retrieve media information
Job inspectionJob;
Track sourceTrack;
try {
inspectionJob = inspect(job, new URI(sourceTrackUri));
sourceTrack = (Track) MediaPackageElementParser.getFromXml(inspectionJob.getPayload());
} catch (URISyntaxException e) {
throw new ProcessFailedException("Source URI " + sourceTrackUri + " is not valid.");
} catch (MediaInspectionException e) {
throw new ProcessFailedException("Media inspection of " + sourceTrackUri + " failed", e);
} catch (MediaPackageException e) {
throw new ProcessFailedException("Deserialization of source track " + sourceTrackUri + " failed", e);
}
// get output file extension
String outputFileExtension = properties.getProperty(VideoEditorProperties.DEFAULT_EXTENSION, ".mp4");
outputFileExtension = properties.getProperty(VideoEditorProperties.OUTPUT_FILE_EXTENSION, outputFileExtension);
if (!outputFileExtension.startsWith(".")) {
outputFileExtension = '.' + outputFileExtension;
}
// create working directory
File tempDirectory = new File(new File(workspace.rootDirectory()), "editor");
tempDirectory = new File(tempDirectory, Long.toString(job.getId()));
String filename = String.format("%s-%s%s", sourceTrackFlavor, sourceFile.getName(), outputFileExtension);
File outputPath = new File(tempDirectory, filename);
if (!outputPath.getParentFile().exists()) {
outputPath.getParentFile().mkdirs();
}
URI newTrackURI;
// default source - add to source table as 0
inputfile.add(sourceFile.getAbsolutePath());
// index = 0
int srcIndex = inputfile.indexOf(sourceFile.getAbsolutePath());
logger.info("Start processing srcfile {}", sourceFile.getAbsolutePath());
try {
// parse body elements
for (SmilMediaObject element : smil.getBody().getMediaElements()) {
// body should contain par elements
if (element.isContainer()) {
SmilMediaContainer container = (SmilMediaContainer) element;
if (SmilMediaContainer.ContainerType.PAR == container.getContainerType()) {
// par element should contain media elements
for (SmilMediaObject elementChild : container.getElements()) {
if (!elementChild.isContainer()) {
SmilMediaElement media = (SmilMediaElement) elementChild;
if (trackParamGroupId.equals(media.getParamGroup())) {
long begin = media.getClipBeginMS();
long end = media.getClipEndMS();
URI clipTrackURI = media.getSrc();
File clipSourceFile = null;
if (clipTrackURI != null) {
try {
clipSourceFile = workspace.get(clipTrackURI);
} catch (IOException ex) {
throw new ProcessFailedException("Can't read " + clipTrackURI);
} catch (NotFoundException ex) {
throw new ProcessFailedException("Workspace does not contain a track " + clipTrackURI);
}
}
int index;
if (clipSourceFile != null) {
// clip has different source
// Look for known tracks
index = inputfile.indexOf(clipSourceFile.getAbsolutePath());
if (index == -1) {
// add new track
inputfile.add(clipSourceFile.getAbsolutePath());
// TODO: inspect each new video file, bad input will throw exc
}
index = inputfile.indexOf(clipSourceFile.getAbsolutePath());
} else {
// default src
index = srcIndex;
}
videoclips.add(new VideoClip(index, begin / 1000.0, end / 1000.0));
}
} else {
throw new ProcessFailedException("Smil container '" + ((SmilMediaContainer) elementChild).getContainerType().toString() + "'is not supportet yet");
}
}
} else {
throw new ProcessFailedException("Smil container '" + container.getContainerType().toString() + "'is not supportet yet");
}
}
}
// remove very short cuts that will look bad
List<VideoClip> cleanclips = sortSegments(videoclips);
String error = null;
// TODO: fetch the largest output resolution from SMIL.head.layout.root-layout
String outputResolution = "";
// When outputResolution is set to WxH, all clips are scaled to that size in the output video.
// TODO: Each clips could have a region id, relative to the root-layout
// Then each clip is zoomed/panned/padded to WxH befor concatenation
FFmpegEdit ffmpeg = new FFmpegEdit(properties);
error = ffmpeg.processEdits(inputfile, outputPath.getAbsolutePath(), outputResolution, cleanclips, sourceTrack.hasAudio(), sourceTrack.hasVideo());
if (error != null) {
FileUtils.deleteQuietly(tempDirectory);
throw new ProcessFailedException("Editing pipeline exited abnormaly! Error: " + error);
}
// create Track for edited file
String newTrackId = idBuilder.createNew().toString();
InputStream in = new FileInputStream(outputPath);
try {
newTrackURI = workspace.putInCollection(COLLECTION_ID, String.format("%s-%s%s", sourceTrackFlavor.getType(), newTrackId, outputFileExtension), in);
} catch (IllegalArgumentException ex) {
throw new ProcessFailedException("Copy track into workspace failed! " + ex.getMessage());
} finally {
IOUtils.closeQuietly(in);
FileUtils.deleteQuietly(tempDirectory);
}
// inspect new Track
try {
inspectionJob = inspect(job, newTrackURI);
} catch (MediaInspectionException e) {
throw new ProcessFailedException("Media inspection of " + newTrackURI + " failed", e);
}
Track editedTrack = (Track) MediaPackageElementParser.getFromXml(inspectionJob.getPayload());
logger.info("Finished editing track {}", editedTrack);
editedTrack.setIdentifier(newTrackId);
editedTrack.setFlavor(new MediaPackageElementFlavor(sourceTrackFlavor.getType(), SINK_FLAVOR_SUBTYPE));
return editedTrack;
} catch (MediaInspectionException ex) {
throw new ProcessFailedException("Inspecting encoded Track failed with: " + ex.getMessage());
} catch (MediaPackageException ex) {
throw new ProcessFailedException("Unable to serialize edited Track! " + ex.getMessage());
} catch (Exception ex) {
throw new ProcessFailedException("Unable to process SMIL: " + ex.getMessage(), ex);
} finally {
FileUtils.deleteQuietly(tempDirectory);
}
}
use of org.opencastproject.mediapackage.MediaPackageException in project opencast by opencast.
the class SchedulerRestService method addEvent.
/**
* Creates new event based on parameters. All times and dates are in milliseconds.
*/
@POST
@Path("/")
@RestQuery(name = "newrecording", description = "Creates new event with specified parameters", returnDescription = "If an event was successfully created", restParameters = { @RestParameter(name = "start", isRequired = true, type = Type.INTEGER, description = "The start date of the event in milliseconds from 1970-01-01T00:00:00Z"), @RestParameter(name = "end", isRequired = true, type = Type.INTEGER, description = "The end date of the event in milliseconds from 1970-01-01T00:00:00Z"), @RestParameter(name = "agent", isRequired = true, type = Type.STRING, description = "The agent of the event"), @RestParameter(name = "users", isRequired = false, type = Type.STRING, description = "Comma separated list of user ids (speakers/lecturers) for the event"), @RestParameter(name = "mediaPackage", isRequired = true, type = Type.TEXT, description = "The media package of the event"), @RestParameter(name = "wfproperties", isRequired = false, type = Type.TEXT, description = "Workflow " + "configuration keys for the event. Each key will be prefixed by 'org.opencastproject.workflow" + ".config.' and added to the capture agent parameters."), @RestParameter(name = "agentparameters", isRequired = false, type = Type.TEXT, description = "The capture agent properties for the event"), @RestParameter(name = "optOut", isRequired = false, type = Type.BOOLEAN, description = "The opt out status of the event"), @RestParameter(name = "source", isRequired = false, type = Type.STRING, description = "The scheduling source of the event"), @RestParameter(name = "origin", isRequired = false, type = Type.STRING, description = "The origin") }, reponses = { @RestResponse(responseCode = HttpServletResponse.SC_CREATED, description = "Event is successfully created"), @RestResponse(responseCode = HttpServletResponse.SC_CONFLICT, description = "Unable to create event, conflicting events found (ConflicsFound)"), @RestResponse(responseCode = HttpServletResponse.SC_CONFLICT, description = "Unable to create event, event locked by a transaction (TransactionLock)"), @RestResponse(responseCode = HttpServletResponse.SC_UNAUTHORIZED, description = "You do not have permission to create the event. Maybe you need to authenticate."), @RestResponse(responseCode = HttpServletResponse.SC_BAD_REQUEST, description = "Missing or invalid information for this request") })
public Response addEvent(@FormParam("start") long startTime, @FormParam("end") long endTime, @FormParam("agent") String agentId, @FormParam("users") String users, @FormParam("mediaPackage") String mediaPackageXml, @FormParam("wfproperties") String workflowProperties, @FormParam("agentparameters") String agentParameters, @FormParam("optOut") Boolean optOut, @FormParam("source") String schedulingSource, @FormParam("origin") String origin) throws UnauthorizedException {
if (StringUtils.isBlank(origin))
origin = SchedulerService.ORIGIN;
if (endTime <= startTime || startTime < 0) {
logger.debug("Cannot add event without proper start and end time");
return RestUtil.R.badRequest("Cannot add event without proper start and end time");
}
if (StringUtils.isBlank(agentId)) {
logger.debug("Cannot add event without agent identifier");
return RestUtil.R.badRequest("Cannot add event without agent identifier");
}
if (StringUtils.isBlank(mediaPackageXml)) {
logger.debug("Cannot add event without media package");
return RestUtil.R.badRequest("Cannot add event without media package");
}
MediaPackage mediaPackage;
try {
mediaPackage = MediaPackageParser.getFromXml(mediaPackageXml);
} catch (MediaPackageException e) {
logger.debug("Could not parse media package", e);
return RestUtil.R.badRequest("Could not parse media package");
}
String eventId = mediaPackage.getIdentifier().compact();
Map<String, String> caProperties = new HashMap<>();
if (StringUtils.isNotBlank(agentParameters)) {
try {
Properties prop = parseProperties(agentParameters);
caProperties.putAll((Map) prop);
} catch (Exception e) {
logger.info("Could not parse capture agent properties: {}", agentParameters);
return RestUtil.R.badRequest("Could not parse capture agent properties");
}
}
Map<String, String> wfProperties = new HashMap<>();
if (StringUtils.isNotBlank(workflowProperties)) {
try {
Properties prop = parseProperties(workflowProperties);
wfProperties.putAll((Map) prop);
} catch (IOException e) {
logger.info("Could not parse workflow configuration properties: {}", workflowProperties);
return RestUtil.R.badRequest("Could not parse workflow configuration properties");
}
}
Set<String> userIds = new HashSet<>();
String[] ids = StringUtils.split(users, ",");
if (ids != null)
userIds.addAll(Arrays.asList(ids));
DateTime startDate = new DateTime(startTime).toDateTime(DateTimeZone.UTC);
DateTime endDate = new DateTime(endTime).toDateTime(DateTimeZone.UTC);
try {
service.addEvent(startDate.toDate(), endDate.toDate(), agentId, userIds, mediaPackage, wfProperties, caProperties, Opt.nul(optOut), Opt.nul(schedulingSource), origin);
return Response.status(Status.CREATED).header("Location", serverUrl + serviceUrl + '/' + eventId + "/mediapackage.xml").build();
} catch (UnauthorizedException e) {
throw e;
} catch (SchedulerTransactionLockException | SchedulerConflictException e) {
return Response.status(Status.CONFLICT).entity(generateErrorResponse(e)).type(MediaType.APPLICATION_JSON).build();
} catch (Exception e) {
logger.error("Unable to create new event with id '{}'", eventId, e);
return Response.serverError().build();
}
}
use of org.opencastproject.mediapackage.MediaPackageException in project opencast by opencast.
the class WorkflowServiceImpl method remove.
/**
* {@inheritDoc}
*
* @see org.opencastproject.workflow.api.WorkflowService#remove(long)
*/
@Override
public void remove(long workflowInstanceId) throws WorkflowDatabaseException, NotFoundException, UnauthorizedException, WorkflowParsingException, WorkflowStateException {
final Lock lock = this.lock.get(workflowInstanceId);
lock.lock();
try {
WorkflowQuery query = new WorkflowQuery();
query.withId(Long.toString(workflowInstanceId));
WorkflowSet workflows = index.getWorkflowInstances(query, Permissions.Action.READ.toString(), false);
if (workflows.size() == 1) {
WorkflowInstance instance = workflows.getItems()[0];
WorkflowInstance.WorkflowState state = instance.getState();
if (state != WorkflowState.SUCCEEDED && state != WorkflowState.FAILED && state != WorkflowState.STOPPED)
throw new WorkflowStateException("Workflow instance with state '" + state + "' cannot be removed. Only states SUCCEEDED, FAILED & STOPPED are allowed");
try {
assertPermission(instance, Permissions.Action.WRITE.toString());
} catch (MediaPackageException e) {
throw new WorkflowParsingException(e);
}
// First, remove temporary files DO THIS BEFORE REMOVING FROM INDEX
try {
removeTempFiles(instance);
} catch (NotFoundException e) {
// If the files aren't their anymore, we don't have to cleanup up them :-)
logger.debug("Temporary files of workflow instance %d seem to be gone already...", workflowInstanceId);
}
// Second, remove jobs related to a operation which belongs to the workflow instance
List<WorkflowOperationInstance> operations = instance.getOperations();
List<Long> jobsToDelete = new ArrayList<>();
for (WorkflowOperationInstance op : operations) {
if (op.getId() != null) {
long workflowOpId = op.getId();
if (workflowOpId != workflowInstanceId) {
jobsToDelete.add(workflowOpId);
}
}
}
try {
serviceRegistry.removeJobs(jobsToDelete);
} catch (ServiceRegistryException e) {
logger.warn("Problems while removing jobs related to workflow operations '%s': %s", jobsToDelete, e.getMessage());
} catch (NotFoundException e) {
logger.debug("No jobs related to one of the workflow operations '%s' found in the service registry", jobsToDelete);
}
// Third, remove workflow instance job itself
try {
serviceRegistry.removeJobs(Collections.singletonList(workflowInstanceId));
messageSender.sendObjectMessage(WorkflowItem.WORKFLOW_QUEUE, MessageSender.DestinationType.Queue, WorkflowItem.deleteInstance(workflowInstanceId, instance));
} catch (ServiceRegistryException e) {
logger.warn("Problems while removing workflow instance job '%d': %s", workflowInstanceId, ExceptionUtils.getStackTrace(e));
} catch (NotFoundException e) {
logger.info("No workflow instance job '%d' found in the service registry", workflowInstanceId);
}
// At last, remove workflow instance from the index
try {
index.remove(workflowInstanceId);
} catch (NotFoundException e) {
// This should never happen, because we got workflow instance by querying the index...
logger.warn("Workflow instance could not be removed from index: %s", ExceptionUtils.getStackTrace(e));
}
} else if (workflows.size() == 0) {
throw new NotFoundException("Workflow instance with id '" + Long.toString(workflowInstanceId) + "' could not be found");
} else {
throw new WorkflowDatabaseException("More than one workflow found with id: " + Long.toString(workflowInstanceId));
}
} finally {
lock.unlock();
}
}
use of org.opencastproject.mediapackage.MediaPackageException in project opencast by opencast.
the class WorkflowServiceImpl method getWorkflowById.
/**
* {@inheritDoc}
*
* @see org.opencastproject.workflow.api.WorkflowService#getWorkflowById(long)
*/
@Override
public WorkflowInstanceImpl getWorkflowById(long id) throws WorkflowDatabaseException, NotFoundException, UnauthorizedException {
try {
Job job = serviceRegistry.getJob(id);
if (Status.DELETED.equals(job.getStatus())) {
throw new NotFoundException("Workflow '" + id + "' has been deleted");
}
if (JOB_TYPE.equals(job.getJobType()) && Operation.START_WORKFLOW.toString().equals(job.getOperation())) {
WorkflowInstanceImpl workflow = WorkflowParser.parseWorkflowInstance(job.getPayload());
assertPermission(workflow, Permissions.Action.READ.toString());
return workflow;
} else {
throw new NotFoundException("'" + id + "' is a job identifier, but it is not a workflow identifier");
}
} catch (WorkflowParsingException e) {
throw new IllegalStateException("The workflow job payload is malformed");
} catch (ServiceRegistryException e) {
throw new IllegalStateException("Error loading workflow job from the service registry");
} catch (MediaPackageException e) {
throw new IllegalStateException("Unable to read mediapackage from workflow " + id, e);
}
}
use of org.opencastproject.mediapackage.MediaPackageException in project opencast by opencast.
the class WaveformServiceImpl method process.
/**
* {@inheritDoc}
*
* @see org.opencastproject.job.api.AbstractJobProducer#process(org.opencastproject.job.api.Job)
*/
@Override
protected String process(Job job) throws Exception {
Operation op = null;
String operation = job.getOperation();
List<String> arguments = job.getArguments();
try {
op = Operation.valueOf(operation);
switch(op) {
case Waveform:
Track track = (Track) MediaPackageElementParser.getFromXml(arguments.get(0));
Attachment waveformMpe = extractWaveform(track);
return MediaPackageElementParser.getAsXml(waveformMpe);
default:
throw new ServiceRegistryException("This service can't handle operations of type '" + op + "'");
}
} catch (IndexOutOfBoundsException e) {
throw new ServiceRegistryException("This argument list for operation '" + op + "' does not meet expectations", e);
} catch (MediaPackageException | WaveformServiceException e) {
throw new ServiceRegistryException("Error handling operation '" + op + "'", e);
}
}
Aggregations