mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-11-14 06:18:12 +00:00
initial implementation of autodetecting mp4 properties
This commit is contained in:
1 parent
6d5e3e54f6
commit
31690cfdea
15 files changed
+233
-30
No files matched your search
+28
@@ -0,0 +1,28 @@
|
||||
package com.sap.sailing.domain.common.dto;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class VideoMetadataDTO {
|
||||
|
||||
private boolean canDownload;
|
||||
private Date recordStartedTime;
|
||||
private boolean spherical;
|
||||
|
||||
public VideoMetadataDTO(boolean canDownload, boolean spherical, Date recordStartedTime) {
|
||||
this.canDownload = canDownload;
|
||||
this.spherical = spherical;
|
||||
this.recordStartedTime = recordStartedTime;
|
||||
}
|
||||
|
||||
public boolean isDownloadable() {
|
||||
return canDownload;
|
||||
}
|
||||
|
||||
public boolean isSpherical() {
|
||||
return spherical;
|
||||
}
|
||||
|
||||
public Date getRecordStartedTime() {
|
||||
return recordStartedTime;
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,8 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sse.shared.android,
|
||||
com.sap.sailing.competitorimport,
|
||||
com.sap.sailing.expeditionconnector,
|
||||
com.sap.sailing.expeditionconnector.common
|
||||
com.sap.sailing.expeditionconnector.common,
|
||||
org.mp4parser.isoparser;bundle-version="1.9.31"
|
||||
Bundle-Activator: com.sap.sailing.gwt.ui.server.Activator
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Import-Package: javax.servlet;version="3.1.0",
|
||||
|
||||
+1
-1
@@ -473,7 +473,7 @@ public class MediaPanel extends FlowPanel implements MediaTracksRefresher {
|
||||
}
|
||||
|
||||
private void addUrlMediaTrack() {
|
||||
NewMediaWithRaceSelectionDialog dialog = new NewMediaWithRaceSelectionDialog(getDefaultStartTime(),
|
||||
NewMediaWithRaceSelectionDialog dialog = new NewMediaWithRaceSelectionDialog(mediaService, getDefaultStartTime(),
|
||||
stringMessages, sailingService, errorReporter, regattaRefresher, regattasDisplayers,
|
||||
new DialogCallback<MediaTrack>() {
|
||||
|
||||
|
||||
+9
@@ -1,7 +1,14 @@
|
||||
package com.sap.sailing.gwt.ui.client;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import com.google.gwt.user.client.rpc.RemoteService;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.dto.VideoMetadataDTO;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
|
||||
public interface MediaService extends RemoteService {
|
||||
@@ -26,4 +33,6 @@ public interface MediaService extends RemoteService {
|
||||
|
||||
void updateRace(MediaTrack mediaTrack);
|
||||
|
||||
VideoMetadataDTO checkMetadata(String url) throws IOException, ParserConfigurationException, SAXException;
|
||||
|
||||
}
|
||||
+3
@@ -2,6 +2,7 @@ package com.sap.sailing.gwt.ui.client;
|
||||
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.dto.VideoMetadataDTO;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
|
||||
public interface MediaServiceAsync {
|
||||
@@ -27,5 +28,7 @@ public interface MediaServiceAsync {
|
||||
void updateDuration(MediaTrack mediaTrack, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void updateRace(MediaTrack mediaTrack, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void checkMetadata(String url, AsyncCallback<VideoMetadataDTO> asyncCallback);
|
||||
|
||||
}
|
||||
+1
-1
@@ -616,7 +616,7 @@ public class MediaPlayerManagerComponent extends AbstractComponent<MediaPlayerSe
|
||||
public void addMediaTrack() {
|
||||
TimePoint raceStartTime = getRaceStartTime();
|
||||
TimePoint defaultStartTime = raceStartTime;
|
||||
NewMediaDialog dialog = new NewMediaDialog(defaultStartTime, MediaPlayerManagerComponent.this.stringMessages,
|
||||
NewMediaDialog dialog = new NewMediaDialog(mediaService, defaultStartTime, MediaPlayerManagerComponent.this.stringMessages,
|
||||
this.getCurrentRace(), new DialogCallback<MediaTrack>() {
|
||||
|
||||
@Override
|
||||
|
||||
+65
-25
@@ -12,6 +12,8 @@ import com.google.gwt.event.dom.client.ChangeEvent;
|
||||
import com.google.gwt.event.dom.client.ChangeHandler;
|
||||
import com.google.gwt.media.client.Audio;
|
||||
import com.google.gwt.media.client.MediaBase;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.FocusWidget;
|
||||
import com.google.gwt.user.client.ui.Grid;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
@@ -21,7 +23,9 @@ import com.google.gwt.user.client.ui.TextBox;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.dto.VideoMetadataDTO;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.gwt.ui.client.MediaServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.common.client.YoutubeApi;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
@@ -63,13 +67,16 @@ public class NewMediaDialog extends DataEntryDialog<MediaTrack> {
|
||||
|
||||
final private RegattaAndRaceIdentifier raceIdentifier;
|
||||
|
||||
public NewMediaDialog(TimePoint defaultStartTime, StringMessages stringMessages,
|
||||
private MediaServiceAsync mediaService;
|
||||
|
||||
public NewMediaDialog(MediaServiceAsync mediaService, TimePoint defaultStartTime, StringMessages stringMessages,
|
||||
RegattaAndRaceIdentifier raceIdentifier, DialogCallback<MediaTrack> dialogCallback) {
|
||||
super(stringMessages.addMediaTrack(), "", stringMessages.ok(), stringMessages.cancel(), MEDIA_TRACK_VALIDATOR,
|
||||
dialogCallback);
|
||||
this.defaultStartTime = defaultStartTime != null ? defaultStartTime : MillisecondsTimePoint.now();
|
||||
this.stringMessages = stringMessages;
|
||||
this.raceIdentifier = raceIdentifier;
|
||||
this.mediaService = mediaService;
|
||||
registerNativeMethods();
|
||||
}
|
||||
|
||||
@@ -88,7 +95,7 @@ public class NewMediaDialog extends DataEntryDialog<MediaTrack> {
|
||||
String duration = durationBox.getValue();
|
||||
if (duration != null && !duration.trim().isEmpty()) {
|
||||
mediaTrack.duration = TimeFormatUtil.hrsMinSecToMilliSeconds(duration);
|
||||
} else {
|
||||
} else {
|
||||
mediaTrack.duration = null;
|
||||
}
|
||||
}
|
||||
@@ -106,7 +113,7 @@ public class NewMediaDialog extends DataEntryDialog<MediaTrack> {
|
||||
Date startTime = TimeFormatUtil.DATETIME_FORMAT.parse(startTimeText);
|
||||
mediaTrack.startTime = new MillisecondsTimePoint(startTime);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
//TODO: highlight format error in UI
|
||||
// TODO: highlight format error in UI
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -165,7 +172,7 @@ public class NewMediaDialog extends DataEntryDialog<MediaTrack> {
|
||||
durationBox = createTextBox(null);
|
||||
formGrid.setWidget(4, 1, durationBox);
|
||||
mainPanel.add(formGrid);
|
||||
|
||||
|
||||
return mainPanel;
|
||||
}
|
||||
|
||||
@@ -249,11 +256,12 @@ public class NewMediaDialog extends DataEntryDialog<MediaTrack> {
|
||||
setTimeout(
|
||||
function() {
|
||||
//Remove temporary script element.
|
||||
if (window != null && window.youtubeMetadataCallbackScript != null) {
|
||||
document.body
|
||||
.removeChild(window.youtubeMetadataCallbackScript);
|
||||
|
||||
delete window.youtubeMetadataCallbackScript;
|
||||
if (window != null
|
||||
&& window.youtubeMetadataCallbackScript != null) {
|
||||
document.body
|
||||
.removeChild(window.youtubeMetadataCallbackScript);
|
||||
|
||||
delete window.youtubeMetadataCallbackScript;
|
||||
}
|
||||
that.@com.sap.sailing.gwt.ui.client.media.NewMediaDialog::setUiEnabled(Z)(true);
|
||||
}, 2000);
|
||||
@@ -264,8 +272,7 @@ public class NewMediaDialog extends DataEntryDialog<MediaTrack> {
|
||||
setUiEnabled(true);
|
||||
mediaTrack.title = title;
|
||||
try {
|
||||
long duration = (long) Math.round(1000 * Double
|
||||
.valueOf(durationInSeconds));
|
||||
long duration = (long) Math.round(1000 * Double.valueOf(durationInSeconds));
|
||||
if (duration > 0) {
|
||||
mediaTrack.duration = new MillisecondsDurationImpl(duration);
|
||||
} else {
|
||||
@@ -285,23 +292,13 @@ public class NewMediaDialog extends DataEntryDialog<MediaTrack> {
|
||||
infoLabel.setWidget(new Label(mediaTrack.url));
|
||||
} else {
|
||||
infoLabelLabel.setText(stringMessages.mimeType() + ":");
|
||||
if(mediaTrack.mimeType == MimeType.mp4 || mediaTrack.mimeType == MimeType.mp4panorama){
|
||||
ListBox mimeTypeListBox = createListBox(false);
|
||||
mimeTypeListBox.addItem(MimeType.mp4.name());
|
||||
mimeTypeListBox.addItem(MimeType.mp4panorama.name());
|
||||
infoLabel.setWidget(mimeTypeListBox);
|
||||
mimeTypeListBox.addChangeHandler(new ChangeHandler() {
|
||||
|
||||
@Override
|
||||
public void onChange(ChangeEvent event) {
|
||||
mediaTrack.mimeType = MimeType.valueOf(mimeTypeListBox.getSelectedValue());
|
||||
}
|
||||
});
|
||||
}else{
|
||||
if (mediaTrack.mimeType == MimeType.mp4 || mediaTrack.mimeType == MimeType.mp4panorama) {
|
||||
processMp4(mediaTrack, infoLabel);
|
||||
} else {
|
||||
infoLabel.setWidget(new Label(mediaTrack.typeToString()));
|
||||
}
|
||||
}
|
||||
TimePoint startTime = mediaTrack.startTime != null ? mediaTrack.startTime : defaultStartTime;
|
||||
TimePoint startTime = mediaTrack.startTime != null ? mediaTrack.startTime : defaultStartTime;
|
||||
String startTimeText = TimeFormatUtil.DATETIME_FORMAT.format(startTime.asDate());
|
||||
|
||||
startTimeBox.setText(startTimeText);
|
||||
@@ -313,6 +310,49 @@ public class NewMediaDialog extends DataEntryDialog<MediaTrack> {
|
||||
}
|
||||
}
|
||||
|
||||
private void processMp4(MediaTrack mediaTrack, SimplePanel infoLabel2) {
|
||||
this.setUiEnabled(false);
|
||||
infoLabel.setWidget(new Label("TODO Please wait, analyzing"));
|
||||
if (mediaTrack.startTime == null) {
|
||||
mediaService.checkMetadata(mediaTrack.url, new AsyncCallback<VideoMetadataDTO>() {
|
||||
|
||||
@Override
|
||||
public void onSuccess(VideoMetadataDTO result) {
|
||||
setUiEnabled(true);
|
||||
if (!result.isDownloadable()) {
|
||||
Window.alert("Could not download file " + mediaTrack.url);
|
||||
manualMimeTypeSelection(mediaTrack);
|
||||
} else {
|
||||
mediaTrack.mimeType = result.isSpherical() ? MimeType.mp4panorama : MimeType.mp4;
|
||||
// check for startime here
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
setUiEnabled(true);
|
||||
manualMimeTypeSelection(mediaTrack);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
manualMimeTypeSelection(mediaTrack);
|
||||
}
|
||||
}
|
||||
|
||||
private void manualMimeTypeSelection(MediaTrack mediaTrack) {
|
||||
ListBox mimeTypeListBox = createListBox(false);
|
||||
mimeTypeListBox.addItem(MimeType.mp4.name());
|
||||
mimeTypeListBox.addItem(MimeType.mp4panorama.name());
|
||||
infoLabel.setWidget(mimeTypeListBox);
|
||||
mimeTypeListBox.addChangeHandler(new ChangeHandler() {
|
||||
|
||||
@Override
|
||||
public void onChange(ChangeEvent event) {
|
||||
mediaTrack.mimeType = MimeType.valueOf(mimeTypeListBox.getSelectedValue());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FocusWidget getInitialFocusWidget() {
|
||||
return urlBox;
|
||||
|
||||
+3
-2
@@ -7,6 +7,7 @@ import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.gwt.ui.adminconsole.AssignRacesToMediaDialog;
|
||||
import com.sap.sailing.gwt.ui.client.MediaServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.RegattaRefresher;
|
||||
import com.sap.sailing.gwt.ui.client.RegattasDisplayer;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
@@ -29,11 +30,11 @@ public class NewMediaWithRaceSelectionDialog extends NewMediaDialog {
|
||||
|
||||
private AssignRacesToMediaDialog racesForMediaDialog;
|
||||
|
||||
public NewMediaWithRaceSelectionDialog(TimePoint defaultStartTime, StringMessages stringMessages,
|
||||
public NewMediaWithRaceSelectionDialog(MediaServiceAsync mediaService,TimePoint defaultStartTime, StringMessages stringMessages,
|
||||
SailingServiceAsync sailingService, ErrorReporter errorReporter, RegattaRefresher regattaRefresher,
|
||||
Set<RegattasDisplayer> regattasDisplayers,
|
||||
com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback<MediaTrack> dialogCallback) {
|
||||
super(defaultStartTime, stringMessages, null, dialogCallback);
|
||||
super(mediaService, defaultStartTime, stringMessages, null, dialogCallback);
|
||||
this.sailingService = sailingService;
|
||||
this.errorReporter = errorReporter;
|
||||
this.regattaRefresher = regattaRefresher;
|
||||
|
||||
+58
@@ -1,13 +1,32 @@
|
||||
package com.sap.sailing.gwt.ui.server;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.Channels;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.mp4parser.IsoFile;
|
||||
import org.mp4parser.boxes.UserBox;
|
||||
import org.mp4parser.boxes.iso14496.part12.MovieBox;
|
||||
import org.mp4parser.boxes.iso14496.part12.MovieHeaderBox;
|
||||
import org.mp4parser.tools.Path;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.util.tracker.ServiceTracker;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.dto.VideoMetadataDTO;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.gwt.ui.client.MediaService;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
@@ -88,5 +107,44 @@ public class MediaServiceImpl extends RemoteServiceServlet implements MediaServi
|
||||
racingEventService().mediaTrackAssignedRacesChanged(mediaTrack);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public VideoMetadataDTO checkMetadata(String url)
|
||||
throws IOException, ParserConfigurationException, SAXException {
|
||||
|
||||
URL input = new URL(url);
|
||||
boolean canDownload = false;
|
||||
boolean spherical = false;
|
||||
Date recordStartedTimer = null;
|
||||
try(IsoFile isof = new IsoFile(Channels.newChannel(input.openStream()))){
|
||||
canDownload = true;
|
||||
// MovieHeaderBox movieHeaderBox = Path.getPath(isof, "moov[0]/mvhd");
|
||||
// System.out.println(movieHeaderBox.getCreationTime());
|
||||
UserBox uuidBox = Path.getPath(isof, "moov[0]/trak[0]/uuid");
|
||||
|
||||
MovieBox mbox = isof.getMovieBox();
|
||||
if(mbox != null){
|
||||
MovieHeaderBox mhb = mbox.getMovieHeaderBox();
|
||||
if(mhb != null){
|
||||
recordStartedTimer = mhb.getCreationTime();
|
||||
}
|
||||
}
|
||||
|
||||
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
|
||||
Document doc = dBuilder.parse(new ByteArrayInputStream(uuidBox.getData()));
|
||||
|
||||
NodeList childs = doc.getDocumentElement().getChildNodes();
|
||||
for (int i = 0; i < childs.getLength(); i++) {
|
||||
Node child = childs.item(i);
|
||||
if (child.getNodeName().toLowerCase().contains(":spherical")) {
|
||||
spherical = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return new VideoMetadataDTO(canDownload, spherical, recordStartedTimer);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry exported="true" kind="lib" path="lib/isoparser-1.9.31.jar"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>org.mp4parser.isoparser</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.ManifestBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.SchemaBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.pde.PluginNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,13 @@
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Selenium
|
||||
Bundle-SymbolicName: org.mp4parser.isoparser
|
||||
Bundle-Version: 1.9.31
|
||||
Bundle-ClassPath: lib/isoparser-1.9.31.jar
|
||||
Bundle-Vendor: Sebastian Annies
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Export-Package: org.mp4parser,
|
||||
org.mp4parser.boxes,
|
||||
org.mp4parser.boxes.iso14496.part12,
|
||||
org.mp4parser.tools
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
bin.includes = META-INF/,\
|
||||
lib/isoparser-1.9.31.jar
|
||||
Binary file not shown.
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>root</artifactId>
|
||||
<groupId>com.sap.sailing</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>org.mp4parser.isoparser</artifactId>
|
||||
<version>1.9.31</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
</project>
|
||||
Reference in new issue
Block a user