use of org.opencastproject.animate.api.AnimateServiceException in project opencast by opencast.
the class AnimateServiceImpl method process.
/**
* {@inheritDoc}
*
* @see org.opencastproject.job.api.AbstractJobProducer#process(org.opencastproject.job.api.Job)
*/
@Override
protected String process(Job job) throws Exception {
logger.debug("Started processing job {}", job.getId());
if (!OPERATION.equals(job.getOperation())) {
throw new ServiceRegistryException(String.format("This service can't handle operations of type '%s'", job.getOperation()));
}
List<String> arguments = job.getArguments();
URI animation = new URI(arguments.get(0));
Gson gson = new Gson();
Map<String, String> metadata = gson.fromJson(arguments.get(1), stringMapType);
List<String> options = gson.fromJson(arguments.get(2), stringListType);
// filter animation and get new, custom input file
File input = customAnimation(job, animation, metadata);
// prepare output file
File output = new File(workspace.rootDirectory(), String.format("animate/%d/%s.%s", job.getId(), FilenameUtils.getBaseName(animation.getPath()), "mkv"));
FileUtils.forceMkdirParent(output);
// create animation process.
final List<String> command = new ArrayList<>();
command.add(synfigBinary);
command.add("-i");
command.add(input.getAbsolutePath());
command.add("-o");
command.add(output.getAbsolutePath());
command.addAll(options);
logger.info("Executing animation command: {}", command);
Process process = null;
try {
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.redirectErrorStream(true);
process = processBuilder.start();
// print synfig (+ffmpeg) output
try (BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = in.readLine()) != null) {
logger.debug("Synfig: {}", line);
}
}
// wait until the task is finished
int exitCode = process.waitFor();
if (exitCode != 0) {
throw new AnimateServiceException(String.format("Synfig exited abnormally with status %d (command: %s)", exitCode, command));
}
if (!output.isFile()) {
throw new AnimateServiceException("Synfig produced no output");
}
logger.info("Animation generated successfully: {}", output);
} catch (Exception e) {
// Ensure temporary data are removed
FileUtils.deleteQuietly(output.getParentFile());
logger.debug("Removed output directory of failed animation process: {}", output.getParentFile());
throw new AnimateServiceException(e);
} finally {
IoSupport.closeQuietly(process);
FileUtils.deleteQuietly(input);
}
URI uri = workspace.putInCollection("animate-" + job.getId(), output.getName(), new FileInputStream(output));
FileUtils.deleteQuietly(new File(workspace.rootDirectory(), String.format("animate/%d", job.getId())));
return uri.toString();
}
use of org.opencastproject.animate.api.AnimateServiceException in project opencast by opencast.
the class AnimateServiceImpl method animate.
@Override
public Job animate(URI animation, Map<String, String> metadata, List<String> arguments) throws AnimateServiceException {
Gson gson = new Gson();
List<String> jobArguments = Arrays.asList(animation.toString(), gson.toJson(metadata), gson.toJson(arguments));
try {
logger.debug("Create animate service job");
return serviceRegistry.createJob(JOB_TYPE, OPERATION, jobArguments, jobLoad);
} catch (ServiceRegistryException e) {
throw new AnimateServiceException(e);
}
}
use of org.opencastproject.animate.api.AnimateServiceException in project opencast by opencast.
the class AnimateWorkflowOperationHandler 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 animate workflow operation for media package {}", mediaPackage);
WorkflowOperationInstance operation = workflowInstance.getCurrentOperation();
List<String> arguments;
// Check required options
final File animationFile = new File(StringUtils.trimToEmpty(operation.getConfiguration(ANIMATION_FILE_PROPERTY)));
if (!animationFile.isFile()) {
throw new WorkflowOperationException(String.format("Animation file `%s` does not exist", animationFile));
}
URI animation = animationFile.toURI();
final MediaPackageElementFlavor targetFlavor;
try {
targetFlavor = MediaPackageElementFlavor.parseFlavor(StringUtils.trimToNull(operation.getConfiguration(TARGET_FLAVOR_PROPERTY)));
} catch (IllegalArgumentException e) {
throw new WorkflowOperationException("Invalid target flavor", e);
}
// Get optional options
String targetTagsProperty = StringUtils.trimToNull(operation.getConfiguration(TARGET_TAGS_PROPERTY));
// Check if we have custom command line options
String cmd = operation.getConfiguration(COMMANDLINE_ARGUMENTS_PROPERTY);
if (StringUtils.isNotEmpty(cmd)) {
arguments = Arrays.asList(StringUtils.split(cmd));
} else {
// set default encoding
arguments = new ArrayList<>();
arguments.add("-t");
arguments.add("ffmpeg");
arguments.add("--video-codec");
arguments.add("libx264-lossless");
arguments.add("--video-bitrate");
arguments.add("10000");
addArgumentIfExists(operation, arguments, WIDTH_PROPERTY, "-w");
addArgumentIfExists(operation, arguments, HEIGHT_PROPERTY, "-h");
addArgumentIfExists(operation, arguments, FPS_PROPERTY, "--fps");
}
final Map<String, String> metadata = getMetadata(mediaPackage);
Job job;
try {
job = animateService.animate(animation, metadata, arguments);
} catch (AnimateServiceException e) {
throw new WorkflowOperationException(String.format("Rendering animation from '%s' in media package '%s' failed", animation, mediaPackage), e);
}
if (!waitForStatus(job).isSuccess()) {
throw new WorkflowOperationException(String.format("Animate job for media package '%s' failed", mediaPackage));
}
// put animated clip into media package
try {
URI output = new URI(job.getPayload());
String id = UUID.randomUUID().toString();
InputStream in = workspace.read(output);
URI uri = workspace.put(mediaPackage.getIdentifier().toString(), id, FilenameUtils.getName(output.getPath()), in);
TrackImpl track = new TrackImpl();
track.setIdentifier(id);
track.setFlavor(targetFlavor);
track.setURI(uri);
Job inspection = mediaInspectionService.enrich(track, true);
if (!waitForStatus(inspection).isSuccess()) {
throw new AnimateServiceException(String.format("Animating %s failed", animation));
}
track = (TrackImpl) MediaPackageElementParser.getFromXml(inspection.getPayload());
// add track to media package
for (String tag : asList(targetTagsProperty)) {
track.addTag(tag);
}
mediaPackage.add(track);
workspace.delete(output);
} catch (Exception e) {
throw new WorkflowOperationException("Error handling animation service output", e);
}
try {
workspace.cleanup(mediaPackage.getIdentifier());
} catch (IOException e) {
throw new WorkflowOperationException(e);
}
logger.info("Animate workflow operation for media package {} completed", mediaPackage);
return createResult(mediaPackage, WorkflowOperationResult.Action.CONTINUE);
}
use of org.opencastproject.animate.api.AnimateServiceException in project opencast by opencast.
the class AnimateServiceRestEndpoint method animate.
@POST
@Produces(MediaType.TEXT_XML)
@Path("animate")
@RestQuery(name = "animate", description = "Create animates video clip", restParameters = { @RestParameter(name = "animation", isRequired = true, type = STRING, description = "Location of to the animation"), @RestParameter(name = "arguments", isRequired = true, type = STRING, description = "Synfig command line arguments as JSON array"), @RestParameter(name = "metadata", isRequired = true, type = STRING, description = "Metadata for replacement as JSON object") }, reponses = { @RestResponse(description = "Animation created successfully", responseCode = HttpServletResponse.SC_OK), @RestResponse(description = "Invalid data", responseCode = HttpServletResponse.SC_BAD_REQUEST), @RestResponse(description = "Internal error", responseCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR) }, returnDescription = "Returns the path to the generated animation video")
public Response animate(@FormParam("animation") String animation, @FormParam("arguments") String argumentsString, @FormParam("metadata") String metadataString) {
Gson gson = new Gson();
try {
Map<String, String> metadata = gson.fromJson(metadataString, stringMapType);
List<String> arguments = gson.fromJson(argumentsString, stringListType);
logger.debug("Start animation");
Job job = animateService.animate(new URI(animation), metadata, arguments);
return Response.ok(new JaxbJob(job)).build();
} catch (JsonSyntaxException | URISyntaxException | NullPointerException e) {
logger.debug("Invalid data passed to REST endpoint:\nanimation: {}\nmetadata: {}\narguments: {})", animation, metadataString, argumentsString);
return Response.status(Response.Status.BAD_REQUEST).build();
} catch (AnimateServiceException e) {
logger.error("Error animating file {}", animation, e);
return Response.serverError().build();
}
}
use of org.opencastproject.animate.api.AnimateServiceException in project opencast by opencast.
the class AnimateServiceRemoteImpl method animate.
@Override
public Job animate(URI animation, Map<String, String> metadata, List<String> options) throws AnimateServiceException {
// serialize arguments and metadata
String metadataJson = gson.toJson(metadata);
String optionJson = gson.toJson(options);
// Build form parameters
List<NameValuePair> params = new ArrayList<>();
params.add(new BasicNameValuePair("animation", animation.toString()));
params.add(new BasicNameValuePair("arguments", optionJson));
params.add(new BasicNameValuePair("metadata", metadataJson));
logger.info("Animating {}", animation);
HttpResponse response = null;
try {
HttpPost post = new HttpPost("/animate");
post.setEntity(new UrlEncodedFormEntity(params));
response = getResponse(post);
if (response == null) {
throw new AnimateServiceException("No response from service");
}
Job receipt = JobParser.parseJob(response.getEntity().getContent());
logger.info("Completed animating {}", animation);
return receipt;
} catch (IOException e) {
throw new AnimateServiceException("Failed building service request", e);
} finally {
closeConnection(response);
}
}
Aggregations