native-media-jni.c revision c3d6dd225415ac68b1868575e793eb352c7105e2
19a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten/* 29a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten * Copyright (C) 2010 The Android Open Source Project 39a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten * 49a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten * Licensed under the Apache License, Version 2.0 (the "License"); 59a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten * you may not use this file except in compliance with the License. 69a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten * You may obtain a copy of the License at 79a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten * 89a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten * http://www.apache.org/licenses/LICENSE-2.0 99a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten * 109a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten * Unless required by applicable law or agreed to in writing, software 119a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten * distributed under the License is distributed on an "AS IS" BASIS, 129a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten * See the License for the specific language governing permissions and 149a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten * limitations under the License. 159a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten */ 169a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 179a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten#include <assert.h> 189a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten#include <jni.h> 199a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten#include <pthread.h> 209a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten#include <string.h> 2134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten//#define LOG_NDEBUG 0 229a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten#define LOG_TAG "NativeMedia" 239a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten#include <utils/Log.h> 24c09fe859aabccb8b18e6c857d087686b37d48c1fJean-Michel Trivi 25a6c5e52ded343b557152156c33d33a10d29bf6f1Glenn Kasten#include <OMXAL/OpenMAXAL.h> 26a6c5e52ded343b557152156c33d33a10d29bf6f1Glenn Kasten#include <OMXAL/OpenMAXAL_Android.h> 27c09fe859aabccb8b18e6c857d087686b37d48c1fJean-Michel Trivi 2873d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi#include <android/native_window_jni.h> 299a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 309a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// engine interfaces 319a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenstatic XAObjectItf engineObject = NULL; 3234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenstatic XAEngineItf engineEngine = NULL; 339a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 349a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// output mix interfaces 359a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenstatic XAObjectItf outputMixObject = NULL; 369a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 379a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// streaming media player interfaces 382f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivistatic XAObjectItf playerObj = NULL; 392f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivistatic XAPlayItf playerPlayItf = NULL; 402f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivistatic XAAndroidBufferQueueItf playerBQItf = NULL; 41fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivistatic XAStreamInformationItf playerStreamInfoItf = NULL; 4234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenstatic XAVolumeItf playerVolItf = NULL; 4334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 44f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi// number of required interfaces for the MediaPlayer creation 45fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi#define NB_MAXAL_INTERFACES 3 // XAAndroidBufferQueueItf, XAStreamInformationItf and XAPlayItf 469a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4749dfad6a8f91f0cce729f6db143f26c188caf523Glenn Kasten// video sink for the player 4873d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivistatic ANativeWindow* theNativeWindow; 499a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 5034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten// number of buffers in our buffer queue, an arbitrary number 51f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi#define NB_BUFFERS 16 5234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 53f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi// we're streaming MPEG-2 transport stream data, operate on transport stream block size 54f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi#define MPEG2_TS_BLOCK_SIZE 188 5534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 5634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten// number of MPEG-2 transport stream blocks per buffer, an arbitrary number 5734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten#define BLOCKS_PER_BUFFER 20 5834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 59f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi// determines how much memory we're dedicating to memory caching 6034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten#define BUFFER_SIZE (BLOCKS_PER_BUFFER*MPEG2_TS_BLOCK_SIZE) 61f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi 62f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi// where we cache in memory the data to play 6334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten// note this memory is re-used by the buffer queue callback 64f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivichar dataCache[BUFFER_SIZE * NB_BUFFERS]; 6534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 662f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi// handle of the file to play 672f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel TriviFILE *file; 6834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 695b21a0626e173d407aa3835e5cffcaa9b582016dJean-Michel Trivi// has the app reached the end of the file 7034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenjboolean reachedEof = JNI_FALSE; 7134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 7234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten// for mutual exclusion between callback thread and application thread(s) 7334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenpthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 7434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenpthread_cond_t cond = PTHREAD_COND_INITIALIZER; 7534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 7634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten// whether a discontinuity is in progress 7734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenjboolean discontinuity = JNI_FALSE; 7834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 7934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenstatic jboolean enqueueInitialBuffers(jboolean discontinuity); 802f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi 812f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi// AndroidBufferQueueItf callback for an audio player 822f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel TriviXAresult AndroidBufferQueueCallback( 832f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi XAAndroidBufferQueueItf caller, 84fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi void *pCallbackContext, /* input */ 85fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi void *pBufferContext, /* input */ 86fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi void *pBufferData, /* input */ 87f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi XAuint32 dataSize, /* input */ 88f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi XAuint32 dataUsed, /* input */ 89f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi const XAAndroidBufferItem *pItems,/* input */ 90f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi XAuint32 itemsLength /* input */) 912f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi{ 9234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten XAresult res; 9334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten int ok; 9434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 9534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // pCallbackContext was specified as NULL at RegisterCallback and is unused here 9634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(NULL == pCallbackContext); 9734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 9834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // note there is never any contention on this mutex unless a discontinuity request is active 9934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten ok = pthread_mutex_lock(&mutex); 10034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(0 == ok); 10134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 10234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // was a discontinuity requested? 10334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten if (discontinuity) { 10434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // FIXME sorry, can't rewind after EOS 10534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten if (!reachedEof) { 10634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // clear the buffer queue 10734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten res = (*playerBQItf)->Clear(playerBQItf); 10834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(XA_RESULT_SUCCESS == res); 10934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // rewind the data source so we are guaranteed to be at an appropriate point 11034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten rewind(file); 11134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // Enqueue the initial buffers, with a discontinuity indicator on first buffer 11234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten (void) enqueueInitialBuffers(JNI_TRUE); 11334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten } 11434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // acknowledge the discontinuity request 11534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten discontinuity = JNI_FALSE; 11634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten ok = pthread_cond_signal(&cond); 11734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(0 == ok); 11834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten goto exit; 11934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten } 12034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 121fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi if (pBufferData == NULL) { 122fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi // this is the case when our buffer with the EOS message has been consumed 12334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(0 == dataSize); 12434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten goto exit; 125fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi } 126fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi 12734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // pBufferData is a pointer to a buffer that we previously Enqueued 12834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(BUFFER_SIZE == dataSize); 12934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(dataCache <= (char *) pBufferData && (char *) pBufferData < 13034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten &dataCache[BUFFER_SIZE * NB_BUFFERS]); 13134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(0 == (((char *) pBufferData - dataCache) % BUFFER_SIZE)); 13234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 133fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi#if 0 134fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi // sample code to use the XAVolumeItf 135fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi XAAndroidBufferQueueState state; 136fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi (*caller)->GetState(caller, &state); 137fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi switch (state.index) { 138fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi case 300: 139fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi (*playerVolItf)->SetVolumeLevel(playerVolItf, -600); // -6dB 140fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi LOGV("setting volume to -6dB"); 141fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi break; 142fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi case 400: 143fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi (*playerVolItf)->SetVolumeLevel(playerVolItf, -1200); // -12dB 144fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi LOGV("setting volume to -12dB"); 145fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi break; 146fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi case 500: 147fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi (*playerVolItf)->SetVolumeLevel(playerVolItf, 0); // full volume 148fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi LOGV("setting volume to 0dB (full volume)"); 149fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi break; 150fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi case 600: 151fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi (*playerVolItf)->SetMute(playerVolItf, XA_BOOLEAN_TRUE); // mute 152fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi LOGV("muting player"); 153fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi break; 154fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi case 700: 155fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi (*playerVolItf)->SetMute(playerVolItf, XA_BOOLEAN_FALSE); // unmute 156fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi LOGV("unmuting player"); 157fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi break; 158fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi case 800: 159fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi (*playerVolItf)->SetStereoPosition(playerVolItf, -1000); 160fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi (*playerVolItf)->EnableStereoPosition(playerVolItf, XA_BOOLEAN_TRUE); 161fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi LOGV("pan sound to the left (hard-left)"); 162fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi break; 163fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi case 900: 164fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi (*playerVolItf)->EnableStereoPosition(playerVolItf, XA_BOOLEAN_FALSE); 165fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi LOGV("disabling stereo position"); 166fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi break; 167fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi default: 168fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi break; 169fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi } 170fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi#endif 171fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi 17234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // don't bother trying to read more data once we've hit EOF 17334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten if (reachedEof) { 17434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten goto exit; 17534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten } 17634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 17734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten size_t nbRead; 17834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // note we do call fread from multiple threads, but never concurrently 17934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten nbRead = fread(pBufferData, BUFFER_SIZE, 1, file); 18034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten if (nbRead > 0) { 18134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(1 == nbRead); 18234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten res = (*caller)->Enqueue(caller, NULL /*pBufferContext*/, 183f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi pBufferData /*pData*/, 18434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten nbRead * BUFFER_SIZE /*dataLength*/, 185f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi NULL /*pMsg*/, 186f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi 0 /*msgLength*/); 18734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(XA_RESULT_SUCCESS == res); 18834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten } else { 189f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi // signal EOS 19034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten XAAndroidBufferItem msgEos[1]; 19134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten msgEos[0].itemKey = XA_ANDROID_ITEMKEY_EOS; 19234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten msgEos[0].itemSize = 0; 193f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi // EOS message has no parameters, so the total size of the message is the size of the key 194f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi // plus the size if itemSize, both XAuint32 19534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten res = (*caller)->Enqueue(caller, NULL /*pBufferContext*/, 196fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi NULL /*pData*/, 0 /*dataLength*/, 19734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten msgEos /*pMsg*/, 19834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // FIXME == sizeof(BufferItem)? */ 199fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi sizeof(XAuint32)*2 /*msgLength*/); 20034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(XA_RESULT_SUCCESS == res); 20134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten reachedEof = JNI_TRUE; 2022f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi } 2032f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi 20434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenexit: 20534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten ok = pthread_mutex_unlock(&mutex); 20634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(0 == ok); 2072f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi return XA_RESULT_SUCCESS; 2082f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi} 2092f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi 2102f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi 211fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivivoid StreamChangeCallback (XAStreamInformationItf caller, 212fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi XAuint32 eventId, 213fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi XAuint32 streamIndex, 214fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi void * pEventData, 215fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi void * pContext ) 216fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi{ 21734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten LOGV("StreamChangeCallback called for stream %u", streamIndex); 21834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // pContext was specified as NULL at RegisterStreamChangeCallback and is unused here 21934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(NULL == pContext); 22034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten switch (eventId) { 22134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten case XA_STREAMCBEVENT_PROPERTYCHANGE: { 22234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten /** From spec 1.0.1: 22334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten "This event indicates that stream property change has occurred. 22434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten The streamIndex parameter identifies the stream with the property change. 22534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten The pEventData parameter for this event is not used and shall be ignored." 22634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten */ 22734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 22834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten XAresult res; 229fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi XAuint32 domain; 23034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten res = (*caller)->QueryStreamType(caller, streamIndex, &domain); 23134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(XA_RESULT_SUCCESS == res); 23234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten switch (domain) { 23334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten case XA_DOMAINTYPE_VIDEO: { 23434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten XAVideoStreamInformation videoInfo; 23534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten res = (*caller)->QueryStreamInformation(caller, streamIndex, &videoInfo); 23634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(XA_RESULT_SUCCESS == res); 23734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten LOGI("Found video size %u x %u, codec ID=%u, frameRate=%u, bitRate=%u, duration=%u ms", 23834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten videoInfo.width, videoInfo.height, videoInfo.codecId, videoInfo.frameRate, 23934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten videoInfo.bitRate, videoInfo.duration); 24034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten } break; 24134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten default: 24234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten fprintf(stderr, "Unexpected domain %u\n", domain); 24334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten break; 244fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi } 24534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten } break; 24634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten default: 24734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten fprintf(stderr, "Unexpected stream event ID %u\n", eventId); 24834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten break; 249fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi } 250fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi} 251fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi 252fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi 2539a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// create the engine and output mix objects 2549a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_createEngine(JNIEnv* env, jclass clazz) 2559a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{ 2562f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi XAresult res; 2579a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 2589a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // create engine 2592f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi res = xaCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); 2602f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 2619a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 2629a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // realize the engine 2632f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi res = (*engineObject)->Realize(engineObject, XA_BOOLEAN_FALSE); 2642f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 2659a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 2669a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // get the engine interface, which is needed in order to create other objects 2672f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi res = (*engineObject)->GetInterface(engineObject, XA_IID_ENGINE, &engineEngine); 2682f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 2699a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 2709a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // create output mix 2712f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi res = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL); 2722f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 2739a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 2749a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // realize the output mix 2752f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi res = (*outputMixObject)->Realize(outputMixObject, XA_BOOLEAN_FALSE); 2762f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 2779a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 2789a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten} 2799a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 2809a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 28134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten// Enqueue the initial buffers, and optionally signal a discontinuity in the first buffer 28234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenstatic jboolean enqueueInitialBuffers(jboolean discontinuity) 28334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten{ 28434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 28534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten /* Fill our cache */ 28634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten size_t nbRead; 28734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten nbRead = fread(dataCache, BUFFER_SIZE, NB_BUFFERS, file); 28834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten if (nbRead <= 0) { 28934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // could be premature EOF or I/O error 29034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten LOGE("Error filling cache, exiting\n"); 29134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten return JNI_FALSE; 29234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten } 29334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(1 <= nbRead && nbRead <= NB_BUFFERS); 29434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten LOGV("Initially queueing %u buffers of %u bytes each", nbRead, BUFFER_SIZE); 29534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 29634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten /* Enqueue the content of our cache before starting to play, 29734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten we don't want to starve the player */ 29834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten size_t i; 29934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten for (i = 0; i < nbRead; i++) { 30034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten XAresult res; 30134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten if (discontinuity) { 30234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // signal discontinuity 30334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten XAAndroidBufferItem items[1]; 30434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten items[0].itemKey = XA_ANDROID_ITEMKEY_DISCONTINUITY; 30534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten items[0].itemSize = 0; 30634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // DISCONTINUITY message has no parameters, 30734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // so the total size of the message is the size of the key 30834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // plus the size if itemSize, both XAuint32 30934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten res = (*playerBQItf)->Enqueue(playerBQItf, NULL /*pBufferContext*/, 31034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten dataCache + i*BUFFER_SIZE, BUFFER_SIZE, items /*pMsg*/, 31134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // FIXME == sizeof(BufferItem)? */ 31234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten sizeof(XAuint32)*2 /*msgLength*/); 31334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten discontinuity = JNI_FALSE; 31434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten } else { 31534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten res = (*playerBQItf)->Enqueue(playerBQItf, NULL /*pBufferContext*/, 31634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten dataCache + i*BUFFER_SIZE, BUFFER_SIZE, NULL, 0); 31734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten } 31834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(XA_RESULT_SUCCESS == res); 31934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten } 32034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 32134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten return JNI_TRUE; 32234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten} 32334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 32434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 3259a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// create streaming media player 3269a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenjboolean Java_com_example_nativemedia_NativeMedia_createStreamingMediaPlayer(JNIEnv* env, 3279a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten jclass clazz, jstring filename) 3289a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{ 3292f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi XAresult res; 3309a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 3319a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // convert Java string to UTF-8 3329a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten const char *utf8 = (*env)->GetStringUTFChars(env, filename, NULL); 3339a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten assert(NULL != utf8); 3349a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 3352f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi // open the file to play 3362f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi file = fopen(utf8, "rb"); 3372f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi if (file == NULL) { 3382f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi LOGE("Failed to open %s", utf8); 3392f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi return JNI_FALSE; 3402f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi } 3412f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi 3422f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi // configure data source 343f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi XADataLocator_AndroidBufferQueue loc_abq = { XA_DATALOCATOR_ANDROIDBUFFERQUEUE, NB_BUFFERS }; 344f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi XADataFormat_MIME format_mime = { 345f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi XA_DATAFORMAT_MIME, (XAchar *)"video/mp2ts", XA_CONTAINERTYPE_MPEG_TS }; 3462f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi XADataSource dataSrc = {&loc_abq, &format_mime}; 3479a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 3489a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // configure audio sink 349f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi XADataLocator_OutputMix loc_outmix = { XA_DATALOCATOR_OUTPUTMIX, outputMixObject }; 350f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi XADataSink audioSnk = { &loc_outmix, NULL }; 3519a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 3529a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // configure image video sink 35373d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi XADataLocator_NativeDisplay loc_nd = { 35413a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten XA_DATALOCATOR_NATIVEDISPLAY, // locatorType 35549dfad6a8f91f0cce729f6db143f26c188caf523Glenn Kasten // the video sink must be an ANativeWindow created from a Surface or SurfaceTexture 35613a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten (void*)theNativeWindow, // hWindow 35713a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten // must be NULL 35813a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten NULL // hDisplay 35913a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten }; 3609a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten XADataSink imageVideoSink = {&loc_nd, NULL}; 3619a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 3622f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi // declare interfaces to use 363fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi XAboolean required[NB_MAXAL_INTERFACES] 364fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi = {XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE}; 365fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi XAInterfaceID iidArray[NB_MAXAL_INTERFACES] 366c3d6dd225415ac68b1868575e793eb352c7105e2Glenn Kasten = {XA_IID_PLAY, XA_IID_ANDROIDBUFFERQUEUESOURCE, 367c3d6dd225415ac68b1868575e793eb352c7105e2Glenn Kasten XA_IID_STREAMINFORMATION}; 368fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi 3692f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi 3709a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // create media player 3712f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi res = (*engineEngine)->CreateMediaPlayer(engineEngine, &playerObj, &dataSrc, 3722f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi NULL, &audioSnk, &imageVideoSink, NULL, NULL, 373f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi NB_MAXAL_INTERFACES /*XAuint32 numInterfaces*/, 3742f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi iidArray /*const XAInterfaceID *pInterfaceIds*/, 3752f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi required /*const XAboolean *pInterfaceRequired*/); 3762f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 3779a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 3789a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // release the Java string and UTF-8 3799a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten (*env)->ReleaseStringUTFChars(env, filename, utf8); 3809a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 3819a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // realize the player 3822f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi res = (*playerObj)->Realize(playerObj, XA_BOOLEAN_FALSE); 3832f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 3849a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 3859a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // get the play interface 3862f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi res = (*playerObj)->GetInterface(playerObj, XA_IID_PLAY, &playerPlayItf); 3872f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 3882f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi 389fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi // get the stream information interface (for video size) 390fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi res = (*playerObj)->GetInterface(playerObj, XA_IID_STREAMINFORMATION, &playerStreamInfoItf); 391fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 392fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi 393fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi // get the volume interface 394fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi res = (*playerObj)->GetInterface(playerObj, XA_IID_VOLUME, &playerVolItf); 395fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 396fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi 3972f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi // get the Android buffer queue interface 398c3d6dd225415ac68b1868575e793eb352c7105e2Glenn Kasten res = (*playerObj)->GetInterface(playerObj, XA_IID_ANDROIDBUFFERQUEUESOURCE, &playerBQItf); 3992f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 4002f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi 40134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // specify which events we want to be notified of 40234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten res = (*playerBQItf)->SetCallbackEventsMask(playerBQItf, XA_ANDROIDBUFFERQUEUEEVENT_PROCESSED); 40334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 4042f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi // register the callback from which OpenMAX AL can retrieve the data to play 405f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi res = (*playerBQItf)->RegisterCallback(playerBQItf, AndroidBufferQueueCallback, NULL); 406fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 407fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi 408fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi // we want to be notified of the video size once it's found, so we register a callback for that 409fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi res = (*playerStreamInfoItf)->RegisterStreamChangeCallback(playerStreamInfoItf, 410fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi StreamChangeCallback, NULL); 411f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi 41234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // enqueue the initial buffers 41334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten if (!enqueueInitialBuffers(JNI_FALSE)) { 414f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi return JNI_FALSE; 415f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi } 416f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi 4172f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi // prepare the player 4182f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PAUSED); 4192f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 4202f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi 421fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi // set the volume 422fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi res = (*playerVolItf)->SetVolumeLevel(playerVolItf, 0);//-300); 423fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 424fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi 425fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi // start the playback 4262f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PLAYING); 4272f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 4289a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4299a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten return JNI_TRUE; 4309a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten} 4319a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4329a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4339a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// set the playing state for the streaming media player 4349a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setPlayingStreamingMediaPlayer(JNIEnv* env, 4359a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten jclass clazz, jboolean isPlaying) 4369a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{ 4372f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi XAresult res; 4389a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4399a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // make sure the streaming media player was created 4402f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi if (NULL != playerPlayItf) { 4419a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4429a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // set the player's state 4432f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi res = (*playerPlayItf)->SetPlayState(playerPlayItf, isPlaying ? 4449a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten XA_PLAYSTATE_PLAYING : XA_PLAYSTATE_PAUSED); 4452f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 4469a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4479a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten } 4489a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4499a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten} 4509a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4519a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4529a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// shut down the native media system 4539a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_shutdown(JNIEnv* env, jclass clazz) 4549a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{ 4559a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // destroy streaming media player object, and invalidate all associated interfaces 4562f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi if (playerObj != NULL) { 4572f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi (*playerObj)->Destroy(playerObj); 4582f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi playerObj = NULL; 4592f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi playerPlayItf = NULL; 4602f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi playerBQItf = NULL; 46134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten playerStreamInfoItf = NULL; 46234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten playerVolItf = NULL; 4639a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten } 4649a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4659a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // destroy output mix object, and invalidate all associated interfaces 4669a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten if (outputMixObject != NULL) { 4679a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten (*outputMixObject)->Destroy(outputMixObject); 4689a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten outputMixObject = NULL; 4699a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten } 4709a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4719a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // destroy engine object, and invalidate all associated interfaces 4729a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten if (engineObject != NULL) { 4739a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten (*engineObject)->Destroy(engineObject); 4749a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten engineObject = NULL; 4759a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten engineEngine = NULL; 4769a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten } 4779a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4782f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi // close the file 4792f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi if (file != NULL) { 4802f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi fclose(file); 4812a1042f54c8e61a0c2a062709367093100ea6f8fGlenn Kasten file = NULL; 4822f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi } 48373d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi 48473d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi // make sure we don't leak native windows 48513a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten if (theNativeWindow != NULL) { 48613a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten ANativeWindow_release(theNativeWindow); 4872a1042f54c8e61a0c2a062709367093100ea6f8fGlenn Kasten theNativeWindow = NULL; 48813a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten } 4899a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten} 4909a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4919a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4929a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// set the surface 4939a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setSurface(JNIEnv *env, jclass clazz, jobject surface) 4949a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{ 49573d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi // obtain a native window from a Java surface 49673d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi theNativeWindow = ANativeWindow_fromSurface(env, surface); 49713a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten} 49813a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten 49913a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten 50013a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten// set the surface texture 50113a07de046bce3663b905a892dbaf770a54d982dGlenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setSurfaceTexture(JNIEnv *env, jclass clazz, 50213a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten jobject surfaceTexture) 50313a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten{ 50413a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten // obtain a native window from a Java surface texture 50513a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten theNativeWindow = ANativeWindow_fromSurfaceTexture(env, surfaceTexture); 5069a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten} 50734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 50834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 50934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten// rewind the streaming media player 51034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_rewindStreamingMediaPlayer(JNIEnv *env, jclass clazz) 51134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten{ 51234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten XAresult res; 51334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 51434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // make sure the streaming media player was created 51534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten if (NULL != playerBQItf && NULL != file) { 51634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // first wait for buffers currently in queue to be drained 51734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten int ok; 51834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten ok = pthread_mutex_lock(&mutex); 51934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(0 == ok); 52034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten discontinuity = JNI_TRUE; 52134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // wait for discontinuity request to be observed by buffer queue callback 52234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // FIXME sorry, can't rewind after EOS 52334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten while (discontinuity && !reachedEof) { 52434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten ok = pthread_cond_wait(&cond, &mutex); 52534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(0 == ok); 52634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten } 52734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten ok = pthread_mutex_unlock(&mutex); 52834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(0 == ok); 52934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten } 53034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 53134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten} 532