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