char data[MPEG2TS_PACKET_SIZE];
} MPEG2TS_Packet;
-#if 0
-// Each buffer in Android buffer queue
-typedef struct {
- MPEG2TS_Packet packets[PACKETS_PER_BUFFER];
-} Buffer;
-#endif
-
// Globals shared between main thread and buffer queue callback
MPEG2TS_Packet *packets;
-size_t numPackets;
-size_t curPacket;
-size_t discPacket;
+size_t totalPackets; // total number of packets in input file
+size_t numPackets; // number of packets to play, defaults to totalPackets - firstPacket
+size_t curPacket; // current packet index
+size_t discPacket; // discontinuity packet index, defaults to no discontinuity requested
+size_t afterDiscPacket; // packet index to switch to after the discontinuity
+size_t firstPacket; // first packet index to be played, defaults to zero
+size_t lastPacket; // last packet index to be played
+size_t formatPacket; // format change packet index, defaults to no format change requested
+XAmillisecond seekPos = XA_TIME_UNKNOWN; // seek to this position initially
+int pauseMs = -1; // pause after this many ms into playback
+XAboolean forceCallbackFailure = XA_BOOLEAN_FALSE; // force callback failures occasionally
+XAboolean sentEOS = XA_BOOLEAN_FALSE; // whether we have enqueued EOS yet
// These are extensions to OpenMAX AL 1.0.1 values
// pContext is unused here, so we pass NULL
assert(NULL == pContext);
+ XAresult result;
XAmillisecond position;
+ result = (*caller)->GetPosition(caller, &position);
+ assert(XA_RESULT_SUCCESS == result);
if (XA_PLAYEVENT_HEADATEND & event) {
- printf("XA_PLAYEVENT_HEADATEND reached\n");
- //SignalEos();
+ printf("XA_PLAYEVENT_HEADATEND current position=%u ms\n", position);
}
- XAresult result;
if (XA_PLAYEVENT_HEADATNEWPOS & event) {
- result = (*caller)->GetPosition(caller, &position);
- assert(XA_RESULT_SUCCESS == result);
- printf("XA_PLAYEVENT_HEADATNEWPOS current position=%ums\n", position);
+ printf("XA_PLAYEVENT_HEADATNEWPOS current position=%u ms\n", position);
}
if (XA_PLAYEVENT_HEADATMARKER & event) {
- result = (*caller)->GetPosition(caller, &position);
- assert(XA_RESULT_SUCCESS == result);
- printf("XA_PLAYEVENT_HEADATMARKER current position=%ums\n", position);
+ printf("XA_PLAYEVENT_HEADATMARKER current position=%u ms\n", position);
}
}
const XAAndroidBufferItem *pItems,
XAuint32 itemsLength)
{
+ XAPlayItf playerPlay = (XAPlayItf) pCallbackContext;
// enqueue the .ts data directly from mapped memory, so ignore the empty buffer pBufferData
- if (curPacket <= numPackets) {
+ if (curPacket <= lastPacket) {
static const XAAndroidBufferItem discontinuity = {XA_ANDROID_ITEMKEY_DISCONTINUITY, 0};
static const XAAndroidBufferItem eos = {XA_ANDROID_ITEMKEY_EOS, 0};
+ static const XAAndroidBufferItem formatChange = {XA_ANDROID_ITEMKEY_FORMAT_CHANGE, 0};
const XAAndroidBufferItem *items;
XAuint32 itemSize;
// compute number of packets to be enqueued in this buffer
- XAuint32 packetsThisBuffer = numPackets - curPacket;
+ XAuint32 packetsThisBuffer = lastPacket - curPacket;
if (packetsThisBuffer > PACKETS_PER_BUFFER) {
packetsThisBuffer = PACKETS_PER_BUFFER;
}
// last packet? this should only happen once
- if (curPacket == numPackets) {
- (void) write(1, "e", 1);
+ if (curPacket == lastPacket) {
+ if (sentEOS) {
+ printf("buffer completion callback after EOS\n");
+ return XA_RESULT_SUCCESS;
+ }
+ printf("sending EOS\n");
items = &eos;
itemSize = sizeof(eos);
+ sentEOS = XA_BOOLEAN_TRUE;
// discontinuity requested?
} else if (curPacket == discPacket) {
- printf("sending discontinuity, rewinding from beginning of stream\n");
+ printf("sending discontinuity at packet %zu, then resuming at packet %zu\n", discPacket,
+ afterDiscPacket);
items = &discontinuity;
itemSize = sizeof(discontinuity);
- curPacket = 0;
+ curPacket = afterDiscPacket;
+ // format change requested?
+ } else if (curPacket == formatPacket) {
+ printf("sending format change");
+ items = &formatChange;
+ itemSize = sizeof(formatChange);
// pure data with no items
} else {
items = NULL;
sizeof(MPEG2TS_Packet) * packetsThisBuffer, items, itemSize);
assert(XA_RESULT_SUCCESS == result);
curPacket += packetsThisBuffer;
+ // display position periodically
+ if (curPacket % 1000 == 0) {
+ XAmillisecond position;
+ result = (*playerPlay)->GetPosition(playerPlay, &position);
+ assert(XA_RESULT_SUCCESS == result);
+ printf("Position after enqueueing packet %u: %u ms\n", curPacket, position);
+ }
+ }
+ if (forceCallbackFailure && (curPacket % 1230 == 0)) {
+ return (XAresult) curPacket;
+ } else {
+ return XA_RESULT_SUCCESS;
+ }
+}
+
+// convert a domain type to string
+static const char *domainToString(XAuint32 domain)
+{
+ switch (domain) {
+ case 0: // FIXME There's a private declaration '#define XA_DOMAINTYPE_CONTAINER 0' in src/data.h
+ // but we don't have access to it. Plan to file a bug with Khronos about this symbol.
+ return "media container";
+#define _(x) case x: return #x;
+ _(XA_DOMAINTYPE_AUDIO)
+ _(XA_DOMAINTYPE_VIDEO)
+ _(XA_DOMAINTYPE_IMAGE)
+ _(XA_DOMAINTYPE_TIMEDTEXT)
+ _(XA_DOMAINTYPE_MIDI)
+ _(XA_DOMAINTYPE_VENDOR)
+ _(XA_DOMAINTYPE_UNKNOWN)
+#undef _
+ default:
+ return "unknown";
}
- return XA_RESULT_SUCCESS;
}
// main program
XAboolean abq = XA_BOOLEAN_FALSE; // use AndroidBufferQueue, default is URI
XAboolean looping = XA_BOOLEAN_FALSE;
-#ifdef REINITIALIZE
- int reinit_counter = 0;
-#endif
for (i = 1; i < argc; ++i) {
const char *arg = argv[i];
if (arg[0] != '-')
case 'a':
abq = XA_BOOLEAN_TRUE;
break;
+ case 'c':
+ forceCallbackFailure = XA_BOOLEAN_TRUE;
+ break;
case 'd':
discPacket = atoi(&arg[2]);
break;
+ case 'D':
+ afterDiscPacket = atoi(&arg[2]);
+ break;
+ case 'f':
+ firstPacket = atoi(&arg[2]);
+ break;
+ case 'F':
+ formatPacket = atoi(&arg[2]);
+ break;
case 'l':
looping = XA_BOOLEAN_TRUE;
break;
-#ifdef REINITIALIZE
- case 'r':
- reinit_counter = atoi(&arg[2]);
+ case 'n':
+ numPackets = atoi(&arg[2]);
+ break;
+ case 'p':
+ pauseMs = atoi(&arg[2]);
+ break;
+ case 's':
+ seekPos = atoi(&arg[2]);
break;
-#endif
default:
fprintf(stderr, "%s: unknown option %s\n", prog, arg);
break;
// check that exactly one URI was specified
if (argc - i != 1) {
- fprintf(stderr, "usage: %s [-a] [-d#] [-l] uri\n", prog);
+ fprintf(stderr, "usage: %s [-a] [-c] [-d#] [-D#] [-f#] [-F#] [-l] [-n#] [-p#] [-s#] uri\n",
+ prog);
+ fprintf(stderr, " -a Use Android buffer queue to supply data, default is URI\n");
+ fprintf(stderr, " -c Force callback to return an error randomly, for debugging only\n");
+ fprintf(stderr, " -d# Packet index to insert a discontinuity, default is none\n");
+ fprintf(stderr, " -D# Packet index to switch to after the discontinuity\n");
+ fprintf(stderr, " -f# First packet index, defaults to 0\n");
+ fprintf(stderr, " -F# Packet index to insert a format change, default is none\n");
+ fprintf(stderr, " -l Enable looping, for URI only\n");
+ fprintf(stderr, " -n# Number of packets to enqueue\n");
+ fprintf(stderr, " -p# Pause playback for 5 seconds after this many milliseconds\n");
+ fprintf(stderr, " -s# Seek position in milliseconds, for URI only\n");
return EXIT_FAILURE;
}
const char *uri = argv[i];
MPEG2TS_PACKET_SIZE);
}
packets = (MPEG2TS_Packet *) ptr;
- numPackets = filelen / MPEG2TS_PACKET_SIZE;
- printf("%s has %zu packets\n", uri, numPackets);
+ totalPackets = filelen / MPEG2TS_PACKET_SIZE;
+ printf("%s has %zu total packets\n", uri, totalPackets);
+ if (firstPacket >= totalPackets) {
+ fprintf(stderr, "-f%zu ignored\n", firstPacket);
+ firstPacket = 0;
+ }
+ if (numPackets == 0) {
+ numPackets = totalPackets - firstPacket;
+ } else if (firstPacket + numPackets > totalPackets) {
+ fprintf(stderr, "-n%zu ignored\n", numPackets);
+ numPackets = totalPackets - firstPacket;
+ }
+ lastPacket = firstPacket + numPackets;
+ if (discPacket != 0 && (discPacket < firstPacket || discPacket >= lastPacket)) {
+ fprintf(stderr, "-d%zu ignored\n", discPacket);
+ discPacket = 0;
+ }
+ if (afterDiscPacket < firstPacket || afterDiscPacket >= lastPacket) {
+ fprintf(stderr, "-D%zu ignored\n", afterDiscPacket);
+ afterDiscPacket = 0;
+ }
+ if (formatPacket != 0 && (formatPacket < firstPacket || formatPacket >= lastPacket)) {
+ fprintf(stderr, "-F%zu ignored\n", formatPacket);
+ formatPacket = 0;
+ }
}
ANativeWindow *nativeWindow;
-#ifdef REINITIALIZE
-reinitialize: ;
-#endif
-
XAresult result;
XAObjectItf engineObject;
XAObjectItf playerObject;
XAInterfaceID ids[4] = {XA_IID_STREAMINFORMATION, XA_IID_PREFETCHSTATUS, XA_IID_SEEK,
XA_IID_ANDROIDBUFFERQUEUESOURCE};
- XAboolean req[4] = {XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE};
+ XAboolean req[4] = {XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE, XA_BOOLEAN_FALSE, XA_BOOLEAN_TRUE};
result = (*engineEngine)->CreateMediaPlayer(engineEngine, &playerObject, &dataSrc, NULL,
&audioSnk, nativeWindow != NULL ? &imageVideoSink : NULL, NULL, NULL, abq ? 4 : 3, ids,
req);
result = (*playerObject)->Realize(playerObject, XA_BOOLEAN_FALSE);
assert(XA_RESULT_SUCCESS == result);
+ // get the play interface
+ XAPlayItf playerPlay;
+ result = (*playerObject)->GetInterface(playerObject, XA_IID_PLAY, &playerPlay);
+ assert(XA_RESULT_SUCCESS == result);
+
if (abq) {
// get the Android buffer queue interface
// register the buffer queue callback
result = (*playerAndroidBufferQueue)->RegisterCallback(playerAndroidBufferQueue,
- bufferQueueCallback, NULL);
+ bufferQueueCallback, (void *) playerPlay);
assert(XA_RESULT_SUCCESS == result);
result = (*playerAndroidBufferQueue)->SetCallbackEventsMask(playerAndroidBufferQueue,
XA_ANDROIDBUFFERQUEUEEVENT_PROCESSED);
assert(XA_RESULT_SUCCESS == result);
+ // set the player's state to paused, to start prefetching
+ printf("start early prefetch\n");
+ result = (*playerPlay)->SetPlayState(playerPlay, XA_PLAYSTATE_PAUSED);
+ assert(XA_RESULT_SUCCESS == result);
+
// enqueue the initial buffers until buffer queue is full
XAuint32 packetsThisBuffer;
- for (curPacket = 0; curPacket < numPackets; curPacket += packetsThisBuffer) {
+ for (curPacket = firstPacket; curPacket < lastPacket; curPacket += packetsThisBuffer) {
// handle the unlikely case of a very short .ts
- packetsThisBuffer = numPackets - curPacket;
+ packetsThisBuffer = lastPacket - curPacket;
if (packetsThisBuffer > PACKETS_PER_BUFFER) {
packetsThisBuffer = PACKETS_PER_BUFFER;
}
result = (*playerAndroidBufferQueue)->Enqueue(playerAndroidBufferQueue, NULL,
&packets[curPacket], MPEG2TS_PACKET_SIZE * packetsThisBuffer, NULL, 0);
if (XA_RESULT_BUFFER_INSUFFICIENT == result) {
- printf("Enqueued initial %u packets in %u buffers\n", curPacket, curPacket / PACKETS_PER_BUFFER);
+ printf("Enqueued initial %u packets in %u buffers\n", curPacket - firstPacket,
+ (curPacket - firstPacket + PACKETS_PER_BUFFER - 1) / PACKETS_PER_BUFFER);
break;
}
assert(XA_RESULT_SUCCESS == result);
XA_PREFETCHEVENT_FILLLEVELCHANGE | XA_PREFETCHEVENT_STATUSCHANGE);
assert(XA_RESULT_SUCCESS == result);
- // get the seek interface
- if (looping) {
+ // get the seek interface for seeking and/or looping
+ if (looping || seekPos != XA_TIME_UNKNOWN) {
XASeekItf playerSeek;
result = (*playerObject)->GetInterface(playerObject, XA_IID_SEEK, &playerSeek);
assert(XA_RESULT_SUCCESS == result);
- result = (*playerSeek)->SetLoop(playerSeek, XA_BOOLEAN_TRUE, (XAmillisecond) 0,
- XA_TIME_UNKNOWN);
- assert(XA_RESULT_SUCCESS == result);
+ if (seekPos != XA_TIME_UNKNOWN) {
+ result = (*playerSeek)->SetPosition(playerSeek, seekPos, XA_SEEKMODE_ACCURATE);
+ if (XA_RESULT_FEATURE_UNSUPPORTED == result) {
+ fprintf(stderr, "-s%u (seek to initial position) is unsupported\n", seekPos);
+ } else {
+ assert(XA_RESULT_SUCCESS == result);
+ }
+ }
+ if (looping) {
+ result = (*playerSeek)->SetLoop(playerSeek, XA_BOOLEAN_TRUE, (XAmillisecond) 0,
+ XA_TIME_UNKNOWN);
+ if (XA_RESULT_FEATURE_UNSUPPORTED) {
+ fprintf(stderr, "-l (looping) is unsupported\n");
+ } else {
+ assert(XA_RESULT_SUCCESS == result);
+ }
+ }
}
- // get the play interface
- XAPlayItf playerPlay;
- result = (*playerObject)->GetInterface(playerObject, XA_IID_PLAY, &playerPlay);
- assert(XA_RESULT_SUCCESS == result);
-
// register play event callback
result = (*playerPlay)->RegisterCallback(playerPlay, playEventCallback, NULL);
assert(XA_RESULT_SUCCESS == result);
-#if 0 // FIXME broken
result = (*playerPlay)->SetCallbackEventsMask(playerPlay,
XA_PLAYEVENT_HEADATEND | XA_PLAYEVENT_HEADATMARKER | XA_PLAYEVENT_HEADATNEWPOS);
assert(XA_RESULT_SUCCESS == result);
-#endif
// set a marker
- result = (*playerPlay)->SetMarkerPosition(playerPlay, 10000);
+ result = (*playerPlay)->SetMarkerPosition(playerPlay, 5000);
assert(XA_RESULT_SUCCESS == result);
// set position update period
- result = (*playerPlay)->SetPositionUpdatePeriod(playerPlay, 1000);
+ result = (*playerPlay)->SetPositionUpdatePeriod(playerPlay, 2000);
assert(XA_RESULT_SUCCESS == result);
- // get the duration
+ // get the position before prefetch
+ XAmillisecond position;
+ result = (*playerPlay)->GetPosition(playerPlay, &position);
+ assert(XA_RESULT_SUCCESS == result);
+ printf("Position before prefetch: %u ms\n", position);
+
+ // get the duration before prefetch
XAmillisecond duration;
result = (*playerPlay)->GetDuration(playerPlay, &duration);
assert(XA_RESULT_SUCCESS == result);
if (XA_TIME_UNKNOWN == duration)
- printf("Duration: unknown\n");
+ printf("Duration before prefetch: unknown as expected\n");
else
- printf("Duration: %.1f\n", duration / 1000.0f);
+ printf("Duration before prefetch: %.1f (surprise!)\n", duration / 1000.0f);
// set the player's state to paused, to start prefetching
printf("start prefetch\n");
goto destroyRes;
}
- // get duration again, now it should be known
+ // get the position after prefetch
+ result = (*playerPlay)->GetPosition(playerPlay, &position);
+ assert(XA_RESULT_SUCCESS == result);
+ printf("Position after prefetch: %u ms\n", position);
+
+ // get duration again, now it should be known for the file source or unknown for TS
result = (*playerPlay)->GetDuration(playerPlay, &duration);
assert(XA_RESULT_SUCCESS == result);
if (duration == XA_TIME_UNKNOWN) {
- fprintf(stdout, "Content duration is unknown (after prefetch completed)\n");
+ printf("Duration after prefetch: unknown (expected for TS, unexpected for file)\n");
} else {
- fprintf(stdout, "Content duration is %u ms (after prefetch completed)\n", duration);
+ printf("Duration after prefetch: %u ms (expected for file, unexpected for TS)\n", duration);
}
+ // query for media container information
+ result = (*playerStreamInformation)->QueryMediaContainerInformation(playerStreamInformation,
+ NULL);
+ assert(XA_RESULT_PARAMETER_INVALID == result);
+ XAMediaContainerInformation mediaContainerInformation;
+ // this verifies it is filling in all the fields
+ memset(&mediaContainerInformation, 0x55, sizeof(XAMediaContainerInformation));
+ result = (*playerStreamInformation)->QueryMediaContainerInformation(playerStreamInformation,
+ &mediaContainerInformation);
+ assert(XA_RESULT_SUCCESS == result);
+ printf("Media container information:\n");
+ printf(" containerType = %u\n", mediaContainerInformation.containerType);
+ printf(" mediaDuration = %u\n", mediaContainerInformation.mediaDuration);
+ printf(" numStreams = %u\n", mediaContainerInformation.numStreams);
+
+ // Now query for each the streams. Note that stream indices go up to and including
+ // mediaContainerInformation.numStreams, because stream 0 is the container itself,
+ // while stream 1 to mediaContainerInformation.numStreams are the contained streams.
+ XAuint32 numStreams = mediaContainerInformation.numStreams;
+ XAuint32 streamIndex;
+ for (streamIndex = 0; streamIndex <= mediaContainerInformation.numStreams; ++streamIndex) {
+ XAuint32 domain;
+ XAuint16 nameSize;
+ XAchar name[64];
+ printf("stream[%u]:\n", streamIndex);
+ if (streamIndex == 0) {
+ result = (*playerStreamInformation)->QueryStreamType(playerStreamInformation,
+ streamIndex, &domain);
+ assert(XA_RESULT_PARAMETER_INVALID == result);
+ result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
+ streamIndex, &mediaContainerInformation);
+ //assert(XA_RESULT_PARAMETER_INVALID == result);
+ nameSize = sizeof(name);
+ result = (*playerStreamInformation)->QueryStreamName(playerStreamInformation,
+streamIndex, &nameSize, name);
+ //assert(XA_RESULT_PARAMETER_INVALID == result);
+ continue;
+ }
+ result = (*playerStreamInformation)->QueryStreamType(playerStreamInformation, streamIndex,
+ NULL);
+ assert(XA_RESULT_PARAMETER_INVALID == result);
+ domain = 12345;
+ result = (*playerStreamInformation)->QueryStreamType(playerStreamInformation, streamIndex,
+ &domain);
+ assert(XA_RESULT_SUCCESS == result);
+ printf(" QueryStreamType: domain = 0x%X (%s)\n", domain, domainToString(domain));
+ nameSize = sizeof(name);
+ result = (*playerStreamInformation)->QueryStreamName(playerStreamInformation, streamIndex,
+ &nameSize, name);
+#if 0
+ assert(XA_RESULT_SUCCESS == result);
+ assert(sizeof(name) >= nameSize);
+ if (sizeof(name) != nameSize) {
+ assert('\0' == name[nameSize]);
+ }
+ printf(" QueryStreamName: nameSize=%u, name=\"%.*s\"\n", nameSize, nameSize, name);
+ result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
+ streamIndex, NULL);
+ assert(XA_RESULT_PARAMETER_INVALID == result);
+#endif
+
+ printf(" QueryStreamInformation:\n");
+ switch (domain) {
+#if 0
+ case 0: // FIXME container
+ result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
+streamIndex, &mediaContainerInformation);
+ assert(XA_RESULT_SUCCESS == result);
+ printf(" containerType = %u (1=unspecified)\n",
+ mediaContainerInformation.containerType);
+ printf(" mediaDuration = %u\n", mediaContainerInformation.mediaDuration);
+ printf(" numStreams = %u\n", mediaContainerInformation.numStreams);
+ break;
+#endif
+ case XA_DOMAINTYPE_AUDIO: {
+ XAAudioStreamInformation audioStreamInformation;
+ memset(&audioStreamInformation, 0x55, sizeof(XAAudioStreamInformation));
+ result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
+ streamIndex, &audioStreamInformation);
+ assert(XA_RESULT_PARAMETER_INVALID == result);
+ printf(" codecId = %u\n", audioStreamInformation.codecId);
+ printf(" channels = %u\n", audioStreamInformation.channels);
+ printf(" sampleRate = %u\n", audioStreamInformation.sampleRate);
+ printf(" bitRate = %u\n", audioStreamInformation.bitRate);
+ printf(" langCountry = \"%s\"\n", audioStreamInformation.langCountry);
+ printf(" duration = %u\n", audioStreamInformation.duration);
+ } break;
+ case XA_DOMAINTYPE_VIDEO: {
+ XAVideoStreamInformation videoStreamInformation;
+ result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
+ streamIndex, &videoStreamInformation);
+ assert(XA_RESULT_SUCCESS == result);
+ printf(" codecId = %u\n", videoStreamInformation.codecId);
+ printf(" width = %u\n", videoStreamInformation.width);
+ printf(" height = %u\n", videoStreamInformation.height);
+ printf(" frameRate = %u\n", videoStreamInformation.frameRate);
+ printf(" bitRate = %u\n", videoStreamInformation.bitRate);
+ printf(" duration = %u\n", videoStreamInformation.duration);
+ } break;
+ case XA_DOMAINTYPE_IMAGE: {
+ XAImageStreamInformation imageStreamInformation;
+ result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
+ streamIndex, &imageStreamInformation);
+ assert(XA_RESULT_SUCCESS == result);
+ printf(" codecId = %u\n", imageStreamInformation.codecId);
+ printf(" width = %u\n", imageStreamInformation.width);
+ printf(" height = %u\n", imageStreamInformation.height);
+ printf(" presentationDuration = %u\n", imageStreamInformation.presentationDuration);
+ } break;
+ case XA_DOMAINTYPE_TIMEDTEXT: {
+ XATimedTextStreamInformation timedTextStreamInformation;
+ result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
+ streamIndex, &timedTextStreamInformation);
+ assert(XA_RESULT_SUCCESS == result);
+ printf(" layer = %u\n", timedTextStreamInformation.layer);
+ printf(" width = %u\n", timedTextStreamInformation.width);
+ printf(" height = %u\n", timedTextStreamInformation.height);
+ printf(" tx = %u\n", timedTextStreamInformation.tx);
+ printf(" ty = %u\n", timedTextStreamInformation.ty);
+ printf(" bitrate = %u\n", timedTextStreamInformation.bitrate);
+ printf(" langCountry = \"%s\"\n", timedTextStreamInformation.langCountry);
+ printf(" duration = %u\n", timedTextStreamInformation.duration);
+ } break;
+ case XA_DOMAINTYPE_MIDI: {
+ XAMIDIStreamInformation midiStreamInformation;
+ result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
+ streamIndex, &midiStreamInformation);
+ assert(XA_RESULT_SUCCESS == result);
+ printf(" channels = %u\n", midiStreamInformation.channels);
+ printf(" tracks = %u\n", midiStreamInformation.tracks);
+ printf(" bankType = %u\n", midiStreamInformation.bankType);
+ printf(" langCountry = \"%s\"\n", midiStreamInformation.langCountry);
+ printf(" duration = %u\n", midiStreamInformation.duration);
+ } break;
+ case XA_DOMAINTYPE_VENDOR: {
+ XAVendorStreamInformation vendorStreamInformation;
+ result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
+ streamIndex, &vendorStreamInformation);
+ assert(XA_RESULT_SUCCESS == result);
+ printf(" VendorStreamInfo = %p\n", vendorStreamInformation.VendorStreamInfo);
+ } break;
+ case XA_DOMAINTYPE_UNKNOWN: {
+ // "It is not possible to query Information for streams identified as
+ // XA_DOMAINTYPE_UNKNOWN, any attempt to do so shall return a result of
+ // XA_RESULT_CONTENT_UNSUPPORTED."
+ char big[256];
+ result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
+ streamIndex, &big);
+ assert(XA_RESULT_CONTENT_UNSUPPORTED == result);
+ } break;
+ default:
+ break;
+ }
+
+ }
+ // Try one more stream index beyond the valid range
+ XAuint32 domain;
+ result = (*playerStreamInformation)->QueryStreamType(playerStreamInformation, streamIndex,
+ &domain);
+ assert(XA_RESULT_PARAMETER_INVALID == result);
+ XATimedTextStreamInformation big;
+ result = (*playerStreamInformation)->QueryStreamInformation(playerStreamInformation,
+ streamIndex, &big);
+ assert(XA_RESULT_PARAMETER_INVALID == result);
+
+ printf("QueryActiveStreams:\n");
+ result = (*playerStreamInformation)->QueryActiveStreams(playerStreamInformation, NULL, NULL);
+ assert(XA_RESULT_PARAMETER_INVALID == result);
+ XAuint32 numStreams1 = 0x12345678;
+ result = (*playerStreamInformation)->QueryActiveStreams(playerStreamInformation, &numStreams1,
+ NULL);
+ assert(XA_RESULT_SUCCESS == result);
+ printf(" numStreams = %u\n", numStreams1);
+ XAboolean *activeStreams = calloc(numStreams1 + 1, sizeof(XAboolean));
+ assert(NULL != activeStreams);
+ printf(" active stream(s) =");
+ XAuint32 numStreams2 = numStreams1;
+ result = (*playerStreamInformation)->QueryActiveStreams(playerStreamInformation, &numStreams2,
+ activeStreams);
+ assert(XA_RESULT_SUCCESS == result);
+ assert(numStreams2 == numStreams1);
+ for (streamIndex = 0; streamIndex <= numStreams1; ++streamIndex) {
+ if (activeStreams[streamIndex])
+ printf(" %u", streamIndex);
+ }
+ printf("\n");
+
+ // SetActiveStream is untested
+
// start playing
printf("starting to play\n");
result = (*playerPlay)->SetPlayState(playerPlay, XA_PLAYSTATE_PLAYING);
if (status == XA_PLAYSTATE_PAUSED)
break;
assert(status == XA_PLAYSTATE_PLAYING);
- sleep(1);
+ usleep(100000);
+ if (pauseMs >= 0) {
+ result = (*playerPlay)->GetPosition(playerPlay, &position);
+ assert(XA_RESULT_SUCCESS == result);
+ if (position >= pauseMs) {
+ printf("Pausing for 5 seconds at position %u\n", position);
+ result = (*playerPlay)->SetPlayState(playerPlay, XA_PLAYSTATE_PAUSED);
+ assert(XA_RESULT_SUCCESS == result);
+ sleep(5);
+ // FIXME clear ABQ queue here
+ result = (*playerPlay)->SetPlayState(playerPlay, XA_PLAYSTATE_PLAYING);
+ assert(XA_RESULT_SUCCESS == result);
+ pauseMs = -1;
+ }
+ }
}
// wait a bit more in case of additional callbacks
printf("end of media\n");
sleep(3);
+ // get final position
+ result = (*playerPlay)->GetPosition(playerPlay, &position);
+ assert(XA_RESULT_SUCCESS == result);
+ printf("Position at end: %u ms\n", position);
+
+ // get duration again, now it should be known
+ result = (*playerPlay)->GetDuration(playerPlay, &duration);
+ assert(XA_RESULT_SUCCESS == result);
+ if (duration == XA_TIME_UNKNOWN) {
+ printf("Duration at end: unknown\n");
+ } else {
+ printf("Duration at end: %u ms\n", duration);
+ }
+
destroyRes:
// destroy the player
// destroy the engine
(*engineObject)->Destroy(engineObject);
-#ifdef REINITIALIZE
- if (--reinit_count > 0) {
- prefetch_status = PREFETCHSTATUS_UNKNOWN;
- goto reinitialize;
- }
-#endif
-
#if 0
if (nativeWindow != NULL) {
ANativeWindow_release(nativeWindow);
(void) close(fd);
}
+ disposeNativeWindow();
+
return EXIT_SUCCESS;
}