This is IVdrD.m in view mode; [Download] [Up]
#import "IVdrD.h" #import <appkit/NXBitmapImageRep.h> #import <appkit/tiff.h> #import <appkit/Panel.h> #import <appkit/Application.h> #import <dpsclient/dpsclient.h> #import <objc/hashtable.h> #import <appkit/ButtonCell.h> #import <sys/time.h> #import <math.h> #import "IGraphicImage.h" #import "ITimedImage.h" #import "ITimedSound.h" #import "vdr.h" #import "drawRect.h" #define TOLERANCE 0.010 #define IMAGE_FRAME_LAG_TIME -0.15 @implementation IVdrD static NXAtom rtfControlWord; static NXAtom fileExtension; static double tolerance = TOLERANCE; + initialize { rtfControlWord = NXUniqueStringNoCopy("MMvdr"); fileExtension = NXUniqueStringNoCopy("vdr"); return(self); } + (NXAtom)rtfControlWord { return(rtfControlWord); } + (NXAtom)fileExtension; { return(fileExtension); } + (NXAtom)pasteboardType { return(NULL); } + (const char *)icon { return("mtif_icon"); } - (NXImage *)image { return(image); } - (BOOL)readFromStream:(NXStream *)inStream { char *buffer; int len, maxLen; NXStream *tempStream; BOOL endOfStream; struct videoHeader *header; NXBitmapImageRep *bitmap; ITimedImage *frame; ITimedSound *fragment; double time, previousFrameTime; NXSize videoFrameSize; NXRect videoViewFrame; NXRect videoButtonsFrame; NXRect videoWindowFrame; [super readFromStream:inStream]; frameList = [List allocFromZone:[self zone]]; fragmentList = [List allocFromZone:[self zone]]; NXGetMemoryBuffer(stream, &buffer, &len, &maxLen); interval = MAXDOUBLE; previousFrameTime = -MAXDOUBLE; header = (struct videoHeader *)buffer; endOfStream = NO; while(endOfStream == NO) { tempStream = NXOpenMemory(NULL, 0, NX_READWRITE); NXWrite(tempStream, (char *)header + sizeof(struct videoHeader), header->length); NXSeek(tempStream, (long)0, NX_FROMSTART); switch(header->magic) { case VID_TIFF_MAGIC: bitmap = [[NXBitmapImageRep alloc] initFromStream:tempStream]; if (bitmap != nil) { [bitmap getSize:&videoFrameSize]; frame = [[ITimedImage allocFromZone:[self zone]] initSize:&videoFrameSize]; [frame setTime:header->time]; [frame lockFocus]; [bitmap draw]; [frame unlockFocus]; [bitmap free]; time = [frame time]; if (time - previousFrameTime < interval) { interval = time - previousFrameTime; } previousFrameTime = time; [frameList addObject:frame]; } else { NXRunAlertPanel("NewsBase", "Cannot load video frame", NULL, NULL, NULL); } break; case VID_SND_MAGIC: fragment = [ITimedSound new]; [fragment setTime:header->time]; [fragment readStream:tempStream]; [fragmentList addObject:fragment]; break; case VID_END_MAGIC: endOfStream = YES; break; } NXCloseMemory(tempStream, NX_FREEBUFFER); header = (struct videoHeader *)((char *)header + sizeof(struct videoHeader) + header->length); } interval /= 2.0; NXSeek(stream, (long)0, NX_FROMEND); size = NXTell(stream); NXSeek(stream, (long)0, NX_FROMSTART); videoButtonsFrame.origin.x = videoButtonsFrame.origin.y = 0.0; videoButtonsFrame.size.width = videoFrameSize.width; videoButtonsFrame.size.height = 30.0; videoButtons = [[Matrix alloc] initFrame:&videoButtonsFrame mode:NX_RADIOMODE cellClass:[ButtonCell class] numRows:2 numCols:2]; [videoButtons setAutosizeCells:YES]; [videoButtons setTarget:self]; [videoButtons setAction:@selector(actionForButtons:)]; [videoButtons setTitle:"PLAY" at:0 :0]; [videoButtons setTitle:"STOP" at:0 :1]; [videoButtons setTitle:"STEP" at:1 :0]; [videoButtons setTitle:"BACK" at:1 :1]; [videoButtons setTag:0 at:0 :0]; [videoButtons setTag:1 at:0 :1]; [videoButtons setTag:2 at:1 :0]; [videoButtons setTag:3 at:1 :1]; videoViewFrame.origin.x = 0.0; videoViewFrame.origin.y = videoButtonsFrame.size.height; videoViewFrame.size = videoFrameSize; videoView = [[View alloc] initFrame:&videoViewFrame]; videoWindowFrame.origin.x = videoWindowFrame.origin.y = 0.0; videoWindowFrame.size.width = videoViewFrame.size.width; videoWindowFrame.size.height = videoButtonsFrame.size.height + videoViewFrame.size.height; videoWindow = [[View alloc] initFrame:&videoWindowFrame]; [videoWindow addSubview:videoView]; [videoWindow addSubview:videoButtons]; dpsTimedEntryId = (DPSTimedEntry)-1; currentFrameNo = 0; image = [[NXImage alloc] setSize:&videoWindowFrame.size]; [image lockFocus]; [[frameList objectAt:currentFrameNo] composite:NX_COPY toPoint:&videoViewFrame.origin]; [videoButtons drawSelf:(NXRect *)0 :0]; [image unlockFocus]; return(YES); } - (void)writeToStream:(NXStream *)outStream { if (stream != NULL) { [super writeToStream:outStream]; } } - free { if (dpsTimedEntryId != (DPSTimedEntry)-1) { [self stopPlay]; } if ([videoWindow superview] != nil) { [videoWindow removeFromSuperview]; } [frameList freeObjects]; [frameList free]; [fragmentList freeObjects]; [fragmentList free]; [image free]; [videoButtons free]; [videoView free]; [videoWindow free]; return([super free]); } - performDoubleClickAction:sender { NXPoint point; NXRect videoWindowFrame; void removeVideoViewFromSuperview(DPSTimedEntry, double, char *); if ([videoWindow superview] == nil) { // notify the IGraphicImage and INewsBaseText that there is an // embedded view [sender setIsActiveEmbeddedView:YES]; [[sender view] addEmbeddedViewController:sender]; [[sender view] display]; [sender getOrigin:&point]; [videoWindow getFrame:&videoWindowFrame]; [[sender view] addSubview:videoWindow]; [videoWindow moveTo:point.x :point.y - videoWindowFrame.size.height]; [videoWindow display]; } else { if (dpsTimedEntryId != (DPSTimedEntry)-1) { [self stopPlay]; } /* [videoButtons lockFocus]; [image composite:NX_COPY toPoint:&point]; [videoButtons unlockFocus]; [[videoWindow window] flushWindow]; */ DPSAddTimedEntry(0.0, (DPSTimedEntryProc)removeVideoViewFromSuperview, (void *)self, NX_MODALRESPTHRESHOLD); [sender setIsActiveEmbeddedView:NO]; [[sender view] removeEmbeddedViewController:sender]; [[sender view] display]; } return(self); } - actionForButtons:sender { enum {PLAY = 0, STOP = 1, PLUS = 2, MINUS = 3}; switch([[sender selectedCell] tag]) { case PLAY: return([self play]); case STOP: return([self stop]); case PLUS: return([self plus]); case MINUS: return([self minus]); } return(self); } - play { void startEventsForTime(DPSTimedEntry, double, char *); if (dpsTimedEntryId == (DPSTimedEntry)-1) { if (currentFrameNo >= [frameList count]) { currentFragmentNo = currentFrameNo = 0; } SNDReserve(SND_ACCESS_IN | SND_ACCESS_OUT | SND_ACCESS_DSP, MAXINT); realStartTime = -MAXDOUBLE; startTime = -MAXDOUBLE; dpsTimedEntryId = DPSAddTimedEntry(interval, (DPSTimedEntryProc)startEventsForTime, (void *)self, NX_MODALRESPTHRESHOLD); } return(self); } - stop { if (dpsTimedEntryId != (DPSTimedEntry)-1) { [self stopPlay]; } return(self); } - plus { [self displayNextFrame:1]; return(self); } - minus { [self displayNextFrame:-1]; return(self); } - stopPlay { DPSRemoveTimedEntry(dpsTimedEntryId); dpsTimedEntryId = (DPSTimedEntry)-1; SNDUnreserve(SND_ACCESS_IN | SND_ACCESS_OUT | SND_ACCESS_DSP); return(self); } - (BOOL)displayNextFrame:(int)direction { static NXPoint point = {0.0, 0.0}; NXImage *frame; if (dpsTimedEntryId != (DPSTimedEntry)-1) { [self stopPlay]; } currentFrameNo += direction; if (currentFrameNo >= (int)[frameList count]) { currentFrameNo = 0; } else if (currentFrameNo <= -1) { currentFrameNo = [frameList count] - 1; } frame = [frameList objectAt:currentFrameNo]; [videoView lockFocus]; [frame composite:NX_COPY toPoint:&point]; [videoView unlockFocus]; [[videoWindow window] flushWindow]; return(YES); } - (BOOL)startEventsForTime:(double)realTime { static NXPoint point = {0.0, 0.0}; static double frameLagTime = IMAGE_FRAME_LAG_TIME; double realElapsedTime; double startFrameTime, startFragmentTime, elapsedTime; ITimedImage *frame; ITimedSound *fragment; static ITimedSound *previousFragment; struct timezone tzone; struct timeval realtime; gettimeofday(&realtime,&tzone); realTime = (double)realtime.tv_sec + (double)realtime.tv_usec/1.0E6; if (realStartTime == -MAXDOUBLE) { realStartTime = realTime; if ((frame = [frameList objectAt:currentFrameNo]) != nil) { startFrameTime = [frame time]; } else { startFrameTime = MAXDOUBLE; } if ((fragment = [fragmentList objectAt:currentFragmentNo]) != nil) { startFragmentTime = [fragment time]; } else { startFragmentTime = MAXDOUBLE; } if (startFrameTime < startFragmentTime) { startTime = startFrameTime; } else { startTime = startFragmentTime; } // framesPlayed = 0; // framesSkipped = 0; previousFragment = nil; } realElapsedTime = realTime - realStartTime; while ((fragment = [fragmentList objectAt:currentFragmentNo]) != nil && (elapsedTime = [fragment time] - startTime) < realElapsedTime - tolerance) { fprintf(stderr, "fragment no = %d %e\n", currentFragmentNo, elapsedTime - realElapsedTime); ++currentFragmentNo; } if (fragment != nil && elapsedTime - realElapsedTime < 2.0 * interval && fragment != previousFragment) { [previousFragment stop]; [fragment play]; previousFragment = fragment; fprintf(stderr, "playing sound fragment %d\n", currentFragmentNo); } while ((frame = [frameList objectAt:currentFrameNo]) != nil && (elapsedTime = [frame time] - startTime) < realElapsedTime + frameLagTime - tolerance) { // ++framesSkipped; ++currentFrameNo; gettimeofday(&realtime,&tzone); realTime = (double)realtime.tv_sec + (double)realtime.tv_usec/1.0E6; realElapsedTime = realTime - realStartTime; } if (frame != nil && elapsedTime - (realElapsedTime + frameLagTime) < 2.0 * interval) { [videoView lockFocus]; [frame composite:NX_COPY toPoint:&point]; [videoView unlockFocus]; [[videoWindow window] flushWindow]; NXPing(); // ++framesPlayed; ++currentFrameNo; } if (fragment == nil && frame == nil) { [previousFragment stop]; return(NO); } else { return(YES); } } void startEventsForTime(DPSTimedEntry teNo, double time, char * video) { if ([(IVdrD *)video startEventsForTime:time] == NO) { [(IVdrD *)video stopPlay]; } } void removeVideoViewFromSuperview(DPSTimedEntry teNo, double time, char * video) { View *superview; superview = [((IVdrD *)video)->videoWindow superview]; [((IVdrD *)video)->videoWindow removeFromSuperview]; DPSRemoveTimedEntry(teNo); [superview display]; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.