home *** CD-ROM | disk | FTP | other *** search
-
- #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
-