native-media-jni.c revision c6853892c94800e72c0bd676d5d2136d48cea76e
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> 2137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi#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; 3297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenstatic XAEngineItf engineEngine; 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; 4237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivistatic XAVolumeItf playerVolItf; 43d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi// number of required interfaces for the MediaPlayer creation 4437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi#define NB_MAXAL_INTERFACES 3 // XAAndroidBufferQueueItf, XAStreamInformationItf and XAPlayItf 4597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 4639310fca2e30101fa6e5168da443581cc60c20bfGlenn Kasten// video sink for the player 47295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivistatic ANativeWindow* theNativeWindow; 4897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 49d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi// number of buffers in our buffer queue 50d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi#define NB_BUFFERS 16 51d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi// we're streaming MPEG-2 transport stream data, operate on transport stream block size 52d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi#define MPEG2_TS_BLOCK_SIZE 188 53d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi// determines how much memory we're dedicating to memory caching 54d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi#define BUFFER_SIZE 20*MPEG2_TS_BLOCK_SIZE // 20 is an arbitrary number chosen here 55d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi 56d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi// where we cache in memory the data to play 57d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivichar dataCache[BUFFER_SIZE * NB_BUFFERS]; 58eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi// handle of the file to play 59eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel TriviFILE *file; 6070c49ae2867094072a4365423417ea452bf82231Jean-Michel Trivi// has the app reached the end of the file 6170c49ae2867094072a4365423417ea452bf82231Jean-Michel Trivichar reachedEof = 0; 62eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi 63eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi// AndroidBufferQueueItf callback for an audio player 64eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel TriviXAresult AndroidBufferQueueCallback( 65eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi XAAndroidBufferQueueItf caller, 6637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi void *pCallbackContext, /* input */ 6737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi void *pBufferContext, /* input */ 6837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi void *pBufferData, /* input */ 69d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi XAuint32 dataSize, /* input */ 70d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi XAuint32 dataUsed, /* input */ 71d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi const XAAndroidBufferItem *pItems,/* input */ 72d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi XAuint32 itemsLength /* input */) 73eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi{ 74d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi // assert(BUFFER_SIZE <= dataSize); 7537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi if (pBufferData == NULL) { 7637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi // this is the case when our buffer with the EOS message has been consumed 7737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi return XA_RESULT_SUCCESS; 7837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi } 7937dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi 8037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi#if 0 8137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi // sample code to use the XAVolumeItf 8237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi XAAndroidBufferQueueState state; 8337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi (*caller)->GetState(caller, &state); 8437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi switch (state.index) { 8537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi case 300: 8637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi (*playerVolItf)->SetVolumeLevel(playerVolItf, -600); // -6dB 8737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi LOGV("setting volume to -6dB"); 8837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi break; 8937dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi case 400: 9037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi (*playerVolItf)->SetVolumeLevel(playerVolItf, -1200); // -12dB 9137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi LOGV("setting volume to -12dB"); 9237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi break; 9337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi case 500: 9437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi (*playerVolItf)->SetVolumeLevel(playerVolItf, 0); // full volume 9537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi LOGV("setting volume to 0dB (full volume)"); 9637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi break; 9737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi case 600: 9837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi (*playerVolItf)->SetMute(playerVolItf, XA_BOOLEAN_TRUE); // mute 9937dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi LOGV("muting player"); 10037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi break; 10137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi case 700: 10237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi (*playerVolItf)->SetMute(playerVolItf, XA_BOOLEAN_FALSE); // unmute 10337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi LOGV("unmuting player"); 10437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi break; 10537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi case 800: 10637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi (*playerVolItf)->SetStereoPosition(playerVolItf, -1000); 10737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi (*playerVolItf)->EnableStereoPosition(playerVolItf, XA_BOOLEAN_TRUE); 10837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi LOGV("pan sound to the left (hard-left)"); 10937dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi break; 11037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi case 900: 11137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi (*playerVolItf)->EnableStereoPosition(playerVolItf, XA_BOOLEAN_FALSE); 11237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi LOGV("disabling stereo position"); 11337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi break; 11437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi default: 11537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi break; 11637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi } 11737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi#endif 11837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi 119d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi size_t nbRead = fread((void*)pBufferData, 1, BUFFER_SIZE, file); 12037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi if ((nbRead > 0) && (NULL != pBufferData)) { 12137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi (*caller)->Enqueue(caller, NULL /*pBufferContext*/, 122d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi pBufferData /*pData*/, 123d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi nbRead /*dataLength*/, 124d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi NULL /*pMsg*/, 125d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi 0 /*msgLength*/); 12670c49ae2867094072a4365423417ea452bf82231Jean-Michel Trivi } else if (!reachedEof) { 127d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi // signal EOS 128d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi XAAndroidBufferItem msgEos; 129d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi msgEos.itemKey = XA_ANDROID_ITEMKEY_EOS; 130d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi msgEos.itemSize = 0; 131d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi // EOS message has no parameters, so the total size of the message is the size of the key 132d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi // plus the size if itemSize, both XAuint32 13337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi (*caller)->Enqueue(caller, NULL /*pBufferContext*/, 13437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi NULL /*pData*/, 0 /*dataLength*/, 13537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi &msgEos /*pMsg*/, 13637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi sizeof(XAuint32)*2 /*msgLength*/); 13770c49ae2867094072a4365423417ea452bf82231Jean-Michel Trivi reachedEof = 1; 138eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi } 139eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi 140eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi return XA_RESULT_SUCCESS; 141eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi} 142eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi 143eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi 14437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivivoid StreamChangeCallback (XAStreamInformationItf caller, 14537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi XAuint32 eventId, 14637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi XAuint32 streamIndex, 14737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi void * pEventData, 14837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi void * pContext ) 14937dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi{ 15037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi if (XA_STREAMCBEVENT_PROPERTYCHANGE == eventId) { 15158432eb9cea995c69b4f905e68b38c1b8216edebGlenn Kasten LOGD("StreamChangeCallback called for stream %u", streamIndex); 15237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi 15337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi XAuint32 domain; 15437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi if (XA_RESULT_SUCCESS == (*caller)->QueryStreamType(caller, streamIndex, &domain)) { 15537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi if (XA_DOMAINTYPE_VIDEO == domain) { 15637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi XAVideoStreamInformation videoInfo; 15737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi if (XA_RESULT_SUCCESS == (*caller)->QueryStreamInformation(caller, streamIndex, 15837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi &videoInfo)) { 15958432eb9cea995c69b4f905e68b38c1b8216edebGlenn Kasten LOGI("Found video size %u x %u", videoInfo.width, videoInfo.height); 16037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi } 16137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi } 16237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi } 16337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi } 16437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi} 16537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi 16637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi 16797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// create the engine and output mix objects 16897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenvoid Java_com_example_nativemedia_NativeMedia_createEngine(JNIEnv* env, jclass clazz) 16997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{ 170eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi XAresult res; 17197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 17297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // create engine 173eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi res = xaCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); 174eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 17597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 17697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // realize the engine 177eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi res = (*engineObject)->Realize(engineObject, XA_BOOLEAN_FALSE); 178eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 17997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 18097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // get the engine interface, which is needed in order to create other objects 181eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi res = (*engineObject)->GetInterface(engineObject, XA_IID_ENGINE, &engineEngine); 182eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 18397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 18497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // create output mix 185eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi res = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL); 186eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 18797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 18897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // realize the output mix 189eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi res = (*outputMixObject)->Realize(outputMixObject, XA_BOOLEAN_FALSE); 190eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 19197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 19297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten} 19397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 19497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 19597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// create streaming media player 19697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenjboolean Java_com_example_nativemedia_NativeMedia_createStreamingMediaPlayer(JNIEnv* env, 19797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten jclass clazz, jstring filename) 19897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{ 199eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi XAresult res; 20097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 20197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // convert Java string to UTF-8 20297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten const char *utf8 = (*env)->GetStringUTFChars(env, filename, NULL); 20397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten assert(NULL != utf8); 20497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 205eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi // open the file to play 206eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi file = fopen(utf8, "rb"); 207eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi if (file == NULL) { 208eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi LOGE("Failed to open %s", utf8); 209eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi return JNI_FALSE; 210eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi } 211eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi 212eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi // configure data source 213d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi XADataLocator_AndroidBufferQueue loc_abq = { XA_DATALOCATOR_ANDROIDBUFFERQUEUE, NB_BUFFERS }; 214d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi XADataFormat_MIME format_mime = { 215d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi XA_DATAFORMAT_MIME, (XAchar *)"video/mp2ts", XA_CONTAINERTYPE_MPEG_TS }; 216eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi XADataSource dataSrc = {&loc_abq, &format_mime}; 21797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 21897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // configure audio sink 219d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi XADataLocator_OutputMix loc_outmix = { XA_DATALOCATOR_OUTPUTMIX, outputMixObject }; 220d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi XADataSink audioSnk = { &loc_outmix, NULL }; 22197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 22297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // configure image video sink 223295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi XADataLocator_NativeDisplay loc_nd = { 224ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten XA_DATALOCATOR_NATIVEDISPLAY, // locatorType 22539310fca2e30101fa6e5168da443581cc60c20bfGlenn Kasten // the video sink must be an ANativeWindow created from a Surface or SurfaceTexture 226ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten (void*)theNativeWindow, // hWindow 227ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten // must be NULL 228ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten NULL // hDisplay 229ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten }; 23097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten XADataSink imageVideoSink = {&loc_nd, NULL}; 23197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 232eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi // declare interfaces to use 23337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi XAboolean required[NB_MAXAL_INTERFACES] 23437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi = {XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE}; 23537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi XAInterfaceID iidArray[NB_MAXAL_INTERFACES] 23637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi = {XA_IID_PLAY, XA_IID_ANDROIDBUFFERQUEUE, XA_IID_STREAMINFORMATION}; 23737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi 238eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi 23997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // create media player 240eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi res = (*engineEngine)->CreateMediaPlayer(engineEngine, &playerObj, &dataSrc, 241eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi NULL, &audioSnk, &imageVideoSink, NULL, NULL, 242d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi NB_MAXAL_INTERFACES /*XAuint32 numInterfaces*/, 243eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi iidArray /*const XAInterfaceID *pInterfaceIds*/, 244eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi required /*const XAboolean *pInterfaceRequired*/); 245eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 24697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 24797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // release the Java string and UTF-8 24897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten (*env)->ReleaseStringUTFChars(env, filename, utf8); 24997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 25097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // realize the player 251eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi res = (*playerObj)->Realize(playerObj, XA_BOOLEAN_FALSE); 252eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 25397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 25497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // get the play interface 255eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi res = (*playerObj)->GetInterface(playerObj, XA_IID_PLAY, &playerPlayItf); 256eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 257eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi 25837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi // get the stream information interface (for video size) 25937dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi res = (*playerObj)->GetInterface(playerObj, XA_IID_STREAMINFORMATION, &playerStreamInfoItf); 26037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 26137dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi 26237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi // get the volume interface 26337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi res = (*playerObj)->GetInterface(playerObj, XA_IID_VOLUME, &playerVolItf); 26437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 26537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi 266eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi // get the Android buffer queue interface 267eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi res = (*playerObj)->GetInterface(playerObj, XA_IID_ANDROIDBUFFERQUEUE, &playerBQItf); 268eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 269eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi 270eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi // register the callback from which OpenMAX AL can retrieve the data to play 271d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi res = (*playerBQItf)->RegisterCallback(playerBQItf, AndroidBufferQueueCallback, NULL); 27237dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 27337dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi 27437dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi // we want to be notified of the video size once it's found, so we register a callback for that 27537dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi res = (*playerStreamInfoItf)->RegisterStreamChangeCallback(playerStreamInfoItf, 27637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi StreamChangeCallback, NULL); 277d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi 278d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi /* Fill our cache */ 279d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi if (fread(dataCache, 1, BUFFER_SIZE * NB_BUFFERS, file) <= 0) { 280d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi LOGE("Error filling cache, exiting\n"); 281d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi return JNI_FALSE; 282d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi } 283d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi /* Enqueue the content of our cache before starting to play, 284d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi we don't want to starve the player */ 285d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi int i; 286d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi for (i=0 ; i < NB_BUFFERS ; i++) { 28737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi res = (*playerBQItf)->Enqueue(playerBQItf, NULL /*pBufferContext*/, 28837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi dataCache + i*BUFFER_SIZE, BUFFER_SIZE, NULL, 0); 289d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 290d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi } 291d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi 292eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi // prepare the player 293eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PAUSED); 294eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 295eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi 29637dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi // set the volume 29737dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi res = (*playerVolItf)->SetVolumeLevel(playerVolItf, 0);//-300); 29837dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 29937dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi 30037dc2fccf3f122b79ebd554de209d0a3c94ae161Jean-Michel Trivi // start the playback 301eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PLAYING); 302eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 30397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 30497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten return JNI_TRUE; 30597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten} 30697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 30797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 30897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// set the playing state for the streaming media player 30997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setPlayingStreamingMediaPlayer(JNIEnv* env, 31097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten jclass clazz, jboolean isPlaying) 31197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{ 312eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi XAresult res; 31397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 31497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // make sure the streaming media player was created 315eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi if (NULL != playerPlayItf) { 31697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 31797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // set the player's state 318eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi res = (*playerPlayItf)->SetPlayState(playerPlayItf, isPlaying ? 31997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten XA_PLAYSTATE_PLAYING : XA_PLAYSTATE_PAUSED); 320eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi assert(XA_RESULT_SUCCESS == res); 32197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 32297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten } 32397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 32497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten} 32597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 32697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 32797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// shut down the native media system 32897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenvoid Java_com_example_nativemedia_NativeMedia_shutdown(JNIEnv* env, jclass clazz) 32997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{ 33097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // destroy streaming media player object, and invalidate all associated interfaces 331eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi if (playerObj != NULL) { 332eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi (*playerObj)->Destroy(playerObj); 333eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi playerObj = NULL; 334eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi playerPlayItf = NULL; 335eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi playerBQItf = NULL; 33697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten } 33797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 33897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // destroy output mix object, and invalidate all associated interfaces 33997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten if (outputMixObject != NULL) { 34097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten (*outputMixObject)->Destroy(outputMixObject); 34197bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten outputMixObject = NULL; 34297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten } 34397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 34497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten // destroy engine object, and invalidate all associated interfaces 34597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten if (engineObject != NULL) { 34697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten (*engineObject)->Destroy(engineObject); 34797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten engineObject = NULL; 34897bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten engineEngine = NULL; 34997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten } 35097bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 351eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi // close the file 352eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi if (file != NULL) { 353eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi fclose(file); 354b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten file = NULL; 355eae4df541ba1d46f65d37e959baf2127aa632c93Jean-Michel Trivi } 356295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi 357295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi // make sure we don't leak native windows 358ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten if (theNativeWindow != NULL) { 359ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten ANativeWindow_release(theNativeWindow); 360b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten theNativeWindow = NULL; 361ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten } 36297bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten} 36397bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 36497bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten 36597bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten// set the surface 36697bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setSurface(JNIEnv *env, jclass clazz, jobject surface) 36797bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten{ 368295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi // obtain a native window from a Java surface 369295395c087000a9d804f8d12d58dea4cd9e7d26aJean-Michel Trivi theNativeWindow = ANativeWindow_fromSurface(env, surface); 370ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten} 371ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten 372ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten 373ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten// set the surface texture 374ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kastenvoid Java_com_example_nativemedia_NativeMedia_setSurfaceTexture(JNIEnv *env, jclass clazz, 375ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten jobject surfaceTexture) 376ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten{ 377ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten // obtain a native window from a Java surface texture 378ad1ab1d13a9b043202b9d5cdc1d8c4ef66cbbca8Glenn Kasten theNativeWindow = ANativeWindow_fromSurfaceTexture(env, surfaceTexture); 37997bdbe13fc48640babe6c1ce270660476f04c3dfGlenn Kasten} 380