use of org.opencastproject.inspection.api.MediaInspectionException in project opencast by opencast.
the class MediaInspector method enrichElement.
/**
* Enriches the media package element metadata such as the mime type, the file size etc. The method mutates the
* argument element.
*
* @param element
* the media package element
* @param override
* <code>true</code> to overwrite existing metadata
* @return the enriched element
* @throws MediaInspectionException
* if enriching fails
*/
private MediaPackageElement enrichElement(final MediaPackageElement element, final boolean override, final Map<String, String> options) throws MediaInspectionException {
try {
File file;
try {
file = workspace.get(element.getURI());
} catch (NotFoundException e) {
throw new MediaInspectionException("Unable to find " + element.getURI() + " in the workspace", e);
} catch (IOException e) {
throw new MediaInspectionException("Error accessing " + element.getURI() + " in the workspace", e);
}
// Checksum
if (element.getChecksum() == null || override) {
try {
element.setChecksum(Checksum.create(ChecksumType.DEFAULT_TYPE, file));
} catch (IOException e) {
throw new MediaInspectionException("Error generating checksum for " + element.getURI(), e);
}
}
// Mimetype
if (element.getMimeType() == null || override) {
try {
element.setMimeType(MimeTypes.fromURI(file.toURI()));
} catch (UnknownFileTypeException e) {
logger.info("unable to determine the mime type for {}", file.getName());
}
}
logger.info("Successfully inspected element {}", element);
return element;
} catch (Exception e) {
logger.warn("Error enriching element " + element, e);
if (e instanceof MediaInspectionException) {
throw (MediaInspectionException) e;
} else {
throw new MediaInspectionException(e);
}
}
}
use of org.opencastproject.inspection.api.MediaInspectionException in project opencast by opencast.
the class MediaInspector method enrichTrack.
/**
* Enriches the track's metadata and can be executed in an asynchronous way.
*
* @param originalTrack
* the original track
* @param override
* <code>true</code> to override existing metadata
* @return the media package element
* @throws MediaInspectionException
*/
private MediaPackageElement enrichTrack(final Track originalTrack, final boolean override, final Map<String, String> options) throws MediaInspectionException {
try {
URI originalTrackUrl = originalTrack.getURI();
MediaPackageElementFlavor flavor = originalTrack.getFlavor();
logger.debug("enrich(" + originalTrackUrl + ") called");
// Get the file from the URL
File file = null;
try {
file = workspace.get(originalTrackUrl);
} catch (NotFoundException e) {
throw new MediaInspectionException("File " + originalTrackUrl + " was not found and can therefore not be " + "inspected", e);
} catch (IOException e) {
throw new MediaInspectionException("Error accessing " + originalTrackUrl, e);
}
// TODO: Try to guess the extension from the container's metadata
if ("".equals(FilenameUtils.getExtension(file.getName()))) {
throw new MediaInspectionException("Can not inspect files without a filename extension");
}
MediaContainerMetadata metadata = getFileMetadata(file, getAccurateFrameCount(options));
if (metadata == null) {
throw new MediaInspectionException("Unable to acquire media metadata for " + originalTrackUrl);
} else {
TrackImpl track = null;
try {
track = (TrackImpl) MediaPackageElementBuilderFactory.newInstance().newElementBuilder().elementFromURI(originalTrackUrl, MediaPackageElement.Type.Track, flavor);
} catch (UnsupportedElementException e) {
throw new MediaInspectionException("Unable to create track element from " + file, e);
}
// init the new track with old
track.setChecksum(originalTrack.getChecksum());
track.setDuration(originalTrack.getDuration());
track.setElementDescription(originalTrack.getElementDescription());
track.setFlavor(flavor);
track.setIdentifier(originalTrack.getIdentifier());
track.setMimeType(originalTrack.getMimeType());
track.setReference(originalTrack.getReference());
track.setSize(file.length());
track.setURI(originalTrackUrl);
for (String tag : originalTrack.getTags()) {
track.addTag(tag);
}
// enrich the new track with basic info
if (track.getDuration() == null || override)
track.setDuration(metadata.getDuration());
if (track.getChecksum() == null || override) {
try {
track.setChecksum(Checksum.create(ChecksumType.DEFAULT_TYPE, file));
} catch (IOException e) {
throw new MediaInspectionException("Unable to read " + file, e);
}
}
// Add the mime type if it's not already present
if (track.getMimeType() == null || override) {
try {
MimeType mimeType = MimeTypes.fromURI(track.getURI());
// The mimetype library doesn't know about audio/video metadata, so the type might be wrong.
if ("audio".equals(mimeType.getType()) && metadata.hasVideoStreamMetadata()) {
mimeType = MimeTypes.parseMimeType("video/" + mimeType.getSubtype());
} else if ("video".equals(mimeType.getType()) && !metadata.hasVideoStreamMetadata()) {
mimeType = MimeTypes.parseMimeType("audio/" + mimeType.getSubtype());
}
track.setMimeType(mimeType);
} catch (UnknownFileTypeException e) {
logger.info("Unable to detect the mimetype for track {} at {}", track.getIdentifier(), track.getURI());
}
}
// find all streams
Dictionary<String, Stream> streamsId2Stream = new Hashtable<String, Stream>();
for (Stream stream : originalTrack.getStreams()) {
streamsId2Stream.put(stream.getIdentifier(), stream);
}
// audio list
try {
addAudioStreamMetadata(track, metadata);
} catch (Exception e) {
throw new MediaInspectionException("Unable to extract audio metadata from " + file, e);
}
// video list
try {
addVideoStreamMetadata(track, metadata);
} catch (Exception e) {
throw new MediaInspectionException("Unable to extract video metadata from " + file, e);
}
logger.info("Successfully inspected track {}", track);
return track;
}
} catch (Exception e) {
logger.warn("Error enriching track " + originalTrack, e);
if (e instanceof MediaInspectionException) {
throw (MediaInspectionException) e;
} else {
throw new MediaInspectionException(e);
}
}
}
use of org.opencastproject.inspection.api.MediaInspectionException in project opencast by opencast.
the class MediaInspector method getFileMetadata.
/**
* Asks the media analyzer to extract the file's metadata.
*
* @param file
* the file
* @return the file container metadata
* @throws MediaInspectionException
* if metadata extraction fails
*/
private MediaContainerMetadata getFileMetadata(File file, boolean accurateFrameCount) throws MediaInspectionException {
if (file == null)
throw new IllegalArgumentException("file to analyze cannot be null");
try {
MediaAnalyzer analyzer = new FFmpegAnalyzer(accurateFrameCount);
analyzer.setConfig(map(Tuple.<String, Object>tuple(FFmpegAnalyzer.FFPROBE_BINARY_CONFIG, ffprobePath)));
return analyzer.analyze(file);
} catch (MediaAnalyzerException e) {
throw new MediaInspectionException(e);
}
}
use of org.opencastproject.inspection.api.MediaInspectionException in project opencast by opencast.
the class InspectWorkflowOperationHandler method start.
/**
* {@inheritDoc}
*
* @see org.opencastproject.workflow.api.WorkflowOperationHandler#start(org.opencastproject.workflow.api.WorkflowInstance,
* JobContext)
*/
@Override
public WorkflowOperationResult start(WorkflowInstance workflowInstance, JobContext context) throws WorkflowOperationException {
MediaPackage mediaPackage = (MediaPackage) workflowInstance.getMediaPackage().clone();
// Inspect the tracks
long totalTimeInQueue = 0;
WorkflowOperationInstance operation = workflowInstance.getCurrentOperation();
boolean rewrite = "true".equalsIgnoreCase(operation.getConfiguration(OPT_OVERWRITE));
boolean acceptNoMedia = "true".equalsIgnoreCase(operation.getConfiguration(OPT_ACCEPT_NO_MEDIA));
final Map<String, String> options = new HashMap<String, String>();
if ("true".equalsIgnoreCase(operation.getConfiguration(OPT_ACCURATE_FRAME_COUNT))) {
logger.info("Using accurate frame count for inspection media package {}", mediaPackage);
options.put(MediaInspectionOptions.OPTION_ACCURATE_FRAME_COUNT, Boolean.TRUE.toString());
}
// Test if there are tracks in the mediapackage
if (mediaPackage.getTracks().length == 0) {
logger.warn("Recording {} contains no media", mediaPackage);
if (!acceptNoMedia)
throw new WorkflowOperationException("Mediapackage " + mediaPackage + " contains no media");
}
for (Track track : mediaPackage.getTracks()) {
logger.info("Inspecting track '{}' of {}", track.getIdentifier(), mediaPackage);
Job inspectJob = null;
Track inspectedTrack;
if (track != null && track.getURI() != null && (track.getURI().toString().endsWith(".vtt") || track.getURI().toString().endsWith(".srt"))) {
inspectedTrack = (Track) track.clone();
inspectedTrack.setMimeType(MimeType.mimeType("text", "vtt"));
logger.info("Track '{}' of {} contains captions", track.getIdentifier(), mediaPackage);
} else {
try {
inspectJob = inspectionService.enrich(track, rewrite, options);
if (!waitForStatus(inspectJob).isSuccess()) {
throw new WorkflowOperationException("Track " + track + " could not be inspected");
}
} catch (MediaInspectionException e) {
throw new WorkflowOperationException("Error inspecting media package", e);
} catch (MediaPackageException e) {
throw new WorkflowOperationException("Error parsing media package", e);
}
// add this receipt's queue and execution times to the total
long timeInQueue = inspectJob.getQueueTime() == null ? 0 : inspectJob.getQueueTime();
totalTimeInQueue += timeInQueue;
try {
inspectedTrack = (Track) MediaPackageElementParser.getFromXml(inspectJob.getPayload());
} catch (MediaPackageException e) {
throw new WorkflowOperationException("Unable to parse track from job " + inspectJob.getId(), e);
}
if (inspectedTrack == null)
throw new WorkflowOperationException("Track " + track + " could not be inspected");
if (inspectedTrack.getStreams().length == 0)
throw new WorkflowOperationException(format("Track %s does not contain any streams", track));
}
// Replace the original track with the inspected one
try {
mediaPackage.remove(track);
mediaPackage.add(inspectedTrack);
} catch (UnsupportedElementException e) {
logger.error("Error adding {} to media package", inspectedTrack, e);
}
}
// Update dublin core with metadata
try {
updateDublinCore(mediaPackage);
} catch (Exception e) {
logger.warn("Unable to update dublin core data: {}", e.getMessage(), e);
throw new WorkflowOperationException(e.getMessage());
}
return createResult(mediaPackage, Action.CONTINUE, totalTimeInQueue);
}
use of org.opencastproject.inspection.api.MediaInspectionException in project opencast by opencast.
the class VideoEditorTest method setUp.
/**
* Setup for the video editor service, including creation of a mock workspace and all dependencies.
*
* @throws Exception
* if setup fails
*/
@Before
public void setUp() throws Exception {
File tmpDir = folder.newFolder(getClass().getName());
// output file
tempFile1 = new File(tmpDir, "testoutput.mp4");
/* mock the workspace for the input/output file */
// workspace.get(new URI(sourceTrackUri));
Workspace workspace = EasyMock.createMock(Workspace.class);
EasyMock.expect(workspace.rootDirectory()).andReturn(tmpDir.getAbsolutePath());
EasyMock.expect(workspace.get(track1.getURI())).andReturn(new File(track1.getURI())).anyTimes();
EasyMock.expect(workspace.get(track2.getURI())).andReturn(new File(track2.getURI())).anyTimes();
EasyMock.expect(workspace.putInCollection(EasyMock.anyString(), EasyMock.anyString(), EasyMock.anyObject(InputStream.class))).andAnswer(() -> {
InputStream in = (InputStream) EasyMock.getCurrentArguments()[2];
IOUtils.copy(in, new FileOutputStream(tempFile1));
return tempFile1.toURI();
});
/* mock the role/org/security dependencies */
User anonymous = new JaxbUser("anonymous", "test", new DefaultOrganization(), new JaxbRole(DefaultOrganization.DEFAULT_ORGANIZATION_ANONYMOUS, new DefaultOrganization()));
UserDirectoryService userDirectoryService = EasyMock.createMock(UserDirectoryService.class);
EasyMock.expect(userDirectoryService.loadUser((String) EasyMock.anyObject())).andReturn(anonymous).anyTimes();
Organization organization = new DefaultOrganization();
OrganizationDirectoryService organizationDirectoryService = EasyMock.createMock(OrganizationDirectoryService.class);
EasyMock.expect(organizationDirectoryService.getOrganization((String) EasyMock.anyObject())).andReturn(organization).anyTimes();
SecurityService securityService = EasyMock.createNiceMock(SecurityService.class);
EasyMock.expect(securityService.getUser()).andReturn(anonymous).anyTimes();
EasyMock.expect(securityService.getOrganization()).andReturn(organization).anyTimes();
/* mock the osgi init for the video editor itself */
BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
File storageDir = folder.newFolder();
logger.info("storageDir: {}", storageDir);
EasyMock.expect(bc.getProperty("org.opencastproject.storage.dir")).andReturn(storageDir.getPath()).anyTimes();
EasyMock.expect(bc.getProperty("org.opencastproject.composer.ffmpegpath")).andReturn(FFMPEG_BINARY).anyTimes();
EasyMock.expect(bc.getProperty(FFmpegAnalyzer.FFPROBE_BINARY_CONFIG)).andReturn("ffprobe").anyTimes();
ComponentContext cc = EasyMock.createNiceMock(ComponentContext.class);
EasyMock.expect(cc.getBundleContext()).andReturn(bc).anyTimes();
EasyMock.replay(bc, cc, workspace, userDirectoryService, organizationDirectoryService, securityService);
/* mock inspector output so that the job will alway pass */
String sourceTrackXml = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" + "<track xmlns=\"http://mediapackage.opencastproject.org\" type='presentation/source' id='deadbeef-a926-4ba9-96d9-2fafbcc30d2a'>" + "<audio id='audio-1'><encoder type='MP3 (MPEG audio layer 3)'/><channels>2</channels>" + "<bitrate>96000.0</bitrate></audio><video id='video-1'><device/>" + "<encoder type='FLV / Sorenson Spark / Sorenson H.263 (Flash Video)'/>" + "<bitrate>512000.0</bitrate><framerate>15.0</framerate>" + "<resolution>854x480</resolution></video>" + "<mimetype>video/mpeg</mimetype><url>video.mp4</url></track>";
inspectedTrack = (Track) MediaPackageElementParser.getFromXml(sourceTrackXml);
veditor = new VideoEditorServiceImpl() {
@Override
protected Job inspect(Job job, URI workspaceURI) throws MediaInspectionException, ProcessFailedException {
Job inspectionJob = EasyMock.createNiceMock(Job.class);
try {
EasyMock.expect(inspectionJob.getPayload()).andReturn(MediaPackageElementParser.getAsXml(inspectedTrack));
} catch (MediaPackageException e) {
throw new MediaInspectionException(e);
}
EasyMock.replay(inspectionJob);
return inspectionJob;
}
};
/* set up video editor */
veditor.activate(cc);
veditor.setWorkspace(workspace);
veditor.setSecurityService(securityService);
veditor.setUserDirectoryService(userDirectoryService);
veditor.setSmilService(smilService);
veditor.setOrganizationDirectoryService(organizationDirectoryService);
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(() -> {
Job job = new JobImpl(0);
logger.error("type: {}", type.getValue());
job.setJobType(type.getValue());
job.setOperation(operation.getValue());
job.setArguments(args.getValue());
job.setPayload(veditor.process(job));
return job;
}).anyTimes();
EasyMock.replay(serviceRegistry);
veditor.setServiceRegistry(serviceRegistry);
}
Aggregations