aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2013-08-26 10:09:33 +0200
committerSven Gothel <[email protected]>2013-08-26 10:09:33 +0200
commit248256fc8eee90f8d11f66d4b5dba8ad296653a1 (patch)
tree7550ea3c019384d56940ad6103c43b827caaba59
parente28a3b39e1e8caf3f6cf3bfe82efdaae818a6c7b (diff)
libav/ffmpeg: version9: Add libavresample support ; Proper AudioFormat negotiation w/ AudioSink; Misc
- Add libavresample support - Resample if avail && (!AV_SAMPLE_FMT_S16 || !prefSampleRate || !sinkSupported) - Resample to: prefSampleRate (if set), AV_SAMPLE_FMT_S16 and min(channelCount, maxChannelCount) - Proper AudioFormat negotiation w/ AudioSink; - Utilize AudioSink's 'isSupported(AudioFormat)' - Misc - use 'av_get_bytes_per_sample(fmt)' always, don't assume 2
-rw-r--r--src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGDynamicLibraryBundleInfo.java77
-rw-r--r--src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java174
-rw-r--r--src/jogl/native/libav/ffmpeg_tool.h26
-rw-r--r--src/jogl/native/libav/jogamp_opengl_util_av_impl_FFMPEGMediaPlayer.c209
4 files changed, 378 insertions, 108 deletions
diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGDynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGDynamicLibraryBundleInfo.java
index b0181bd7d..2f92f9bf3 100644
--- a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGDynamicLibraryBundleInfo.java
+++ b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGDynamicLibraryBundleInfo.java
@@ -59,12 +59,13 @@ class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo {
private static final List<String> glueLibNames = new ArrayList<String>(); // none
- private static final int symbolCount = 43;
+ private static final int symbolCount = 51;
private static final String[] symbolNames = {
"avcodec_version",
"avformat_version",
-/* 3 */ "avutil_version",
-
+ "avutil_version",
+/* 4 */ "avresample_version",
+
// libavcodec
"avcodec_close",
"avcodec_string",
@@ -83,15 +84,17 @@ class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo {
"av_free_packet",
"avcodec_decode_audio4", // 53.25.0 (opt)
"avcodec_decode_audio3", // 52.23.0
-/* 21 */ "avcodec_decode_video2", // 52.23.0
+/* 22 */ "avcodec_decode_video2", // 52.23.0
// libavutil
"av_pix_fmt_descriptors",
"av_frame_unref", // 55.0.0 (opt)
"av_free",
"av_get_bits_per_pixel",
-/* 26 */ "av_samples_get_buffer_size",
-
+ "av_samples_get_buffer_size",
+ "av_get_bytes_per_sample", // 51.4.0
+/* 29 */ "av_opt_set_int", // 51.12.0
+
// libavformat
"avformat_alloc_context",
"avformat_free_context", // 52.96.0 (opt)
@@ -109,7 +112,14 @@ class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo {
"avformat_network_init", // 53.13.0 (opt)
"avformat_network_deinit", // 53.13.0 (opt)
"avformat_find_stream_info", // 53.3.0 (opt)
-/* 43 */ "av_find_stream_info",
+/* 46 */ "av_find_stream_info",
+
+ // libavresample
+ "avresample_alloc_context", // 1.0.1
+ "avresample_open",
+ "avresample_close",
+ "avresample_free",
+/* 51 */ "avresample_convert"
};
// alternate symbol names
@@ -128,23 +138,34 @@ class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo {
"avformat_seek_file", // ??? (opt)
"avcodec_free_frame", // 54.28.0 (opt)
"av_frame_unref", // 55.0.0 (opt)
+
+ // libavresample
+ "avresample_version", // 1.0.1
+ "avresample_alloc_context", // 1.0.1
+ "avresample_open",
+ "avresample_close",
+ "avresample_free",
+ "avresample_convert",
};
private static long[] symbolAddr;
private static final boolean ready;
private static final boolean libsLoaded;
+ private static final boolean avresampleLoaded; // optional
static {
// native ffmpeg media player implementation is included in jogl_desktop and jogl_mobile
GLProfile.initSingleton();
boolean _ready = false;
boolean[] _libsLoaded= { false };
+ boolean[] _avresampleLoaded= { false };
try {
- _ready = initSymbols(_libsLoaded);
+ _ready = initSymbols(_libsLoaded, _avresampleLoaded);
} catch (Throwable t) {
t.printStackTrace();
}
libsLoaded = _libsLoaded[0];
+ avresampleLoaded = _avresampleLoaded[0];
ready = _ready;
if(!libsLoaded) {
System.err.println("LIB_AV Not Available");
@@ -154,9 +175,10 @@ class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo {
}
static boolean libsLoaded() { return libsLoaded; }
+ static boolean avResampleLoaded() { return avresampleLoaded; }
static boolean initSingleton() { return ready; }
- private static final boolean initSymbols(boolean[] libsLoaded) {
+ private static final boolean initSymbols(boolean[] libsLoaded, boolean[] avresampleLoaded) {
libsLoaded[0] = false;
final DynamicLibraryBundle dl = AccessController.doPrivileged(new PrivilegedAction<DynamicLibraryBundle>() {
public DynamicLibraryBundle run() {
@@ -167,10 +189,12 @@ class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo {
final boolean avcodecLoaded = dl.isToolLibLoaded(2);
if(!avutilLoaded || !avformatLoaded || !avcodecLoaded) {
throw new RuntimeException("FFMPEG Tool library incomplete: [ avutil "+avutilLoaded+", avformat "+avformatLoaded+", avcodec "+avcodecLoaded+"]");
- }
+ }
+ avresampleLoaded[0] = dl.isToolLibLoaded(3);
+ /** Ignore .. due to optional libavresample
if(!dl.isToolLibComplete()) {
throw new RuntimeException("FFMPEG Tool libraries incomplete");
- }
+ } */
libsLoaded[0] = true;
if(symbolNames.length != symbolCount) {
throw new InternalError("XXX0 "+symbolNames.length+" != "+symbolCount);
@@ -205,6 +229,7 @@ class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo {
} } );
// validate results
+ boolean res = true;
for(int i = 0; i<symbolCount; i++) {
if( 0 == symbolAddr[i] ) {
// no symbol, check optional and alternative symbols
@@ -226,14 +251,14 @@ class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo {
}
if(!ok) {
System.err.println("Fail: Could not resolve symbol <"+symbolNames[i]+">: not optional, no alternatives.");
- return false;
+ res = false;
}
} else if(DEBUG) {
System.err.println("OK: Unresolved optional symbol <"+symbolNames[i]+">");
}
}
}
- return initSymbols0(symbolAddr, symbolCount);
+ return initSymbols0(symbolAddr, symbolCount) && res;
}
protected FFMPEGDynamicLibraryBundleInfo() {
@@ -265,11 +290,13 @@ class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo {
final List<String> avutil = new ArrayList<String>();
avutil.add("avutil"); // default
- avutil.add("libavutil.so.52"); // dummy future proof
+ avutil.add("libavutil.so.53"); // dummy future proof
+ avutil.add("libavutil.so.52"); // 9
avutil.add("libavutil.so.51"); // 0.8
avutil.add("libavutil.so.50"); // 0.7
- avutil.add("avutil-52"); // dummy future proof
+ avutil.add("avutil-53"); // dummy future proof
+ avutil.add("avutil-52"); // 9
avutil.add("avutil-51"); // 0.8
avutil.add("avutil-50"); // 0.7
libsList.add(avutil);
@@ -278,12 +305,12 @@ class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo {
avformat.add("avformat"); // default
avformat.add("libavformat.so.55"); // dummy future proof
- avformat.add("libavformat.so.54"); // 0.?
+ avformat.add("libavformat.so.54"); // 9
avformat.add("libavformat.so.53"); // 0.8
avformat.add("libavformat.so.52"); // 0.7
avformat.add("avformat-55"); // dummy future proof
- avformat.add("avformat-54"); // 0.?
+ avformat.add("avformat-54"); // 9
avformat.add("avformat-53"); // 0.8
avformat.add("avformat-52"); // 0.7
libsList.add(avformat);
@@ -292,16 +319,26 @@ class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo {
avcodec.add("avcodec"); // default
avcodec.add("libavcodec.so.55"); // dummy future proof
- avcodec.add("libavcodec.so.54"); // 0.?
+ avcodec.add("libavcodec.so.54"); // 9
avcodec.add("libavcodec.so.53"); // 0.8
avcodec.add("libavcodec.so.52"); // 0.7
avcodec.add("avcodec-55"); // dummy future proof
- avcodec.add("avcodec-54"); // 0.?
+ avcodec.add("avcodec-54"); // 9
avcodec.add("avcodec-53"); // 0.8
avcodec.add("avcodec-52"); // 0.7
libsList.add(avcodec);
-
+
+ final List<String> avresample = new ArrayList<String>();
+ avresample.add("avresample"); // default
+
+ avresample.add("libavresample.so.2"); // dummy future proof
+ avresample.add("libavresample.so.1"); // 9
+
+ avresample.add("avresample-2"); // dummy future proof
+ avresample.add("avresample-1"); // 9
+ libsList.add(avresample);
+
return libsList;
}
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 78f5954e5..80b946456 100644
--- a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java
+++ b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java
@@ -44,8 +44,7 @@ import com.jogamp.gluegen.runtime.ProcAddressTable;
import com.jogamp.opengl.util.TimeFrameI;
import com.jogamp.opengl.util.GLPixelStorageModes;
import com.jogamp.opengl.util.av.AudioSink;
-import com.jogamp.opengl.util.av.AudioSink.AudioDataFormat;
-import com.jogamp.opengl.util.av.AudioSink.AudioDataType;
+import com.jogamp.opengl.util.av.AudioSink.AudioFormat;
import com.jogamp.opengl.util.av.AudioSinkFactory;
import com.jogamp.opengl.util.av.GLMediaPlayer;
import com.jogamp.opengl.util.texture.Texture;
@@ -117,9 +116,11 @@ public class FFMPEGMediaPlayer extends GLMediaPlayerImpl {
private static final int avUtilMajorVersionCC;
private static final int avFormatMajorVersionCC;
private static final int avCodecMajorVersionCC;
+ private static final int avResampleMajorVersionCC;
private static final VersionNumber avUtilVersion;
private static final VersionNumber avFormatVersion;
private static final VersionNumber avCodecVersion;
+ private static final VersionNumber avResampleVersion;
private static final boolean available;
static {
@@ -129,15 +130,19 @@ public class FFMPEGMediaPlayer extends GLMediaPlayerImpl {
avUtilMajorVersionCC = getAvUtilMajorVersionCC0();
avFormatMajorVersionCC = getAvFormatMajorVersionCC0();
avCodecMajorVersionCC = getAvCodecMajorVersionCC0();
+ avResampleMajorVersionCC = getAvResampleMajorVersionCC0();
avUtilVersion = getAVVersion(getAvUtilVersion0());
avFormatVersion = getAVVersion(getAvFormatVersion0());
avCodecVersion = getAVVersion(getAvCodecVersion0());
- System.err.println("LIB_AV Util : "+avUtilVersion+" [cc "+avUtilMajorVersionCC+"]");
- System.err.println("LIB_AV Format: "+avFormatVersion+" [cc "+avFormatMajorVersionCC+"]");
- System.err.println("LIB_AV Codec : "+avCodecVersion+" [cc "+avCodecMajorVersionCC+"]");
+ avResampleVersion = getAVVersion(getAvResampleVersion0());
+ System.err.println("LIB_AV Util : "+avUtilVersion+" [cc "+avUtilMajorVersionCC+"]");
+ System.err.println("LIB_AV Format : "+avFormatVersion+" [cc "+avFormatMajorVersionCC+"]");
+ System.err.println("LIB_AV Codec : "+avCodecVersion+" [cc "+avCodecMajorVersionCC+"]");
+ System.err.println("LIB_AV Resample: "+avResampleVersion+" [cc "+avResampleMajorVersionCC+"]");
libAVVersionGood = avUtilMajorVersionCC == avUtilVersion.getMajor() &&
avFormatMajorVersionCC == avFormatVersion.getMajor() &&
- avCodecMajorVersionCC == avCodecVersion.getMajor();
+ avCodecMajorVersionCC == avCodecVersion.getMajor() &&
+ avResampleMajorVersionCC == avResampleVersion.getMajor();
if( !libAVVersionGood ) {
System.err.println("LIB_AV Not Matching Compile-Time / Runtime Major-Version");
}
@@ -145,9 +150,11 @@ public class FFMPEGMediaPlayer extends GLMediaPlayerImpl {
avUtilMajorVersionCC = 0;
avFormatMajorVersionCC = 0;
avCodecMajorVersionCC = 0;
+ avResampleMajorVersionCC = 0;
avUtilVersion = null;
avFormatVersion = null;
avCodecVersion = null;
+ avResampleVersion = null;
libAVVersionGood = false;
}
available = libAVGood && libAVVersionGood ? initIDs0() : false;
@@ -185,9 +192,7 @@ public class FFMPEGMediaPlayer extends GLMediaPlayerImpl {
// Audio
//
- private SampleFormat aSampleFmt = null;
- private AudioSink.AudioDataFormat avChosenAudioFormat;
- private AudioSink.AudioDataFormat sinkChosenAudioFormat;
+ private AudioSink.AudioFormat avChosenAudioFormat;
private int audioSamplesPerFrameAndChannel = 0;
public FFMPEGMediaPlayer() {
@@ -237,7 +242,7 @@ public class FFMPEGMediaPlayer extends GLMediaPlayerImpl {
} else {
audioSink = AudioSinkFactory.createDefault();
}
- final AudioDataFormat preferredAudioFormat = audioSink.getPreferredFormat();
+ final AudioFormat preferredAudioFormat = audioSink.getPreferredFormat();
if(DEBUG) {
System.err.println("initStream: p2 preferred "+preferredAudioFormat+", "+this);
}
@@ -274,7 +279,9 @@ public class FFMPEGMediaPlayer extends GLMediaPlayerImpl {
resStreamLocS = streamLocS;
inFormat = null;
}
- setStream0(moviePtr, resStreamLocS, inFormat, vid, aid, snoopVideoFrameCount, preferredAudioFormat.channelCount, preferredAudioFormat.sampleRate);
+ final int aMaxChannelCount = audioSink.getMaxSupportedChannels();
+ final int aPrefSampleRate = preferredAudioFormat.sampleRate;
+ setStream0(moviePtr, resStreamLocS, inFormat, vid, aid, snoopVideoFrameCount, aMaxChannelCount, aPrefSampleRate);
}
@Override
@@ -308,20 +315,20 @@ public class FFMPEGMediaPlayer extends GLMediaPlayerImpl {
} else {
frameDuration = AudioSink.DefaultFrameDuration;
}
-
- sinkChosenAudioFormat = audioSink.init(avChosenAudioFormat, frameDuration, AudioSink.DefaultInitialQueueSize, AudioSink.DefaultQueueGrowAmount, audioQueueLimit);
if(DEBUG) {
- System.err.println("initGL: p3 avChosen "+avChosenAudioFormat+", chosen "+sinkChosenAudioFormat);
+ System.err.println("initGL: p3 avChosen "+avChosenAudioFormat);
}
- if( null == sinkChosenAudioFormat ) {
+
+ final boolean audioSinkOK = audioSink.init(avChosenAudioFormat, frameDuration, AudioSink.DefaultInitialQueueSize, AudioSink.DefaultQueueGrowAmount, audioQueueLimit);
+ if( !audioSinkOK ) {
System.err.println("AudioSink "+audioSink.getClass().getName()+" does not support "+avChosenAudioFormat+", using Null");
audioSink.destroy();
audioSink = AudioSinkFactory.createNull();
- sinkChosenAudioFormat = audioSink.init(avChosenAudioFormat, 0, AudioSink.DefaultInitialQueueSize, AudioSink.DefaultQueueGrowAmount, audioQueueLimit);
+ audioSink.init(avChosenAudioFormat, 0, AudioSink.DefaultInitialQueueSize, AudioSink.DefaultQueueGrowAmount, audioQueueLimit);
}
if(DEBUG) {
- System.err.println("initGL: p4 chosen "+sinkChosenAudioFormat);
- System.err.println("initGL: "+audioSink);
+ System.err.println("initGL: p4 chosen "+avChosenAudioFormat);
+ System.err.println("initGL: p4 chosen "+audioSink);
}
if( null != gl ) {
@@ -350,6 +357,84 @@ public class FFMPEGMediaPlayer extends GLMediaPlayerImpl {
}
/**
+ * @param sampleRate sample rate in Hz (1/s)
+ * @param sampleSize sample size in bits
+ * @param channelCount number of channels
+ * @param signed true if signed number, false for unsigned
+ * @param fixedP true for fixed point value, false for unsigned floating point value with a sampleSize of 32 (float) or 64 (double)
+ * @param planar true for planar data package (each channel in own data buffer), false for packed data channels interleaved in one buffer.
+ * @param littleEndian true for little-endian, false for big endian
+ * @return
+ */
+
+ /**
+ * Converts the given libav/ffmpeg values to {@link AudioFormat} and returns {@link AudioSink#isSupported(AudioFormat)}.
+ * @param audioSampleFmt ffmpeg/libav audio-sample-format, see {@link SampleFormat}.
+ * @param audioSampleRate sample rate in Hz (1/s)
+ * @param audioChannels number of channels
+ */
+ private final boolean isAudioFormatSupported(int audioSampleFmt, int audioSampleRate, int audioChannels) {
+ final AudioFormat audioFormat = avAudioFormat2Local(SampleFormat.valueOf(audioSampleFmt), audioSampleRate, audioChannels);
+ final boolean res = audioSink.isSupported(audioFormat);
+ if( DEBUG ) {
+ System.err.println("AudioSink.isSupported: "+res+": "+audioFormat);
+ }
+ return res;
+ }
+
+ /**
+ * Returns {@link AudioFormat} as converted from the given libav/ffmpeg values.
+ * @param audioSampleFmt ffmpeg/libav audio-sample-format, see {@link SampleFormat}.
+ * @param audioSampleRate sample rate in Hz (1/s)
+ * @param audioChannels number of channels
+ */
+ private final AudioFormat avAudioFormat2Local(SampleFormat audioSampleFmt, int audioSampleRate, int audioChannels) {
+ final int sampleSize;
+ boolean planar = true;
+ final boolean signed, fixedP;
+ switch( audioSampleFmt ) {
+ case S32:
+ planar = false;
+ case S32P:
+ sampleSize = 32;
+ signed = true;
+ fixedP = true;
+ break;
+ case S16:
+ planar = false;
+ case S16P:
+ sampleSize = 16;
+ signed = true;
+ fixedP = true;
+ break;
+ case U8:
+ planar = false;
+ case U8P:
+ sampleSize = 8;
+ signed = false;
+ fixedP = true;
+ break;
+ case DBL:
+ planar = false;
+ case DBLP:
+ sampleSize = 64;
+ signed = true;
+ fixedP = true;
+ break;
+ case FLT:
+ planar = false;
+ case FLTP:
+ sampleSize = 32;
+ signed = true;
+ fixedP = true;
+ break;
+ default: // FIXME: Add more formats !
+ throw new IllegalArgumentException("Unsupported sampleformat: "+audioSampleFmt);
+ }
+ return new AudioFormat(audioSampleRate, sampleSize, audioChannels, signed, fixedP, planar, true /* littleEndian */);
+ }
+
+ /**
* @param pixFmt
* @param planes
* @param bitsPerPixel
@@ -400,44 +485,9 @@ public class FFMPEGMediaPlayer extends GLMediaPlayerImpl {
default: // FIXME: Add more formats !
throw new RuntimeException("Unsupported pixelformat: "+vPixelFmt);
}
- aSampleFmt = SampleFormat.valueOf(audioSampleFmt);
- final int sampleSize;
- final boolean signed, fixedP;
- switch( aSampleFmt ) {
- case S32:
- case S32P:
- sampleSize = 32;
- signed = true;
- fixedP = true;
- break;
- case S16:
- case S16P:
- sampleSize = 16;
- signed = true;
- fixedP = true;
- break;
- case U8:
- case U8P:
- sampleSize = 8;
- signed = false;
- fixedP = true;
- break;
- case DBL:
- case DBLP:
- sampleSize = 64;
- signed = true;
- fixedP = true;
- break;
- case FLT:
- case FLTP:
- sampleSize = 32;
- signed = true;
- fixedP = true;
- break;
- default: // FIXME: Add more formats !
- throw new RuntimeException("Unsupported sampleformat: "+aSampleFmt);
- }
- avChosenAudioFormat = new AudioDataFormat(AudioDataType.PCM, audioSampleRate, sampleSize, audioChannels, signed, fixedP, true /* littleEndian */);
+ final SampleFormat aSampleFmt = SampleFormat.valueOf(audioSampleFmt);
+ avChosenAudioFormat = avAudioFormat2Local(aSampleFmt, audioSampleRate, audioChannels);
+
this.audioSamplesPerFrameAndChannel = audioSamplesPerFrameAndChannel;
if(DEBUG) {
@@ -587,6 +637,8 @@ public class FFMPEGMediaPlayer extends GLMediaPlayerImpl {
private static native int getAvFormatMajorVersionCC0();
private static native int getAvCodecVersion0();
private static native int getAvCodecMajorVersionCC0();
+ private static native int getAvResampleVersion0();
+ private static native int getAvResampleMajorVersionCC0();
private static native boolean initIDs0();
private native long createInstance0(boolean verbose);
private native void destroyInstance0(long moviePtr);
@@ -595,7 +647,7 @@ public class FFMPEGMediaPlayer extends GLMediaPlayerImpl {
* Issues {@link #updateAttributes(int, int, int, int, int, int, int, float, int, int, String, String)}
* and {@link #updateAttributes2(int, int, int, int, int, int, int, int, int, int)}.
* <p>
- * Always uses {@link AudioSink.AudioDataFormat}:
+ * Always uses {@link AudioSink.AudioFormat}:
* <pre>
* [type PCM, sampleRate [10000(?)..44100..48000], sampleSize 16, channelCount 1-2, signed, littleEndian]
* </pre>
@@ -607,10 +659,10 @@ public class FFMPEGMediaPlayer extends GLMediaPlayerImpl {
* @param aid
* @param snoopVideoFrameCount snoop this number of video-frames to gather audio-frame-count per video-frame.
* If zero, gathering audio-frame-count is disabled!
- * @param aChannelCount
- * @param aSampleRate
+ * @param aPrefChannelCount
+ * @param aPrefSampleRate
*/
- private native void setStream0(long moviePtr, String url, String inFormat, int vid, int aid, int snoopVideoFrameCount, int aChannelCount, int aSampleRate);
+ private native void setStream0(long moviePtr, String url, String inFormat, int vid, int aid, int snoopVideoFrameCount, int aMaxChannelCount, int aPrefSampleRate);
private native void setGLFuncs0(long moviePtr, long procAddrGLTexSubImage2D, long procAddrGLGetError, long procAddrGLFlush, long procAddrGLFinish);
private native int getVideoPTS0(long moviePtr);
@@ -627,6 +679,7 @@ public class FFMPEGMediaPlayer extends GLMediaPlayerImpl {
private native int pause0(long moviePtr);
private native int seek0(long moviePtr, int position);
+ /** FFMPEG/libAV Audio Sample Format */
public static enum SampleFormat {
// NONE = -1,
U8, ///< unsigned 8 bits
@@ -653,6 +706,7 @@ public class FFMPEGMediaPlayer extends GLMediaPlayerImpl {
}
};
+ /** FFMPEG/libAV Pixel Format */
public static enum PixelFormat {
// NONE= -1,
YUV420P, ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
diff --git a/src/jogl/native/libav/ffmpeg_tool.h b/src/jogl/native/libav/ffmpeg_tool.h
index 783746378..0a65723fe 100644
--- a/src/jogl/native/libav/ffmpeg_tool.h
+++ b/src/jogl/native/libav/ffmpeg_tool.h
@@ -43,6 +43,15 @@
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
+#include <libavutil/avutil.h>
+#if LIBAVCODEC_VERSION_MAJOR >= 54
+#include <libavresample/avresample.h>
+#endif
+
+#ifndef LIBAVRESAMPLE_VERSION_MAJOR
+#define LIBAVRESAMPLE_VERSION_MAJOR 0
+typedef void* AVAudioResampleContext;
+#endif
#include <stdarg.h>
#include <stdio.h>
@@ -85,6 +94,12 @@ typedef void (APIENTRYP PFNGLFINISH) (void);
/** Since 55.0.0 */
#define AV_HAS_API_REFCOUNTED_FRAMES(pAV) (AV_VERSION_MAJOR(pAV->avcodecVersion) >= 55)
+/** Since 54.0.0.1 */
+#define AV_HAS_API_AVRESAMPLE(pAV) (AV_VERSION_MAJOR(pAV->avresampleVersion) >= 1)
+
+#define MAX_INT(a,b) ( (a >= b) ? a : b )
+#define MIN_INT(a,b) ( (a <= b) ? a : b )
+
static inline float my_av_q2f(AVRational a){
return a.num / (float) a.den;
}
@@ -112,6 +127,7 @@ typedef struct {
uint32_t avcodecVersion;
uint32_t avformatVersion;
uint32_t avutilVersion;
+ uint32_t avresampleVersion;
int32_t useRefCountedFrames;
@@ -144,10 +160,16 @@ typedef struct {
NIOBuffer_t* pANIOBuffers;
int32_t aFrameCount;
int32_t aFrameCurrent;
- int32_t aSampleRate;
- int32_t aChannels;
int32_t aFrameSize; // in samples per channel!
enum AVSampleFormat aSampleFmt; // native decoder fmt
+ int32_t aSampleRate;
+ int32_t aChannels;
+ int32_t aSinkSupport; // supported by AudioSink
+ AVAudioResampleContext *aResampleCtx;
+ uint8_t* aResampleBuffer;
+ enum AVSampleFormat aSampleFmtOut; // out fmt
+ int32_t aChannelsOut;
+ int32_t aSampleRateOut;
int32_t aPTS; // msec - overall last audio PTS
PTSStats aPTSStats;
int32_t aFramesPerVideoFrame; // is 'snooped'
diff --git a/src/jogl/native/libav/jogamp_opengl_util_av_impl_FFMPEGMediaPlayer.c b/src/jogl/native/libav/jogamp_opengl_util_av_impl_FFMPEGMediaPlayer.c
index 7bf936113..514c60800 100644
--- a/src/jogl/native/libav/jogamp_opengl_util_av_impl_FFMPEGMediaPlayer.c
+++ b/src/jogl/native/libav/jogamp_opengl_util_av_impl_FFMPEGMediaPlayer.c
@@ -30,7 +30,6 @@
#include "JoglCommon.h"
#include "ffmpeg_tool.h"
-#include <libavutil/avutil.h>
#include <libavutil/pixdesc.h>
#include <libavutil/samplefmt.h>
#if LIBAVUTIL_VERSION_MAJOR < 53
@@ -45,18 +44,20 @@ static jclass ffmpegMediaPlayerClazz = NULL;
static jmethodID jni_mid_pushSound = NULL;
static jmethodID jni_mid_updateAttributes1 = NULL;
static jmethodID jni_mid_updateAttributes2 = NULL;
+static jmethodID jni_mid_isAudioFormatSupported = NULL;
#define HAS_FUNC(f) (NULL!=(f))
typedef unsigned (APIENTRYP AVCODEC_VERSION)(void);
typedef unsigned (APIENTRYP AVUTIL_VERSION)(void);
typedef unsigned (APIENTRYP AVFORMAT_VERSION)(void);
+typedef unsigned (APIENTRYP AVRESAMPLE_VERSION)(void);
static AVCODEC_VERSION sp_avcodec_version;
static AVFORMAT_VERSION sp_avformat_version;
static AVUTIL_VERSION sp_avutil_version;
-// count: 3
-
+static AVRESAMPLE_VERSION sp_avresample_version;
+// count: 4
// libavcodec
typedef int (APIENTRYP AVCODEC_CLOSE)(AVCodecContext *avctx);
@@ -96,19 +97,23 @@ static AV_FREE_PACKET sp_av_free_packet;
static AVCODEC_DECODE_AUDIO4 sp_avcodec_decode_audio4; // 53.25.0
static AVCODEC_DECODE_AUDIO3 sp_avcodec_decode_audio3; // 52.23.0
static AVCODEC_DECODE_VIDEO2 sp_avcodec_decode_video2; // 52.23.0
-// count: 21
+// count: 22
// libavutil
typedef void (APIENTRYP AV_FRAME_UNREF)(AVFrame *frame);
typedef void (APIENTRYP AV_FREE)(void *ptr);
typedef int (APIENTRYP AV_GET_BITS_PER_PIXEL)(const AVPixFmtDescriptor *pixdesc);
typedef int (APIENTRYP AV_SAMPLES_GET_BUFFER_SIZE)(int *linesize, int nb_channels, int nb_samples, enum AVSampleFormat sample_fmt, int align);
+typedef int (APIENTRYP AV_GET_BYTES_PER_SAMPLE)(enum AVSampleFormat sample_fmt);
+typedef int (APIENTRYP AV_OPT_SET_INT)(void *obj, const char *name, int64_t val, int search_flags);
static const AVPixFmtDescriptor* sp_av_pix_fmt_descriptors;
static AV_FRAME_UNREF sp_av_frame_unref;
static AV_FREE sp_av_free;
static AV_GET_BITS_PER_PIXEL sp_av_get_bits_per_pixel;
static AV_SAMPLES_GET_BUFFER_SIZE sp_av_samples_get_buffer_size;
-// count: 26
+static AV_GET_BYTES_PER_SAMPLE sp_av_get_bytes_per_sample;
+static AV_OPT_SET_INT sp_av_opt_set_int;
+// count: 28
// libavformat
typedef AVFormatContext *(APIENTRYP AVFORMAT_ALLOC_CONTEXT)(void);
@@ -146,9 +151,24 @@ static AVFORMAT_NETWORK_INIT sp_avformat_network_init; // 53.13.0
static AVFORMAT_NETWORK_DEINIT sp_avformat_network_deinit; // 53.13.0
static AVFORMAT_FIND_STREAM_INFO sp_avformat_find_stream_info; // 53.3.0
static AV_FIND_STREAM_INFO sp_av_find_stream_info;
-// count: 43
-
-#define SYMBOL_COUNT 43
+// count: 46
+
+// libavresample [1.0.1]
+typedef AVAudioResampleContext* (APIENTRYP AVRESAMPLE_ALLOC_CONTEXT)(void); // 1.0.1
+typedef int (APIENTRYP AVRESAMPLE_OPEN)(AVAudioResampleContext *avr); // 1.0.1
+typedef void (APIENTRYP AVRESAMPLE_CLOSE)(AVAudioResampleContext *avr); // 1.0.1
+typedef void (APIENTRYP AVRESAMPLE_FREE)(AVAudioResampleContext **avr); // 1.0.1
+typedef int (APIENTRYP AVRESAMPLE_CONVERT)(AVAudioResampleContext *avr, uint8_t **output,
+ int out_plane_size, int out_samples, uint8_t **input,
+ int in_plane_size, int in_samples); // 1.0.1
+static AVRESAMPLE_ALLOC_CONTEXT sp_avresample_alloc_context;
+static AVRESAMPLE_OPEN sp_avresample_open;
+static AVRESAMPLE_CLOSE sp_avresample_close;
+static AVRESAMPLE_FREE sp_avresample_free;
+static AVRESAMPLE_CONVERT sp_avresample_convert;
+// count: 51
+
+#define SYMBOL_COUNT 51
JNIEXPORT jboolean JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGDynamicLibraryBundleInfo_initSymbols0
(JNIEnv *env, jclass clazz, jobject jSymbols, jint count)
@@ -169,7 +189,8 @@ JNIEXPORT jboolean JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGDynamicLibraryB
sp_avcodec_version = (AVCODEC_VERSION) (intptr_t) symbols[i++];
sp_avformat_version = (AVFORMAT_VERSION) (intptr_t) symbols[i++];
sp_avutil_version = (AVUTIL_VERSION) (intptr_t) symbols[i++];
- // count: 3
+ sp_avresample_version = (AVRESAMPLE_VERSION) (intptr_t) symbols[i++];
+ // count: 4
sp_avcodec_close = (AVCODEC_CLOSE) (intptr_t) symbols[i++];
sp_avcodec_string = (AVCODEC_STRING) (intptr_t) symbols[i++];
@@ -189,14 +210,16 @@ JNIEXPORT jboolean JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGDynamicLibraryB
sp_avcodec_decode_audio4 = (AVCODEC_DECODE_AUDIO4) (intptr_t) symbols[i++];
sp_avcodec_decode_audio3 = (AVCODEC_DECODE_AUDIO3) (intptr_t) symbols[i++];
sp_avcodec_decode_video2 = (AVCODEC_DECODE_VIDEO2) (intptr_t) symbols[i++];
- // count: 18
+ // count: 22
sp_av_pix_fmt_descriptors = (const AVPixFmtDescriptor*) (intptr_t) symbols[i++];
sp_av_frame_unref = (AV_FRAME_UNREF) (intptr_t) symbols[i++];
sp_av_free = (AV_FREE) (intptr_t) symbols[i++];
sp_av_get_bits_per_pixel = (AV_GET_BITS_PER_PIXEL) (intptr_t) symbols[i++];
sp_av_samples_get_buffer_size = (AV_SAMPLES_GET_BUFFER_SIZE) (intptr_t) symbols[i++];
- // count: 22
+ sp_av_get_bytes_per_sample = (AV_GET_BYTES_PER_SAMPLE) (intptr_t) symbols[i++];
+ sp_av_opt_set_int = (AV_OPT_SET_INT) (intptr_t) symbols[i++];
+ // count: 29
sp_avformat_alloc_context = (AVFORMAT_ALLOC_CONTEXT) (intptr_t) symbols[i++];;
sp_avformat_free_context = (AVFORMAT_FREE_CONTEXT) (intptr_t) symbols[i++];
@@ -215,7 +238,14 @@ JNIEXPORT jboolean JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGDynamicLibraryB
sp_avformat_network_deinit = (AVFORMAT_NETWORK_DEINIT) (intptr_t) symbols[i++];
sp_avformat_find_stream_info = (AVFORMAT_FIND_STREAM_INFO) (intptr_t) symbols[i++];
sp_av_find_stream_info = (AV_FIND_STREAM_INFO) (intptr_t) symbols[i++];
- // count: 38
+ // count: 46
+
+ sp_avresample_alloc_context = (AVRESAMPLE_ALLOC_CONTEXT) (intptr_t) symbols[i++];
+ sp_avresample_open = (AVRESAMPLE_OPEN) (intptr_t) symbols[i++];
+ sp_avresample_close = (AVRESAMPLE_CLOSE) (intptr_t) symbols[i++];
+ sp_avresample_free = (AVRESAMPLE_FREE) (intptr_t) symbols[i++];
+ sp_avresample_convert = (AVRESAMPLE_CONVERT) (intptr_t) symbols[i++];
+ // count: 51
(*env)->ReleasePrimitiveArrayCritical(env, jSymbols, symbols, 0);
@@ -229,6 +259,10 @@ JNIEXPORT jboolean JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGDynamicLibraryB
return JNI_TRUE;
}
+static int _isAudioFormatSupported(JNIEnv *env, jobject instance, enum AVSampleFormat aSampleFmt, int32_t aSampleRate, int32_t aChannels)
+{
+ return JNI_TRUE == (*env)->CallBooleanMethod(env, instance, jni_mid_isAudioFormatSupported, aSampleFmt, aSampleRate, aChannels);
+}
static void _updateJavaAttributes(JNIEnv *env, jobject instance, FFMPEGToolBasicAV_t* pAV)
{
// int shallBeDetached = 0;
@@ -247,7 +281,7 @@ static void _updateJavaAttributes(JNIEnv *env, jobject instance, FFMPEGToolBasic
pAV->vBitsPerPixel, pAV->vBytesPerPixelPerPlane,
pAV->vLinesize[0], pAV->vLinesize[1], pAV->vLinesize[2],
pAV->vTexWidth[0], pAV->vTexWidth[1], pAV->vTexWidth[2], h,
- pAV->aFramesPerVideoFrame, pAV->aSampleFmt, pAV->aSampleRate, pAV->aChannels, pAV->aFrameSize);
+ pAV->aFramesPerVideoFrame, pAV->aSampleFmtOut, pAV->aSampleRateOut, pAV->aChannelsOut, pAV->aFrameSize);
(*env)->CallVoidMethod(env, instance, jni_mid_updateAttributes1,
pAV->vid, pAV->aid,
w, h,
@@ -261,6 +295,16 @@ static void _updateJavaAttributes(JNIEnv *env, jobject instance, FFMPEGToolBasic
static void freeInstance(JNIEnv *env, FFMPEGToolBasicAV_t* pAV) {
int i;
if(NULL != pAV) {
+ // Close the A resampler
+ if( NULL != pAV->aResampleCtx ) {
+ sp_avresample_free(&pAV->aResampleCtx);
+ pAV->aResampleCtx = NULL;
+ }
+ if( NULL != pAV->aResampleBuffer ) {
+ sp_av_free(pAV->aResampleBuffer);
+ pAV->aResampleBuffer = NULL;
+ }
+
// Close the V codec
if(NULL != pAV->pVCodecCtx) {
sp_avcodec_close(pAV->pVCodecCtx);
@@ -390,6 +434,19 @@ JNIEXPORT jint JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGMediaPlayer_getAvCo
return (jint) LIBAVCODEC_VERSION_MAJOR;
}
+JNIEXPORT jint JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGMediaPlayer_getAvResampleVersion0
+ (JNIEnv *env, jclass clazz) {
+ if(HAS_FUNC(sp_avresample_version)) {
+ return (jint) sp_avresample_version();
+ } else {
+ return 0;
+ }
+}
+JNIEXPORT jint JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGMediaPlayer_getAvResampleMajorVersionCC0
+ (JNIEnv *env, jclass clazz) {
+ return (jint) LIBAVRESAMPLE_VERSION_MAJOR;
+}
+
JNIEXPORT jboolean JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGMediaPlayer_initIDs0
(JNIEnv *env, jclass clazz)
{
@@ -413,10 +470,12 @@ JNIEXPORT jboolean JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGMediaPlayer_ini
jni_mid_pushSound = (*env)->GetMethodID(env, ffmpegMediaPlayerClazz, "pushSound", "(Ljava/nio/ByteBuffer;II)V");
jni_mid_updateAttributes1 = (*env)->GetMethodID(env, ffmpegMediaPlayerClazz, "updateAttributes", "(IIIIIIIFIIILjava/lang/String;Ljava/lang/String;)V");
jni_mid_updateAttributes2 = (*env)->GetMethodID(env, ffmpegMediaPlayerClazz, "updateAttributes2", "(IIIIIIIIIIIIIIII)V");
+ jni_mid_isAudioFormatSupported = (*env)->GetMethodID(env, ffmpegMediaPlayerClazz, "isAudioFormatSupported", "(III)Z");
if(jni_mid_pushSound == NULL ||
jni_mid_updateAttributes1 == NULL ||
- jni_mid_updateAttributes2 == NULL) {
+ jni_mid_updateAttributes2 == NULL ||
+ jni_mid_isAudioFormatSupported == NULL) {
return JNI_FALSE;
}
return JNI_TRUE;
@@ -433,6 +492,11 @@ JNIEXPORT jlong JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGMediaPlayer_create
pAV->avcodecVersion = sp_avcodec_version();
pAV->avformatVersion = sp_avformat_version();
pAV->avutilVersion = sp_avutil_version();
+ if(HAS_FUNC(sp_avresample_version)) {
+ pAV->avresampleVersion = sp_avresample_version();
+ } else {
+ pAV->avresampleVersion = 0;
+ }
#if LIBAVCODEC_VERSION_MAJOR >= 55
// TODO: We keep code on using 1 a/v frame per decoding cycle now.
@@ -489,7 +553,7 @@ static int64_t evalPTS(PTSStats *ptsStats, int64_t inPTS, int64_t inDTS);
JNIEXPORT void JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGMediaPlayer_setStream0
(JNIEnv *env, jobject instance, jlong ptr, jstring jURL, jstring jInFmtStr, jint vid, jint aid,
- jint snoopVideoFrameCount, jint aChannelCount, jint aSampleRate)
+ jint snoopVideoFrameCount, jint aMaxChannelCount, jint aPrefSampleRate)
{
int res, i;
jboolean iscopy;
@@ -609,12 +673,15 @@ JNIEXPORT void JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGMediaPlayer_setStre
pAV->pACodecCtx->workaround_bugs=FF_BUG_AUTODETECT;
pAV->pACodecCtx->skip_frame=AVDISCARD_DEFAULT;
- pAV->pACodecCtx->request_channel_layout=getDefaultAudioChannelLayout(aChannelCount);
- if( AV_HAS_API_REQUEST_CHANNELS(pAV) && 1 <= aChannelCount && aChannelCount <= 2 ) {
- pAV->pACodecCtx->request_channels=aChannelCount;
- }
+ // Note: OpenAL well supports n-channel by now (SOFT),
+ // however - AFAIK AV_SAMPLE_FMT_S16 would allow no conversion!
pAV->pACodecCtx->request_sample_fmt=AV_SAMPLE_FMT_S16;
- // ignored: aSampleRate !
+ if( 1 <= aMaxChannelCount && aMaxChannelCount <= 2 ) {
+ pAV->pACodecCtx->request_channel_layout=getDefaultAudioChannelLayout(aMaxChannelCount);
+ if( AV_HAS_API_REQUEST_CHANNELS(pAV) ) {
+ pAV->pACodecCtx->request_channels=aMaxChannelCount;
+ }
+ }
pAV->pACodecCtx->skip_frame=AVDISCARD_DEFAULT;
sp_avcodec_string(pAV->acodec, sizeof(pAV->acodec), pAV->pACodecCtx, 0);
@@ -651,13 +718,66 @@ JNIEXPORT void JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGMediaPlayer_setStre
pAV->aFrameSize = pAV->pACodecCtx->frame_size; // in samples per channel!
pAV->aSampleFmt = pAV->pACodecCtx->sample_fmt;
pAV->frames_audio = pAV->pAStream->nb_frames;
+ pAV->aSinkSupport = _isAudioFormatSupported(env, instance, pAV->aSampleFmt, pAV->aSampleRate, pAV->aChannels);
if( pAV->verbose ) {
- fprintf(stderr, "A channels %d [l %d], sample_rate %d, frame_size %d, frame_number %d, r_frame_rate %f, avg_frame_rate %f, nb_frames %d, [req_chan_layout %d, req_chan %d] \n",
+ fprintf(stderr, "A channels %d [l %d], sample_rate %d, frame_size %d, frame_number %d, r_frame_rate %f, avg_frame_rate %f, nb_frames %d, [maxChan %d, prefRate %d, req_chan_layout %d, req_chan %d], sink-support %d \n",
pAV->aChannels, pAV->pACodecCtx->channel_layout, pAV->aSampleRate, pAV->aFrameSize, pAV->pACodecCtx->frame_number,
my_av_q2f(pAV->pAStream->r_frame_rate),
my_av_q2f(pAV->pAStream->avg_frame_rate),
pAV->pAStream->nb_frames,
- pAV->pACodecCtx->request_channel_layout, pAV->pACodecCtx->request_channels);
+ aMaxChannelCount, aPrefSampleRate, pAV->pACodecCtx->request_channel_layout, pAV->pACodecCtx->request_channels,
+ pAV->aSinkSupport);
+ }
+
+ // default
+ pAV->aSampleFmtOut = pAV->aSampleFmt;
+ pAV->aChannelsOut = pAV->aChannels;
+ pAV->aSampleRateOut = pAV->aSampleRate;
+
+ if( AV_HAS_API_AVRESAMPLE(pAV) &&
+ ( pAV->aSampleFmt != AV_SAMPLE_FMT_S16 ||
+ ( 0 != aPrefSampleRate && pAV->aSampleRate != aPrefSampleRate ) ||
+ !pAV->aSinkSupport )
+ ) {
+ if( 0 == aPrefSampleRate ) {
+ aPrefSampleRate = pAV->aSampleRate;
+ }
+ int32_t aSinkSupport = 0;
+ enum AVSampleFormat aSampleFmtOut = AV_SAMPLE_FMT_S16;
+ int32_t aChannelsOut;
+ int32_t aSampleRateOut;
+ int32_t minChannelCount = MIN_INT(aMaxChannelCount,pAV->pACodecCtx->channels);
+
+ if( _isAudioFormatSupported(env, instance, aSampleFmtOut, aPrefSampleRate, pAV->pACodecCtx->channels) ) {
+ aChannelsOut = pAV->pACodecCtx->channels;
+ aSampleRateOut = aPrefSampleRate;
+ aSinkSupport = 1;
+ } else if( _isAudioFormatSupported(env, instance, aSampleFmtOut, aPrefSampleRate, minChannelCount) ) {
+ aChannelsOut = minChannelCount;
+ aSampleRateOut = aPrefSampleRate;
+ aSinkSupport = 1;
+ }
+ if( aSinkSupport ) {
+ pAV->aResampleCtx = sp_avresample_alloc_context();
+ sp_av_opt_set_int(pAV->aResampleCtx, "in_channel_layout", pAV->pACodecCtx->channel_layout, 0);
+ sp_av_opt_set_int(pAV->aResampleCtx, "out_channel_layout", getDefaultAudioChannelLayout(aChannelsOut), 0);
+ sp_av_opt_set_int(pAV->aResampleCtx, "in_sample_rate", pAV->aSampleRate, 0);
+ sp_av_opt_set_int(pAV->aResampleCtx, "out_sample_rate", aSampleRateOut, 0);
+ sp_av_opt_set_int(pAV->aResampleCtx, "in_sample_fmt", pAV->aSampleFmt, 0);
+ sp_av_opt_set_int(pAV->aResampleCtx, "out_sample_fmt", aSampleFmtOut, 0);
+
+ if ( sp_avresample_open(pAV->aResampleCtx) < 0 ) {
+ sp_avresample_free(&pAV->aResampleCtx);
+ pAV->aResampleCtx = NULL;
+ fprintf(stderr, "error initializing libavresample\n");
+ } else {
+ // OK
+ pAV->aSampleFmtOut = aSampleFmtOut;
+ pAV->aChannelsOut = aChannelsOut;
+ pAV->aSampleRateOut = aSampleRateOut;
+ pAV->aSinkSupport = 1;
+ }
+ }
}
if( 0 >= snoopVideoFrameCount ) {
@@ -961,7 +1081,7 @@ JNIEXPORT jint JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGMediaPlayer_readNex
if( 0 == frameCount && AV_NOPTS_VALUE != pkt_pts ) { // 1st frame only, discard invalid PTS ..
pAV->aPTS = my_av_q2i32( pkt_pts * 1000, time_base);
} else { // subsequent frames or invalid PTS ..
- const int32_t bytesPerSample = 2; // av_get_bytes_per_sample( pAV->pACodecCtx->sample_fmt );
+ const int32_t bytesPerSample = sp_av_get_bytes_per_sample( pAV->pACodecCtx->sample_fmt );
pAV->aPTS += data_size / ( pAV->aChannels * bytesPerSample * ( pAV->aSampleRate / 1000 ) );
}
if( pAV->verbose ) {
@@ -972,9 +1092,46 @@ JNIEXPORT jint JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGMediaPlayer_readNex
pAV->aFrameCurrent, pAV->aFrameCount, pAFrameCurrent, pAFrameCurrent->data[0], data_size);
}
if( NULL != env ) {
+ void* data_ptr = pAFrameCurrent->data[0]; // default
+
+ if( NULL != pAV->aResampleCtx ) {
+ enum AVSampleFormat aSampleFmtOut; // out fmt
+ int32_t aChannelsOut;
+ int32_t aSampleRateOut;
+
+ uint8_t *tmp_out;
+ int out_samples, out_size, out_linesize;
+ int osize = sp_av_get_bytes_per_sample( pAV->aSampleFmtOut );
+ int nb_samples = pAFrameCurrent->nb_samples;
+
+ out_size = sp_av_samples_get_buffer_size(&out_linesize,
+ pAV->aChannelsOut,
+ nb_samples,
+ pAV->aSampleFmtOut, 0 /* align */);
+
+ tmp_out = av_realloc(pAV->aResampleBuffer, out_size);
+ if (!tmp_out) {
+ JoglCommon_throwNewRuntimeException(env, "Couldn't alloc resample buffer of size %d", out_size);
+ return;
+ }
+ pAV->aResampleBuffer = tmp_out;
+
+ out_samples = sp_avresample_convert(pAV->aResampleCtx,
+ &pAV->aResampleBuffer,
+ out_linesize, nb_samples,
+ pAFrameCurrent->data,
+ pAFrameCurrent->linesize[0],
+ pAFrameCurrent->nb_samples);
+ if (out_samples < 0) {
+ JoglCommon_throwNewRuntimeException(env, "avresample_convert() failed");
+ return;
+ }
+ data_size = out_samples * osize * pAV->aChannelsOut;
+ data_ptr = tmp_out;
+ }
NIOBuffer_t * pNIOBufferCurrent = &pAV->pANIOBuffers[pAV->aFrameCurrent];
int newNIO = NULL == pNIOBufferCurrent->nioRef;
- if( !newNIO && ( pAFrameCurrent->data[0] != pNIOBufferCurrent->origPtr || data_size > pNIOBufferCurrent->size ) ) {
+ if( !newNIO && ( data_ptr != pNIOBufferCurrent->origPtr || data_size > pNIOBufferCurrent->size ) ) {
if(pAV->verbose) {
fprintf(stderr, "A NIO: Free.0 ptr %p / ref %p, %d bytes\n",
pNIOBufferCurrent->origPtr, pNIOBufferCurrent->nioRef, pNIOBufferCurrent->size);
@@ -983,9 +1140,9 @@ JNIEXPORT jint JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGMediaPlayer_readNex
newNIO = 1;
}
if( newNIO ) {
- jobject jSampleData = (*env)->NewDirectByteBuffer(env, pAFrameCurrent->data[0], data_size);
+ jobject jSampleData = (*env)->NewDirectByteBuffer(env, data_ptr, data_size);
pNIOBufferCurrent->nioRef = (*env)->NewGlobalRef(env, jSampleData);
- pNIOBufferCurrent->origPtr = pAFrameCurrent->data[0];
+ pNIOBufferCurrent->origPtr = data_ptr;
pNIOBufferCurrent->size = data_size;
if(pAV->verbose) {
fprintf(stderr, "A NIO: Alloc ptr %p / ref %p, %d bytes\n",