use of org.opencastproject.composer.api.EncodingProfile in project opencast by opencast.
the class ComposerServiceImpl method concat.
@Override
public Job concat(String profileId, Dimension outputDimension, float outputFrameRate, Track... tracks) throws EncoderException, MediaPackageException {
ArrayList<String> arguments = new ArrayList<String>();
arguments.add(0, profileId);
if (outputDimension != null) {
arguments.add(1, Serializer.json(outputDimension).toJson());
} else {
arguments.add(1, "");
}
arguments.add(2, String.format(Locale.US, "%f", outputFrameRate));
for (int i = 0; i < tracks.length; i++) {
arguments.add(i + 3, MediaPackageElementParser.getAsXml(tracks[i]));
}
try {
final EncodingProfile profile = profileScanner.getProfile(profileId);
return serviceRegistry.createJob(JOB_TYPE, Operation.Concat.toString(), arguments, profile.getJobLoad());
} catch (ServiceRegistryException e) {
throw new EncoderException("Unable to create concat job", e);
}
}
use of org.opencastproject.composer.api.EncodingProfile in project opencast by opencast.
the class ComposerServiceImpl method encode.
/**
* Encodes audio and video track to a file. If both an audio and a video track are given, they are muxed together into
* one movie container.
*
* @param tracks
* tracks to use for processing
* @param profileId
* the encoding profile
* @param properties
* encoding properties
* @return the encoded track or none if the operation does not return a track. This may happen for example when doing
* two pass encodings where the first pass only creates metadata for the second one
* @throws EncoderException
* if encoding fails
*/
private Option<Track> encode(final Job job, Map<String, Track> tracks, String profileId) throws EncoderException, MediaPackageException {
final String targetTrackId = idBuilder.createNew().toString();
Map<String, File> files = new HashMap<>();
// Get the tracks and make sure they exist
for (Entry<String, Track> track : tracks.entrySet()) {
files.put(track.getKey(), loadTrackIntoWorkspace(job, track.getKey(), track.getValue()));
}
// Get the encoding profile
final EncodingProfile profile = getProfile(job, profileId);
List<String> trackMsg = new LinkedList<>();
for (Entry<String, Track> track : tracks.entrySet()) {
trackMsg.add(String.format("%s: %s", track.getKey(), track.getValue().getIdentifier()));
}
logger.info("Encoding {} into {} using profile {}", StringUtils.join(trackMsg, ", "), targetTrackId, profileId);
// Do the work
final EncoderEngine encoder = getEncoderEngine();
List<File> output;
try {
output = encoder.process(files, profile, null);
} catch (EncoderException e) {
Map<String, String> params = new HashMap<>();
for (Entry<String, Track> track : tracks.entrySet()) {
params.put(track.getKey(), track.getValue().getIdentifier());
}
params.put("profile", profile.getIdentifier());
params.put("properties", "EMPTY");
incident().recordFailure(job, ENCODING_FAILED, e, params, detailsFor(e, encoder));
throw e;
} finally {
activeEncoder.remove(encoder);
}
// We expect zero or one file as output
if (output.size() == 0) {
return none();
} else if (output.size() != 1) {
// Ensure we do not leave behind old files in the workspace
for (File file : output) {
FileUtils.deleteQuietly(file);
}
throw new EncoderException("Composite does not support multiple files as output");
}
// Put the file in the workspace
URI workspaceURI = putToCollection(job, output.get(0), "encoded file");
// Have the encoded track inspected and return the result
Job inspectionJob = inspect(job, workspaceURI);
Track inspectedTrack = (Track) MediaPackageElementParser.getFromXml(inspectionJob.getPayload());
inspectedTrack.setIdentifier(targetTrackId);
if (profile.getMimeType() != null)
inspectedTrack.setMimeType(MimeTypes.parseMimeType(profile.getMimeType()));
return some(inspectedTrack);
}
use of org.opencastproject.composer.api.EncodingProfile in project opencast by opencast.
the class ComposerServiceImpl method convertImage.
/**
* Converts an image from <code>sourceImage</code> to a new format.
*
* @param job
* the associated job
* @param sourceImage
* the source image
* @param profileId
* the identifer of the encoding profile to use
* @return the image as an attachment or none if the operation does not return an image. This may happen for example
* when doing two pass encodings where the first pass only creates metadata for the second one
* @throws EncoderException
* if converting the image fails
*/
private Option<Attachment> convertImage(Job job, Attachment sourceImage, String profileId) throws EncoderException, MediaPackageException {
logger.info("Converting {}", sourceImage);
// Get the encoding profile
final EncodingProfile profile = getProfile(job, profileId);
// Create the encoding engine
final EncoderEngine encoderEngine = getEncoderEngine();
// Finally get the file that needs to be encoded
File imageFile;
try {
imageFile = workspace.get(sourceImage.getURI());
} catch (NotFoundException e) {
incident().recordFailure(job, WORKSPACE_GET_NOT_FOUND, e, getWorkspaceMediapackageParams("source image", sourceImage), NO_DETAILS);
throw new EncoderException("Requested video track " + sourceImage + " was not found", e);
} catch (IOException e) {
incident().recordFailure(job, WORKSPACE_GET_IO_EXCEPTION, e, getWorkspaceMediapackageParams("source image", sourceImage), NO_DETAILS);
throw new EncoderException("Error accessing video track " + sourceImage, e);
}
// Do the work
File output;
try {
output = encoderEngine.encode(imageFile, profile, null);
} catch (EncoderException e) {
Map<String, String> params = new HashMap<>();
params.put("image", sourceImage.getURI().toString());
params.put("profile", profile.getIdentifier());
incident().recordFailure(job, CONVERT_IMAGE_FAILED, e, params, detailsFor(e, encoderEngine));
throw e;
} finally {
activeEncoder.remove(encoderEngine);
}
// encoding did not return a file
if (!output.exists() || output.length() == 0)
return none();
// Put the file in the workspace
URI workspaceURI = putToCollection(job, output, "converted image file");
MediaPackageElementBuilder builder = MediaPackageElementBuilderFactory.newInstance().newElementBuilder();
Attachment attachment = (Attachment) builder.elementFromURI(workspaceURI, Attachment.TYPE, null);
return some(attachment);
}
use of org.opencastproject.composer.api.EncodingProfile in project opencast by opencast.
the class ComposerServiceImpl method concat.
private Option<Track> concat(Job job, List<Track> tracks, String profileId, Dimension outputDimension, float outputFrameRate) throws EncoderException, MediaPackageException {
if (tracks.size() < 2) {
Map<String, String> params = new HashMap<>();
params.put("tracks-size", Integer.toString(tracks.size()));
params.put("tracks", StringUtils.join(tracks, ","));
incident().recordFailure(job, CONCAT_LESS_TRACKS, params);
throw new EncoderException("The track parameter must at least have two tracks present");
}
boolean onlyAudio = true;
for (Track t : tracks) {
if (t.hasVideo()) {
onlyAudio = false;
break;
}
}
if (!onlyAudio && outputDimension == null) {
Map<String, String> params = new HashMap<>();
params.put("tracks", StringUtils.join(tracks, ","));
incident().recordFailure(job, CONCAT_NO_DIMENSION, params);
throw new EncoderException("The output dimension id parameter must not be null when concatenating video");
}
final String targetTrackId = idBuilder.createNew().toString();
// Get the tracks and make sure they exist
List<File> trackFiles = new ArrayList<>();
int i = 0;
for (Track track : tracks) {
if (!track.hasAudio() && !track.hasVideo()) {
Map<String, String> params = new HashMap<>();
params.put("track-id", track.getIdentifier());
params.put("track-url", track.getURI().toString());
incident().recordFailure(job, NO_STREAMS, params);
throw new EncoderException("Track has no audio or video stream available: " + track);
}
trackFiles.add(i++, loadTrackIntoWorkspace(job, "concat", track));
}
// Create the engine
final EncoderEngine encoderEngine = getEncoderEngine();
if (onlyAudio) {
logger.info("Concatenating audio tracks {} into {}", trackFiles, targetTrackId);
} else {
logger.info("Concatenating video tracks {} into {}", trackFiles, targetTrackId);
}
// Get the encoding profile
EncodingProfile profile = getProfile(job, profileId);
// Creating video filter command for concat
final String concatCommand = buildConcatCommand(onlyAudio, outputDimension, outputFrameRate, trackFiles, tracks);
Map<String, String> properties = new HashMap<>();
properties.put(EncoderEngine.CMD_SUFFIX + ".concatCommand", concatCommand);
File output;
try {
output = encoderEngine.encode(trackFiles.get(0), profile, properties);
} catch (EncoderException e) {
Map<String, String> params = new HashMap<>();
List<String> trackList = new ArrayList<>();
for (Track t : tracks) {
trackList.add(t.getURI().toString());
}
params.put("tracks", StringUtils.join(trackList, ","));
params.put("profile", profile.getIdentifier());
params.put("properties", properties.toString());
incident().recordFailure(job, CONCAT_FAILED, e, params, detailsFor(e, encoderEngine));
throw e;
} finally {
activeEncoder.remove(encoderEngine);
}
// concat did not return a file
if (!output.exists() || output.length() == 0)
return none();
// Put the file in the workspace
URI workspaceURI = putToCollection(job, output, "concatenated file");
// Have the concat track inspected and return the result
Job inspectionJob = inspect(job, workspaceURI);
Track inspectedTrack = (Track) MediaPackageElementParser.getFromXml(inspectionJob.getPayload());
inspectedTrack.setIdentifier(targetTrackId);
if (profile.getMimeType() != null)
inspectedTrack.setMimeType(MimeTypes.parseMimeType(profile.getMimeType()));
return some(inspectedTrack);
}
use of org.opencastproject.composer.api.EncodingProfile in project opencast by opencast.
the class EncodingProfileScanner method install.
/**
* {@inheritDoc}
*
* @see org.apache.felix.fileinstall.ArtifactInstaller#install(java.io.File)
*/
@Override
public void install(File artifact) throws Exception {
logger.info("Registering encoding profiles from {}", artifact);
try {
Map<String, EncodingProfile> profileMap = loadFromProperties(artifact);
for (Map.Entry<String, EncodingProfile> entry : profileMap.entrySet()) {
logger.info("Installed profile {}", entry.getValue().getIdentifier());
profiles.put(entry.getKey(), entry.getValue());
}
sumInstalledFiles++;
} catch (Exception e) {
logger.error("Encoding profiles could not be read from {}: {}", artifact, e.getMessage());
}
// Determine the number of available profiles
String[] filesInDirectory = artifact.getParentFile().list(new FilenameFilter() {
public boolean accept(File arg0, String name) {
return name.endsWith(".properties");
}
});
// Once all profiles have been loaded, announce readiness
if (filesInDirectory.length == sumInstalledFiles) {
Dictionary<String, String> properties = new Hashtable<String, String>();
properties.put(ARTIFACT, "encodingprofile");
logger.debug("Indicating readiness of encoding profiles");
bundleCtx.registerService(ReadinessIndicator.class.getName(), new ReadinessIndicator(), properties);
logger.info("All {} encoding profiles installed", filesInDirectory.length);
} else {
logger.debug("{} of {} encoding profiles installed", sumInstalledFiles, filesInDirectory.length);
}
}
Aggregations