This is Controller.m in view mode; [Download] [Up]
#import <math.h> #import <strings.h> #import <dpsclient/wraps.h> #import <appkit/graphics.h> #import <appkit/OpenPanel.h> #import <appkit/NXImage.h> #import <appkit/Application.h> #import <appkit/Matrix.h> #import <appkit/Form.h> #import <appkit/NXBitmapImageRep.h> #import <appkit/publicWraps.h> #import <appkit/tiff.h> #import <appkit/MenuCell.h> #import <defaults/defaults.h> #import <objc/NXBundle.h> // Local Categories #import "TimeCell.h" // Local Objects #import "Controller.h" #import <sys/param.h> #import <libc.h> /* Globals */ char *gpchProgName = "MPEG Play"; char *gpchOK = "OK"; /* File extensions for MPEG files */ const char *mpgType = "mpg"; @implementation Controller:Object /*** Instance methods ***/ - (mpegInfo *)getMPEGFrameSize:(NXSize *)fSize forFile:(const char *)mpegFile { char *pchAlertTitle = "Error in Controller method -getMPEGFrameSize:forFile:"; FILE *input; long data; mpegInfo *pInfo; // Check for NULL pointer or empty string if (!mpegFile || !*mpegFile) { NXRunAlertPanel(pchAlertTitle, "No filename was specified.", gpchOK, NULL, NULL); return NULL; } if (NULL == (input = fopen(mpegFile, "r"))) { NXRunAlertPanel(pchAlertTitle, "Could not open file - %s.", gpchOK, NULL, NULL, mpegFile); return NULL; } #define SEQ_START_CODE 0x000001b3 // read first start code, make sure it is a sequence start code fread(&data, 4, 1, input); if (SEQ_START_CODE != data) { NXRunAlertPanel(pchAlertTitle, "This is not an MPEG stream.", gpchOK, NULL, NULL); return NULL; } if (!(pInfo = calloc(1, sizeof(mpegInfo)))) { NXRunAlertPanel(pchAlertTitle, "Unable to allocate memory.", gpchOK, NULL, NULL); return NULL; } // Get horizontal and vertical size of image space // as two 12 bit words, respectively // then aspect ratio and picture rate // as two 4 bit words. fread(&data, 4, 1, input); pInfo->picture_rate = 0x0F & data; data >>= 4; pInfo->aspect_ratio = 0x0F & data; data >>= 4; // In Motorola format, least significant bits come last // v_size is actually the second value in the file // i.e. h:12,v:12,a:4,p:4 pInfo->v_size = 0x0FFF & data; pInfo->h_size = 0x0FFF & data >> 12; fSize->width = ((pInfo->h_size + 15) / 16) * 16.0; fSize->height = ((pInfo->v_size + 15) / 16) * 16.0; // Get bit rate, vbv buffer size, and constrained parameter flag fread(&data, 4, 1, input); // throw away (non) intra quant matrix flags data >>= 2; pInfo->const_param_flag = 1 & data; data >>= 1; pInfo->vbv_buffer_size = 0x03FF & data; data >>= 10 + 1; // 1 marker bit pInfo->bit_rate = 0x03FFFF & data; fclose(input); pInfo->fps = pInfo->picture_rate; [self showInfo:pInfo]; return pInfo; } - showInfo:(mpegInfo *)pInfo { [panel disableDisplay]; // window settings [colorSpaceMatrix selectCellWithTag:pInfo->colorSpace]; [zoomMatrix selectCellWithTag:pInfo->zoom]; [backingMatrix selectCellWithTag:pInfo->backing]; [buttonMatrix setState:pInfo->sync at:FLAG_SYNC :0]; [buttonMatrix setState:pInfo->drop at:FLAG_DROP :0]; [fpsForm setFloatValue:pInfo->fps at:0]; [fpsSlider setFloatValue:pInfo->fps]; // stream attributes [attributesForm setIntValue:pInfo->h_size at:I_WIDTH]; [attributesForm setIntValue:pInfo->v_size at:I_HEIGHT]; [attributesForm setIntValue:pInfo->aspect_ratio at:I_ASPECT]; [attributesForm setIntValue:pInfo->picture_rate at:I_PICT_RATE]; [attributesForm setIntValue:pInfo->bit_rate at:I_BIT_RATE]; // measured statistics [statsForm setIntValue:pInfo->totalFrames at:STATS_TOTAL]; [statsForm setIntValue:pInfo->frameCount at:STATS_FRAMES]; [[statsForm cellAt:STATS_ELAPSED :0] setTimeFloatValue:pInfo->elapsedTime]; [statsForm setFloatValue:((pInfo->frameCount + 1) / pInfo->elapsedTime) at:STATS_FPS_RATE]; [[statsForm cellAt:STATS_ORIG_TIME :0] setTimeFloatValue:(pInfo->frameCount / pInfo->picture_rate)]; [panel display]; // -reenableDisplay return self; } - setFrameNumber:(int)frame { [form setIntValue:frame at:0]; return self; } - (int)frameNumber { return [form intValueAt:0]; } /*** Instance variable access methods ***/ - setColorSpace:sender { colorSpace = [[sender selectedCell] tag]; return self; } - (int)colorSpace { return colorSpace; } - setZoom:sender { id window = [NXApp mainWindow]; id contentView = [window contentView]; zoom = [[sender selectedCell] tag]; if ([contentView respondsTo:@selector(newZoom:)]) { NXSize *pSize = [contentView newZoom:zoom]; [window sizeWindow:(pSize->width * zoom) :(pSize->height * zoom)]; [window center]; [self windowDidMove:window]; [contentView display]; [contentView banner]; } return self; } - (int)zoom { return zoom; } - setBacking:sender { backing = [[sender selectedCell] tag]; [[NXApp mainWindow] setBackingType:backing]; return self; } - setFlag:sender { id view = [[NXApp mainWindow] contentView]; id button = [sender selectedCell]; BOOL flag = [button state]; switch ([button tag]) { case FLAG_SYNC: if ([view respondsTo:@selector(newSync:)]) [view newSync:(sync = flag)]; break; case FLAG_DROP: if ([view respondsTo:@selector(newDrop:)]) [view newDrop:(drop = flag)]; break; default: return nil; } return self; } - setFPS:sender { id view = [[NXApp mainWindow] contentView]; float value = [sender floatValue]; if (sender == fpsSlider) [fpsForm setFloatValue:value at:0]; else [fpsSlider setFloatValue:value]; if ([view respondsTo:@selector(newFrameRate:)]) [view newFrameRate:value]; return self; } /*** Target/Action methods ***/ - openRequest:sender { id openReq; const char *const fileTypes[] = { mpgType, NULL }; openReq = [OpenPanel new]; if ([openReq runModalForTypes:fileTypes]) { int ok; [NXApp openFile:[openReq filename] ok:&ok]; } return self; } - playAgain:sender { id view = [[NXApp mainWindow] contentView]; if ([view respondsTo:@selector(runAgain)]) [view runAgain]; return self; } - updateInfoPanels:sender { mpegInfo *pInfo = [sender info]; [playAgainMenuItem setEnabled:[sender ready]]; pInfo->backing = [[sender window] backingType]; return [self showInfo:pInfo]; } /*** Application delegate methods ***/ - appWillInit:sender { [colorSpaceMatrix selectCellWithTag:(colorSpace = RGB_COLOR)]; [zoomMatrix selectCellWithTag:(zoom = 1)]; [backingMatrix selectCellWithTag:(backing = NX_BUFFERED)]; [buttonMatrix setState:(sync = NO) at:FLAG_SYNC :0]; [buttonMatrix setState:(drop = NO) at:FLAG_DROP :0]; return self; } /* We always want to accept files. */ - (BOOL)appAcceptsAnotherFile:sender { return YES; } /* Open mpg file from workspace. */ // -appOpenFile:type: is defunct and does not appear in the headers - (int)app:sender openFile:(const char *)filename type:(const char *)aType { id window, view; mpegInfo *pInfo; NXSize size; NXRect rect; if (strcmp(aType, mpgType)) { NXRunAlertPanel("Error Opening File", "Must have `.mpg' extension. Cannot open %s.", gpchOK, NULL, NULL, filename); return NO; } if (NULL == (pInfo = [self getMPEGFrameSize:&size forFile:filename])) { NXRunAlertPanel("Error Parsing MPEG File", "Could not determine frame size for file %s.", gpchOK, NULL, NULL, filename); return NO; } pInfo->colorSpace = colorSpace; pInfo->zoom = zoom; pInfo->backing = backing; pInfo->sync = sync; pInfo->drop = drop; if (nil == (view = [[MPEGView alloc] initSize:(const NXSize *)&size info:pInfo])) { NXRunAlertPanel("Error Allocating View Object", "Could not allocate and initialize an instance of MPEGView " "with the following attributes: Width=%d, Height=%d, Zoom=%d", gpchOK, NULL, NULL, size.width, size.height, zoom); free(pInfo); return NO; } /* Create a new window the size of the image */ NXSetRect(&rect, 0.0, 0.0, size.width * zoom, size.height * zoom); window = [[Window alloc] initContent:&rect style:NX_TITLEDSTYLE backing:backing buttonMask:NX_CLOSEBUTTONMASK defer:NO]; [window setDelegate:self]; [window setTitleAsFilename:filename]; /* Replace the current contentView of the window with my new view */ /* and free up the old contentView */ [[window setContentView:view] free]; [window center]; /* Put the window in the center of the screen */ // -center does not call -windowDidMove: ... so do it now [self windowDidMove:window]; [window makeKeyAndOrderFront:self]; [window display]; [view runFromFile:filename]; return YES; } /*** Window delegate methods ***/ - windowDidMove:sender { NXRect rect; [sender getFrame:&rect]; // restrict left edge to 8 pixel boundary to enhance drawing speed [sender moveTo:(8.0 * rint(rect.origin.x / 8)) :rect.origin.y]; return self; } - windowWillClose:sender { // this won't work because Menus are counted as Windows if (!([[NXApp windowList] count])) [playAgainMenuItem setEnabled:NO]; return self; } - windowDidBecomeMain:sender { id view = [sender contentView]; if ([view respondsTo:@selector(info)]) [self updateInfoPanels:view]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.