diff options
Diffstat (limited to 'src/jogl/native/libav')
-rw-r--r-- | src/jogl/native/libav/jogamp_opengl_util_av_impl_FFMPEGMediaPlayer.c | 130 |
1 files changed, 110 insertions, 20 deletions
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 28e9e852c..d93caa30b 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 @@ -38,6 +38,7 @@ typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLi static const char * const ClazzNameFFMPEGMediaPlayer = "jogamp/opengl/util/av/impl/FFMPEGMediaPlayer"; static jclass ffmpegMediaPlayerClazz = NULL; +static jmethodID jni_mid_updateSound = NULL; static jmethodID jni_mid_updateAttributes1 = NULL; static jmethodID jni_mid_updateAttributes2 = NULL; @@ -84,10 +85,12 @@ static AVCODEC_DECODE_VIDEO2 sp_avcodec_decode_video2; // 52.23.0 // libavutil 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); static const AVPixFmtDescriptor* sp_av_pix_fmt_descriptors; static AV_FREE sp_av_free; static AV_GET_BITS_PER_PIXEL sp_av_get_bits_per_pixel; -// count: 18 +static AV_SAMPLES_GET_BUFFER_SIZE sp_av_samples_get_buffer_size; +// count: 19 // libavformat typedef AVFormatContext *(APIENTRYP AVFORMAT_ALLOC_CONTEXT)(void); @@ -117,9 +120,9 @@ 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: 31 +// count: 32 -#define SYMBOL_COUNT 31 +#define SYMBOL_COUNT 32 JNIEXPORT jboolean JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGDynamicLibraryBundleInfo_initSymbols0 (JNIEnv *env, jclass clazz, jobject jSymbols, jint count) @@ -159,7 +162,8 @@ JNIEXPORT jboolean JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGDynamicLibraryB sp_av_pix_fmt_descriptors = (const AVPixFmtDescriptor*) (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++]; - // count: 18 + sp_av_samples_get_buffer_size = (AV_SAMPLES_GET_BUFFER_SIZE) (intptr_t) symbols[i++]; + // count: 19 sp_avformat_alloc_context = (AVFORMAT_ALLOC_CONTEXT) (intptr_t) symbols[i++];; sp_avformat_free_context = (AVFORMAT_FREE_CONTEXT) (intptr_t) symbols[i++]; @@ -174,7 +178,7 @@ 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: 31 + // count: 32 (*env)->ReleasePrimitiveArrayCritical(env, jSymbols, symbols, 0); @@ -188,6 +192,41 @@ JNIEXPORT jboolean JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGDynamicLibraryB return JNI_TRUE; } +static void _updateSound(JNIEnv *env, jobject instance, int8_t *data, int32_t data_size, int32_t aPTS) { + if(NULL!=env) { + jbyteArray jbArray = (*env)->NewByteArray(env, data_size); + if (jbArray == NULL) { + fprintf(stderr, "FFMPEGMediaPlayer out of memory at native code _updateSound"); + return; /* out of memory error thrown */ + } + +/* + // Visualize sample waveform + int i; + for(i=0;i<40;i++){ + int8_t b = data[i]; + if(b<0) { + printf(" "); + } else if(b<64) { + printf("_"); + } else if(b < 128) { + printf("-"); + } else if(b == 128) { + printf("="); + } else if(b < 256-64) { + printf("\""); + } else { + printf("'"); + } + } + printf("nA\n"); +*/ + + (*env)->SetByteArrayRegion(env, jbArray, 0, data_size, data); + (*env)->CallVoidMethod(env, instance, jni_mid_updateSound, jbArray, data_size, aPTS); + } +} + static void _updateJavaAttributes(JNIEnv *env, jobject instance, FFMPEGToolBasicAV_t* pAV) { // int shallBeDetached = 0; @@ -331,10 +370,12 @@ JNIEXPORT jboolean JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGMediaPlayer_ini JoglCommon_FatalError(env, "JOGL FFMPEG: can't use %s", ClazzNameFFMPEGMediaPlayer); } + jni_mid_updateSound = (*env)->GetMethodID(env, ffmpegMediaPlayerClazz, "updateSound", "([BII)V"); jni_mid_updateAttributes1 = (*env)->GetMethodID(env, ffmpegMediaPlayerClazz, "updateAttributes", "(IIIIIFIILjava/lang/String;Ljava/lang/String;)V"); jni_mid_updateAttributes2 = (*env)->GetMethodID(env, ffmpegMediaPlayerClazz, "updateAttributes2", "(IIIIIIIIII)V"); - if(jni_mid_updateAttributes1 == NULL || + if(jni_mid_updateSound == NULL || + jni_mid_updateAttributes1 == NULL || jni_mid_updateAttributes2 == NULL) { return JNI_FALSE; } @@ -579,7 +620,6 @@ JNIEXPORT jint JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGMediaPlayer_readNex int frameFinished; if(sp_av_read_frame(pAV->pFormatCtx, &packet)>=0) { - /** if(packet.stream_index==pAV->aid) { // Decode audio frame if(NULL == pAV->pAFrame) { @@ -590,16 +630,19 @@ JNIEXPORT jint JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGMediaPlayer_readNex int new_packet = 1; int len1; int flush_complete = 0; - int data_size = 0; while (packet.size > 0 || (!packet.data && new_packet)) { new_packet = 0; if (flush_complete) { break; } if(HAS_FUNC(sp_avcodec_decode_audio4)) { - len1 = sp_avcodec_decode_audio4(pAV->pVCodecCtx, pAV->pAFrame, &frameFinished, &packet); + len1 = sp_avcodec_decode_audio4(pAV->pACodecCtx, pAV->pAFrame, &frameFinished, &packet); } else { - len1 = sp_avcodec_decode_audio3(pAV->pVCodecCtx, int16_t *samples, int *frame_size_ptr, &frameFinished, &packet); + #if 0 + len1 = sp_avcodec_decode_audio3(pAV->pACodecCtx, int16_t *samples, int *frame_size_ptr, &frameFinished, &packet); + #endif + JoglCommon_throwNewRuntimeException(env, "Unimplemented: FFMPEGMediaPlayer sp_avcodec_decode_audio3 fallback"); + return 0; } if (len1 < 0) { // if error, we skip the frame @@ -611,28 +654,73 @@ JNIEXPORT jint JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGMediaPlayer_readNex if (!frameFinished) { // stop sending empty packets if the decoder is finished - if (!packet.data && pAV->pVCodecCtx->codec->capabilities & CODEC_CAP_DELAY) { + if (!packet.data && pAV->pACodecCtx->codec->capabilities & CODEC_CAP_DELAY) { flush_complete = 1; } continue; } - int32_t pts = pAV->pAFrame->pkt_pts * my_av_q2i32(1000, pAV->pAStream->time_base); - pAV->aPTS += ( data_size * 1000 ) / (2 * pAV->pVCodecCtx->channels * pAV->pVCodecCtx->sample_rate); - printf("A pts %d - %d\n", pts, pAV->aPTS); + int data_size = 0; + if(HAS_FUNC(sp_av_samples_get_buffer_size)) { + data_size = sp_av_samples_get_buffer_size(NULL /* linesize, may be NULL */, + pAV->aChannels, + pAV->pAFrame->nb_samples, + pAV->pAFrame->format, + 1 /* align */); + } + int32_t pts = (int64_t) ( pAV->pAFrame->pkt_pts * (int64_t) 1000 * (int64_t) pAV->pAStream->time_base.num ) + / (int64_t) pAV->pAStream->time_base.den; + #if 0 + printf("channels %d sample_rate %d \n", pAV->aChannels , pAV->aSampleRate); + printf("data %d \n", pAV->aFrameSize); + #endif + pAV->aPTS += (int64_t) ( data_size * (int64_t) 1000 ) + / (int64_t) (2 * (int64_t) pAV->aChannels * (int64_t) pAV->aSampleRate); + if( pAV->verbose ) { + printf("A pts %d - %d\n", pts, pAV->aPTS); + } + // TODO: Wrap audio buffer data in a com.jogamp.openal.sound3d.Buffer or similar + // and hand it over to the user using a suitable API. + // TODO: OR send the audio buffer data down to sound card directly using JOAL. + _updateSound(env, instance, pAV->pAFrame->data[0], data_size, pAV->aPTS); + res = 1; } - } else */ if(packet.stream_index==pAV->vid) { + } else if(packet.stream_index==pAV->vid) { // Decode video frame if(NULL == pAV->pVFrame) { sp_av_free_packet(&packet); return res; } - sp_avcodec_decode_video2(pAV->pVCodecCtx, pAV->pVFrame, &frameFinished, &packet); - // Did we get a video frame? - if(frameFinished) - { + int new_packet = 1; + int len1; + int flush_complete = 0; + while (packet.size > 0 || (!packet.data && new_packet)) { + + new_packet = 0; + if (flush_complete) { + break; + } + + len1 = sp_avcodec_decode_video2(pAV->pVCodecCtx, pAV->pVFrame, &frameFinished, &packet); + + if (len1 < 0) { + // if error, we skip the frame + packet.size = 0; + break; + } + packet.data += len1; + packet.size -= len1; + + if (!frameFinished) { + // stop sending empty packets if the decoder is finished + if (!packet.data && pAV->pVCodecCtx->codec->capabilities & CODEC_CAP_DELAY) { + flush_complete = 1; + } + continue; + } + res = 2; // FIXME: Libav Binary compatibility! JAU01 const AVRational time_base = pAV->pVStream->time_base; @@ -678,7 +766,9 @@ JNIEXPORT jint JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGMediaPlayer_readNex } // Free the packet that was allocated by av_read_frame - sp_av_free_packet(&packet); + // This code cause a double free and have been commented out. + // TODO: check what release the packets memory. + // sp_av_free_packet(&packet); } return res; } |