void flipThread(void *refcon) { KplScreen screen = refcon; FskThread mainThread = FskThreadGetMain(); FskTimeRecord later; SInt32 ms; FskThreadInitializationComplete(FskThreadGetCurrent()); while (!gQuitting) { //Save the last Flip time FskTimeGetNow(&gKplScreen->lastFlipTime); FskTimeCopy(&later, &gKplScreen->nextFlipTime); FskTimeSub(&gKplScreen->lastFlipTime, &later); ms = FskTimeInMS(&later); if (ms > 0) { FskDelay(ms); MLOG("[%s] delay %d ms\n", threadName, ms); } // Kick off the next cycle if (gKplScreen->drawingPumpEnabled) { FskSemaphoreAcquire(screen->flipSemaphore); gKplScreen->callbackPostedCount++; FskThreadPostCallback(mainThread, drawingPumpCallback, (void*)gKplScreen->callbackPostedCount, NULL, NULL, NULL); } } }
static void drawingPumpUpdate(FskWindow win) { FskTimeRecord delta, now; FskTimeGetNow(&now); gKplScreen->unlocked = false; FskTimeCopy(&delta, &now); FskTimeSub(&gKplScreen->lastUpdateTime, &delta); FskTimeCopy(&gKplScreen->lastUpdateTime, &now); MLOG("[%s] called %d ms after last update\n", threadName, FskTimeInMS(&delta)); // estimate next flip time by adding vSync interval to previous flip time FskTimeCopy(&gKplScreen->nextFlipTime, &gKplScreen->lastFlipTime); FskTimeAdd(&gKplScreen->vSyncIntervalTime, &gKplScreen->nextFlipTime); while (FskTimeCompare(&gKplScreen->nextFlipTime, &now) > 0) FskTimeAdd(&gKplScreen->vSyncIntervalTime, &gKplScreen->nextFlipTime); MLOG("Next flip time %ld.%06ld \n", gKplScreen->nextFlipTime.seconds, gKplScreen->nextFlipTime.useconds); FskWindowCheckEventQueue(win); FskWindowUpdate(win, &gKplScreen->nextFlipTime); if (!gKplScreen->unlocked) FskSemaphoreRelease(gKplScreen->flipSemaphore); MLOG("[%s] Finished callback %ld, nextFlipTime %1d.%03d\n", threadName, gKplScreen->callbackFiredCount, gKplScreen->nextFlipTime.seconds, gKplScreen->nextFlipTime.useconds / 1000); }
void KplTimeGetNow(KplTime t) { #if USE_POSIX_CLOCK struct timespec tp; clock_gettime(CLOCK_MONOTONIC, &tp); t->seconds = tp.tv_sec; t->useconds = tp.tv_nsec / kFskTimeNsecPerUsec; FskTimeSub(&sBasetime, t); #else struct timeval tv; struct timezone tz; gettimeofday(&tv, &tz); t->seconds = tv.tv_sec; t->useconds = tv.tv_usec; // correction for system time adjusted with KplTimeStime FskTimeSub(&gDeltaTime, (FskTime)t); #endif }
FskErr mp3ReaderGetSeekableSegment(void *readerState, void *track, UInt32 propertyID, FskMediaPropertyValue property) { mp3Reader state = readerState; property->type = kFskMediaPropertyTypeFloat; if (state->isOrbiter) { FskTimeRecord now; FskTimeGetNow(&now); FskTimeSub(&state->orbStart, &now); property->value.number = FskTimeInMS(&now) / 500.0; // assume it can transcode at twice real time if (property->value.number > state->mi.duration) { property->value.number = state->mi.duration; state->reader->needsIdle = false; } return kFskErrNone; } if (!(kFskMediaSpoolerDownloading & state->spooler->flags) || (-1 == state->mi.duration)) return kFskErrUnimplemented; if ((state->spoolerPosition <= state->mi.dataOffset) || (0 == state->mi.dataSize)) property->value.number = 0; else { FskInt64 position = state->spoolerPosition - state->mi.dataOffset; double time; time = (((double)position) / ((double)state->mi.dataSize)) * (double)(state->mi.duration * state->mi.frequency); while (state->mi.xingToc) { FskInt64 xingPos; mp3TimeToPosition(state, time, &xingPos); xingPos -= state->mi.dataOffset; if (xingPos <= position) break; if (0 == time) break; if (time < state->mi.frequency) time = 0; else time -= state->mi.frequency; } property->value.number = time / ((double)state->mi.frequency); } return kFskErrNone; }
FskErr FskAudioDecompressFrames(FskAudioDecompress deco, const void *data, UInt32 dataSize, UInt32 frameCount, UInt32 *frameSizes, void **samples, UInt32 *audioFormat, UInt32 *sampleCount, UInt32 *channelCount) { FskErr err; UInt32 samplesSize = 0; #if SUPPORT_INSTRUMENTATION FskTimeRecord start, now; if (FskInstrumentedItemHasListenersForLevel(deco, kFskInstrumentationLevelDebug)) FskTimeGetNow(&start); else start.seconds = start.useconds = 0; #endif *samples = 0; *sampleCount = 0; err = (deco->decoder->doDecompressFrames)(deco->state, deco, data, dataSize, frameCount, frameSizes, samples, &samplesSize); if (err) { FskInstrumentedItemSendMessageMinimal(deco, kFskAudioDecompressInstrDecompressFailed, (void *)err); goto bail; } deco->frameNumber += frameCount; *sampleCount = samplesSize / (2 * deco->outputChannelCount); if (audioFormat) *audioFormat = deco->outputFormat; if (channelCount) *channelCount = deco->outputChannelCount; #if SUPPORT_INSTRUMENTATION if (FskInstrumentedItemHasListenersForLevel(deco, kFskInstrumentationLevelMinimal)) { void *msgData[5]; msgData[0] = (void *)data; msgData[1] = (void *)dataSize; msgData[2] = (void *)frameCount; msgData[3] = (void *)*sampleCount; if (!start.seconds) msgData[4] = (void *)0; else { FskTimeGetNow(&now); FskTimeSub(&start, &now); msgData[4] = (void *)FskTimeInMS(&now); } FskInstrumentedItemSendMessageForLevel(deco, kFskAudioDecompressInstrDecompress, msgData, kFskInstrumentationLevelMinimal); } #endif bail: return err; }
UInt32 KplTimeCallbackGetNextTimeDelta() { KplTimeRecord now, nextTimeBasedCallback; SInt32 msec; KplTimeGetNow(&now); KplTimeCallbackGetNextTime(&now, &nextTimeBasedCallback, NULL); FskTimeSub((FskTime)&now, (FskTime)&nextTimeBasedCallback); msec = FskTimeInMS((FskTime)&nextTimeBasedCallback); // Clamp if (msec > 1000000) msec = 1000000; else if (msec < 1) msec = 1; return msec; }
FskErr KplTimeStime(SInt32 secs) { #ifdef ANDROID_PLATFORM FskErr err = kFskErrUnimplemented; return err; #else int result; FskErr err = kFskErrNone; time_t tsecs = secs; #if USE_POSIX_CLOCK result = stime(&tsecs); if (0 != result) err = kFskErrUnknown; #else struct timeval tv; FskTimeRecord b, a; gettimeofday(&tv, NULL); b.seconds = tv.tv_sec; b.useconds= tv.tv_usec; result = stime(&tsecs); gettimeofday(&tv, NULL); a.seconds = tv.tv_sec; a.useconds= tv.tv_usec; FskTimeSub(&b, &a); if (0 != result) err = kFskErrUnknown; else gDeltaTime.seconds += a.seconds; // stime only adjusts seconds #endif return err; #endif }
FskErr KplScreenGetBitmap(KplBitmap *bitmap) { FskErr err = kFskErrNone; KplScreen screen = NULL; int bpp; // Perform one-time intialization on the first request if (!gKplScreen) { FrameBufferVectorSet vectors; char *fbdev = deviceName; FskTimeRecord now; if (getenv("FRAMEBUFFER")) fbdev = getenv("FRAMEBUFFER"); BAIL_IF_ERR(err = FskMemPtrNewClear(sizeof(KplScreenRecord), (FskMemPtr *)&screen)); BAIL_IF_ERR(err = FskMemPtrNewClear(sizeof(KplBitmapRecord), (FskMemPtr *)&screen->bitmap)); screen->fbfd = open(fbdev, O_RDWR); if (-1 != screen->fbfd) { if (ioctl(screen->fbfd, FBIOGET_FSCREENINFO, &screen->finfo)) { fprintf(stderr, "Error: fb - reading fixed info\n"); exit(2); } if (ioctl(screen->fbfd, FBIOGET_VSCREENINFO, &screen->vinfo)) { fprintf(stderr, "Error: fb - reading variable info\n"); exit(3); } gScreenWidth = screen->vinfo.xres; gScreenHeight = screen->vinfo.yres; bpp = screen->vinfo.bits_per_pixel; screen->rowBytes = screen->vinfo.xres_virtual * bpp / 8; screen->screensize = gScreenHeight * screen->rowBytes; screen->framebuffer = (char*)mmap((void*)screen->finfo.smem_start, screen->finfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, screen->fbfd, 0); fprintf(stderr, "framebuffer mem_start: %d, length %d\n", screen->finfo.smem_start, screen->finfo.smem_len); fprintf(stderr, "mmio_start: %d, mmio_len: %d\n", screen->finfo.mmio_start, screen->finfo.mmio_len); if (screen->framebuffer == (char*)-1) { fprintf(stderr,"Error: can't map framebuffer %d\n", errno); exit(4); } screen->displayPage = 0; screen->baseAddr[0] = screen->framebuffer; // screen->baseAddr[1] = screen->framebuffer + screen->finfo.ypanstep * screen->finfo.line_length; FskBitmapNew(gScreenWidth, gScreenHeight, kFskBitmapFormat16RGB565LE, &screen->bitmaps[0]); // FskBitmapNew(gScreenWidth, gScreenHeight, kFskBitmapFormat16RGB565LE, &screen->bitmaps[1]); FskBitmapWriteBegin(screen->bitmaps[0], NULL, NULL, NULL); // FskBitmapWriteBegin(screen->bitmaps[1], NULL, NULL, NULL); FskMutexNew(&screen->withCare, "screen flipper"); } else { fprintf(stderr, "Error: can't open framebuffer device - use ram\n"); gScreenWidth = 320; gScreenHeight = 240; bpp = 16; screen->rowBytes = gScreenWidth * bpp / 8; screen->screensize = gScreenHeight * screen->rowBytes; FskMemPtrNew(screen->screensize, (FskMemPtr*)&screen->framebuffer); } #if 0 devFBFlip(screen); devFBFlip(screen); #endif FskTimeGetNow(&now); devFBFlip(screen); FskTimeGetNow(&screen->vSyncIntervalTime); FskTimeSub(&now, &screen->vSyncIntervalTime); screen->vSyncInterval = FskTimeInMS(&screen->vSyncIntervalTime); // if (!screen->vSyncInterval) screen->vSyncInterval = 1; if (!screen->vSyncInterval) screen->vSyncInterval = 32; FskInstrumentedTypePrintfDebug(&gKplScreenTypeInstrumentation, "VsyncInterval = %d", screen->vSyncInterval); screen->bitmap->baseAddress = screen->baseAddr[screen->displayPage]; screen->bitmap->rowBytes = screen->rowBytes; screen->bitmap->pixelFormat = kFskBitmapFormat16RGB565LE; screen->bitmap->depth = 16; screen->bitmap->width = gScreenWidth; screen->bitmap->height = gScreenHeight; #if SUPPORT_FLIP_THREAD FskSemaphoreNew(&screen->flipSemaphore, 0); FskThreadCreate(&screen->flipThread, flipThread, kFskThreadFlagsJoinable | kFskThreadFlagsWaitForInit | kFskThreadFlagsHighPriority, screen, "dfb flip"); #endif BAIL_IF_ERR(err = FskFrameBufferGetVectors(&vectors)); vectors->doHasProperty = KplScreenHasProperty; vectors->doSetProperty = KplScreenSetProperty; vectors->doGetProperty = KplScreenGetProperty; gKplScreen = screen; initializeLinuxInput(gScreenWidth, gScreenHeight); } *bitmap = gKplScreen->bitmap; if (NULL == *bitmap) err = kFskErrNotFound; bail: if (err) { if (screen) { //dispose of data structures here FskMemPtrDispose(screen); } *bitmap = NULL; } return err; }