native-media-jni.c revision 73d888bb7b15745c6456dc0fab97c39854827d2a
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <assert.h> 18#include <jni.h> 19#include <pthread.h> 20#include <string.h> 21#define LOG_TAG "NativeMedia" 22#include <utils/Log.h> 23//FIXME shouldn't be needed here, but needed for declaration of XA_IID_ANDROIDBUFFERQUEUE 24#include "SLES/OpenSLES.h" 25#include "SLES/OpenSLES_Android.h" 26#include "OMXAL/OpenMAXAL.h" 27#include "OMXAL/OpenMAXAL_Android.h" 28#include <android/native_window_jni.h> 29 30// engine interfaces 31static XAObjectItf engineObject = NULL; 32static XAEngineItf engineEngine; 33 34// output mix interfaces 35static XAObjectItf outputMixObject = NULL; 36 37// streaming media player interfaces 38static XAObjectItf playerObj = NULL; 39static XAPlayItf playerPlayItf = NULL; 40static XAAndroidBufferQueueItf playerBQItf = NULL; 41 42// cached surface where the video display happens 43static ANativeWindow* theNativeWindow; 44 45// handle of the file to play 46FILE *file; 47 48// AndroidBufferQueueItf callback for an audio player 49XAresult AndroidBufferQueueCallback( 50 XAAndroidBufferQueueItf caller, 51 void *pContext, 52 XAuint32 bufferId, 53 XAuint32 bufferLength, 54 void *pBufferDataLocation) 55 56{ 57 size_t nbRead = fread(pBufferDataLocation, 1, bufferLength, file); 58 59 XAAbufferQueueEvent event = XA_ANDROIDBUFFERQUEUE_EVENT_NONE; 60 if (nbRead <= 0) { 61 event = XA_ANDROIDBUFFERQUEUE_EVENT_EOS; 62 } else { 63 event = XA_ANDROIDBUFFERQUEUE_EVENT_NONE; // no event to report 64 } 65 66 // enqueue the data right-away because in this example we're reading from a file, so we 67 // can afford to do that. When streaming from the network, we would write from our cache 68 // to this queue. 69 // last param is NULL because we've already written the data in the buffer queue 70 (*caller)->Enqueue(caller, bufferId, nbRead, event, NULL); 71 72 return XA_RESULT_SUCCESS; 73} 74 75 76// create the engine and output mix objects 77void Java_com_example_nativemedia_NativeMedia_createEngine(JNIEnv* env, jclass clazz) 78{ 79 XAresult res; 80 81 // create engine 82 res = xaCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); 83 assert(XA_RESULT_SUCCESS == res); 84 85 // realize the engine 86 res = (*engineObject)->Realize(engineObject, XA_BOOLEAN_FALSE); 87 assert(XA_RESULT_SUCCESS == res); 88 89 // get the engine interface, which is needed in order to create other objects 90 res = (*engineObject)->GetInterface(engineObject, XA_IID_ENGINE, &engineEngine); 91 assert(XA_RESULT_SUCCESS == res); 92 93 // create output mix 94 res = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL); 95 assert(XA_RESULT_SUCCESS == res); 96 97 // realize the output mix 98 res = (*outputMixObject)->Realize(outputMixObject, XA_BOOLEAN_FALSE); 99 assert(XA_RESULT_SUCCESS == res); 100 101} 102 103 104// create streaming media player 105jboolean Java_com_example_nativemedia_NativeMedia_createStreamingMediaPlayer(JNIEnv* env, 106 jclass clazz, jstring filename) 107{ 108 XAresult res; 109 110 // convert Java string to UTF-8 111 const char *utf8 = (*env)->GetStringUTFChars(env, filename, NULL); 112 assert(NULL != utf8); 113 114 // open the file to play 115 file = fopen(utf8, "rb"); 116 if (file == NULL) { 117 LOGE("Failed to open %s", utf8); 118 return JNI_FALSE; 119 } 120 121 // configure data source 122 XADataLocator_AndroidBufferQueue loc_abq = {XA_DATALOCATOR_ANDROIDBUFFERQUEUE, 123 0, 0 /* number of buffers and size of queue are ignored for now, subject to change */}; 124 XADataFormat_MIME format_mime = {XA_DATAFORMAT_MIME, NULL, XA_CONTAINERTYPE_UNSPECIFIED}; 125 XADataSource dataSrc = {&loc_abq, &format_mime}; 126 127 // configure audio sink 128 XADataLocator_OutputMix loc_outmix = {XA_DATALOCATOR_OUTPUTMIX, outputMixObject}; 129 XADataSink audioSnk = {&loc_outmix, NULL}; 130 131 // configure image video sink 132 XADataLocator_NativeDisplay loc_nd = { 133 XA_DATALOCATOR_NATIVEDISPLAY /* locatorType */, 134 // currently the video sink only works on ANativeWindow created from a Surface 135 (void*)theNativeWindow /* hWindow */, 136 // ignored here 137 0 /* hDisplay */}; 138 XADataSink imageVideoSink = {&loc_nd, NULL}; 139 140 // declare interfaces to use 141 XAboolean required[2] = {XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE}; 142 XAInterfaceID iidArray[2] = {XA_IID_PLAY, XA_IID_ANDROIDBUFFERQUEUE}; 143 144 // create media player 145 res = (*engineEngine)->CreateMediaPlayer(engineEngine, &playerObj, &dataSrc, 146 NULL, &audioSnk, &imageVideoSink, NULL, NULL, 147 2 /*XAuint32 numInterfaces*/, 148 iidArray /*const XAInterfaceID *pInterfaceIds*/, 149 required /*const XAboolean *pInterfaceRequired*/); 150 assert(XA_RESULT_SUCCESS == res); 151 152 // release the Java string and UTF-8 153 (*env)->ReleaseStringUTFChars(env, filename, utf8); 154 155 // realize the player 156 res = (*playerObj)->Realize(playerObj, XA_BOOLEAN_FALSE); 157 assert(XA_RESULT_SUCCESS == res); 158 159 // get the play interface 160 res = (*playerObj)->GetInterface(playerObj, XA_IID_PLAY, &playerPlayItf); 161 assert(XA_RESULT_SUCCESS == res); 162 163 // get the Android buffer queue interface 164 res = (*playerObj)->GetInterface(playerObj, XA_IID_ANDROIDBUFFERQUEUE, &playerBQItf); 165 assert(XA_RESULT_SUCCESS == res); 166 167 // register the callback from which OpenMAX AL can retrieve the data to play 168 res = (*playerBQItf)->RegisterCallback(playerBQItf, AndroidBufferQueueCallback, &playerBQItf); 169 170 // prepare the player 171 res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PAUSED); 172 assert(XA_RESULT_SUCCESS == res); 173 174 res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PLAYING); 175 assert(XA_RESULT_SUCCESS == res); 176 177 return JNI_TRUE; 178} 179 180 181// set the playing state for the streaming media player 182void Java_com_example_nativemedia_NativeMedia_setPlayingStreamingMediaPlayer(JNIEnv* env, 183 jclass clazz, jboolean isPlaying) 184{ 185 XAresult res; 186 187 // make sure the streaming media player was created 188 if (NULL != playerPlayItf) { 189 190 // set the player's state 191 res = (*playerPlayItf)->SetPlayState(playerPlayItf, isPlaying ? 192 XA_PLAYSTATE_PLAYING : XA_PLAYSTATE_PAUSED); 193 assert(XA_RESULT_SUCCESS == res); 194 195 } 196 197} 198 199 200// shut down the native media system 201void Java_com_example_nativemedia_NativeMedia_shutdown(JNIEnv* env, jclass clazz) 202{ 203 // destroy streaming media player object, and invalidate all associated interfaces 204 if (playerObj != NULL) { 205 (*playerObj)->Destroy(playerObj); 206 playerObj = NULL; 207 playerPlayItf = NULL; 208 playerBQItf = NULL; 209 } 210 211 // destroy output mix object, and invalidate all associated interfaces 212 if (outputMixObject != NULL) { 213 (*outputMixObject)->Destroy(outputMixObject); 214 outputMixObject = NULL; 215 } 216 217 // destroy engine object, and invalidate all associated interfaces 218 if (engineObject != NULL) { 219 (*engineObject)->Destroy(engineObject); 220 engineObject = NULL; 221 engineEngine = NULL; 222 } 223 224 // close the file 225 if (file != NULL) { 226 fclose(file); 227 } 228 229 // make sure we don't leak native windows 230 ANativeWindow_release(theNativeWindow); 231} 232 233 234// set the surface 235void Java_com_example_nativemedia_NativeMedia_setSurface(JNIEnv *env, jclass clazz, jobject surface) 236{ 237 // obtain a native window from a Java surface 238 theNativeWindow = ANativeWindow_fromSurface(env, surface); 239} 240