1cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten/* 2cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten * Copyright (C) 2011 The Android Open Source Project 3cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten * 4cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten * Licensed under the Apache License, Version 2.0 (the "License"); 5cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten * you may not use this file except in compliance with the License. 6cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten * You may obtain a copy of the License at 7cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten * 8cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten * http://www.apache.org/licenses/LICENSE-2.0 9cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten * 10cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten * Unless required by applicable law or agreed to in writing, software 11cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten * distributed under the License is distributed on an "AS IS" BASIS, 12cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten * See the License for the specific language governing permissions and 14cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten * limitations under the License. 15cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten */ 16cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 17cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten// OpenMAX AL MediaPlayer command-line player 18cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 19cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#include <assert.h> 20cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#include <pthread.h> 21cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#include <stdio.h> 22cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#include <stdlib.h> 23cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#include <fcntl.h> 24cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#include <sys/mman.h> 25cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#include <sys/stat.h> 26cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#include <unistd.h> 27cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#include <OMXAL/OpenMAXAL.h> 28cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#include <OMXAL/OpenMAXAL_Android.h> 29cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#include "nativewindow.h" 30cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 31cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#define MPEG2TS_PACKET_SIZE 188 // MPEG-2 transport stream packet size in bytes 32cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#define PACKETS_PER_BUFFER 20 // Number of MPEG-2 transport stream packets per buffer 33cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 34cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#define NB_BUFFERS 2 // Number of buffers in Android buffer queue 35cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 36cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten// MPEG-2 transport stream packet 37cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kastentypedef struct { 38cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten char data[MPEG2TS_PACKET_SIZE]; 39cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten} MPEG2TS_Packet; 40cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 41cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#if 0 42cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten// Each buffer in Android buffer queue 43cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kastentypedef struct { 44cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten MPEG2TS_Packet packets[PACKETS_PER_BUFFER]; 45cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten} Buffer; 46cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#endif 47cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 48cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten// Globals shared between main thread and buffer queue callback 49cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn KastenMPEG2TS_Packet *packets; 50cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kastensize_t numPackets; 51cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kastensize_t curPacket; 52cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kastensize_t discPacket; 53cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 54cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten// These are extensions to OpenMAX AL 1.0.1 values 55cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 56cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#define PREFETCHSTATUS_UNKNOWN ((XAuint32) 0) 57cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#define PREFETCHSTATUS_ERROR ((XAuint32) (-1)) 58cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 59cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten// Mutex and condition shared with main program to protect prefetch_status 60cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 61cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kastenstatic pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 62cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kastenstatic pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 63cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn KastenXAuint32 prefetch_status = PREFETCHSTATUS_UNKNOWN; 64cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 65cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten/* used to detect errors likely to have occured when the OpenMAX AL framework fails to open 66cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten * a resource, for instance because a file URI is invalid, or an HTTP server doesn't respond. 67cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten */ 68cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#define PREFETCHEVENT_ERROR_CANDIDATE \ 69cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten (XA_PREFETCHEVENT_STATUSCHANGE | XA_PREFETCHEVENT_FILLLEVELCHANGE) 70cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 71cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten// stream event change callback 72cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kastenvoid streamEventChangeCallback(XAStreamInformationItf caller, XAuint32 eventId, 73cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAuint32 streamIndex, void *pEventData, void *pContext) 74cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten{ 75cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // context parameter is specified as NULL and is unused here 76cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(NULL == pContext); 77cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten switch (eventId) { 78cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten case XA_STREAMCBEVENT_PROPERTYCHANGE: 79cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten printf("XA_STREAMCBEVENT_PROPERTYCHANGE on stream index %u, pEventData %p\n", streamIndex, 80cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten pEventData); 81cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten break; 82cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten default: 83cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten printf("Unknown stream event ID %u\n", eventId); 84cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten break; 85cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 86cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten} 87cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 88cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten// prefetch status callback 89cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kastenvoid prefetchStatusCallback(XAPrefetchStatusItf caller, void *pContext, XAuint32 event) 90cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten{ 91cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // pContext is unused here, so we pass NULL 92cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(pContext == NULL); 93cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XApermille level = 0; 94cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAresult result; 95cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*caller)->GetFillLevel(caller, &level); 96cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 97cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAuint32 status; 98cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*caller)->GetPrefetchStatus(caller, &status); 99cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 100cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (event & XA_PREFETCHEVENT_FILLLEVELCHANGE) { 101cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten printf("PrefetchEventCallback: Buffer fill level is = %d\n", level); 102cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 103cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (event & XA_PREFETCHEVENT_STATUSCHANGE) { 104cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten printf("PrefetchEventCallback: Prefetch Status is = %u\n", status); 105cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 106cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAuint32 new_prefetch_status; 107cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if ((PREFETCHEVENT_ERROR_CANDIDATE == (event & PREFETCHEVENT_ERROR_CANDIDATE)) 108cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten && (level == 0) && (status == XA_PREFETCHSTATUS_UNDERFLOW)) { 109cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten printf("PrefetchEventCallback: Error while prefetching data, exiting\n"); 110cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten new_prefetch_status = PREFETCHSTATUS_ERROR; 111cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } else if (event == XA_PREFETCHEVENT_STATUSCHANGE) { 112cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten new_prefetch_status = status; 113cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } else { 114cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten return; 115cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 116cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten int ok; 117cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten ok = pthread_mutex_lock(&mutex); 118cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(ok == 0); 119cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten prefetch_status = new_prefetch_status; 120cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten ok = pthread_cond_signal(&cond); 121cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(ok == 0); 122cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten ok = pthread_mutex_unlock(&mutex); 123cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(ok == 0); 124cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten} 125cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 126cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten// playback event callback 127cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kastenvoid playEventCallback(XAPlayItf caller, void *pContext, XAuint32 event) 128cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten{ 129cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // pContext is unused here, so we pass NULL 130cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(NULL == pContext); 131cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 132cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAmillisecond position; 133cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 134cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (XA_PLAYEVENT_HEADATEND & event) { 135cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten printf("XA_PLAYEVENT_HEADATEND reached\n"); 136cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten //SignalEos(); 137cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 138cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 139cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAresult result; 140cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (XA_PLAYEVENT_HEADATNEWPOS & event) { 141cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*caller)->GetPosition(caller, &position); 142cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 143cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten printf("XA_PLAYEVENT_HEADATNEWPOS current position=%ums\n", position); 144cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 145cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 146cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (XA_PLAYEVENT_HEADATMARKER & event) { 147cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*caller)->GetPosition(caller, &position); 148cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 149cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten printf("XA_PLAYEVENT_HEADATMARKER current position=%ums\n", position); 150cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 151cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten} 152cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 153cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten// Android buffer queue callback 154cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn KastenXAresult bufferQueueCallback( 155cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAAndroidBufferQueueItf caller, 156cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten void *pCallbackContext, 157cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten void *pBufferContext, 158cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten void *pBufferData, 159cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAuint32 dataSize, 160cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAuint32 dataUsed, 161cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten const XAAndroidBufferItem *pItems, 162cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAuint32 itemsLength) 163cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten{ 164cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // enqueue the .ts data directly from mapped memory, so ignore the empty buffer pBufferData 165cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (curPacket <= numPackets) { 166cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten static const XAAndroidBufferItem discontinuity = {XA_ANDROID_ITEMKEY_DISCONTINUITY, 0}; 167cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten static const XAAndroidBufferItem eos = {XA_ANDROID_ITEMKEY_EOS, 0}; 168cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten const XAAndroidBufferItem *items; 169cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAuint32 itemSize; 170cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // compute number of packets to be enqueued in this buffer 171cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAuint32 packetsThisBuffer = numPackets - curPacket; 172cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (packetsThisBuffer > PACKETS_PER_BUFFER) { 173cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten packetsThisBuffer = PACKETS_PER_BUFFER; 174cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 175cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // last packet? this should only happen once 176cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (curPacket == numPackets) { 177cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten (void) write(1, "e", 1); 178cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten items = &eos; 179cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten itemSize = sizeof(eos); 180cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // discontinuity requested? 181cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } else if (curPacket == discPacket) { 182cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten printf("sending discontinuity, rewinding from beginning of stream\n"); 183cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten items = &discontinuity; 184cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten itemSize = sizeof(discontinuity); 185cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten curPacket = 0; 186cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // pure data with no items 187cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } else { 188cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten items = NULL; 189cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten itemSize = 0; 190cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 191cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAresult result; 192cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // enqueue the optional data and optional items; there is always at least one or the other 193cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(packetsThisBuffer > 0 || itemSize > 0); 194cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*caller)->Enqueue(caller, NULL, &packets[curPacket], 195cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten sizeof(MPEG2TS_Packet) * packetsThisBuffer, items, itemSize); 196cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 197cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten curPacket += packetsThisBuffer; 198cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 199cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten return XA_RESULT_SUCCESS; 200cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten} 201cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 202cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten// main program 203cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kastenint main(int argc, char **argv) 204cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten{ 205cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten const char *prog = argv[0]; 206cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten int i; 207cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 208cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAboolean abq = XA_BOOLEAN_FALSE; // use AndroidBufferQueue, default is URI 209cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAboolean looping = XA_BOOLEAN_FALSE; 210cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#ifdef REINITIALIZE 211cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten int reinit_counter = 0; 212cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#endif 213cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten for (i = 1; i < argc; ++i) { 214cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten const char *arg = argv[i]; 215cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (arg[0] != '-') 216cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten break; 217cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten switch (arg[1]) { 218cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten case 'a': 219cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten abq = XA_BOOLEAN_TRUE; 220cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten break; 221cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten case 'd': 222cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten discPacket = atoi(&arg[2]); 223cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten break; 224cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten case 'l': 225cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten looping = XA_BOOLEAN_TRUE; 226cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten break; 227cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#ifdef REINITIALIZE 228cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten case 'r': 229cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten reinit_counter = atoi(&arg[2]); 230cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten break; 231cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#endif 232cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten default: 233cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten fprintf(stderr, "%s: unknown option %s\n", prog, arg); 234cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten break; 235cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 236cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 237cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 238cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // check that exactly one URI was specified 239cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (argc - i != 1) { 240cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten fprintf(stderr, "usage: %s [-a] [-d#] [-l] uri\n", prog); 241cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten return EXIT_FAILURE; 242cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 243cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten const char *uri = argv[i]; 244cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 245cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // for AndroidBufferQueue, interpret URI as a filename and open 246cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten int fd = -1; 247cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (abq) { 248cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten fd = open(uri, O_RDONLY); 249cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (fd < 0) { 250cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten perror(uri); 251cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten goto close; 252cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 253cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten int ok; 254cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten struct stat statbuf; 255cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten ok = fstat(fd, &statbuf); 256cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (ok < 0) { 257cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten perror(uri); 258cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten goto close; 259cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 260cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (!S_ISREG(statbuf.st_mode)) { 261cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten fprintf(stderr, "%s: not an ordinary file\n", uri); 262cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten goto close; 263cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 264cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten void *ptr; 265cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten ptr = mmap(NULL, statbuf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, (off_t) 0); 266cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (ptr == MAP_FAILED) { 267cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten perror(uri); 268cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten goto close; 269cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 270cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten size_t filelen = statbuf.st_size; 271cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if ((filelen % MPEG2TS_PACKET_SIZE) != 0) { 272cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten fprintf(stderr, "%s: warning file length %zu is not a multiple of %d\n", uri, filelen, 273cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten MPEG2TS_PACKET_SIZE); 274cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 275cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten packets = (MPEG2TS_Packet *) ptr; 276cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten numPackets = filelen / MPEG2TS_PACKET_SIZE; 277cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten printf("%s has %zu packets\n", uri, numPackets); 278cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 279cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 280cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten ANativeWindow *nativeWindow; 281cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 282cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#ifdef REINITIALIZE 283cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kastenreinitialize: ; 284cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#endif 285cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 286cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAresult result; 287cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAObjectItf engineObject; 288cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 289cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // create engine 290cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = xaCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); 291cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 292cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*engineObject)->Realize(engineObject, XA_BOOLEAN_FALSE); 293cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 294cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAEngineItf engineEngine; 295cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*engineObject)->GetInterface(engineObject, XA_IID_ENGINE, &engineEngine); 296cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 297cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 298cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // create output mix 299cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAObjectItf outputMixObject; 300cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL); 301cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 302cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*outputMixObject)->Realize(outputMixObject, XA_BOOLEAN_FALSE); 303cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 304cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 305cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // configure media source 306cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XADataLocator_URI locUri; 307cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten locUri.locatorType = XA_DATALOCATOR_URI; 308cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten locUri.URI = (XAchar *) uri; 309cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XADataFormat_MIME fmtMime; 310cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten fmtMime.formatType = XA_DATAFORMAT_MIME; 311cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (abq) { 312adf3525f038c77f6a122b4e88762bde9cc0a48bbGlenn Kasten fmtMime.mimeType = (XAchar *) XA_ANDROID_MIME_MP2TS; 313cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten fmtMime.containerType = XA_CONTAINERTYPE_MPEG_TS; 314cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } else { 315cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten fmtMime.mimeType = NULL; 316cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten fmtMime.containerType = XA_CONTAINERTYPE_UNSPECIFIED; 317cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 318cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XADataLocator_AndroidBufferQueue locABQ; 319cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten locABQ.locatorType = XA_DATALOCATOR_ANDROIDBUFFERQUEUE; 320cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten locABQ.numBuffers = NB_BUFFERS; 321cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XADataSource dataSrc; 322cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (abq) { 323cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten dataSrc.pLocator = &locABQ; 324cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } else { 325cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten dataSrc.pLocator = &locUri; 326cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 327cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten dataSrc.pFormat = &fmtMime; 328cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 329cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // configure audio sink 330cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XADataLocator_OutputMix locOM; 331cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten locOM.locatorType = XA_DATALOCATOR_OUTPUTMIX; 332cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten locOM.outputMix = outputMixObject; 333cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XADataSink audioSnk; 334cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten audioSnk.pLocator = &locOM; 335cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten audioSnk.pFormat = NULL; 336cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 337cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // configure video sink 338cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten nativeWindow = getNativeWindow(); 339cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XADataLocator_NativeDisplay locND; 340cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten locND.locatorType = XA_DATALOCATOR_NATIVEDISPLAY; 341cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten locND.hWindow = nativeWindow; 342cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten locND.hDisplay = NULL; 343cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XADataSink imageVideoSink; 344cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten imageVideoSink.pLocator = &locND; 345cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten imageVideoSink.pFormat = NULL; 346cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 347cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // create media player 348cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAObjectItf playerObject; 349cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAInterfaceID ids[4] = {XA_IID_STREAMINFORMATION, XA_IID_PREFETCHSTATUS, XA_IID_SEEK, 350c3d6dd225415ac68b1868575e793eb352c7105e2Glenn Kasten XA_IID_ANDROIDBUFFERQUEUESOURCE}; 351cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAboolean req[4] = {XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE}; 352cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*engineEngine)->CreateMediaPlayer(engineEngine, &playerObject, &dataSrc, NULL, 353cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten &audioSnk, nativeWindow != NULL ? &imageVideoSink : NULL, NULL, NULL, abq ? 4 : 3, ids, 354cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten req); 355cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 356cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 357cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // realize the player 358cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*playerObject)->Realize(playerObject, XA_BOOLEAN_FALSE); 359cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 360cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 361cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (abq) { 362cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 363cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // get the Android buffer queue interface 364cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAAndroidBufferQueueItf playerAndroidBufferQueue; 365c3d6dd225415ac68b1868575e793eb352c7105e2Glenn Kasten result = (*playerObject)->GetInterface(playerObject, XA_IID_ANDROIDBUFFERQUEUESOURCE, 366cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten &playerAndroidBufferQueue); 367cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 368cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 369cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // register the buffer queue callback 370cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*playerAndroidBufferQueue)->RegisterCallback(playerAndroidBufferQueue, 371cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten bufferQueueCallback, NULL); 372cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 373cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*playerAndroidBufferQueue)->SetCallbackEventsMask(playerAndroidBufferQueue, 374cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XA_ANDROIDBUFFERQUEUEEVENT_PROCESSED); 375cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 376cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 377cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // enqueue the initial buffers until buffer queue is full 378cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAuint32 packetsThisBuffer; 379cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten for (curPacket = 0; curPacket < numPackets; curPacket += packetsThisBuffer) { 380cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // handle the unlikely case of a very short .ts 381cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten packetsThisBuffer = numPackets - curPacket; 382cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (packetsThisBuffer > PACKETS_PER_BUFFER) { 383cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten packetsThisBuffer = PACKETS_PER_BUFFER; 384cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 385cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*playerAndroidBufferQueue)->Enqueue(playerAndroidBufferQueue, NULL, 386cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten &packets[curPacket], MPEG2TS_PACKET_SIZE * packetsThisBuffer, NULL, 0); 387cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (XA_RESULT_BUFFER_INSUFFICIENT == result) { 388cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten printf("Enqueued initial %u packets in %u buffers\n", curPacket, curPacket / PACKETS_PER_BUFFER); 389cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten break; 390cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 391cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 392cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 393cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 394cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 395cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 396cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // get the stream information interface 397cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAStreamInformationItf playerStreamInformation; 398cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*playerObject)->GetInterface(playerObject, XA_IID_STREAMINFORMATION, 399cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten &playerStreamInformation); 400cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 401cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 402cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // register the stream event change callback 403cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*playerStreamInformation)->RegisterStreamChangeCallback(playerStreamInformation, 404cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten streamEventChangeCallback, NULL); 405cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 406cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 407cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // get the prefetch status interface 408cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAPrefetchStatusItf playerPrefetchStatus; 409cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*playerObject)->GetInterface(playerObject, XA_IID_PREFETCHSTATUS, 410cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten &playerPrefetchStatus); 411cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 412cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 413cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // register prefetch status callback 414cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*playerPrefetchStatus)->RegisterCallback(playerPrefetchStatus, prefetchStatusCallback, 415cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten NULL); 416cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 417cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*playerPrefetchStatus)->SetCallbackEventsMask(playerPrefetchStatus, 418cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XA_PREFETCHEVENT_FILLLEVELCHANGE | XA_PREFETCHEVENT_STATUSCHANGE); 419cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 420cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 421cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // get the seek interface 422cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (looping) { 423cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XASeekItf playerSeek; 424cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*playerObject)->GetInterface(playerObject, XA_IID_SEEK, &playerSeek); 425cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 426cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*playerSeek)->SetLoop(playerSeek, XA_BOOLEAN_TRUE, (XAmillisecond) 0, 427cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XA_TIME_UNKNOWN); 428cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 429cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 430cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 431cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // get the play interface 432cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAPlayItf playerPlay; 433cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*playerObject)->GetInterface(playerObject, XA_IID_PLAY, &playerPlay); 434cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 435cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 436cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // register play event callback 437cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*playerPlay)->RegisterCallback(playerPlay, playEventCallback, NULL); 438cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 439cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#if 0 // FIXME broken 440cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*playerPlay)->SetCallbackEventsMask(playerPlay, 441cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XA_PLAYEVENT_HEADATEND | XA_PLAYEVENT_HEADATMARKER | XA_PLAYEVENT_HEADATNEWPOS); 442cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 443cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#endif 444cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 445cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // set a marker 446cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*playerPlay)->SetMarkerPosition(playerPlay, 10000); 447cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 448cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 449cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // set position update period 450cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*playerPlay)->SetPositionUpdatePeriod(playerPlay, 1000); 451cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 452cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 453cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // get the duration 454cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAmillisecond duration; 455cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*playerPlay)->GetDuration(playerPlay, &duration); 456cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 457cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (XA_TIME_UNKNOWN == duration) 458cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten printf("Duration: unknown\n"); 459cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten else 460cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten printf("Duration: %.1f\n", duration / 1000.0f); 461cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 462cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // set the player's state to paused, to start prefetching 463cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten printf("start prefetch\n"); 464cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*playerPlay)->SetPlayState(playerPlay, XA_PLAYSTATE_PAUSED); 465cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 466cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 467cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // wait for prefetch status callback to indicate either sufficient data or error 468cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten pthread_mutex_lock(&mutex); 469cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten while (prefetch_status == PREFETCHSTATUS_UNKNOWN) { 470cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten pthread_cond_wait(&cond, &mutex); 471cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 472cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten pthread_mutex_unlock(&mutex); 473cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (prefetch_status == PREFETCHSTATUS_ERROR) { 474cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten fprintf(stderr, "Error during prefetch, exiting\n"); 475cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten goto destroyRes; 476cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 477cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 478cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // get duration again, now it should be known 479cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*playerPlay)->GetDuration(playerPlay, &duration); 480cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 481cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (duration == XA_TIME_UNKNOWN) { 482cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten fprintf(stdout, "Content duration is unknown (after prefetch completed)\n"); 483cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } else { 484cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten fprintf(stdout, "Content duration is %u ms (after prefetch completed)\n", duration); 485cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 486cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 487cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // start playing 488cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten printf("starting to play\n"); 489cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*playerPlay)->SetPlayState(playerPlay, XA_PLAYSTATE_PLAYING); 490cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 491cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 492cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // continue playing until end of media 493cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten for (;;) { 494cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten XAuint32 status; 495cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten result = (*playerPlay)->GetPlayState(playerPlay, &status); 496cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(XA_RESULT_SUCCESS == result); 497cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (status == XA_PLAYSTATE_PAUSED) 498cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten break; 499cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten assert(status == XA_PLAYSTATE_PLAYING); 500cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten sleep(1); 501cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 502cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 503cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // wait a bit more in case of additional callbacks 504cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten printf("end of media\n"); 505cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten sleep(3); 506cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 507cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn KastendestroyRes: 508cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 509cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // destroy the player 510cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten (*playerObject)->Destroy(playerObject); 511cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 512cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // destroy the output mix 513cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten (*outputMixObject)->Destroy(outputMixObject); 514cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 515cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten // destroy the engine 516cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten (*engineObject)->Destroy(engineObject); 517cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 518cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#ifdef REINITIALIZE 519cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (--reinit_count > 0) { 520cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten prefetch_status = PREFETCHSTATUS_UNKNOWN; 521cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten goto reinitialize; 522cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 523cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#endif 524cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 525cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#if 0 526cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (nativeWindow != NULL) { 527cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten ANativeWindow_release(nativeWindow); 528cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 529cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten#endif 530cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 531cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kastenclose: 532cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten if (fd >= 0) { 533cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten (void) close(fd); 534cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten } 535cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten 536cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten return EXIT_SUCCESS; 537cb9de966a5f0b9773fee2aa7b5142d69d7cf7e37Glenn Kasten} 538