Skip to content

Commit 41172b8

Browse files
Version API (#137)
* Require version to be passed into init(), check version is satisfied, and provide methods to test or require version based on that passed into init(). * Add @Gst.Since annotation for use on classes, methods or fields that require a GStreamer version higher than baseline (1.8). Shows up in Javadoc and runtime introspectable. * Add testing for new Gst.init() with version request failures.
1 parent bcf3568 commit 41172b8

File tree

3 files changed

+187
-29
lines changed

3 files changed

+187
-29
lines changed

src/org/freedesktop/gstreamer/Gst.java

Lines changed: 140 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
2+
* Copyright (c) 2019 Neil C Smith
23
* Copyright (c) 2018 Antonio Morales
3-
* Copyright (c) 2018 Neil C Smith
44
* Copyright (c) 2007 Wayne Meissner
55
*
66
* This file is part of gstreamer-java.
@@ -60,6 +60,9 @@
6060
import com.sun.jna.Pointer;
6161
import com.sun.jna.ptr.IntByReference;
6262
import com.sun.jna.ptr.PointerByReference;
63+
import java.lang.annotation.Documented;
64+
import java.lang.annotation.Retention;
65+
import java.lang.annotation.RetentionPolicy;
6366
import java.util.Arrays;
6467
import java.util.logging.Level;
6568
import static org.freedesktop.gstreamer.lowlevel.GstParseAPI.GSTPARSE_API;
@@ -70,14 +73,19 @@
7073
*/
7174
@SuppressWarnings("deprecation")
7275
public final class Gst {
73-
private static Logger logger = Logger.getLogger(Gst.class.getName());
76+
77+
private final static Logger LOG = Logger.getLogger(Gst.class.getName());
78+
private final static AtomicInteger INIT_COUNT = new AtomicInteger(0);
79+
private final static boolean CHECK_VERSIONS = !Boolean.getBoolean("gstreamer.suppressVersionChecks");
80+
7481

7582
private static ScheduledExecutorService executorService;
7683
private static volatile CountDownLatch quit = new CountDownLatch(1);
7784
private static GMainContext mainContext;
7885
private static boolean useDefaultContext = false;
79-
private static final AtomicInteger initCount = new AtomicInteger(0);
80-
private static List<Runnable> shutdownTasks = Collections.synchronizedList(new ArrayList<Runnable>());
86+
private static List<Runnable> shutdownTasks = Collections.synchronizedList(new ArrayList<Runnable>());
87+
// set minorVersion to a value guaranteed to be >= anything else unless set in init()
88+
private static int minorVersion = Integer.MAX_VALUE;
8189

8290
public static class NativeArgs {
8391
public IntByReference argcRef;
@@ -135,7 +143,7 @@ private Gst() {
135143
public static Version getVersion() {
136144
long[] major = { 0 }, minor = { 0 }, micro = { 0 }, nano = { 0 };
137145
GST_API.gst_version(major, minor, micro, nano);
138-
return new Version(major[0], minor[0], micro[0], nano[0]);
146+
return new Version((int) major[0], (int) minor[0], (int) micro[0], (int) nano[0]);
139147
}
140148

141149
/**
@@ -167,7 +175,7 @@ public static void setSegTrap(boolean enabled) {
167175
* @return true if the GStreamer library already initialized.
168176
*/
169177
public static synchronized final boolean isInitialized() {
170-
return initCount.get() > 0;
178+
return INIT_COUNT.get() > 0;
171179
}
172180

173181
/**
@@ -234,7 +242,7 @@ public static Element parseLaunch(String pipelineDescription, List<GError> error
234242
if (errors != null) {
235243
errors.add(new GError(new GErrorStruct(err[0])));
236244
} else {
237-
logger.log(Level.WARNING, new GError(new GErrorStruct(err[0])).getMessage());
245+
LOG.log(Level.WARNING, new GError(new GErrorStruct(err[0])).getMessage());
238246
}
239247
}
240248

@@ -283,7 +291,7 @@ public static Element parseLaunch(String[] pipelineDescription, List<GError> err
283291
if (errors != null) {
284292
errors.add(new GError(new GErrorStruct(err[0])));
285293
} else {
286-
logger.log(Level.WARNING, new GError(new GErrorStruct(err[0])).getMessage());
294+
LOG.log(Level.WARNING, new GError(new GErrorStruct(err[0])).getMessage());
287295
}
288296
}
289297

@@ -330,7 +338,7 @@ public static Bin parseBinFromDescription(String binDescription, boolean ghostUn
330338
if (errors != null) {
331339
errors.add(new GError(new GErrorStruct(err[0])));
332340
} else {
333-
logger.log(Level.WARNING, new GError(new GErrorStruct(err[0])).getMessage());
341+
LOG.log(Level.WARNING, new GError(new GErrorStruct(err[0])).getMessage());
334342
}
335343
}
336344

@@ -411,8 +419,46 @@ public static GMainContext getMainContext() {
411419
*
412420
* @throws org.freedesktop.gstreamer.GstException
413421
*/
422+
@Deprecated
414423
public static final void init() throws GstException {
415-
init("unknown", new String[] {});
424+
init(new Version(1, 8), "gst1-java-core");
425+
}
426+
427+
/**
428+
* Initializes the GStreamer library.
429+
* <p> This is a shortcut if no arguments are to be passed to gstreamer.
430+
*
431+
* @param requiredVersion
432+
* @throws org.freedesktop.gstreamer.GstException
433+
*/
434+
public static final void init(Version requiredVersion) throws GstException {
435+
init(requiredVersion, "gst1-java-core");
436+
}
437+
438+
439+
/**
440+
* Initializes the GStreamer library.
441+
* <p> This sets up internal path lists, registers built-in elements, and
442+
* loads standard plugins.
443+
*
444+
* <p>
445+
* This method should be called before calling any other GLib functions. If
446+
* this is not an option, your program must initialise the GLib thread system
447+
* using g_thread_init() before any other GLib functions are called.
448+
*
449+
* <p>
450+
* <b>Note:</b><p>
451+
* This method will throw a GstException if it fails.
452+
*
453+
* @param progname the java program name.
454+
* @param args the java argument list.
455+
* @return the list of arguments with any gstreamer specific options stripped
456+
* out.
457+
* @throws org.freedesktop.gstreamer.GstException
458+
*/
459+
@Deprecated
460+
public static synchronized final String[] init(String progname, String ... args) throws GstException {
461+
return init(new Version(1, 8), progname, args);
416462
}
417463

418464
/**
@@ -429,29 +475,58 @@ public static final void init() throws GstException {
429475
* <b>Note:</b><p>
430476
* This method will throw a GstException if it fails.
431477
*
478+
* @param requestedVersion the minimum requested GStreamer version.
432479
* @param progname the java program name.
433480
* @param args the java argument list.
434481
* @return the list of arguments with any gstreamer specific options stripped
435482
* out.
436483
* @throws org.freedesktop.gstreamer.GstException
437484
*/
438-
public static synchronized final String[] init(String progname, String[] args) throws GstException {
485+
public static synchronized final String[] init(Version requestedVersion,
486+
String progname, String ... args) throws GstException {
487+
488+
if (CHECK_VERSIONS) {
489+
Version availableVersion = getVersion();
490+
if (requestedVersion.getMajor() != 1 || availableVersion.getMajor() != 1) {
491+
throw new GstException("gst1-java-core only supports GStreamer 1.x");
492+
}
493+
if (requestedVersion.getMinor() < 8) {
494+
requestedVersion = new Version(1, 8);
495+
}
496+
if (!availableVersion.checkSatisfies(requestedVersion)) {
497+
throw new GstException(String.format(
498+
"The requested version of GStreamer is not available\nRequested : %s\nAvailable : %s\n",
499+
requestedVersion, availableVersion));
500+
}
501+
}
502+
439503
//
440504
// Only do real init the first time through
441505
//
442-
if (initCount.getAndIncrement() > 0) {
506+
if (INIT_COUNT.getAndIncrement() > 0) {
507+
if (CHECK_VERSIONS) {
508+
if (requestedVersion.getMinor() > minorVersion) {
509+
minorVersion = (int) requestedVersion.getMinor();
510+
}
511+
}
443512
return args;
444513
}
514+
445515
NativeArgs argv = new NativeArgs(progname, args);
446516

447517
Pointer[] error = { null };
448518
if (!GST_API.gst_init_check(argv.argcRef, argv.argvRef, error)) {
449-
initCount.decrementAndGet();
519+
INIT_COUNT.decrementAndGet();
450520
throw new GstException(new GError(new GErrorStruct(error[0])));
451521
}
452522

453-
logger.fine("after gst_init, argc=" + argv.argcRef.getValue());
454-
523+
LOG.fine("after gst_init, argc=" + argv.argcRef.getValue());
524+
525+
Version runningVersion = getVersion();
526+
if (runningVersion.getMajor() != 1) {
527+
LOG.warning("gst1-java-core only supports GStreamer 1.x");
528+
}
529+
455530
if (useDefaultContext) {
456531
mainContext = GMainContext.getDefaultContext();
457532
executorService = new MainContextExecutorService(mainContext);
@@ -461,6 +536,11 @@ public static synchronized final String[] init(String progname, String[] args) t
461536
}
462537
quit = new CountDownLatch(1);
463538
loadAllClasses();
539+
540+
if (CHECK_VERSIONS) {
541+
minorVersion = requestedVersion.getMinor();
542+
}
543+
464544
return argv.toStringArray();
465545
}
466546

@@ -473,7 +553,7 @@ public static synchronized final void deinit() {
473553
//
474554
// Only perform real shutdown if called as many times as Gst.init() is
475555
//
476-
if (initCount.decrementAndGet() > 0) {
556+
if (INIT_COUNT.decrementAndGet() > 0) {
477557
return;
478558
}
479559
// Perform any cleanup tasks
@@ -527,6 +607,36 @@ public static void setUseDefaultContext(boolean useDefault) {
527607
useDefaultContext = useDefault;
528608
}
529609

610+
/**
611+
* Checks that the version of GStreamer requested in init() satisfies the
612+
* given version or throws an exception.
613+
*
614+
* @param major major version, only 1 is supported
615+
* @param minor minor version required
616+
* @throws GstException if the requested version support was not requested
617+
*/
618+
public static void checkVersion(int major, int minor) {
619+
if (CHECK_VERSIONS && (major != 1 || minor > minorVersion)) {
620+
throw new GstException("Not supported by requested GStreamer version");
621+
}
622+
}
623+
624+
/**
625+
* Tests that the version of GStreamer requested in init() satisfies the
626+
* given version.
627+
*
628+
* @param major major version, only 1 is supported
629+
* @param minor minor version required
630+
* @return boolean whether the version requirement can be satisfied
631+
*/
632+
public static boolean testVersion(int major, int minor) {
633+
if (CHECK_VERSIONS && (major != 1 || minor > minorVersion)) {
634+
return false;
635+
}
636+
return true;
637+
}
638+
639+
530640
// Make the gstreamer executor threads daemon, so they don't stop the main
531641
// program from exiting
532642
private static final ThreadFactory threadFactory = new ThreadFactory() {
@@ -640,4 +750,18 @@ private static synchronized void loadAllClasses() {
640750
URIDecodeBin.class,
641751
WebRTCBin.class
642752
);
753+
754+
/**
755+
* Annotation on classes, methods or fields to show the required GStreamer
756+
* version. This should particularly be used where the version required is higher
757+
* than the current baseline supported version (GStreamer 1.8)
758+
*/
759+
@Retention(RetentionPolicy.RUNTIME)
760+
@Documented
761+
public static @interface Since {
762+
public int major() default 1;
763+
public int minor();
764+
}
765+
766+
643767
}

src/org/freedesktop/gstreamer/Version.java

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
2-
* Copyright (c) 2007, 2008 Wayne Meissner
2+
* Copyright (c) 2019 Neil C Smith
3+
* Copyright (c) 2008 Wayne Meissner
34
*
45
* This file is part of gstreamer-java.
56
*
@@ -19,10 +20,17 @@
1920
package org.freedesktop.gstreamer;
2021

2122
/**
22-
* Describes the version of gstreamer currently in use.
23+
* Describes a GStreamer version.
2324
*/
2425
public class Version {
25-
public Version(long major, long minor, long micro, long nano) {
26+
27+
private final int major, minor, micro, nano;
28+
29+
public Version(int major, int minor) {
30+
this(major, minor, 0, 0);
31+
}
32+
33+
public Version(int major, int minor, int micro, int nano) {
2634
this.major = major;
2735
this.minor = minor;
2836
this.micro = micro;
@@ -42,35 +50,46 @@ public String toString() {
4250
}
4351

4452
/**
45-
* Gets the major version of GStreamer at compile time.
53+
* Gets the major version of GStreamer.
4654
* @return the major version.
4755
*/
48-
public long getMajor() {
56+
public int getMajor() {
4957
return major;
5058
}
5159

5260
/**
53-
* Gets the minor version of GStreamer at compile time.
61+
* Gets the minor version of GStreamer.
5462
* @return the minor version.
5563
*/
56-
public long getMinor() {
64+
public int getMinor() {
5765
return minor;
5866
}
5967

6068
/**
61-
* Gets the micro version of GStreamer at compile time.
69+
* Gets the micro version of GStreamer.
6270
* @return the micro version.
6371
*/
64-
public long getMicro() {
72+
public int getMicro() {
6573
return micro;
6674
}
6775

6876
/**
69-
* Gets the nano version of GStreamer at compile time.
77+
* Gets the nano version of GStreamer.
7078
* @return the nano version.
7179
*/
72-
public long getNano() {
80+
public int getNano() {
7381
return nano;
7482
}
75-
private final long major, minor, micro, nano;
83+
84+
/**
85+
* Check whether this version is equal to or greater than the passed in
86+
* version. Roughly comparable to GST_CHECK_VERSION
87+
* @param required version to check against
88+
* @return true if this version satisfies the required version
89+
*/
90+
public boolean checkSatisfies(Version required) {
91+
return (major == required.major && minor > required.minor) ||
92+
(major == required.major && minor == required.minor && micro >= required.micro);
93+
}
94+
7695
}

test/org/freedesktop/gstreamer/InitTest.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/*
2+
* Copyright (c) 2019 Neil C Smith
23
* Copyright (c) 2007 Wayne Meissner
34
*
45
* This file is part of gstreamer-java.
@@ -37,8 +38,22 @@ public InitTest() {
3738
}
3839
@Test
3940
public void testInit() {
40-
String[] args = Gst.init("InitTest", new String[] { "--gst-plugin-spew" });
41+
Version available = Gst.getVersion();
42+
Version notAvailable = new Version(available.getMajor(), available.getMinor() + 2);
43+
try {
44+
Gst.init(notAvailable);
45+
assertTrue("Version check exception not thrown!", false);
46+
} catch (GstException ex) {
47+
System.out.println("Expected init failure");
48+
System.out.println(ex);
49+
}
50+
String[] args = Gst.init(available, "InitTest", "--gst-plugin-spew");
4151
assertTrue(args.length == 0);
52+
53+
assertTrue(Gst.testVersion(available.getMajor(), available.getMinor()));
54+
assertTrue(Gst.testVersion(available.getMajor(), available.getMinor() - 2));
55+
assertTrue(!Gst.testVersion(notAvailable.getMajor(), notAvailable.getMinor()));
56+
4257
Gst.deinit();
4358
}
4459
@BeforeClass

0 commit comments

Comments
 (0)