use of org.opencastproject.composer.api.EncoderException in project opencast by opencast.
the class ComposerRestService method composite.
/**
* Compose two videos into one with an optional watermark.
*
* @param compositeSizeJson
* The composite track dimension as JSON
* @param lowerTrackXml
* The lower track of the composition as XML
* @param lowerLayoutJson
* The lower layout as JSON
* @param upperTrackXml
* The upper track of the composition as XML
* @param upperLayoutJson
* The upper layout as JSON
* @param watermarkAttachmentXml
* The watermark image attachment of the composition as XML
* @param watermarkLayoutJson
* The watermark layout as JSON
* @param profileId
* The encoding profile to use
* @param background
* The background color
* @return A {@link Response} with the resulting track in the response body
* @throws Exception
*/
@POST
@Path("composite")
@Produces(MediaType.TEXT_XML)
@RestQuery(name = "composite", description = "Starts a video compositing process, based on the specified resolution, encoding profile ID, the source elements and their layouts", restParameters = { @RestParameter(description = "The resolution size of the resulting video as JSON", isRequired = true, name = "compositeSize", type = Type.STRING), @RestParameter(description = "The lower source track containing the lower video", isRequired = true, name = "lowerTrack", type = Type.TEXT), @RestParameter(description = "The lower layout containing the JSON definition of the layout", isRequired = true, name = "lowerLayout", type = Type.TEXT), @RestParameter(description = "The upper source track containing the upper video", isRequired = false, name = "upperTrack", type = Type.TEXT), @RestParameter(description = "The upper layout containing the JSON definition of the layout", isRequired = false, name = "upperLayout", type = Type.TEXT), @RestParameter(description = "The watermark source attachment containing watermark image", isRequired = false, name = "watermarkTrack", type = Type.TEXT), @RestParameter(description = "The watermark layout containing the JSON definition of the layout", isRequired = false, name = "watermarkLayout", type = Type.TEXT), @RestParameter(description = "The background color", isRequired = false, name = "background", type = Type.TEXT, defaultValue = "black"), @RestParameter(description = "The encoding profile to use", isRequired = true, name = "profileId", type = Type.STRING) }, reponses = { @RestResponse(description = "Results in an xml document containing the compound video track", responseCode = HttpServletResponse.SC_OK), @RestResponse(description = "If required parameters aren't set or if the source elements aren't from the right type", responseCode = HttpServletResponse.SC_BAD_REQUEST) }, returnDescription = "")
public Response composite(@FormParam("compositeSize") String compositeSizeJson, @FormParam("lowerTrack") String lowerTrackXml, @FormParam("lowerLayout") String lowerLayoutJson, @FormParam("upperTrack") String upperTrackXml, @FormParam("upperLayout") String upperLayoutJson, @FormParam("watermarkAttachment") String watermarkAttachmentXml, @FormParam("watermarkLayout") String watermarkLayoutJson, @FormParam("profileId") String profileId, @FormParam("background") @DefaultValue("black") String background) throws Exception {
// Ensure that the POST parameters are present
if (StringUtils.isBlank(compositeSizeJson) || StringUtils.isBlank(lowerTrackXml) || StringUtils.isBlank(lowerLayoutJson) || StringUtils.isBlank(profileId))
return Response.status(Response.Status.BAD_REQUEST).entity("One of the required parameters must not be null").build();
// Deserialize the source elements
MediaPackageElement lowerTrack = MediaPackageElementParser.getFromXml(lowerTrackXml);
Layout lowerLayout = Serializer.layout(JsonObj.jsonObj(lowerLayoutJson));
if (!Track.TYPE.equals(lowerTrack.getElementType()))
return Response.status(Response.Status.BAD_REQUEST).entity("lowerTrack element must be of type track").build();
LaidOutElement<Track> lowerLaidOutElement = new LaidOutElement<Track>((Track) lowerTrack, lowerLayout);
Option<LaidOutElement<Track>> upperLaidOutElement = Option.<LaidOutElement<Track>>none();
if (StringUtils.isNotBlank(upperTrackXml)) {
MediaPackageElement upperTrack = MediaPackageElementParser.getFromXml(upperTrackXml);
Layout upperLayout = Serializer.layout(JsonObj.jsonObj(upperLayoutJson));
if (!Track.TYPE.equals(upperTrack.getElementType())) {
return Response.status(Response.Status.BAD_REQUEST).entity("upperTrack element must be of type track").build();
}
upperLaidOutElement = Option.option(new LaidOutElement<Track>((Track) upperTrack, upperLayout));
}
Option<LaidOutElement<Attachment>> watermarkLaidOutElement = Option.<LaidOutElement<Attachment>>none();
if (StringUtils.isNotBlank(watermarkAttachmentXml)) {
Layout watermarkLayout = Serializer.layout(JsonObj.jsonObj(watermarkLayoutJson));
MediaPackageElement watermarkAttachment = MediaPackageElementParser.getFromXml(watermarkAttachmentXml);
if (!Attachment.TYPE.equals(watermarkAttachment.getElementType()))
return Response.status(Response.Status.BAD_REQUEST).entity("watermarkTrack element must be of type track").build();
watermarkLaidOutElement = Option.some(new LaidOutElement<Attachment>((Attachment) watermarkAttachment, watermarkLayout));
}
Dimension compositeTrackSize = Serializer.dimension(JsonObj.jsonObj(compositeSizeJson));
try {
// Asynchronously composite the specified source elements
Job job = composerService.composite(compositeTrackSize, upperLaidOutElement, lowerLaidOutElement, watermarkLaidOutElement, profileId, background);
return Response.ok().entity(new JaxbJob(job)).build();
} catch (EncoderException e) {
logger.warn("Unable to composite video: " + e.getMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
}
use of org.opencastproject.composer.api.EncoderException in project opencast by opencast.
the class ComposerServiceTest method setUp.
@Before
public void setUp() throws Exception {
// Skip tests if FFmpeg is not installed
Assume.assumeTrue(ffmpegInstalled);
// Create video only file
File f = getFile("/video.mp4");
sourceVideoOnly = File.createTempFile(FilenameUtils.getBaseName(f.getName()), ".mp4", testDir);
FileUtils.copyFile(f, sourceVideoOnly);
// Create another audio only file
f = getFile("/audio.mp3");
sourceAudioOnly = File.createTempFile(FilenameUtils.getBaseName(f.getName()), ".mp3", testDir);
FileUtils.copyFile(f, sourceAudioOnly);
// Create an image file
f = getFile("/image.jpg");
sourceImage = File.createTempFile(FilenameUtils.getBaseName(f.getName()), ".jpg", testDir);
FileUtils.copyFile(f, sourceImage);
// create the needed mocks
BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
EasyMock.expect(bc.getProperty(EasyMock.anyString())).andReturn(FFMPEG_BINARY);
ComponentContext cc = EasyMock.createNiceMock(ComponentContext.class);
EasyMock.expect(cc.getBundleContext()).andReturn(bc).anyTimes();
JaxbOrganization org = new DefaultOrganization();
HashSet<JaxbRole> roles = new HashSet<>();
roles.add(new JaxbRole(DefaultOrganization.DEFAULT_ORGANIZATION_ADMIN, org, ""));
User user = new JaxbUser("admin", "test", org, roles);
OrganizationDirectoryService orgDirectory = EasyMock.createNiceMock(OrganizationDirectoryService.class);
EasyMock.expect(orgDirectory.getOrganization((String) EasyMock.anyObject())).andReturn(org).anyTimes();
UserDirectoryService userDirectory = EasyMock.createNiceMock(UserDirectoryService.class);
EasyMock.expect(userDirectory.loadUser("admin")).andReturn(user).anyTimes();
SecurityService securityService = EasyMock.createNiceMock(SecurityService.class);
EasyMock.expect(securityService.getOrganization()).andReturn(org).anyTimes();
EasyMock.expect(securityService.getUser()).andReturn(user).anyTimes();
Workspace workspace = EasyMock.createNiceMock(Workspace.class);
EasyMock.expect(workspace.get(EasyMock.anyObject())).andReturn(sourceVideoOnly).anyTimes();
profileScanner = new EncodingProfileScanner();
File encodingProfile = getFile("/encodingprofiles.properties");
assertNotNull("Encoding profile must exist", encodingProfile);
profileScanner.install(encodingProfile);
// Finish setting up the mocks
EasyMock.replay(bc, cc, orgDirectory, userDirectory, securityService, workspace);
// Create an encoding engine factory
inspectedTrack = (Track) MediaPackageElementParser.getFromXml(IOUtils.toString(ComposerServiceTest.class.getResourceAsStream("/composer_test_source_track_video.xml"), Charset.defaultCharset()));
sourceVideoTrack = (Track) MediaPackageElementParser.getFromXml(IOUtils.toString(ComposerServiceTest.class.getResourceAsStream("/composer_test_source_track_video.xml"), Charset.defaultCharset()));
sourceAudioTrack = (Track) MediaPackageElementParser.getFromXml(IOUtils.toString(ComposerServiceTest.class.getResourceAsStream("/composer_test_source_track_audio.xml"), Charset.defaultCharset()));
// Create and populate the composer service
composerService = new ComposerServiceImpl() {
@Override
protected Job inspect(Job job, URI workspaceURI) throws EncoderException {
Job inspectionJob = EasyMock.createNiceMock(Job.class);
try {
EasyMock.expect(inspectionJob.getPayload()).andReturn(MediaPackageElementParser.getAsXml(inspectedTrack));
} catch (MediaPackageException e) {
throw new RuntimeException(e);
}
EasyMock.replay(inspectionJob);
return inspectionJob;
}
};
ServiceRegistry serviceRegistry = EasyMock.createMock(ServiceRegistry.class);
final Capture<String> type = EasyMock.newCapture();
final Capture<String> operation = EasyMock.newCapture();
final Capture<List<String>> args = EasyMock.newCapture();
EasyMock.expect(serviceRegistry.createJob(capture(type), capture(operation), capture(args), EasyMock.anyFloat())).andAnswer(() -> {
// you could do work here to return something different if you needed.
Job job = new JobImpl(0);
job.setJobType(type.getValue());
job.setOperation(operation.getValue());
job.setArguments(args.getValue());
job.setPayload(composerService.process(job));
return job;
}).anyTimes();
composerService.setServiceRegistry(serviceRegistry);
composerService.setProfileScanner(profileScanner);
composerService.setWorkspace(workspace);
EasyMock.replay(serviceRegistry);
}
use of org.opencastproject.composer.api.EncoderException in project opencast by opencast.
the class ComposerServiceRemoteImpl method convertImage.
/**
* {@inheritDoc}
*
* @see org.opencastproject.composer.api.ComposerService#convertImage(org.opencastproject.mediapackage.Attachment,
* java.lang.String)
*/
@Override
public Job convertImage(Attachment image, String profileId) throws EncoderException, MediaPackageException {
HttpPost post = new HttpPost("/convertimage");
try {
List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
params.add(new BasicNameValuePair("sourceImage", MediaPackageElementParser.getAsXml(image)));
params.add(new BasicNameValuePair("profileId", profileId));
post.setEntity(new UrlEncodedFormEntity(params));
} catch (Exception e) {
throw new EncoderException(e);
}
HttpResponse response = null;
try {
response = getResponse(post);
if (response != null) {
Job r = JobParser.parseJob(response.getEntity().getContent());
logger.info("Image conversion job {} started on a remote composer", r.getId());
return r;
}
} catch (Exception e) {
throw new EncoderException(e);
} finally {
closeConnection(response);
}
throw new EncoderException("Unable to convert image at " + image + " using the remote composer service proxy");
}
use of org.opencastproject.composer.api.EncoderException in project opencast by opencast.
the class ComposerServiceRemoteImpl method image.
/**
* {@inheritDoc}
*
* @see org.opencastproject.composer.api.ComposerService#image(Track, String, Map)
*/
@Override
public Job image(Track sourceTrack, String profileId, Map<String, String> properties) throws EncoderException, MediaPackageException {
HttpPost post = new HttpPost("/image");
try {
List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
params.add(new BasicNameValuePair("sourceTrack", MediaPackageElementParser.getAsXml(sourceTrack)));
params.add(new BasicNameValuePair("profileId", profileId));
if (properties != null)
params.add(new BasicNameValuePair("properties", mapToString(properties)));
post.setEntity(new UrlEncodedFormEntity(params));
} catch (Exception e) {
throw new EncoderException(e);
}
HttpResponse response = null;
try {
response = getResponse(post);
if (response != null) {
Job r = JobParser.parseJob(response.getEntity().getContent());
logger.info("Image extraction job {} started on a remote composer", r.getId());
return r;
}
} catch (Exception e) {
throw new EncoderException(e);
} finally {
closeConnection(response);
}
throw new EncoderException("Unable to compose an image from track " + sourceTrack + " using the remote composer service proxy");
}
use of org.opencastproject.composer.api.EncoderException in project opencast by opencast.
the class ComposerServiceRemoteImpl method imageToVideo.
@Override
public Job imageToVideo(Attachment sourceImageAttachment, String profileId, double time) throws EncoderException, MediaPackageException {
HttpPost post = new HttpPost("/imagetovideo");
try {
List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
params.add(new BasicNameValuePair("sourceAttachment", MediaPackageElementParser.getAsXml(sourceImageAttachment)));
params.add(new BasicNameValuePair("profileId", profileId));
params.add(new BasicNameValuePair("time", Double.toString(time)));
post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
} catch (Exception e) {
throw new EncoderException(e);
}
HttpResponse response = null;
try {
response = getResponse(post);
if (response != null) {
Job r = JobParser.parseJob(response.getEntity().getContent());
logger.info("Image to video converting job {} started on a remote composer", r.getId());
return r;
}
} catch (Exception e) {
throw new EncoderException(e);
} finally {
closeConnection(response);
}
throw new EncoderException("Unable to convert an image to a video from attachment " + sourceImageAttachment + " using the remote composer service proxy");
}
Aggregations