Skip to content

Commit eaf26f7

Browse files
committed
adds MediaInfo WASM for getting video metadata
new interface for JSUtilI.java: void getMediaInfoAsync(byte[] videoData, String trackType, String path, Consumer<Map<String, Object>> success, Consumer<String> onError) loads mediainfo.js and MediaInfoModule.wasm from https://unpkg.com Note that the two files can more efficiently be included in a project, as has been done with TrackerJS, where very minor tweaks of the JavaScript allow local file reading from core/_ES6/ -- remove unnecessary script source message at end of mediainfojs -- remove n.locateFile call using 0&n.locateFile -- also, wasm can be in data:application/octet-stream;base64, format if pulled from a byte[] resource.
1 parent f3d8985 commit eaf26f7

File tree

10 files changed

+237
-34
lines changed

10 files changed

+237
-34
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
20240522140614
1+
20240613090629
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
20240522140614
1+
20240613090629
4.08 KB
Binary file not shown.

sources/net.sf.j2s.java.core/src/javajs/util/AjaxURLConnection.java

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ public Map<String, List<String>> getHeaderFields() {
139139
*
140140
*/
141141
@SuppressWarnings("null")
142-
private Object doAjax(boolean isBinary, Function<Object, Void> whenDone) {
142+
private Object doAjax(boolean isBinary, boolean isScript, Function<Object, Void> whenDone) {
143143
getBytesOut();
144144
J2SObjectInterface J2S = /** @j2sNative self.J2S || */
145145
null;
@@ -238,7 +238,7 @@ private Object doAjax(boolean isBinary, Function<Object, Void> whenDone) {
238238
}
239239
}
240240
result = J2S.doAjax(myURL, postOut, bytesOut, info);
241-
if (whenDone != null)
241+
if (whenDone != null || isScript)
242242
return null;
243243
setJQueryResponseCodeFromJQuery(result);
244244
return result;
@@ -410,9 +410,6 @@ public InputStream getInputStream() throws IOException {
410410
return is;
411411
responseCode = -1;
412412
is = getInputStreamAndResponse(false);
413-
switch (responseCode) {
414-
415-
}
416413
if (responseCode == HTTP_BAD_REQUEST) {
417414
throw new java.net.UnknownHostException(url.toString());
418415
} else if (responseCode > HTTP_BAD_REQUEST && responseCode != 404) {
@@ -462,7 +459,7 @@ private void getInputStreamAndResponseAsync(Function<InputStream, Void> whenDone
462459
whenDone.apply(is);
463460
return;
464461
}
465-
doAjax(true, new Function<Object, Void>() {
462+
doAjax(true, false, new Function<Object, Void>() {
466463

467464
@Override
468465
public Void apply(Object response) {
@@ -490,7 +487,12 @@ private BufferedInputStream getInputStreamAndResponse(boolean allowNWError) {
490487
if (is != null || doCache() && (is = getCachedStream(allowNWError)) != null) {
491488
return is;
492489
}
493-
is = attachStreamData(url, doAjax(ajax == null, null));
490+
491+
boolean isScript = /** @j2sNative this.ajax && (this.ajax.dataType == "script")||*/false;
492+
Object result = doAjax(ajax == null, isScript, null);
493+
if (isScript)
494+
return Rdr.getBIS(new byte[0]);
495+
is = attachStreamData(url, result);
494496
if (doCache() && is != null) {
495497
isNetworkError(is);
496498
setCachedStream();
@@ -645,8 +647,9 @@ public static BufferedInputStream attachStreamData(URL url, Object o) {
645647
/**
646648
* @return javajs.util.SB or byte[], depending upon the file type
647649
*/
650+
@Deprecated
648651
public Object getContents() {
649-
return doAjax(false, null);
652+
return doAjax(false, false, null);
650653
}
651654

652655
@Override

sources/net.sf.j2s.java.core/src/swingjs/JSImage.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import java.awt.image.MemoryImageSource;
77
import java.io.File;
88
import java.io.IOException;
9+
import java.util.Map;
10+
import java.util.function.Consumer;
911

1012
import javax.swing.ImageIcon;
1113
import javax.swing.JLabel;
@@ -40,6 +42,8 @@
4042
public class JSImage extends BufferedImage {
4143

4244
public String src;
45+
protected Map<String, Object> videoTrackInfo;
46+
public Object 秘source;
4347

4448
/**
4549
* Frome JSImageKit reading pixels from an image file or MemoryImageSource
@@ -51,6 +55,7 @@ public class JSImage extends BufferedImage {
5155
*/
5256
public JSImage(int[] argb, int width, int height, String src, int type) {
5357
super(width, height, type);
58+
@SuppressWarnings("unused")
5459
MemoryImageSource m; // just an Eclipse tag so we can find this reference;
5560
this.src = src;
5661
if (argb != null)
@@ -139,8 +144,9 @@ public void run() {
139144
}
140145
}
141146
};
142-
if (b != null)
147+
if (b != null) {
143148
src = JSImagekit.getDataBlob(b, "video/mp4");
149+
}
144150
// see https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image
145151
/**
146152
* @j2sNative img.crossOrigin = "Anonymous";

sources/net.sf.j2s.java.core/src/swingjs/JSImagekit.java

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package swingjs;
22

33
import java.util.Hashtable;
4+
import java.util.List;
5+
import java.util.Map;
6+
import java.util.function.Consumer;
47

58
import javax.swing.Icon;
69
import javax.swing.ImageIcon;
@@ -22,6 +25,7 @@
2225
import swingjs.api.Interface;
2326
import swingjs.api.js.DOMNode;
2427
import swingjs.api.js.HTML5Canvas;
28+
import swingjs.json.JSON;
2529

2630
/**
2731
* An image consumer for off-line images.
@@ -325,5 +329,91 @@ public static Object getDataBlob(byte[] b, String type) {
325329
return (/** @j2sNative URL.createObjectURL(new Blob([b], {type:type})) || */null);
326330
}
327331

332+
static boolean mediaInfoLoaded = false;
333+
static Object mediaInfoObject = null;
334+
private static String mediaInfoURL = "https://unpkg.com/mediainfo.js@0.3.1/dist/umd/index.min.js";
335+
336+
337+
/**
338+
* Load mediainfo.js and MediaInfoModule.wasm, then use them to generate a JSON array.
339+
*
340+
* @param data
341+
* @param trackType
342+
* @param success
343+
* @param onError
344+
* @param path
345+
*/
346+
public static void getMediaInfoAsync(byte[] data, String trackType, String path, Consumer<Map<String, Object>> success, Consumer<String> onError) {
347+
348+
if (!mediaInfoLoaded) {
349+
// load MediaInfo.js
350+
JSUtil.loadScriptAsync(path == null ? mediaInfoURL : path.startsWith("http") ? path : JSUtil.newJSUtil().getJ2SPath() + path, () -> {
351+
mediaInfoLoaded = true;
352+
getMediaInfoAsync(data, null, trackType, success, onError);
353+
});
354+
return;
355+
}
356+
Consumer<Object> f;
357+
if (mediaInfoObject == null) {
358+
f = new Consumer<Object>() {
359+
360+
@Override
361+
public void accept(Object mediainfo) {
362+
mediaInfoObject = mediainfo;
363+
getMediaInfoAsync(data, null, trackType, success, onError);
364+
}
365+
366+
};
367+
// load MediaInfo.wasm and create MediaInfo object
368+
/**
369+
* @j2sNative
370+
*
371+
* MediaInfo.mediaInfoFactory( { format: 'JSON' },
372+
* function(mediainfo){ f.accept$O(mediainfo) }
373+
* );
374+
*
375+
*/
376+
return;
377+
}
378+
f = new Consumer<Object>() {
379+
380+
@Override
381+
public void accept(Object result) {
382+
try {
383+
Map<String, Object> info = null;
384+
info = (Map<String, Object>) JSON.parse((String) result);
385+
if (trackType != null) {
386+
info = (Map<String, Object>) info.get("media");
387+
List<Object> tracks = (List<Object>) info.get("track");
388+
info = null;
389+
for (int i = tracks.size(); --i >= 0;) {
390+
info = (Map<String, Object>) tracks.get(i);
391+
if (info.get("@type").equals(trackType))
392+
break;
393+
}
394+
}
395+
success.accept(info);
396+
} catch (Exception e) {
397+
e.printStackTrace();
398+
onError.accept(e.getMessage());
399+
}
400+
}
401+
402+
};
403+
/**
404+
* @j2sNative
405+
*
406+
* C$.mediaInfoObject.analyzeData(data.length,
407+
* function(chunkSize, offset){
408+
* return new Uint8Array(data.slice(offset, offset + chunkSize));
409+
* }
410+
* ).then(
411+
* function(result){f.accept$O(result)},
412+
* function(error){onError ? onError.accept$O(error) : console.log(error)}
413+
* );
414+
*/
415+
416+
}
417+
328418

329419
}

sources/net.sf.j2s.java.core/src/swingjs/JSUtil.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,10 @@ public static String prompt(String msg, String defaultRet) {
753753
}
754754
}
755755

756+
/**
757+
* Sets the url's ajax field to point to it.
758+
* @param url
759+
*/
756760
public static void setAjax(URL url) {
757761
JSON.setAjax(url);
758762
}
@@ -1284,8 +1288,28 @@ public String getJ2SPath() {
12841288
return (String) getAppletAttribute("_j2sFullPath");
12851289
}
12861290

1287-
1288-
1291+
public static void loadScriptAsync(String url, Runnable success) {
1292+
URL u;
1293+
try {
1294+
u = new URL(url);
1295+
JSFunction f = /** @j2sNative function(){success.run$()} || */ null;
1296+
setAjax("url", u, "url", url, "dataType", "script", "success", f);
1297+
u.getContent();
1298+
} catch (Exception e) {
1299+
e.printStackTrace();
1300+
}
1301+
}
12891302

1303+
/**
1304+
* Get
1305+
* @param data
1306+
* @param trackType
1307+
* @param success
1308+
* @param onError
1309+
*/
1310+
@Override
1311+
public void getMediaInfoAsync(byte[] data, String trackType, String path, Consumer<Map<String, Object>> success, Consumer<String> onError) {
1312+
JSImagekit.getMediaInfoAsync(data, trackType, path, success, onError);
1313+
}
12901314
}
12911315

sources/net.sf.j2s.java.core/src/swingjs/api/JSUtilI.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,4 +386,16 @@ public interface JSUtilI {
386386
*/
387387
String getJ2SPath();
388388

389+
/**
390+
* Asyncronously fires either success or onError after running mediainfo.analyzeData
391+
*
392+
* This information is always created in JSImagekit for the JSImage.
393+
*
394+
* @param videoData byte array data of video
395+
* @param trackType the &amp;type for the media track to return, or null to return the full MediaInfo result JSON map
396+
* @param success function to handle the returned map, if everything works out
397+
* @param onError function to handle the error message, if an error occurs
398+
*/
399+
void getMediaInfoAsync(byte[] videoData, String trackType, String path, Consumer<Map<String, Object>> success, Consumer<String> onError);
400+
389401
}

sources/net.sf.j2s.java.core/src/swingjs/api/js/HTML5Video.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ public static JDialog createDialog(Frame parent, Object source, int maxWidth, bo
354354
* @j2sNative
355355
*
356356
* jsvideo.dialog = dialog;
357+
* jsvideo.label = label;
357358
*
358359
*/
359360
Object[] j2sListener = HTML5Video.addActionListener(jsvideo, new ActionListener() {

0 commit comments

Comments
 (0)