This is MPEGView.m in view mode; [Download] [Up]
// MPEGView.m
#import <appkit/NXImage.h>
#import <appkit/graphics.h>
#import <stdio.h>
#import <stdlib.h>
#import <appkit/NXBitmapImageRep.h>
#import <appkit/Application.h>
#import <appkit/Panel.h>
#import <streams/streams.h>
#import <sys/file.h>
#import <sys/time.h>
#import <string.h>
#import <appkit/tiff.h>
#import <dpsclient/event.h> /* for NXEvent */
#import <dpsclient/dpsNeXT.h> // for DPSTimedEntry
#import <dpsclient/psops.h> // for PSshow()
#import <objc/NXBundle.h>
#import <mach/mach.h> // vm_deallocate()
#import <mach/mach_error.h>
// Local Categories
#import "BitmapImageRepData.h"
// Local Objects
#import "wraps.h"
#import "Controller.h"
#import "MPEGThread.h"
#import "MPEGView.h"
#define PERIOD_KEY 46 /* period's character code (portable), used in checking for abort (command-period) */
@implementation MPEGView : View
/*** Initialization methods ***/
- initSize:(const NXSize *)aSize info:(mpegInfo *)pInfo
{
NXRect imageRect;
NXSetRect(&imageRect, 0.0, 0.0, aSize->width, aSize->height);
if (![super initFrame:&imageRect])
return nil;
if (nil == (theBitmap = [[NXBitmapImageRep alloc] initData:NULL
pixelsWide:(int)aSize->width
pixelsHigh:(int)aSize->height
bitsPerSample:8
samplesPerPixel:3 // (cSpace == RGB_COLOR) ? 3 : 1
hasAlpha:NO
isPlanar:NO
colorSpace:NX_RGBColorSpace
bytesPerRow:0
bitsPerPixel:0]))
return [self free];
frameLength = 3 * [theBitmap pixelsWide] * [theBitmap pixelsHigh];
if (nil == (mpegThread = [[MPEGThread alloc]
initSize:(4 + frameLength) forView:self]))
{
[theBitmap free];
return [self free];
}
data = [(NXBitmapImageRep *)theBitmap data];
theSize = *aSize;
info = pInfo;
[self newZoom:pInfo->zoom];
procIndex = (pInfo->drop << 1) + pInfo->sync;
controller = [NXApp delegate];
tag = (DPSTimedEntry)-1;
return self;
}
- free
{
[mpegThread free];
if ((DPSTimedEntry)-1 != tag)
DPSRemoveTimedEntry(tag);
[theBitmap setData:data];
theBitmap = [theBitmap free];
if (address && len)
{
kern_return_t kr;
kr = vm_deallocate(task_self(), (vm_address_t)address, len);
if (KERN_SUCCESS != kr)
mach_error("vm_deallocate() failed in -free", kr);
}
address = NULL;
if (info)
free(info);
info = NULL;
return [super free];
}
/*** Standard C functions ***/
double ReadSysClock(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (tv.tv_sec + tv.tv_usec / 1000000.0);
}
#define DROP_FRAME \
if (0.0 == self->now) \
{ \
self->now = now; \
frameNumber = 0; \
} \
else \
frameNumber = (int)((now - self->now) * self->info->fps); \
if (frameNumber == self->frameNumber) \
return; \
self->adrs = self->address + (4 + self->frameLength) * frameNumber;
#define CHECK_FOR_END \
if (self->adrs >= self->end) \
{ \
self->info->elapsedTime = ReadSysClock() - self->startTime; \
DPSRemoveTimedEntry(tag); \
self->tag = (DPSTimedEntry)-1; \
[self display]; \
self->info->frameCount = self->frameCount; \
if ([self->controller respondsTo:@selector(updateInfoPanels:)]) \
[self->controller updateInfoPanels:self]; \
return; \
}
#define SLOW_STUFF [controller setFrameNumber:frameNumber];
#define SHOW_FRAME \
[self->theBitmap setData:self->adrs]; \
[self display]; \
self->adrs += self->frameLength; \
self->frameCount++;
#define FAST
void te_none(DPSTimedEntry tag, double now, void *userData)
{
MPEGView *self = userData;
int frameNumber;
CHECK_FOR_END
frameNumber = *((long *)self->adrs)++;
#ifndef FAST
SLOW_STUFF
#endif
SHOW_FRAME
}
void te_sync(DPSTimedEntry tag, double now, void *userData)
{
MPEGView *self = userData;
int frameNumber;
CHECK_FOR_END
frameNumber = *((long *)self->adrs)++;
#ifndef FAST
SLOW_STUFF
#endif
SHOW_FRAME
NXPing();
}
void te_drop(DPSTimedEntry tag, double now, void *userData)
{
MPEGView *self = userData;
int frameNumber;
DROP_FRAME
CHECK_FOR_END
frameNumber = *((long *)self->adrs)++;
#ifndef FAST
SLOW_STUFF
#endif
SHOW_FRAME
}
void te_syncNdrop(DPSTimedEntry tag, double now, void *userData)
{
MPEGView *self = userData;
int frameNumber;
DROP_FRAME
CHECK_FOR_END
frameNumber = *((long *)self->adrs)++;
#ifndef FAST
SLOW_STUFF
#endif
SHOW_FRAME
NXPing();
}
DPSTimedEntryProc procs[] = { te_none, te_sync, te_drop, te_syncNdrop };
/*** Instance methods ***/
- runAgain
{
double period = 1.0 / info->fps;
DPSTimedEntryProc proc = procs[procIndex];
frameCount = 0;
frameNumber = -1;
[controller setFrameNumber:0];
[controller updateInfoPanels:self];
adrs = address;
end = address + len - 4;
now = 0.0;
startTime = ReadSysClock();
tag = DPSAddTimedEntry(period, proc, self, MAX_PRIORITY);
if ((DPSTimedEntry)-1 == tag)
fprintf(stderr, "DSPAddTimedEntry() failed in -runAgain\n");
return self;
}
- runFromFile:(const char *)mpegFile
{
// show something in the new window while preloading
[self banner];
[mpegThread decodeFile:mpegFile];
return self;
}
- banner
{
if ([self ready])
return nil;
[self lockFocus];
PSWpreloading(theWidth, theHeight);
[self unlockFocus];
[[self window] flushWindow];
return self;
}
- setAddress:(char *)anAddress len:(int)aLen maxlen:(int)aMaxlen
{
address = anAddress;
len = aLen;
maxlen = aMaxlen;
info->totalFrames = [controller frameNumber];
return self;
}
- (BOOL)ready
{
return address ? YES : NO;
}
- (mpegInfo *)info
{
return info;
}
- (NXSize *)newZoom:(int)zoom
{
info->zoom = zoom;
theWidth = theSize.width * zoom;
theHeight = theSize.height * zoom;
NXSetRect(&theRect, 0, 0, theWidth, theHeight);
return &theSize;
}
- newSync:(BOOL)flag
{
info->sync = flag;
procIndex = (info->drop << 1) + info->sync;
return self;
}
- newDrop:(BOOL)flag
{
info->drop = flag;
procIndex = (info->drop << 1) + info->sync;
return self;
}
- newFrameRate:(float)fps
{
info->fps = fps;
return self;
}
/*** View Instance methods ***/
- drawSelf:(const NXRect *)rects :(int)rectCount
{
[theBitmap drawIn:&theRect];
// [theBitmap draw]; // this method will not scale the bitmap
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.