native-media-jni.c revision 6bc8af4e67051af7c86c311cb9c50e294e547500
197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten/* 297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten * Copyright (C) 2010 The Android Open Source Project 397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten * 497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten * Licensed under the Apache License, Version 2.0 (the "License"); 597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten * you may not use this file except in compliance with the License. 697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten * You may obtain a copy of the License at 797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten * 897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten * http://www.apache.org/licenses/LICENSE-2.0 997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten * 1097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten * Unless required by applicable law or agreed to in writing, software 1197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten * distributed under the License is distributed on an "AS IS" BASIS, 1297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten * See the License for the specific language governing permissions and 1497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten * limitations under the License. 1597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten */ 1697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 1797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten#include <assert.h> 1897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten#include <jni.h> 1997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten#include <pthread.h> 2097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten#include <string.h> 21ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten//#define LOG_NDEBUG 0 2297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten#define LOG_TAG "NativeMedia" 2397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten#include <utils/Log.h> 24f183d0fd23f1c0f45ceaf280d404f1b0709a699aJean-Michel Trivi 25c6853892c94800e72c0bd676d5d2136d48cea76eGlenn Kasten#include <OMXAL/OpenMAXAL.h> 26c6853892c94800e72c0bd676d5d2136d48cea76eGlenn Kasten#include <OMXAL/OpenMAXAL_Android.h> 27f183d0fd23f1c0f45ceaf280d404f1b0709a699aJean-Michel Trivi 28295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi#include <android/native_window_jni.h> 2997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 3097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// engine interfaces 3197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenstatic XAObjectItf engineObject = NULL; 32ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kastenstatic XAEngineItf engineEngine = NULL; 3397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 3497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// output mix interfaces 3597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenstatic XAObjectItf outputMixObject = NULL; 3697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 3797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// streaming media player interfaces 38eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivistatic XAObjectItf playerObj = NULL; 39eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivistatic XAPlayItf playerPlayItf = NULL; 40eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivistatic XAAndroidBufferQueueItf playerBQItf = NULL; 4137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivistatic XAStreamInformationItf playerStreamInfoItf = NULL; 42ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kastenstatic XAVolumeItf playerVolItf = NULL; 43ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 44d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi// number of required interfaces for the MediaPlayer creation 4537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi#define NB_MAXAL_INTERFACES 3 // XAAndroidBufferQueueItf, XAStreamInformationItf and XAPlayItf 4697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 4739310fca2e30101fa6e5168da443581cc60c20bfGlenn Kasten// video sink for the player 48295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivistatic ANativeWindow* theNativeWindow; 4997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 50ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten// number of buffers in our buffer queue, an arbitrary number 51d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi#define NB_BUFFERS 16 52ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 53d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi// we're streaming MPEG-2 transport stream data, operate on transport stream block size 54d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi#define MPEG2_TS_BLOCK_SIZE 188 55ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 56ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten// number of MPEG-2 transport stream blocks per buffer, an arbitrary number 57ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten#define BLOCKS_PER_BUFFER 20 58ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 59d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi// determines how much memory we're dedicating to memory caching 60ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten#define BUFFER_SIZE (BLOCKS_PER_BUFFER*MPEG2_TS_BLOCK_SIZE) 61d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi 62d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi// where we cache in memory the data to play 63ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten// note this memory is re-used by the buffer queue callback 64d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivichar dataCache[BUFFER_SIZE * NB_BUFFERS]; 65ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 66eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi// handle of the file to play 67eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel TriviFILE *file; 68ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 6970c49ae2867094072a4365423417ea452bf82231Jean-Michel Trivi// has the app reached the end of the file 70ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kastenjboolean reachedEof = JNI_FALSE; 71ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 726bc8af4e67051af7c86c311cb9c50e294e547500Jean-Michel Trivi// constant to identify a buffer context which is the end of the stream to decode 736bc8af4e67051af7c86c311cb9c50e294e547500Jean-Michel Trivistatic const int kEosBufferCntxt = 1980; // a magic value we can compare against 746bc8af4e67051af7c86c311cb9c50e294e547500Jean-Michel Trivi 75ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten// for mutual exclusion between callback thread and application thread(s) 76ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kastenpthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 77ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kastenpthread_cond_t cond = PTHREAD_COND_INITIALIZER; 78ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 79ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten// whether a discontinuity is in progress 80ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kastenjboolean discontinuity = JNI_FALSE; 81ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 82ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kastenstatic jboolean enqueueInitialBuffers(jboolean discontinuity); 83eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi 84eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi// AndroidBufferQueueItf callback for an audio player 85eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel TriviXAresult AndroidBufferQueueCallback( 86eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi XAAndroidBufferQueueItf caller, 8737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi void *pCallbackContext, /* input */ 8837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi void *pBufferContext, /* input */ 8937dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi void *pBufferData, /* input */ 90d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi XAuint32 dataSize, /* input */ 91d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi XAuint32 dataUsed, /* input */ 92d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi const XAAndroidBufferItem *pItems,/* input */ 93d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi XAuint32 itemsLength /* input */) 94eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi{ 95ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten XAresult res; 96ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten int ok; 97ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 98ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // pCallbackContext was specified as NULL at RegisterCallback and is unused here 99ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten assert(NULL == pCallbackContext); 100ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 101ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // note there is never any contention on this mutex unless a discontinuity request is active 102ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten ok = pthread_mutex_lock(&mutex); 103ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten assert(0 == ok); 104ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 105ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // was a discontinuity requested? 106ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten if (discontinuity) { 107ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // FIXME sorry, can't rewind after EOS 108ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten if (!reachedEof) { 109ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // clear the buffer queue 110ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten res = (*playerBQItf)->Clear(playerBQItf); 111ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten assert(XA_RESULT_SUCCESS == res); 112ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // rewind the data source so we are guaranteed to be at an appropriate point 113ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten rewind(file); 114ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // Enqueue the initial buffers, with a discontinuity indicator on first buffer 115ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten (void) enqueueInitialBuffers(JNI_TRUE); 116ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten } 117ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // acknowledge the discontinuity request 118ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten discontinuity = JNI_FALSE; 119ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten ok = pthread_cond_signal(&cond); 120ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten assert(0 == ok); 121ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten goto exit; 122ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten } 123ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 1246bc8af4e67051af7c86c311cb9c50e294e547500Jean-Michel Trivi if ((pBufferData == NULL) && (pBufferContext != NULL)) { 1256bc8af4e67051af7c86c311cb9c50e294e547500Jean-Michel Trivi const int processedCommand = *(int *)pBufferContext; 1266bc8af4e67051af7c86c311cb9c50e294e547500Jean-Michel Trivi if (kEosBufferCntxt == processedCommand) { 1276bc8af4e67051af7c86c311cb9c50e294e547500Jean-Michel Trivi LOGV("EOS was processed\n"); 1286bc8af4e67051af7c86c311cb9c50e294e547500Jean-Michel Trivi // our buffer with the EOS message has been consumed 1296bc8af4e67051af7c86c311cb9c50e294e547500Jean-Michel Trivi assert(0 == dataSize); 1306bc8af4e67051af7c86c311cb9c50e294e547500Jean-Michel Trivi goto exit; 1316bc8af4e67051af7c86c311cb9c50e294e547500Jean-Michel Trivi } 13237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi } 13337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi 134ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // pBufferData is a pointer to a buffer that we previously Enqueued 135ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten assert(BUFFER_SIZE == dataSize); 136ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten assert(dataCache <= (char *) pBufferData && (char *) pBufferData < 137ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten &dataCache[BUFFER_SIZE * NB_BUFFERS]); 138ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten assert(0 == (((char *) pBufferData - dataCache) % BUFFER_SIZE)); 139ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 14037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi#if 0 14137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi // sample code to use the XAVolumeItf 14237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi XAAndroidBufferQueueState state; 14337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi (*caller)->GetState(caller, &state); 14437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi switch (state.index) { 14537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi case 300: 14637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi (*playerVolItf)->SetVolumeLevel(playerVolItf, -600); // -6dB 14737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi LOGV("setting volume to -6dB"); 14837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi break; 14937dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi case 400: 15037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi (*playerVolItf)->SetVolumeLevel(playerVolItf, -1200); // -12dB 15137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi LOGV("setting volume to -12dB"); 15237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi break; 15337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi case 500: 15437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi (*playerVolItf)->SetVolumeLevel(playerVolItf, 0); // full volume 15537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi LOGV("setting volume to 0dB (full volume)"); 15637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi break; 15737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi case 600: 15837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi (*playerVolItf)->SetMute(playerVolItf, XA_BOOLEAN_TRUE); // mute 15937dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi LOGV("muting player"); 16037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi break; 16137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi case 700: 16237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi (*playerVolItf)->SetMute(playerVolItf, XA_BOOLEAN_FALSE); // unmute 16337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi LOGV("unmuting player"); 16437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi break; 16537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi case 800: 16637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi (*playerVolItf)->SetStereoPosition(playerVolItf, -1000); 16737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi (*playerVolItf)->EnableStereoPosition(playerVolItf, XA_BOOLEAN_TRUE); 16837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi LOGV("pan sound to the left (hard-left)"); 16937dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi break; 17037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi case 900: 17137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi (*playerVolItf)->EnableStereoPosition(playerVolItf, XA_BOOLEAN_FALSE); 17237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi LOGV("disabling stereo position"); 17337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi break; 17437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi default: 17537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi break; 17637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi } 17737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi#endif 17837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi 179ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // don't bother trying to read more data once we've hit EOF 180ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten if (reachedEof) { 181ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten goto exit; 182ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten } 183ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 184ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten size_t nbRead; 185ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // note we do call fread from multiple threads, but never concurrently 186ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten nbRead = fread(pBufferData, BUFFER_SIZE, 1, file); 187ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten if (nbRead > 0) { 188ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten assert(1 == nbRead); 189ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten res = (*caller)->Enqueue(caller, NULL /*pBufferContext*/, 190d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi pBufferData /*pData*/, 191ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten nbRead * BUFFER_SIZE /*dataLength*/, 192d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi NULL /*pMsg*/, 193d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi 0 /*msgLength*/); 194ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten assert(XA_RESULT_SUCCESS == res); 195ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten } else { 196d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi // signal EOS 197ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten XAAndroidBufferItem msgEos[1]; 198ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten msgEos[0].itemKey = XA_ANDROID_ITEMKEY_EOS; 199ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten msgEos[0].itemSize = 0; 200d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi // EOS message has no parameters, so the total size of the message is the size of the key 201d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi // plus the size if itemSize, both XAuint32 2026bc8af4e67051af7c86c311cb9c50e294e547500Jean-Michel Trivi res = (*caller)->Enqueue(caller, (void *)&kEosBufferCntxt /*pBufferContext*/, 20337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi NULL /*pData*/, 0 /*dataLength*/, 204ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten msgEos /*pMsg*/, 205ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // FIXME == sizeof(BufferItem)? */ 20637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi sizeof(XAuint32)*2 /*msgLength*/); 207ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten assert(XA_RESULT_SUCCESS == res); 208ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten reachedEof = JNI_TRUE; 209eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi } 210eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi 211ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kastenexit: 212ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten ok = pthread_mutex_unlock(&mutex); 213ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten assert(0 == ok); 214eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi return XA_RESULT_SUCCESS; 215eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi} 216eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi 217eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi 21837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivivoid StreamChangeCallback (XAStreamInformationItf caller, 21937dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi XAuint32 eventId, 22037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi XAuint32 streamIndex, 22137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi void * pEventData, 22237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi void * pContext ) 22337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi{ 224ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten LOGV("StreamChangeCallback called for stream %u", streamIndex); 225ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // pContext was specified as NULL at RegisterStreamChangeCallback and is unused here 226ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten assert(NULL == pContext); 227ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten switch (eventId) { 228ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten case XA_STREAMCBEVENT_PROPERTYCHANGE: { 229ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten /** From spec 1.0.1: 230ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten "This event indicates that stream property change has occurred. 231ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten The streamIndex parameter identifies the stream with the property change. 232ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten The pEventData parameter for this event is not used and shall be ignored." 233ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten */ 234ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 235ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten XAresult res; 23637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi XAuint32 domain; 237ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten res = (*caller)->QueryStreamType(caller, streamIndex, &domain); 238ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten assert(XA_RESULT_SUCCESS == res); 239ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten switch (domain) { 240ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten case XA_DOMAINTYPE_VIDEO: { 241ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten XAVideoStreamInformation videoInfo; 242ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten res = (*caller)->QueryStreamInformation(caller, streamIndex, &videoInfo); 243ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten assert(XA_RESULT_SUCCESS == res); 244ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten LOGI("Found video size %u x %u, codec ID=%u, frameRate=%u, bitRate=%u, duration=%u ms", 245ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten videoInfo.width, videoInfo.height, videoInfo.codecId, videoInfo.frameRate, 246ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten videoInfo.bitRate, videoInfo.duration); 247ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten } break; 248ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten default: 249ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten fprintf(stderr, "Unexpected domain %u\n", domain); 250ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten break; 25137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi } 252ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten } break; 253ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten default: 254ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten fprintf(stderr, "Unexpected stream event ID %u\n", eventId); 255ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten break; 25637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi } 25737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi} 25837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi 25937dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi 26097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// create the engine and output mix objects 26197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenvoid Java_com_example_nativemedia_NativeMedia_createEngine(JNIEnv* env, jclass clazz) 26297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{ 263eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi XAresult res; 26497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 26597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // create engine 266eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi res = xaCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); 267eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 26897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 26997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // realize the engine 270eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi res = (*engineObject)->Realize(engineObject, XA_BOOLEAN_FALSE); 271eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 27297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 27397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // get the engine interface, which is needed in order to create other objects 274eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi res = (*engineObject)->GetInterface(engineObject, XA_IID_ENGINE, &engineEngine); 275eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 27697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 27797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // create output mix 278eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi res = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL); 279eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 28097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 28197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // realize the output mix 282eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi res = (*outputMixObject)->Realize(outputMixObject, XA_BOOLEAN_FALSE); 283eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 28497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 28597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten} 28697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 28797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 288ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten// Enqueue the initial buffers, and optionally signal a discontinuity in the first buffer 289ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kastenstatic jboolean enqueueInitialBuffers(jboolean discontinuity) 290ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten{ 291ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 292ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten /* Fill our cache */ 293ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten size_t nbRead; 294ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten nbRead = fread(dataCache, BUFFER_SIZE, NB_BUFFERS, file); 295ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten if (nbRead <= 0) { 296ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // could be premature EOF or I/O error 297ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten LOGE("Error filling cache, exiting\n"); 298ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten return JNI_FALSE; 299ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten } 300ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten assert(1 <= nbRead && nbRead <= NB_BUFFERS); 301ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten LOGV("Initially queueing %u buffers of %u bytes each", nbRead, BUFFER_SIZE); 302ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 303ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten /* Enqueue the content of our cache before starting to play, 304ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten we don't want to starve the player */ 305ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten size_t i; 306ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten for (i = 0; i < nbRead; i++) { 307ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten XAresult res; 308ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten if (discontinuity) { 309ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // signal discontinuity 310ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten XAAndroidBufferItem items[1]; 311ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten items[0].itemKey = XA_ANDROID_ITEMKEY_DISCONTINUITY; 312ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten items[0].itemSize = 0; 313ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // DISCONTINUITY message has no parameters, 314ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // so the total size of the message is the size of the key 315ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // plus the size if itemSize, both XAuint32 316ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten res = (*playerBQItf)->Enqueue(playerBQItf, NULL /*pBufferContext*/, 317ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten dataCache + i*BUFFER_SIZE, BUFFER_SIZE, items /*pMsg*/, 318ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // FIXME == sizeof(BufferItem)? */ 319ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten sizeof(XAuint32)*2 /*msgLength*/); 320ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten discontinuity = JNI_FALSE; 321ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten } else { 322ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten res = (*playerBQItf)->Enqueue(playerBQItf, NULL /*pBufferContext*/, 323ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten dataCache + i*BUFFER_SIZE, BUFFER_SIZE, NULL, 0); 324ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten } 325ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten assert(XA_RESULT_SUCCESS == res); 326ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten } 327ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 328ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten return JNI_TRUE; 329ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten} 330ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 331ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 33297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// create streaming media player 33397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenjboolean Java_com_example_nativemedia_NativeMedia_createStreamingMediaPlayer(JNIEnv* env, 33497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten jclass clazz, jstring filename) 33597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{ 336eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi XAresult res; 33797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 33897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // convert Java string to UTF-8 33997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten const char *utf8 = (*env)->GetStringUTFChars(env, filename, NULL); 34097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten assert(NULL != utf8); 34197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 342eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi // open the file to play 343eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi file = fopen(utf8, "rb"); 344eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi if (file == NULL) { 345eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi LOGE("Failed to open %s", utf8); 346eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi return JNI_FALSE; 347eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi } 348eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi 349eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi // configure data source 350d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi XADataLocator_AndroidBufferQueue loc_abq = { XA_DATALOCATOR_ANDROIDBUFFERQUEUE, NB_BUFFERS }; 351d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi XADataFormat_MIME format_mime = { 352d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi XA_DATAFORMAT_MIME, (XAchar *)"video/mp2ts", XA_CONTAINERTYPE_MPEG_TS }; 353eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi XADataSource dataSrc = {&loc_abq, &format_mime}; 35497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 35597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // configure audio sink 356d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi XADataLocator_OutputMix loc_outmix = { XA_DATALOCATOR_OUTPUTMIX, outputMixObject }; 357d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi XADataSink audioSnk = { &loc_outmix, NULL }; 35897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 35997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // configure image video sink 360295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi XADataLocator_NativeDisplay loc_nd = { 361ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten XA_DATALOCATOR_NATIVEDISPLAY, // locatorType 36239310fca2e30101fa6e5168da443581cc60c20bfGlenn Kasten // the video sink must be an ANativeWindow created from a Surface or SurfaceTexture 363ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten (void*)theNativeWindow, // hWindow 364ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten // must be NULL 365ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten NULL // hDisplay 366ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten }; 36797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten XADataSink imageVideoSink = {&loc_nd, NULL}; 36897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 369eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi // declare interfaces to use 37037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi XAboolean required[NB_MAXAL_INTERFACES] 37137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi = {XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE}; 37237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi XAInterfaceID iidArray[NB_MAXAL_INTERFACES] 37360ca9f9ef02f6e486c3338cb811f603dd7825c05Glenn Kasten = {XA_IID_PLAY, XA_IID_ANDROIDBUFFERQUEUESOURCE, 37460ca9f9ef02f6e486c3338cb811f603dd7825c05Glenn Kasten XA_IID_STREAMINFORMATION}; 37537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi 376eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi 37797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // create media player 378eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi res = (*engineEngine)->CreateMediaPlayer(engineEngine, &playerObj, &dataSrc, 379eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi NULL, &audioSnk, &imageVideoSink, NULL, NULL, 380d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi NB_MAXAL_INTERFACES /*XAuint32 numInterfaces*/, 381eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi iidArray /*const XAInterfaceID *pInterfaceIds*/, 382eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi required /*const XAboolean *pInterfaceRequired*/); 383eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 38497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 38597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // release the Java string and UTF-8 38697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten (*env)->ReleaseStringUTFChars(env, filename, utf8); 38797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 38897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // realize the player 389eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi res = (*playerObj)->Realize(playerObj, XA_BOOLEAN_FALSE); 390eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 39197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 39297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // get the play interface 393eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi res = (*playerObj)->GetInterface(playerObj, XA_IID_PLAY, &playerPlayItf); 394eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 395eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi 39637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi // get the stream information interface (for video size) 39737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi res = (*playerObj)->GetInterface(playerObj, XA_IID_STREAMINFORMATION, &playerStreamInfoItf); 39837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 39937dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi 40037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi // get the volume interface 40137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi res = (*playerObj)->GetInterface(playerObj, XA_IID_VOLUME, &playerVolItf); 40237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 40337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi 404eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi // get the Android buffer queue interface 40560ca9f9ef02f6e486c3338cb811f603dd7825c05Glenn Kasten res = (*playerObj)->GetInterface(playerObj, XA_IID_ANDROIDBUFFERQUEUESOURCE, &playerBQItf); 406eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 407eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi 408ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // specify which events we want to be notified of 409ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten res = (*playerBQItf)->SetCallbackEventsMask(playerBQItf, XA_ANDROIDBUFFERQUEUEEVENT_PROCESSED); 410ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 411eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi // register the callback from which OpenMAX AL can retrieve the data to play 412d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi res = (*playerBQItf)->RegisterCallback(playerBQItf, AndroidBufferQueueCallback, NULL); 41337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 41437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi 41537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi // we want to be notified of the video size once it's found, so we register a callback for that 41637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi res = (*playerStreamInfoItf)->RegisterStreamChangeCallback(playerStreamInfoItf, 41737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi StreamChangeCallback, NULL); 418d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi 419ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // enqueue the initial buffers 420ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten if (!enqueueInitialBuffers(JNI_FALSE)) { 421d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi return JNI_FALSE; 422d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi } 423d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi 424eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi // prepare the player 425eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PAUSED); 426eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 427eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi 42837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi // set the volume 42937dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi res = (*playerVolItf)->SetVolumeLevel(playerVolItf, 0);//-300); 43037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 43137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi 43237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi // start the playback 433eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PLAYING); 434eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 43597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 43697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten return JNI_TRUE; 43797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten} 43897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 43997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 44097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// set the playing state for the streaming media player 44197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setPlayingStreamingMediaPlayer(JNIEnv* env, 44297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten jclass clazz, jboolean isPlaying) 44397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{ 444eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi XAresult res; 44597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 44697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // make sure the streaming media player was created 447eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi if (NULL != playerPlayItf) { 44897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 44997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // set the player's state 450eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi res = (*playerPlayItf)->SetPlayState(playerPlayItf, isPlaying ? 45197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten XA_PLAYSTATE_PLAYING : XA_PLAYSTATE_PAUSED); 452eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 45397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 45497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten } 45597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 45697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten} 45797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 45897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 45997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// shut down the native media system 46097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenvoid Java_com_example_nativemedia_NativeMedia_shutdown(JNIEnv* env, jclass clazz) 46197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{ 46297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // destroy streaming media player object, and invalidate all associated interfaces 463eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi if (playerObj != NULL) { 464eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi (*playerObj)->Destroy(playerObj); 465eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi playerObj = NULL; 466eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi playerPlayItf = NULL; 467eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi playerBQItf = NULL; 468ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten playerStreamInfoItf = NULL; 469ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten playerVolItf = NULL; 47097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten } 47197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 47297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // destroy output mix object, and invalidate all associated interfaces 47397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten if (outputMixObject != NULL) { 47497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten (*outputMixObject)->Destroy(outputMixObject); 47597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten outputMixObject = NULL; 47697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten } 47797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 47897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // destroy engine object, and invalidate all associated interfaces 47997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten if (engineObject != NULL) { 48097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten (*engineObject)->Destroy(engineObject); 48197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten engineObject = NULL; 48297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten engineEngine = NULL; 48397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten } 48497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 485eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi // close the file 486eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi if (file != NULL) { 487eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi fclose(file); 488b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten file = NULL; 489eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi } 490295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi 491295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi // make sure we don't leak native windows 492ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten if (theNativeWindow != NULL) { 493ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten ANativeWindow_release(theNativeWindow); 494b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten theNativeWindow = NULL; 495ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten } 49697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten} 49797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 49897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 49997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// set the surface 50097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setSurface(JNIEnv *env, jclass clazz, jobject surface) 50197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{ 502295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi // obtain a native window from a Java surface 503295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi theNativeWindow = ANativeWindow_fromSurface(env, surface); 504ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten} 505ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten 506ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten 507ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten// set the surface texture 508ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setSurfaceTexture(JNIEnv *env, jclass clazz, 509ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten jobject surfaceTexture) 510ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten{ 511ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten // obtain a native window from a Java surface texture 512ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten theNativeWindow = ANativeWindow_fromSurfaceTexture(env, surfaceTexture); 51397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten} 514ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 515ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 516ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten// rewind the streaming media player 517ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_rewindStreamingMediaPlayer(JNIEnv *env, jclass clazz) 518ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten{ 519ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten XAresult res; 520ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 521ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // make sure the streaming media player was created 522ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten if (NULL != playerBQItf && NULL != file) { 523ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // first wait for buffers currently in queue to be drained 524ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten int ok; 525ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten ok = pthread_mutex_lock(&mutex); 526ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten assert(0 == ok); 527ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten discontinuity = JNI_TRUE; 528ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // wait for discontinuity request to be observed by buffer queue callback 529ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten // FIXME sorry, can't rewind after EOS 530ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten while (discontinuity && !reachedEof) { 531ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten ok = pthread_cond_wait(&cond, &mutex); 532ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten assert(0 == ok); 533ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten } 534ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten ok = pthread_mutex_unlock(&mutex); 535ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten assert(0 == ok); 536ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten } 537ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten 538ac8c7318e1d7ec1358bbf924e1bc2cee45b44fc6Glenn Kasten} 539