use of org.opencastproject.waveform.api.WaveformServiceException in project opencast by opencast.
the class WaveformServiceImpl method extractWaveform.
/**
* Create and run waveform extraction ffmpeg command.
*
* @param track source audio/video track with at least one audio channel
* @return waveform image attachment
* @throws WaveformServiceException if processing fails
*/
private Attachment extractWaveform(Track track) throws WaveformServiceException {
if (!track.hasAudio()) {
throw new WaveformServiceException("Track has no audio");
}
// copy source file into workspace
File mediaFile;
try {
mediaFile = workspace.get(track.getURI());
} catch (NotFoundException e) {
throw new WaveformServiceException("Error finding the media file in the workspace", e);
} catch (IOException e) {
throw new WaveformServiceException("Error reading the media file in the workspace", e);
}
String waveformFilePath = FilenameUtils.removeExtension(mediaFile.getAbsolutePath()).concat('-' + track.getIdentifier()).concat("-waveform.png");
// create ffmpeg command
String[] command = new String[] { binary, "-nostats", "-i", mediaFile.getAbsolutePath(), "-lavfi", createWaveformFilter(track), "-an", "-vn", "-sn", "-y", waveformFilePath };
logger.debug("Start waveform ffmpeg process: {}", StringUtils.join(command, " "));
logger.info("Create waveform image file for track '{}' at {}", track.getIdentifier(), waveformFilePath);
// run ffmpeg
ProcessBuilder pb = new ProcessBuilder(command);
pb.redirectErrorStream(true);
Process ffmpegProcess = null;
int exitCode = 1;
BufferedReader errStream = null;
try {
ffmpegProcess = pb.start();
errStream = new BufferedReader(new InputStreamReader(ffmpegProcess.getInputStream()));
String line = errStream.readLine();
while (line != null) {
logger.debug(line);
line = errStream.readLine();
}
exitCode = ffmpegProcess.waitFor();
} catch (IOException ex) {
throw new WaveformServiceException("Start ffmpeg process failed", ex);
} catch (InterruptedException ex) {
throw new WaveformServiceException("Waiting for encoder process exited was interrupted unexpectly", ex);
} finally {
IoSupport.closeQuietly(ffmpegProcess);
IoSupport.closeQuietly(errStream);
if (exitCode != 0) {
try {
FileUtils.forceDelete(new File(waveformFilePath));
} catch (IOException e) {
// it is ok, no output file was generated by ffmpeg
}
}
}
if (exitCode != 0)
throw new WaveformServiceException("The encoder process exited abnormally with exit code " + exitCode);
// put waveform image into workspace
FileInputStream waveformFileInputStream = null;
URI waveformFileUri;
try {
waveformFileInputStream = new FileInputStream(waveformFilePath);
waveformFileUri = workspace.putInCollection(COLLECTION_ID, FilenameUtils.getName(waveformFilePath), waveformFileInputStream);
logger.info("Copied the created waveform to the workspace {}", waveformFileUri);
} catch (FileNotFoundException ex) {
throw new WaveformServiceException(String.format("Waveform image file '%s' not found", waveformFilePath), ex);
} catch (IOException ex) {
throw new WaveformServiceException(String.format("Can't write waveform image file '%s' to workspace", waveformFilePath), ex);
} catch (IllegalArgumentException ex) {
throw new WaveformServiceException(ex);
} finally {
IoSupport.closeQuietly(waveformFileInputStream);
logger.info("Deleted local waveform image file at {}", waveformFilePath);
FileUtils.deleteQuietly(new File(waveformFilePath));
}
// create media package element
MediaPackageElementBuilder mpElementBuilder = MediaPackageElementBuilderFactory.newInstance().newElementBuilder();
// it is up to the workflow operation handler to set the attachment flavor
Attachment waveformMpe = (Attachment) mpElementBuilder.elementFromURI(waveformFileUri, Type.Attachment, track.getFlavor());
waveformMpe.setIdentifier(IdBuilderFactory.newInstance().newIdBuilder().createNew().compact());
return waveformMpe;
}
use of org.opencastproject.waveform.api.WaveformServiceException in project opencast by opencast.
the class WaveformServiceRemote method createWaveformImage.
/**
* Takes the given track and returns the job that will create an waveform image using a remote service.
*
* @param sourceTrack the track to create waveform image from
* @return a job that will create a waveform image
* @throws MediaPackageException if the serialization of the given track fails
* @throws WaveformServiceException if the job can't be created for any reason
*/
@Override
public Job createWaveformImage(Track sourceTrack) throws MediaPackageException, WaveformServiceException {
HttpPost post = new HttpPost("/create");
try {
List<BasicNameValuePair> params = new ArrayList<>();
params.add(new BasicNameValuePair("track", MediaPackageElementParser.getAsXml(sourceTrack)));
post.setEntity(new UrlEncodedFormEntity(params));
} catch (Exception e) {
throw new WaveformServiceException(e);
}
HttpResponse response = null;
try {
response = getResponse(post);
if (response != null) {
try {
Job receipt = JobParser.parseJob(response.getEntity().getContent());
logger.info("Create waveform image from {}", sourceTrack);
return receipt;
} catch (Exception e) {
throw new WaveformServiceException("Unable to create waveform image from " + sourceTrack + " using a remote service", e);
}
}
} finally {
closeConnection(response);
}
throw new WaveformServiceException("Unable to create waveform image from " + sourceTrack + " using a remote service");
}
use of org.opencastproject.waveform.api.WaveformServiceException 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);
}
}
use of org.opencastproject.waveform.api.WaveformServiceException in project opencast by opencast.
the class WaveformServiceEndpoint method createWaveformImage.
@POST
@Path("/create")
@Produces({ MediaType.APPLICATION_XML })
@RestQuery(name = "create", description = "Create a waveform image from the given track", returnDescription = "Media package attachment for the generated waveform.", restParameters = { @RestParameter(name = "track", type = RestParameter.Type.TEXT, description = "Track with at least one audio channel.", isRequired = true) }, reponses = { @RestResponse(description = "Waveform generation job successfully created.", responseCode = HttpServletResponse.SC_OK), @RestResponse(description = "The given track can't be parsed.", responseCode = HttpServletResponse.SC_BAD_REQUEST), @RestResponse(description = "Internal server error.", responseCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR) })
public Response createWaveformImage(@FormParam("track") String track) {
try {
MediaPackageElement sourceTrack = MediaPackageElementParser.getFromXml(track);
if (!Track.TYPE.equals(sourceTrack.getElementType()))
return Response.status(Response.Status.BAD_REQUEST).entity("Track element must be of type track").build();
Job job = waveformService.createWaveformImage((Track) sourceTrack);
return Response.ok().entity(new JaxbJob(job)).build();
} catch (WaveformServiceException ex) {
logger.error("Creating waveform job for track {} failed: {}", track, ExceptionUtils.getStackTrace(ex));
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
} catch (MediaPackageException ex) {
return Response.status(Response.Status.BAD_REQUEST).entity("Track element parsing failure").build();
}
}
use of org.opencastproject.waveform.api.WaveformServiceException in project opencast by opencast.
the class WaveformWorkflowOperationHandler method start.
/**
* {@inheritDoc}
*
* @see
* org.opencastproject.workflow.api.WorkflowOperationHandler#start(org.opencastproject.workflow.api.WorkflowInstance,
* org.opencastproject.job.api.JobContext)
*/
@Override
public WorkflowOperationResult start(WorkflowInstance workflowInstance, JobContext context) throws WorkflowOperationException {
MediaPackage mediaPackage = workflowInstance.getMediaPackage();
logger.info("Start waveform workflow operation for mediapackage {}", mediaPackage);
String sourceFlavorProperty = StringUtils.trimToNull(workflowInstance.getCurrentOperation().getConfiguration(SOURCE_FLAVOR_PROPERTY));
String sourceTagsProperty = StringUtils.trimToNull(workflowInstance.getCurrentOperation().getConfiguration(SOURCE_TAGS_PROPERTY));
if (StringUtils.isEmpty(sourceFlavorProperty) && StringUtils.isEmpty(sourceTagsProperty)) {
throw new WorkflowOperationException(String.format("Required property %s or %s not set", SOURCE_FLAVOR_PROPERTY, SOURCE_TAGS_PROPERTY));
}
String targetFlavorProperty = StringUtils.trimToNull(workflowInstance.getCurrentOperation().getConfiguration(TARGET_FLAVOR_PROPERTY));
if (targetFlavorProperty == null) {
throw new WorkflowOperationException(String.format("Required property %s not set", TARGET_FLAVOR_PROPERTY));
}
String targetTagsProperty = StringUtils.trimToNull(workflowInstance.getCurrentOperation().getConfiguration(TARGET_TAGS_PROPERTY));
TrackSelector trackSelector = new TrackSelector();
for (String flavor : asList(sourceFlavorProperty)) {
trackSelector.addFlavor(flavor);
}
for (String tag : asList(sourceTagsProperty)) {
trackSelector.addTag(tag);
}
Collection<Track> sourceTracks = trackSelector.select(mediaPackage, false);
if (sourceTracks.isEmpty()) {
logger.info("No tracks found in mediapackage {} with specified {} = {}", mediaPackage, SOURCE_FLAVOR_PROPERTY, sourceFlavorProperty);
createResult(mediaPackage, WorkflowOperationResult.Action.SKIP);
}
List<Job> waveformJobs = new ArrayList<>(sourceTracks.size());
for (Track sourceTrack : sourceTracks) {
// Skip over track with no audio stream
if (!sourceTrack.hasAudio()) {
logger.info("Skipping waveform extraction of track {} since it has no audio", sourceTrack.getIdentifier());
continue;
}
try {
// generate waveform
logger.info("Creating waveform extraction job for track '{}' in mediapackage '{}'", sourceTrack.getIdentifier(), mediaPackage);
Job waveformJob = waveformService.createWaveformImage(sourceTrack);
waveformJobs.add(waveformJob);
} catch (MediaPackageException | WaveformServiceException e) {
logger.error("Creating waveform extraction job for track '{}' in media package '{}' failed", sourceTrack.getIdentifier(), mediaPackage, e);
}
}
logger.debug("Waiting for waveform jobs for media package {}", mediaPackage);
if (!waitForStatus(waveformJobs.toArray(new Job[waveformJobs.size()])).isSuccess()) {
cleanupWorkspace(waveformJobs);
throw new WorkflowOperationException(String.format("Waveform extraction jobs for media package '%s' have not completed successfully", mediaPackage.getIdentifier()));
}
try {
// copy waveform attachments into workspace and add them to the media package
for (Job job : waveformJobs) {
String jobPayload = job.getPayload();
if (StringUtils.isEmpty(jobPayload)) {
continue;
}
MediaPackageElement waveformMpe = null;
try {
waveformMpe = MediaPackageElementParser.getFromXml(jobPayload);
URI newURI = workspace.moveTo(waveformMpe.getURI(), mediaPackage.getIdentifier().toString(), waveformMpe.getIdentifier(), "waveform.png");
waveformMpe.setURI(newURI);
} catch (MediaPackageException ex) {
// unexpected job payload
throw new WorkflowOperationException("Can't parse waveform attachment from job " + job.getId());
} catch (NotFoundException ex) {
throw new WorkflowOperationException("Waveform image file '" + waveformMpe.getURI() + "' not found", ex);
} catch (IOException ex) {
throw new WorkflowOperationException("Can't get workflow image file '" + waveformMpe.getURI() + "' from workspace");
}
// set the waveform attachment flavor and add it to the media package
MediaPackageElementFlavor targetFlavor = MediaPackageElementFlavor.parseFlavor(targetFlavorProperty);
if ("*".equals(targetFlavor.getType())) {
targetFlavor = new MediaPackageElementFlavor(waveformMpe.getFlavor().getType(), targetFlavor.getSubtype());
}
if ("*".equals(targetFlavor.getSubtype())) {
targetFlavor = new MediaPackageElementFlavor(targetFlavor.getType(), waveformMpe.getFlavor().getSubtype());
}
waveformMpe.setFlavor(targetFlavor);
for (String tag : asList(targetTagsProperty)) {
waveformMpe.addTag(tag);
}
mediaPackage.add(waveformMpe);
}
} finally {
cleanupWorkspace(waveformJobs);
}
try {
workspace.cleanup(mediaPackage.getIdentifier());
} catch (IOException e) {
throw new WorkflowOperationException(e);
}
logger.info("Waveform workflow operation for mediapackage {} completed", mediaPackage);
return createResult(mediaPackage, WorkflowOperationResult.Action.CONTINUE);
}
Aggregations