aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Göthel <[email protected]>2024-02-05 20:56:16 +0100
committerSven Göthel <[email protected]>2024-02-05 20:56:16 +0100
commit9bf746d7c8d1e4a3b0c363b54fe9e7a96578228a (patch)
tree4742028d0a7b85038f4e4c504b31314383780b86
parenteff91a9e29fc97d7e5051d9900e79ba9d044fb3a (diff)
Bug 1492: GLMediaPlayer: Add playStream(..) variant passing desired audio- and subtitle language
-rw-r--r--make/scripts/tests.sh1
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/ui/UIMediaGrid01.java12
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java32
-rw-r--r--src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java2
-rw-r--r--src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java77
-rw-r--r--src/jogl/classes/jogamp/opengl/util/av/NullGLMediaPlayer.java2
-rw-r--r--src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java6
-rw-r--r--src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGNatives.java11
-rw-r--r--src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv0400Natives.java2
-rw-r--r--src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv0500Natives.java2
-rw-r--r--src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv0600Natives.java2
-rw-r--r--src/jogl/classes/jogamp/opengl/util/av/impl/OMXGLMediaPlayer.java2
-rw-r--r--src/jogl/native/libav/ffmpeg_impl_template.c133
13 files changed, 190 insertions, 94 deletions
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh
index 4c7a18d77..092aa2b74 100644
--- a/make/scripts/tests.sh
+++ b/make/scripts/tests.sh
@@ -378,7 +378,6 @@ function jrun() {
#D_ARGS="-Djogamp.debug.NativeLibrary -Djogamp.debug.NativeLibrary.Lookup -Djogamp.debug.JNILibLoader -Djogamp.debug.AudioSink -Djogl.debug.GLMediaPlayer"
#D_ARGS="-Djogamp.debug.NativeLibrary -Djogamp.debug.AudioSink"
#D_ARGS="-Djogamp.debug.NativeLibrary -Djogamp.debug.AudioSink -Djoal.openal.lib=system"
- #D_ARGS="-Djogl.debug.GLMediaPlayer"
#D_ARGS="-Djogl.debug.GLMediaPlayer -Djogl.debug.GLSLCode"
#D_ARGS="-Djogl.debug.GLMediaPlayer.StreamWorker.delay=25 -Djogl.debug.GLMediaPlayer"
#D_ARGS="-Djogl.debug.GLMediaPlayer -Djogl.debug.GLMediaPlayer.AVSync -Djogl.debug.GLMediaPlayer.Native -Djogamp.debug.AudioSink"
diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/UIMediaGrid01.java b/src/demos/com/jogamp/opengl/demos/graph/ui/UIMediaGrid01.java
index dd841f3f9..f9949e70c 100644
--- a/src/demos/com/jogamp/opengl/demos/graph/ui/UIMediaGrid01.java
+++ b/src/demos/com/jogamp/opengl/demos/graph/ui/UIMediaGrid01.java
@@ -93,6 +93,8 @@ public class UIMediaGrid01 {
private static final List<String> MEDIA_SUFFIXES = Arrays.asList("mp4", "mkv", "m2v", "avi");
private static int aid = GLMediaPlayer.STREAM_ID_AUTO;
private static int sid = GLMediaPlayer.STREAM_ID_NONE;
+ private static String alang = null;
+ private static String slang = null;
private static int start_pos = 0;
private static float videoAspectRatio = 16f/9f;
private static boolean letterBox = true;
@@ -121,6 +123,12 @@ public class UIMediaGrid01 {
} else if(args[idx[0]].equals("-sid")) {
idx[0]++;
sid = MiscUtils.atoi(args[idx[0]], sid);
+ } else if(args[idx[0]].equals("-alang")) {
+ idx[0]++;
+ alang = args[idx[0]];
+ } else if(args[idx[0]].equals("-slang")) {
+ idx[0]++;
+ slang = args[idx[0]];
} else if(args[idx[0]].equals("-start")) {
idx[0]++;
start_pos = MiscUtils.atoi(args[idx[0]], start_pos);
@@ -150,7 +158,7 @@ public class UIMediaGrid01 {
System.err.println(options);
System.err.println("mediaDir "+mediaDir);
System.err.println("maxMediaFiles "+maxMediaFiles);
- System.err.println("aid "+aid);
+ System.err.println("aid "+aid+", alang "+alang+"; sid "+sid+", slang "+slang);
System.err.println("texCount "+texCount);
System.err.println("boxRatio "+videoAspectRatio);
System.err.println("letterBox "+letterBox);
@@ -400,7 +408,7 @@ public class UIMediaGrid01 {
}
final MediaPlayer graphMPlayer = new MediaPlayer(options.renderModes, scene, glMPlayer, medium, defRatio, letterBox, zoomSize, customCtrls);
grid.addShape( graphMPlayer );
- glMPlayer.playStream(medium, GLMediaPlayer.STREAM_ID_AUTO, aid, sid, texCount);
+ glMPlayer.playStream(medium, GLMediaPlayer.STREAM_ID_AUTO, alang, aid, slang, sid, texCount);
if( start_pos > 0 ) {
glMPlayer.seek(start_pos * 1000);
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java b/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java
index 6eab3fd6f..dba61eda9 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java
@@ -52,6 +52,7 @@ import com.jogamp.opengl.util.texture.TextureSequence;
* </p>
* <p>
* Audio and video streams can be selected or muted via {@link #playStream(Uri, int, int, int, int)}
+ * or {@link #playStream(Uri, int, String, int, String, int, int)}
* using the appropriate <a href="#streamIDs">stream id</a>'s.
* </p>
* <p>
@@ -558,11 +559,33 @@ public interface GLMediaPlayer extends TextureSequence {
* Value is ignored if video is muted.
* @throws IllegalStateException if not invoked in {@link State#Uninitialized}
* @throws IllegalArgumentException if arguments are invalid
+ * @see #playStream(Uri, int, String, int, String, int, int)
* @since 2.6.0
*/
public void playStream(Uri streamLoc, int vid, int aid, int sid, int textureCount) throws IllegalStateException, IllegalArgumentException;
/**
+ * Same as {@link #playStream(Uri, int, int, int, int)}, but providing desired audio- and subtile languages to be selected.
+ * @param streamLoc the stream location
+ * @param vid video stream id, see <a href="#streamIDs">audio and video Stream IDs</a>
+ * @param alang desired audio language, pass {@code null} to use {@code aid}
+ * @param aid fallback audio stream id in case {@code alang} is {@code null}, see <a href="#streamIDs">audio and video Stream IDs</a>
+ * @param slang desired subtitle language, pass {@code null} to use {@code sid}
+ * @param sid fallback subtitle stream id in case {@code alang} is {@code null}, see <a href="#streamIDs">audio and video Stream IDs</a>
+ * @param textureCount desired number of buffered textures to be decoded off-thread, will be validated by implementation.
+ * The minimum value is {@link #TEXTURE_COUNT_MIN} (single-threaded) or above to enable multi-threaded stream decoding.
+ * Default is {@link #TEXTURE_COUNT_DEFAULT}.
+ * Value is ignored if video is muted.
+ * @throws IllegalStateException if not invoked in {@link State#Uninitialized}
+ * @throws IllegalArgumentException if arguments are invalid
+ * @see #playStream(Uri, int, int, int, int)
+ * @since 2.6.0
+ */
+ public void playStream(final Uri streamLoc, final int vid,
+ final String alang, final int aid, final String slang, final int sid,
+ final int reqTextureCount) throws IllegalStateException, IllegalArgumentException;
+
+ /**
* Switches current {@link #playStream(Uri, int, int, int, int)} to given stream IDs and continues at same {@link #getVideoPTS()}.
* <p>
* Implementation just issues {@link #stop()}, {@link #seek(int)} and {@link #playStream(Uri, int, int, int, int)}.
@@ -710,6 +733,7 @@ public interface GLMediaPlayer extends TextureSequence {
* <p>
* The language code is supposed to be 3-letters of `ISO 639-2 language codes`.
* </p>
+ * @see #getLang(int)
*/
public String[] getVLangs();
@@ -731,6 +755,7 @@ public interface GLMediaPlayer extends TextureSequence {
* <p>
* The language code is supposed to be 3-letters of `ISO 639-2 language codes`.
* </p>
+ * @see #getLang(int)
*/
public String[] getALangs();
@@ -752,6 +777,7 @@ public interface GLMediaPlayer extends TextureSequence {
* <p>
* The language code is supposed to be 3-letters of `ISO 639-2 language codes`.
* </p>
+ * @see #getLang(int)
*/
public String[] getSLangs();
@@ -776,6 +802,12 @@ public interface GLMediaPlayer extends TextureSequence {
* <p>
* If the stream ID is not available, {@code und} is returned
* </p>
+ * @see #getVStreams()
+ * @see #getAStreams()
+ * @see #getSStreams()
+ * @see #getVLangs()
+ * @see #getALangs()
+ * @see #getSLangs()
*/
public String getLang(int id);
diff --git a/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java b/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java
index 0924bb67e..f046bcee2 100644
--- a/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java
+++ b/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java
@@ -281,7 +281,7 @@ public class AndroidGLMediaPlayerAPI14 extends GLMediaPlayerImpl {
}
@Override
- protected final void initStreamImpl(final int vid, final int aid, final int sid) throws IOException {
+ protected final void initStreamImpl(final int vid, String alang, final int aid, String slang, final int sid) throws IOException {
if( null == getUri() ) {
return;
}
diff --git a/src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java b/src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java
index 8d45edb87..776a54406 100644
--- a/src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java
+++ b/src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java
@@ -141,57 +141,57 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
private volatile float playSpeed = 1.0f;
private float audioVolume = 1.0f;
- /** Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private String title = "undef";
- /** Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private int[] v_streams = new int[0];
- /** Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private String[] v_langs = new String[0];
- /** Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private int vid = GLMediaPlayer.STREAM_ID_NONE;
- /** Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private int[] a_streams = new int[0];
- /** Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private String[] a_langs = new String[0];
- /** Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private int aid = GLMediaPlayer.STREAM_ID_NONE;
- /** Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private int[] s_streams = new int[0];
- /** Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private String[] s_langs = new String[0];
- /** Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private int sid = GLMediaPlayer.STREAM_ID_NONE;
- /** Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private int width = 0;
- /** Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private int height = 0;
- /** Video avg. fps. Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** Video avg. fps. Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private float fps = 0;
- /** Video avg. frame duration in ms. Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** Video avg. frame duration in ms. Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private float frame_duration = 0f;
- /** Stream bps. Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** Stream bps. Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private int bps_stream = 0;
- /** Video bps. Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** Video bps. Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private int bps_video = 0;
- /** Audio bps. Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** Audio bps. Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private int bps_audio = 0;
- /** In frames. Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** In frames. Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private int videoFrames = 0;
- /** In frames. Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** In frames. Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private int audioFrames = 0;
- /** In ms. Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** In ms. Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private int duration = 0;
- /** Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private CodecID acodecID = CodecID.NONE;
- /** Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private CodecID vcodecID = CodecID.NONE;
- /** Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private CodecID scodecID = CodecID.NONE;
- /** Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private String acodec = unknown;
- /** Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private String vcodec = unknown;
- /** Shall be set by the {@link #initStreamImpl(int, int, int)} method implementation. */
+ /** Shall be set by the {@link #initStreamImpl(int, String, int, String, int)} method implementation. */
private String scodec = unknown;
private volatile int decodedFrameCount = 0;
@@ -210,7 +210,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
private static final int MAX_FRAMELESS_MS_UNTIL_EOS = 5000;
private static final int MAX_FRAMELESS_UNTIL_EOS_DEFAULT = MAX_FRAMELESS_MS_UNTIL_EOS / 30; // default value assuming 30fps
- /** See {@link #getAudioSink()}. Set by implementation if used from within {@link #initStreamImpl(int, int, int)}! */
+ /** See {@link #getAudioSink()}. Set by implementation if used from within {@link #initStreamImpl(int, String, int, String, int)}! */
protected AudioSink audioSink = null;
protected boolean audioSinkPlaySpeedSet = false;
@@ -705,7 +705,13 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
}
@Override
- public final void playStream(final Uri streamLoc, final int vid, final int aid, final int sid, final int reqTextureCount) throws IllegalStateException, IllegalArgumentException {
+ public void playStream(final Uri streamLoc, final int vid, final int aid, final int sid, final int textureCount) throws IllegalStateException, IllegalArgumentException {
+ playStream(streamLoc, vid, null, aid, null, sid, textureCount);
+ }
+ @Override
+ public void playStream(final Uri streamLoc, final int vid,
+ final String alang, final int aid, final String slang, final int sid, final int reqTextureCount) throws IllegalStateException, IllegalArgumentException
+ {
synchronized( stateLock ) {
if(State.Uninitialized != state) {
throw new IllegalStateException("Instance not in state unintialized: "+this);
@@ -753,7 +759,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
public void run() {
try {
// StreamWorker may be used, see API-doc of StreamWorker
- initStreamImpl(vid, aid, sid);
+ initStreamImpl(vid, alang, aid, slang, sid);
} catch (final Throwable t) {
streamErr = new StreamException(t.getClass().getSimpleName()+" while initializing: "+GLMediaPlayerImpl.this.toString(), t);
changeState(new GLMediaPlayer.EventMask(GLMediaPlayer.EventMask.Bit.Error), GLMediaPlayer.State.Uninitialized);
@@ -764,6 +770,11 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
}
/**
* Implementation shall set the following set of data here
+ * @param vid video stream id, see <a href="#streamIDs">audio and video Stream IDs</a>
+ * @param alang desired audio language, pass {@code null} to use {@code aid}
+ * @param aid fallback audio stream id in case {@code alang} is {@code null}, see <a href="#streamIDs">audio and video Stream IDs</a>
+ * @param slang desired subtitle language, pass {@code null} to use {@code sid}
+ * @param sid fallback subtitle stream id in case {@code alang} is {@code null}, see <a href="#streamIDs">audio and video Stream IDs</a>
* @see #vid
* @see #aid
* @see #sid
@@ -776,7 +787,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
* @see #acodec
* @see #vcodec
*/
- protected abstract void initStreamImpl(int vid, int aid, int sid) throws Exception;
+ protected abstract void initStreamImpl(int vid, String alang, int aid, String slang, int sid) throws Exception;
@Override
public void switchStream(final int vid, final int aid, final int sid) throws IllegalStateException, IllegalArgumentException {
@@ -1487,7 +1498,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
* </p>
* <p>
* Implementations using an {@link AudioSink} shall write it's instance to {@link #audioSink}
- * from within their {@link #initStreamImpl(int, int, int)} implementation.
+ * from within their {@link #initStreamImpl(int, String, int, String, int)} implementation.
* </p>
*/
@Override
@@ -1550,7 +1561,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
}
/**
- * After {@link GLMediaPlayerImpl#initStreamImpl(int, int, int) initStreamImpl(..)} is completed via
+ * After {@link GLMediaPlayerImpl#initStreamImpl(int, String, int, String, int) initStreamImpl(..)} is completed via
* {@link GLMediaPlayerImpl#updateAttributes(int, int, int, int, int, int, int, int, int, float, int, int, int, String, String) updateAttributes(..)},
* the latter decides whether StreamWorker is being used.
*/
@@ -1873,7 +1884,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
}
/**
- * Called initially by {@link #initStreamImpl(int, int, int)}, which
+ * Called initially by {@link #initStreamImpl(int, String, int, String, int)}, which
* is called off-thread by {@link #playStream(Uri, int, int, int, int)}.
* <p>
* The latter catches an occurring exception and set the state delivers the error events.
diff --git a/src/jogl/classes/jogamp/opengl/util/av/NullGLMediaPlayer.java b/src/jogl/classes/jogamp/opengl/util/av/NullGLMediaPlayer.java
index b8394dace..d0aa8aa0c 100644
--- a/src/jogl/classes/jogamp/opengl/util/av/NullGLMediaPlayer.java
+++ b/src/jogl/classes/jogamp/opengl/util/av/NullGLMediaPlayer.java
@@ -145,7 +145,7 @@ public class NullGLMediaPlayer extends GLMediaPlayerImpl {
}
@Override
- protected final void initStreamImpl(final int vid, final int aid, final int sid) throws IOException {
+ protected final void initStreamImpl(final int vid, String alang, final int aid, String slang, final int sid) throws IOException {
texData = createTestTextureData();
final float _fps = 24f;
final int _duration = 10*60*1000; // msec
diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java
index 974bdc10b..f3af4d08b 100644
--- a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java
+++ b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java
@@ -352,7 +352,7 @@ public class FFMPEGMediaPlayer extends GLMediaPlayerImpl {
public static final String dev_video_linux = "/dev/video";
@Override
- protected final void initStreamImpl(final int vid, final int aid, final int sid) throws IOException {
+ protected final void initStreamImpl(final int vid, final String alang, final int aid, final String slang, final int sid) throws IOException {
synchronized( moviePtrLock ) {
if(0==moviePtr) {
throw new GLException("FFMPEG native instance null");
@@ -377,7 +377,7 @@ public class FFMPEGMediaPlayer extends GLMediaPlayerImpl {
}
final AudioFormat preferredAudioFormat = audioSink.getPreferredFormat();
if(DEBUG) {
- System.err.println("initStream: p2 aid "+aid+", preferred "+preferredAudioFormat+" on "+audioSink+", "+this);
+ System.err.println("initStream: p2 aid "+aid+"/"+alang+", preferred "+preferredAudioFormat+" on "+audioSink+", "+this);
}
final boolean isCameraInput = null != cameraPath;
@@ -422,7 +422,7 @@ public class FFMPEGMediaPlayer extends GLMediaPlayerImpl {
System.err.println("initStream: p3 stream "+getUri()+" -> "+streamLocS+" -> "+resStreamLocS);
System.err.println("initStream: p3 vid "+vid+", sizes "+sizes+", reqVideo "+rw+"x"+rh+"@"+rr+", aid "+aid+", aMaxChannelCount "+aMaxChannelCount+", aPrefSampleRate "+aPrefSampleRate);
}
- natives.setStream0(moviePtr, resStreamLocS, isCameraInput, vid, sizes, rw, rh, rr, aid, aMaxChannelCount, aPrefSampleRate, sid);
+ natives.setStream0(moviePtr, resStreamLocS, isCameraInput, vid, sizes, rw, rh, rr, alang, aid, aMaxChannelCount, aPrefSampleRate, slang, sid);
}
}
diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGNatives.java b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGNatives.java
index 2fe78cbc6..08e77bc6e 100644
--- a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGNatives.java
+++ b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGNatives.java
@@ -54,20 +54,21 @@ import jogamp.opengl.util.av.GLMediaPlayerImpl;
*
* @param moviePtr
* @param url
- * @param vid
+ * @param vid video stream id
* @param sizes requested video size as string, i.e. 'hd720'. May be null to favor vWidth and vHeight.
* @param vWidth requested video width (for camera mode)
* @param vHeight requested video width (for camera mode)
* @param vRate requested video framerate (for camera mode)
- * @param aid
+ * @param alang desired audio language, pass {@code null} to use {@code aid}
+ * @param aid fallback audio stream id in case {@code alang} is {@code null}
* @param aPrefSampleRate
+ * @param slang desired subtitle language, pass {@code null} to use {@code sid}
+ * @param sid fallback subtitle stream id in case {@code alang} is {@code null}
* @param aPrefChannelCount
- * @param sid subtitle id
*/
abstract void setStream0(long moviePtr, String url, boolean isCameraInput,
int vid, String sizes, int vWidth, int vHeight, int vRate,
- int aid, int aMaxChannelCount, int aPrefSampleRate,
- int sid);
+ String alang, int aid, int aMaxChannelCount, int aPrefSampleRate, String slang, int sid);
abstract void setGLFuncs0(long moviePtr, long procAddrGLTexImage2D, long procAddrGLTexSubImage2D, long procAddrGLGetError, long procAddrGLFlush,
long procAddrGLFinish, long procAddrGLEnable, long procAddrGLBindTexture, boolean hasNPOT);
diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv0400Natives.java b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv0400Natives.java
index a7e6de270..31b2cb65c 100644
--- a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv0400Natives.java
+++ b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv0400Natives.java
@@ -56,7 +56,7 @@ class FFMPEGv0400Natives extends FFMPEGNatives {
native void destroyInstance0(long moviePtr);
@Override
- native void setStream0(long moviePtr, String url, boolean isCameraInput, int vid, String sizes, int vWidth, int vHeight, int vRate, int aid, int aMaxChannelCount, int aPrefSampleRate, int sid);
+ native void setStream0(long moviePtr, String url, boolean isCameraInput, int vid, String sizes, int vWidth, int vHeight, int vRate, String alang, int aid, int aMaxChannelCount, int aPrefSampleRate, String slang, int sid);
@Override
native void setGLFuncs0(long moviePtr, long procAddrGLTexImage2D, long procAddrGLTexSubImage2D, long procAddrGLGetError, long procAddrGLFlush, long procAddrGLFinish, long procAddrGLEnable, long procAddrGLBindTexture, boolean hasNPOT);
diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv0500Natives.java b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv0500Natives.java
index 7268b0627..b811ccc57 100644
--- a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv0500Natives.java
+++ b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv0500Natives.java
@@ -56,7 +56,7 @@ class FFMPEGv0500Natives extends FFMPEGNatives {
native void destroyInstance0(long moviePtr);
@Override
- native void setStream0(long moviePtr, String url, boolean isCameraInput, int vid, String sizes, int vWidth, int vHeight, int vRate, int aid, int aMaxChannelCount, int aPrefSampleRate, int sid);
+ native void setStream0(long moviePtr, String url, boolean isCameraInput, int vid, String sizes, int vWidth, int vHeight, int vRate, String alang, int aid, int aMaxChannelCount, int aPrefSampleRate, String slang, int sid);
@Override
native void setGLFuncs0(long moviePtr, long procAddrGLTexImage2D, long procAddrGLTexSubImage2D, long procAddrGLGetError, long procAddrGLFlush, long procAddrGLFinish, long procAddrGLEnable, long procAddrGLBindTexture, boolean hasNPOT);
diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv0600Natives.java b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv0600Natives.java
index a87c98dbc..d7451e559 100644
--- a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv0600Natives.java
+++ b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGv0600Natives.java
@@ -56,7 +56,7 @@ class FFMPEGv0600Natives extends FFMPEGNatives {
native void destroyInstance0(long moviePtr);
@Override
- native void setStream0(long moviePtr, String url, boolean isCameraInput, int vid, String sizes, int vWidth, int vHeight, int vRate, int aid, int aMaxChannelCount, int aPrefSampleRate, int sid);
+ native void setStream0(long moviePtr, String url, boolean isCameraInput, int vid, String sizes, int vWidth, int vHeight, int vRate, String alang, int aid, int aMaxChannelCount, int aPrefSampleRate, String slang, int sid);
@Override
native void setGLFuncs0(long moviePtr, long procAddrGLTexImage2D, long procAddrGLTexSubImage2D, long procAddrGLGetError, long procAddrGLFlush, long procAddrGLFinish, long procAddrGLEnable, long procAddrGLBindTexture, boolean hasNPOT);
diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/OMXGLMediaPlayer.java b/src/jogl/classes/jogamp/opengl/util/av/impl/OMXGLMediaPlayer.java
index f9786a5ab..01aedd1ef 100644
--- a/src/jogl/classes/jogamp/opengl/util/av/impl/OMXGLMediaPlayer.java
+++ b/src/jogl/classes/jogamp/opengl/util/av/impl/OMXGLMediaPlayer.java
@@ -106,7 +106,7 @@ public class OMXGLMediaPlayer extends EGLMediaPlayerImpl {
}
@Override
- protected void initStreamImpl(final int vid, final int aid, final int sid) throws IOException {
+ protected void initStreamImpl(final int vid, String alang, final int aid, String slang, final int sid) throws IOException {
if(0==moviePtr) {
throw new GLException("OMX native instance null");
}
diff --git a/src/jogl/native/libav/ffmpeg_impl_template.c b/src/jogl/native/libav/ffmpeg_impl_template.c
index d807682b6..570a331ec 100644
--- a/src/jogl/native/libav/ffmpeg_impl_template.c
+++ b/src/jogl/native/libav/ffmpeg_impl_template.c
@@ -934,8 +934,8 @@ static int createOpenedAVCodecContext(JNIEnv* env, FFMPEGToolBasicAV_t *pAV, int
JNIEXPORT void JNICALL FF_FUNC(setStream0)
(JNIEnv *env, jobject instance, jlong ptr, jstring jURL, jboolean jIsCameraInput,
jint vid, jstring jSizeS, jint vWidth, jint vHeight, jint vRate,
- jint aid, jint aMaxChannelCount, jint aPrefSampleRate,
- jint sid)
+ jstring jALang, jint aid, jint aMaxChannelCount, jint aPrefSampleRate,
+ jstring jSLang, jint sid)
{
char cameraName[256];
int res, i;
@@ -1065,10 +1065,6 @@ JNIEXPORT void JNICALL FF_FUNC(setStream0)
pAV->bps_stream = pAV->pFormatCtx->bit_rate;
}
- if(pAV->verbose) {
- fprintf(stderr, "Streams: %d, req vid %d aid %d\n", pAV->pFormatCtx->nb_streams, vid, aid);
- }
-
// Find the first audio and video stream, or the one matching vid
// FIXME: Libav Binary compatibility! JAU01
pAV->a_stream_count=0;
@@ -1079,53 +1075,102 @@ JNIEXPORT void JNICALL FF_FUNC(setStream0)
pAV->v_streams[i]=AV_STREAM_ID_NONE;
pAV->s_streams[i]=AV_STREAM_ID_NONE;
}
- for(i=0; i<pAV->pFormatCtx->nb_streams; i++) {
- AVStream *st = pAV->pFormatCtx->streams[i];
+ {
+ const char *alang = NULL != jALang ? (*env)->GetStringUTFChars(env, jALang, &iscopy) : NULL;
+ const char *slang = NULL != jSLang ? (*env)->GetStringUTFChars(env, jSLang, &iscopy) : NULL;
+ const int hasALang = NULL != alang;
+ const int hasSLang = NULL != slang;
if(pAV->verbose) {
+ fprintf(stderr, "Streams: %d, req vid %d, aid %d (%s), sid %d (%s)\n",
+ pAV->pFormatCtx->nb_streams, vid, aid, hasALang?alang:"null", sid, hasSLang?slang:"null");
+ }
+ int32_t s_aid1 = AV_STREAM_ID_AUTO;
+ int32_t s_aidL = AV_STREAM_ID_AUTO;
+ AVStream* pAStream1 = NULL;
+ AVStream* pAStreamL = NULL;
+ int32_t s_sid1 = AV_STREAM_ID_AUTO;
+ int32_t s_sidL = AV_STREAM_ID_AUTO;
+ AVStream* pSStream1 = NULL;
+ AVStream* pSStreamL = NULL;
+
+ for(i=0; i<pAV->pFormatCtx->nb_streams; i++) {
+ AVStream *st = pAV->pFormatCtx->streams[i];
const char* lang0 = meta_get_language(st->metadata);
const char* lang1 = NULL != lang0 ? lang0 : "n/a";
- fprintf(stderr, "Stream: %d: is-video %d, is-audio %d, is-sub %d, lang %s\n", i,
- AVMEDIA_TYPE_VIDEO == st->codecpar->codec_type, AVMEDIA_TYPE_AUDIO == st->codecpar->codec_type,
- AVMEDIA_TYPE_SUBTITLE == st->codecpar->codec_type, lang1);
- }
- if(AVMEDIA_TYPE_VIDEO == st->codecpar->codec_type) {
- if( pAV->v_stream_count < MAX_STREAM_COUNT-1 ) {
- pAV->v_streams[pAV->v_stream_count++] = i;
- }
- if(AV_STREAM_ID_AUTO==pAV->vid && (AV_STREAM_ID_AUTO==vid || vid == i) ) {
- pAV->pVStream = st;
- pAV->vid=i;
- }
- } else if(AVMEDIA_TYPE_AUDIO == st->codecpar->codec_type) {
- if( pAV->a_stream_count < MAX_STREAM_COUNT-1 ) {
- pAV->a_streams[pAV->a_stream_count++] = i;
+ if(pAV->verbose) {
+ fprintf(stderr, "Stream: %d: is-video %d, is-audio %d, is-sub %d, lang %s\n", i,
+ AVMEDIA_TYPE_VIDEO == st->codecpar->codec_type, AVMEDIA_TYPE_AUDIO == st->codecpar->codec_type,
+ AVMEDIA_TYPE_SUBTITLE == st->codecpar->codec_type, lang1);
}
- if(AV_STREAM_ID_AUTO==pAV->aid && (AV_STREAM_ID_AUTO==aid || aid == i) ) {
- pAV->pAStream = st;
- pAV->aid=i;
+ if(AVMEDIA_TYPE_VIDEO == st->codecpar->codec_type) {
+ if( pAV->v_stream_count < MAX_STREAM_COUNT-1 ) {
+ pAV->v_streams[pAV->v_stream_count++] = i;
+ if( AV_STREAM_ID_AUTO==pAV->vid && ( AV_STREAM_ID_AUTO==vid || vid == i ) ) {
+ pAV->pVStream = st;
+ pAV->vid=i;
+ }
+ }
+ } else if(AVMEDIA_TYPE_AUDIO == st->codecpar->codec_type) {
+ if( pAV->a_stream_count < MAX_STREAM_COUNT-1 ) {
+ pAV->a_streams[pAV->a_stream_count++] = i;
+ if( AV_STREAM_ID_AUTO==s_aidL && AV_STREAM_ID_AUTO==aid && NULL != lang0 && hasALang && 0==strcmp(alang, lang0) ) {
+ pAStreamL = st;
+ s_aidL = i;
+ }
+ if( AV_STREAM_ID_AUTO==s_aid1 && ( AV_STREAM_ID_AUTO==aid || aid == i ) ) {
+ pAStream1 = st;
+ s_aid1 = i;
+ }
+ }
+ } else if(AVMEDIA_TYPE_SUBTITLE == st->codecpar->codec_type) {
+ if( pAV->s_stream_count < MAX_STREAM_COUNT-1 ) {
+ pAV->s_streams[pAV->s_stream_count++] = i;
+ if( AV_STREAM_ID_AUTO==s_sidL && AV_STREAM_ID_AUTO==sid && NULL != lang0 && hasSLang && 0==strcmp(slang, lang0) ) {
+ pSStreamL = st;
+ s_sidL = i;
+ }
+ if( AV_STREAM_ID_AUTO==s_sid1 && ( AV_STREAM_ID_AUTO==sid || sid == i ) ) {
+ pSStream1 = st;
+ s_sid1 = i;
+ }
+ }
}
- } else if(AVMEDIA_TYPE_SUBTITLE == st->codecpar->codec_type) {
- if( pAV->s_stream_count < MAX_STREAM_COUNT-1 ) {
- pAV->s_streams[pAV->s_stream_count++] = i;
+ }
+ if( AV_STREAM_ID_AUTO == pAV->vid ) {
+ pAV->vid = AV_STREAM_ID_NONE;
+ }
+ if( AV_STREAM_ID_AUTO == pAV->aid ) {
+ if( AV_STREAM_ID_AUTO != s_aidL ) {
+ pAV->pAStream = pAStreamL;
+ pAV->aid = s_aidL;
+ } else if( AV_STREAM_ID_AUTO != s_aid1 ) {
+ pAV->pAStream = pAStream1;
+ pAV->aid = s_aid1;
+ } else {
+ pAV->aid = AV_STREAM_ID_NONE;
}
- if(AV_STREAM_ID_AUTO==pAV->sid && (AV_STREAM_ID_AUTO==sid || sid == i) ) {
- pAV->pSStream = st;
- pAV->sid=i;
+ }
+ if( AV_STREAM_ID_AUTO == pAV->sid ) {
+ if( AV_STREAM_ID_AUTO != s_sidL ) {
+ pAV->pSStream = pSStreamL;
+ pAV->sid = s_sidL;
+ } else if( AV_STREAM_ID_AUTO != s_sid1 ) {
+ pAV->pSStream = pSStream1;
+ pAV->sid = s_sid1;
+ } else {
+ pAV->sid = AV_STREAM_ID_NONE;
}
}
- }
- if( AV_STREAM_ID_AUTO == pAV->aid ) {
- pAV->aid = AV_STREAM_ID_NONE;
- }
- if( AV_STREAM_ID_AUTO == pAV->vid ) {
- pAV->vid = AV_STREAM_ID_NONE;
- }
- if( AV_STREAM_ID_AUTO == pAV->sid ) {
- pAV->sid = AV_STREAM_ID_NONE;
- }
- if( pAV->verbose ) {
- fprintf(stderr, "Found vid %d, aid %d, sid %d\n", pAV->vid, pAV->aid, pAV->sid);
+ if( pAV->verbose ) {
+ fprintf(stderr, "Found vid %d, aid %d, sid %d\n", pAV->vid, pAV->aid, pAV->sid);
+ }
+ if( hasALang ) {
+ (*env)->ReleaseStringUTFChars(env, jALang, (const char *)alang);
+ }
+ if( hasSLang ) {
+ (*env)->ReleaseStringUTFChars(env, jSLang, (const char *)slang);
+ }
}
if(0<=pAV->aid) {