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 72e5c2733e99086fb726db9c1cf6cb3f04ae08defbJean-Michel Trivi// constant to identify a buffer context which is the end of the stream to decode 73e5c2733e99086fb726db9c1cf6cb3f04ae08defbJean-Michel Trivistatic const int kEosBufferCntxt = 1980; // a magic value we can compare against 74e5c2733e99086fb726db9c1cf6cb3f04ae08defbJean-Michel Trivi 7534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten// for mutual exclusion between callback thread and application thread(s) 7634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenpthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 7734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenpthread_cond_t cond = PTHREAD_COND_INITIALIZER; 7834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 7934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten// whether a discontinuity is in progress 8034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenjboolean discontinuity = JNI_FALSE; 8134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 8234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenstatic jboolean enqueueInitialBuffers(jboolean discontinuity); 832f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi 84f419fe271ff98424c9f0ddef13f436d4fb1ba538Jean-Michel Trivi// Callback for XAPlayItf through which we receive the XA_PLAYEVENT_HEADATEND event */ 85f419fe271ff98424c9f0ddef13f436d4fb1ba538Jean-Michel Trivivoid PlayCallback(XAPlayItf caller, void *pContext, XAuint32 event) { 86f419fe271ff98424c9f0ddef13f436d4fb1ba538Jean-Michel Trivi if (event & XA_PLAYEVENT_HEADATEND) { 87f419fe271ff98424c9f0ddef13f436d4fb1ba538Jean-Michel Trivi LOGV("XA_PLAYEVENT_HEADATEND received, all MP2TS data has been decoded\n"); 88f419fe271ff98424c9f0ddef13f436d4fb1ba538Jean-Michel Trivi } 89f419fe271ff98424c9f0ddef13f436d4fb1ba538Jean-Michel Trivi} 90f419fe271ff98424c9f0ddef13f436d4fb1ba538Jean-Michel Trivi 912f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi// AndroidBufferQueueItf callback for an audio player 922f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel TriviXAresult AndroidBufferQueueCallback( 932f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi XAAndroidBufferQueueItf caller, 94fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi void *pCallbackContext, /* input */ 95fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi void *pBufferContext, /* input */ 96fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi void *pBufferData, /* input */ 97f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi XAuint32 dataSize, /* input */ 98f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi XAuint32 dataUsed, /* input */ 99f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi const XAAndroidBufferItem *pItems,/* input */ 100f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi XAuint32 itemsLength /* input */) 1012f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi{ 10234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten XAresult res; 10334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten int ok; 10434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 10534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // pCallbackContext was specified as NULL at RegisterCallback and is unused here 10634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(NULL == pCallbackContext); 10734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 10834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // note there is never any contention on this mutex unless a discontinuity request is active 10934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten ok = pthread_mutex_lock(&mutex); 11034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(0 == ok); 11134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 11234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // was a discontinuity requested? 11334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten if (discontinuity) { 11434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // FIXME sorry, can't rewind after EOS 11534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten if (!reachedEof) { 11634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // clear the buffer queue 11734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten res = (*playerBQItf)->Clear(playerBQItf); 11834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(XA_RESULT_SUCCESS == res); 11934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // rewind the data source so we are guaranteed to be at an appropriate point 12034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten rewind(file); 12134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // Enqueue the initial buffers, with a discontinuity indicator on first buffer 12234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten (void) enqueueInitialBuffers(JNI_TRUE); 12334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten } 12434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // acknowledge the discontinuity request 12534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten discontinuity = JNI_FALSE; 12634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten ok = pthread_cond_signal(&cond); 12734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(0 == ok); 12834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten goto exit; 12934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten } 13034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 131e5c2733e99086fb726db9c1cf6cb3f04ae08defbJean-Michel Trivi if ((pBufferData == NULL) && (pBufferContext != NULL)) { 132e5c2733e99086fb726db9c1cf6cb3f04ae08defbJean-Michel Trivi const int processedCommand = *(int *)pBufferContext; 133e5c2733e99086fb726db9c1cf6cb3f04ae08defbJean-Michel Trivi if (kEosBufferCntxt == processedCommand) { 134e5c2733e99086fb726db9c1cf6cb3f04ae08defbJean-Michel Trivi LOGV("EOS was processed\n"); 135e5c2733e99086fb726db9c1cf6cb3f04ae08defbJean-Michel Trivi // our buffer with the EOS message has been consumed 136e5c2733e99086fb726db9c1cf6cb3f04ae08defbJean-Michel Trivi assert(0 == dataSize); 137e5c2733e99086fb726db9c1cf6cb3f04ae08defbJean-Michel Trivi goto exit; 138e5c2733e99086fb726db9c1cf6cb3f04ae08defbJean-Michel Trivi } 139fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi } 140fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi 14134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // pBufferData is a pointer to a buffer that we previously Enqueued 14234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(BUFFER_SIZE == dataSize); 14334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(dataCache <= (char *) pBufferData && (char *) pBufferData < 14434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten &dataCache[BUFFER_SIZE * NB_BUFFERS]); 14534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(0 == (((char *) pBufferData - dataCache) % BUFFER_SIZE)); 14634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 147fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi#if 0 148fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi // sample code to use the XAVolumeItf 149fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi XAAndroidBufferQueueState state; 150fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi (*caller)->GetState(caller, &state); 151fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi switch (state.index) { 152fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi case 300: 153fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi (*playerVolItf)->SetVolumeLevel(playerVolItf, -600); // -6dB 154fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi LOGV("setting volume to -6dB"); 155fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi break; 156fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi case 400: 157fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi (*playerVolItf)->SetVolumeLevel(playerVolItf, -1200); // -12dB 158fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi LOGV("setting volume to -12dB"); 159fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi break; 160fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi case 500: 161fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi (*playerVolItf)->SetVolumeLevel(playerVolItf, 0); // full volume 162fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi LOGV("setting volume to 0dB (full volume)"); 163fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi break; 164fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi case 600: 165fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi (*playerVolItf)->SetMute(playerVolItf, XA_BOOLEAN_TRUE); // mute 166fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi LOGV("muting player"); 167fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi break; 168fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi case 700: 169fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi (*playerVolItf)->SetMute(playerVolItf, XA_BOOLEAN_FALSE); // unmute 170fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi LOGV("unmuting player"); 171fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi break; 172fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi case 800: 173fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi (*playerVolItf)->SetStereoPosition(playerVolItf, -1000); 174fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi (*playerVolItf)->EnableStereoPosition(playerVolItf, XA_BOOLEAN_TRUE); 175fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi LOGV("pan sound to the left (hard-left)"); 176fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi break; 177fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi case 900: 178fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi (*playerVolItf)->EnableStereoPosition(playerVolItf, XA_BOOLEAN_FALSE); 179fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi LOGV("disabling stereo position"); 180fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi break; 181fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi default: 182fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi break; 183fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi } 184fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi#endif 185fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi 18634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // don't bother trying to read more data once we've hit EOF 18734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten if (reachedEof) { 18834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten goto exit; 18934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten } 19034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 19134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten size_t nbRead; 19234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // note we do call fread from multiple threads, but never concurrently 19334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten nbRead = fread(pBufferData, BUFFER_SIZE, 1, file); 19434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten if (nbRead > 0) { 19534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(1 == nbRead); 19634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten res = (*caller)->Enqueue(caller, NULL /*pBufferContext*/, 197f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi pBufferData /*pData*/, 19834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten nbRead * BUFFER_SIZE /*dataLength*/, 199f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi NULL /*pMsg*/, 200f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi 0 /*msgLength*/); 20134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(XA_RESULT_SUCCESS == res); 20234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten } else { 203f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi // signal EOS 20434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten XAAndroidBufferItem msgEos[1]; 20534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten msgEos[0].itemKey = XA_ANDROID_ITEMKEY_EOS; 20634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten msgEos[0].itemSize = 0; 207f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi // EOS message has no parameters, so the total size of the message is the size of the key 208f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi // plus the size if itemSize, both XAuint32 209e5c2733e99086fb726db9c1cf6cb3f04ae08defbJean-Michel Trivi res = (*caller)->Enqueue(caller, (void *)&kEosBufferCntxt /*pBufferContext*/, 210fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi NULL /*pData*/, 0 /*dataLength*/, 21134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten msgEos /*pMsg*/, 21234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // FIXME == sizeof(BufferItem)? */ 213fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi sizeof(XAuint32)*2 /*msgLength*/); 21434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(XA_RESULT_SUCCESS == res); 21534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten reachedEof = JNI_TRUE; 2162f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi } 2172f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi 21834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenexit: 21934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten ok = pthread_mutex_unlock(&mutex); 22034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(0 == ok); 2212f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi return XA_RESULT_SUCCESS; 2222f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi} 2232f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi 2242f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi 225fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivivoid StreamChangeCallback (XAStreamInformationItf caller, 226fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi XAuint32 eventId, 227fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi XAuint32 streamIndex, 228fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi void * pEventData, 229fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi void * pContext ) 230fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi{ 23134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten LOGV("StreamChangeCallback called for stream %u", streamIndex); 23234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // pContext was specified as NULL at RegisterStreamChangeCallback and is unused here 23334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(NULL == pContext); 23434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten switch (eventId) { 23534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten case XA_STREAMCBEVENT_PROPERTYCHANGE: { 23634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten /** From spec 1.0.1: 23734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten "This event indicates that stream property change has occurred. 23834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten The streamIndex parameter identifies the stream with the property change. 23934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten The pEventData parameter for this event is not used and shall be ignored." 24034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten */ 24134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 24234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten XAresult res; 243fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi XAuint32 domain; 24434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten res = (*caller)->QueryStreamType(caller, streamIndex, &domain); 24534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(XA_RESULT_SUCCESS == res); 24634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten switch (domain) { 24734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten case XA_DOMAINTYPE_VIDEO: { 24834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten XAVideoStreamInformation videoInfo; 24934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten res = (*caller)->QueryStreamInformation(caller, streamIndex, &videoInfo); 25034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(XA_RESULT_SUCCESS == res); 25134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten LOGI("Found video size %u x %u, codec ID=%u, frameRate=%u, bitRate=%u, duration=%u ms", 25234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten videoInfo.width, videoInfo.height, videoInfo.codecId, videoInfo.frameRate, 25334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten videoInfo.bitRate, videoInfo.duration); 25434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten } break; 25534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten default: 25634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten fprintf(stderr, "Unexpected domain %u\n", domain); 25734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten break; 258fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi } 25934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten } break; 26034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten default: 26134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten fprintf(stderr, "Unexpected stream event ID %u\n", eventId); 26234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten break; 263fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi } 264fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi} 265fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi 266fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi 2679a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// create the engine and output mix objects 2689a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_createEngine(JNIEnv* env, jclass clazz) 2699a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{ 2702f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi XAresult res; 2719a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 2729a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // create engine 2732f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi res = xaCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); 2742f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 2759a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 2769a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // realize the engine 2772f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi res = (*engineObject)->Realize(engineObject, XA_BOOLEAN_FALSE); 2782f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 2799a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 2809a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // get the engine interface, which is needed in order to create other objects 2812f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi res = (*engineObject)->GetInterface(engineObject, XA_IID_ENGINE, &engineEngine); 2822f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 2839a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 2849a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // create output mix 2852f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi res = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL); 2862f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 2879a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 2889a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // realize the output mix 2892f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi res = (*outputMixObject)->Realize(outputMixObject, XA_BOOLEAN_FALSE); 2902f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 2919a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 2929a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten} 2939a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 2949a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 29534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten// Enqueue the initial buffers, and optionally signal a discontinuity in the first buffer 29634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenstatic jboolean enqueueInitialBuffers(jboolean discontinuity) 29734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten{ 29834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 29934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten /* Fill our cache */ 30034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten size_t nbRead; 30134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten nbRead = fread(dataCache, BUFFER_SIZE, NB_BUFFERS, file); 30234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten if (nbRead <= 0) { 30334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // could be premature EOF or I/O error 30434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten LOGE("Error filling cache, exiting\n"); 30534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten return JNI_FALSE; 30634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten } 30734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(1 <= nbRead && nbRead <= NB_BUFFERS); 30834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten LOGV("Initially queueing %u buffers of %u bytes each", nbRead, BUFFER_SIZE); 30934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 31034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten /* Enqueue the content of our cache before starting to play, 31134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten we don't want to starve the player */ 31234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten size_t i; 31334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten for (i = 0; i < nbRead; i++) { 31434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten XAresult res; 31534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten if (discontinuity) { 31634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // signal discontinuity 31734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten XAAndroidBufferItem items[1]; 31834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten items[0].itemKey = XA_ANDROID_ITEMKEY_DISCONTINUITY; 31934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten items[0].itemSize = 0; 32034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // DISCONTINUITY message has no parameters, 32134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // so the total size of the message is the size of the key 32234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // plus the size if itemSize, both XAuint32 32334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten res = (*playerBQItf)->Enqueue(playerBQItf, NULL /*pBufferContext*/, 32434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten dataCache + i*BUFFER_SIZE, BUFFER_SIZE, items /*pMsg*/, 32534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // FIXME == sizeof(BufferItem)? */ 32634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten sizeof(XAuint32)*2 /*msgLength*/); 32734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten discontinuity = JNI_FALSE; 32834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten } else { 32934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten res = (*playerBQItf)->Enqueue(playerBQItf, NULL /*pBufferContext*/, 33034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten dataCache + i*BUFFER_SIZE, BUFFER_SIZE, NULL, 0); 33134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten } 33234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(XA_RESULT_SUCCESS == res); 33334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten } 33434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 33534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten return JNI_TRUE; 33634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten} 33734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 33834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 3399a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// create streaming media player 3409a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenjboolean Java_com_example_nativemedia_NativeMedia_createStreamingMediaPlayer(JNIEnv* env, 3419a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten jclass clazz, jstring filename) 3429a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{ 3432f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi XAresult res; 3449a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 3459a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // convert Java string to UTF-8 3469a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten const char *utf8 = (*env)->GetStringUTFChars(env, filename, NULL); 3479a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten assert(NULL != utf8); 3489a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 3492f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi // open the file to play 3502f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi file = fopen(utf8, "rb"); 3512f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi if (file == NULL) { 3522f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi LOGE("Failed to open %s", utf8); 3532f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi return JNI_FALSE; 3542f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi } 3552f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi 3562f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi // configure data source 357f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi XADataLocator_AndroidBufferQueue loc_abq = { XA_DATALOCATOR_ANDROIDBUFFERQUEUE, NB_BUFFERS }; 358f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi XADataFormat_MIME format_mime = { 359adf3525f038c77f6a122b4e88762bde9cc0a48bbGlenn Kasten XA_DATAFORMAT_MIME, XA_ANDROID_MIME_MP2TS, XA_CONTAINERTYPE_MPEG_TS }; 3602f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi XADataSource dataSrc = {&loc_abq, &format_mime}; 3619a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 3629a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // configure audio sink 363f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi XADataLocator_OutputMix loc_outmix = { XA_DATALOCATOR_OUTPUTMIX, outputMixObject }; 364f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi XADataSink audioSnk = { &loc_outmix, NULL }; 3659a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 3669a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // configure image video sink 36773d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi XADataLocator_NativeDisplay loc_nd = { 36813a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten XA_DATALOCATOR_NATIVEDISPLAY, // locatorType 36949dfad6a8f91f0cce729f6db143f26c188caf523Glenn Kasten // the video sink must be an ANativeWindow created from a Surface or SurfaceTexture 37013a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten (void*)theNativeWindow, // hWindow 37113a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten // must be NULL 37213a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten NULL // hDisplay 37313a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten }; 3749a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten XADataSink imageVideoSink = {&loc_nd, NULL}; 3759a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 3762f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi // declare interfaces to use 377fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi XAboolean required[NB_MAXAL_INTERFACES] 378fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi = {XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE}; 379fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi XAInterfaceID iidArray[NB_MAXAL_INTERFACES] 380c3d6dd225415ac68b1868575e793eb352c7105e2Glenn Kasten = {XA_IID_PLAY, XA_IID_ANDROIDBUFFERQUEUESOURCE, 381c3d6dd225415ac68b1868575e793eb352c7105e2Glenn Kasten XA_IID_STREAMINFORMATION}; 382fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi 3832f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi 3849a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // create media player 3852f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi res = (*engineEngine)->CreateMediaPlayer(engineEngine, &playerObj, &dataSrc, 3862f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi NULL, &audioSnk, &imageVideoSink, NULL, NULL, 387f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi NB_MAXAL_INTERFACES /*XAuint32 numInterfaces*/, 3882f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi iidArray /*const XAInterfaceID *pInterfaceIds*/, 3892f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi required /*const XAboolean *pInterfaceRequired*/); 3902f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 3919a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 3929a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // release the Java string and UTF-8 3939a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten (*env)->ReleaseStringUTFChars(env, filename, utf8); 3949a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 3959a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // realize the player 3962f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi res = (*playerObj)->Realize(playerObj, XA_BOOLEAN_FALSE); 3972f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 3989a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 3999a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // get the play interface 4002f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi res = (*playerObj)->GetInterface(playerObj, XA_IID_PLAY, &playerPlayItf); 4012f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 4022f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi 403fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi // get the stream information interface (for video size) 404fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi res = (*playerObj)->GetInterface(playerObj, XA_IID_STREAMINFORMATION, &playerStreamInfoItf); 405fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 406fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi 407fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi // get the volume interface 408fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi res = (*playerObj)->GetInterface(playerObj, XA_IID_VOLUME, &playerVolItf); 409fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 410fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi 4112f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi // get the Android buffer queue interface 412c3d6dd225415ac68b1868575e793eb352c7105e2Glenn Kasten res = (*playerObj)->GetInterface(playerObj, XA_IID_ANDROIDBUFFERQUEUESOURCE, &playerBQItf); 4132f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 4142f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi 41534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // specify which events we want to be notified of 41634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten res = (*playerBQItf)->SetCallbackEventsMask(playerBQItf, XA_ANDROIDBUFFERQUEUEEVENT_PROCESSED); 41734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 418f419fe271ff98424c9f0ddef13f436d4fb1ba538Jean-Michel Trivi // use the play interface to set up a callback for the XA_PLAYEVENT_HEADATEND event */ 419f419fe271ff98424c9f0ddef13f436d4fb1ba538Jean-Michel Trivi res = (*playerPlayItf)->SetCallbackEventsMask(playerPlayItf, XA_PLAYEVENT_HEADATEND); 420f419fe271ff98424c9f0ddef13f436d4fb1ba538Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 421f419fe271ff98424c9f0ddef13f436d4fb1ba538Jean-Michel Trivi res = (*playerPlayItf)->RegisterCallback(playerPlayItf, 422f419fe271ff98424c9f0ddef13f436d4fb1ba538Jean-Michel Trivi PlayCallback /*callback*/, NULL /*pContext*/); 423f419fe271ff98424c9f0ddef13f436d4fb1ba538Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 424f419fe271ff98424c9f0ddef13f436d4fb1ba538Jean-Michel Trivi 4252f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi // register the callback from which OpenMAX AL can retrieve the data to play 426f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi res = (*playerBQItf)->RegisterCallback(playerBQItf, AndroidBufferQueueCallback, NULL); 427fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 428fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi 429fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi // we want to be notified of the video size once it's found, so we register a callback for that 430fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi res = (*playerStreamInfoItf)->RegisterStreamChangeCallback(playerStreamInfoItf, 431fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi StreamChangeCallback, NULL); 432f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi 43334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // enqueue the initial buffers 43434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten if (!enqueueInitialBuffers(JNI_FALSE)) { 435f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi return JNI_FALSE; 436f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi } 437f65b260193e5ca669ec4479a7e1c4517e18cc6b0Jean-Michel Trivi 4382f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi // prepare the player 4392f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PAUSED); 4402f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 4412f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi 442fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi // set the volume 443fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi res = (*playerVolItf)->SetVolumeLevel(playerVolItf, 0);//-300); 444fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 445fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi 446fcc996296bdbf6c3949ad4312991fdde4ae2e157Jean-Michel Trivi // start the playback 4472f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PLAYING); 4482f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 4499a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4509a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten return JNI_TRUE; 4519a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten} 4529a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4539a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4549a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// set the playing state for the streaming media player 4559a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setPlayingStreamingMediaPlayer(JNIEnv* env, 4569a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten jclass clazz, jboolean isPlaying) 4579a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{ 4582f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi XAresult res; 4599a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4609a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // make sure the streaming media player was created 4612f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi if (NULL != playerPlayItf) { 4629a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4639a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // set the player's state 4642f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi res = (*playerPlayItf)->SetPlayState(playerPlayItf, isPlaying ? 4659a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten XA_PLAYSTATE_PLAYING : XA_PLAYSTATE_PAUSED); 4662f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 4679a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4689a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten } 4699a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4709a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten} 4719a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4729a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4739a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// shut down the native media system 4749a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_shutdown(JNIEnv* env, jclass clazz) 4759a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{ 4769a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // destroy streaming media player object, and invalidate all associated interfaces 4772f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi if (playerObj != NULL) { 4782f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi (*playerObj)->Destroy(playerObj); 4792f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi playerObj = NULL; 4802f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi playerPlayItf = NULL; 4812f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi playerBQItf = NULL; 48234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten playerStreamInfoItf = NULL; 48334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten playerVolItf = NULL; 4849a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten } 4859a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4869a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // destroy output mix object, and invalidate all associated interfaces 4879a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten if (outputMixObject != NULL) { 4889a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten (*outputMixObject)->Destroy(outputMixObject); 4899a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten outputMixObject = NULL; 4909a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten } 4919a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4929a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten // destroy engine object, and invalidate all associated interfaces 4939a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten if (engineObject != NULL) { 4949a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten (*engineObject)->Destroy(engineObject); 4959a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten engineObject = NULL; 4969a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten engineEngine = NULL; 4979a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten } 4989a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 4992f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi // close the file 5002f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi if (file != NULL) { 5012f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi fclose(file); 5022a1042f54c8e61a0c2a062709367093100ea6f8fGlenn Kasten file = NULL; 5032f4002b9f37501cd15a7e06cd8e19453d2770f30Jean-Michel Trivi } 50473d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi 50573d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi // make sure we don't leak native windows 50613a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten if (theNativeWindow != NULL) { 50713a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten ANativeWindow_release(theNativeWindow); 5082a1042f54c8e61a0c2a062709367093100ea6f8fGlenn Kasten theNativeWindow = NULL; 50913a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten } 5109a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten} 5119a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 5129a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten 5139a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten// set the surface 5149a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setSurface(JNIEnv *env, jclass clazz, jobject surface) 5159a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten{ 51673d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi // obtain a native window from a Java surface 51773d888bb7b15745c6456dc0fab97c39854827d2aJean-Michel Trivi theNativeWindow = ANativeWindow_fromSurface(env, surface); 51813a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten} 51913a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten 52013a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten 52113a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten// set the surface texture 52213a07de046bce3663b905a892dbaf770a54d982dGlenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setSurfaceTexture(JNIEnv *env, jclass clazz, 52313a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten jobject surfaceTexture) 52413a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten{ 52513a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten // obtain a native window from a Java surface texture 52613a07de046bce3663b905a892dbaf770a54d982dGlenn Kasten theNativeWindow = ANativeWindow_fromSurfaceTexture(env, surfaceTexture); 5279a709c6410ac6fd3da51dd02dda72071c5bb9310Glenn Kasten} 52834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 52934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 53034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten// rewind the streaming media player 53134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_rewindStreamingMediaPlayer(JNIEnv *env, jclass clazz) 53234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten{ 53334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten XAresult res; 53434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 53534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // make sure the streaming media player was created 53634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten if (NULL != playerBQItf && NULL != file) { 53734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // first wait for buffers currently in queue to be drained 53834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten int ok; 53934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten ok = pthread_mutex_lock(&mutex); 54034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(0 == ok); 54134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten discontinuity = JNI_TRUE; 54234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // wait for discontinuity request to be observed by buffer queue callback 54334294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten // FIXME sorry, can't rewind after EOS 54434294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten while (discontinuity && !reachedEof) { 54534294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten ok = pthread_cond_wait(&cond, &mutex); 54634294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(0 == ok); 54734294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten } 54834294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten ok = pthread_mutex_unlock(&mutex); 54934294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten assert(0 == ok); 55034294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten } 55134294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten 55234294d068e5560ee29e1e326b7bf49a7068e6cb0Glenn Kasten} 553