📄 gdith.cpp
字号:
/* * gdith.c -- * * Procedures dealing with grey-scale and mono dithering, * as well as X Windows set up procedures. * *//* * Copyright (c) 1995 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. *//* * Portions of this software Copyright (c) 1995 Brown University. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement * is hereby granted, provided that the above copyright notice and the * following two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" * BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */#include <math.h>#include "video.h"#include "proto.h"#include "dither.h"#include "SDL_timer.h"#ifdef USE_ATI#include "vhar128.h"#endif#ifdef __STDC__#include <stdlib.h>#include <string.h>#endif/* Changes to make the code reentrant: X variables now passed in xinfo: display, ximage,cmap,window, gc, etc De-globalized: ditherType, matched_depth, totNumFrames vid_stream->film_has_ended instead of FilmState Additional changes: Now can name and position each movie window individually DISABLE_DITHER cpp define - do not include dither code if defined NOFRAMECOUNT cpp define - do not count frames when running without controls Short circuit InitColorDisplay if not displaying anything ExistingWindow default now 0 -lsh@cs.brown.edu (Loring Holden)*//* Frame Rate Info */extern int framerate;/* Video rates table *//* Cheat on Vid rates, round to 30, and use 30 if illegal value Except for 9, where Xing means 15, and given their popularity, we'll be nice and do it */static double VidRateNum[16]={ 30, 23.97, 24, 25, 29.97, 30, 50, 59.94, 60, 15, 30, 30, 30, 15, 30, 30 };#ifdef CALCULATE_FPSstatic inline void TimestampFPS( VidStream* vid_stream ){ MPEGvideo* mpeg = (MPEGvideo*) vid_stream->_smpeg; vid_stream->frame_time[vid_stream->timestamp_index] = mpeg->Time(); ++vid_stream->timestamp_index; if ( vid_stream->timestamp_index == FPS_WINDOW ) { vid_stream->timestamp_index = 0; }}#endif/* Do frame rate control. Returns _skipFrame*/#define LOOSE_MPEG_SCHEDULING#ifdef LOOSE_MPEG_SCHEDULING#define MAX_FRAME_SKIP 4#define MAX_FUDGE_TIME (MAX_FRAME_SKIP*vid_stream->_oneFrameTime)#else#ifdef TIGHT_MPEG_SCHEDULING#define MAX_FRAME_SKIP 1#define MAX_FUDGE_TIME (MAX_FRAME_SKIP*vid_stream->_oneFrameTime)#else#define MAX_FRAME_SKIP 3#define MAX_FUDGE_TIME (MAX_FRAME_SKIP*vid_stream->_oneFrameTime)#endif /* TIGHT_MPEG_SCHEDULING */#endif /* LOOSE_MPEG_SCHEDULING */#define FUDGE_TIME (((MAX_FRAME_SKIP+1)/2)*vid_stream->_oneFrameTime)/* This results in smoother framerate, but more dropped frames on systems that can play most of the video fine, but have problems with jerkiness in a few spots.*///#define SLOW_START_SCHEDULING#define SLOW_START_INCREMENT 0.3/* Define this to debug the frame scheduler *///#define DEBUG_MPEG_SCHEDULINGinline double CurrentTime( VidStream* vid_stream ){ MPEGvideo* mpeg = (MPEGvideo*) vid_stream->_smpeg; double now; if ( mpeg->TimeSource() ) { now = mpeg->TimeSource()->Time(); } else { now = ReadSysClock() - vid_stream->realTimeStart; } return now;}int MPEGvideo::timeSync( VidStream* vid_stream ){ static double correction = -1; /* Update the number of frames displayed */ vid_stream->totNumFrames++; vid_stream->current_frame++; /* Do we need to initialize framerate? */ if ( vid_stream->rate_deal < 0 ) { switch( framerate ) { case -1: /* Go with stream Value */ vid_stream->rate_deal = VidRateNum[ vid_stream->picture_rate ]; break; case 0: /* as fast as possible */ vid_stream->rate_deal = 0; break; default: vid_stream->rate_deal = framerate; break; } if ( vid_stream->rate_deal ) { vid_stream->_oneFrameTime = 1.0 / vid_stream->rate_deal; } } /* Update the current play time */ play_time += vid_stream->_oneFrameTime; /* Synchronize using system timestamps */ if(vid_stream->current && vid_stream->current->show_time > 0){#ifdef DEBUG_TIMESTAMP_SYNC fprintf(stderr, "video: time:%.3f shift:%.3f\r", play_time, play_time - vid_stream->current->show_time);#endif if(correction == -1)#ifdef STRANGE_SYNC_TEST /* this forces us to maintain the offset we have at the begining all the time, and is only usefull for testing */ correction = play_time - vid_stream->current->show_time;#else correction = 0;#endif#ifdef USE_TIMESTAMP_SYNC play_time = vid_stream->current->show_time + correction ;#endif vid_stream->current->show_time = -1; } /* If we are looking for a particular frame... */ if( vid_stream->_jumpFrame > -1 ) { if ( vid_stream->totNumFrames != vid_stream->_jumpFrame ) { vid_stream->_skipFrame = 1; } else { vid_stream->_skipFrame = 0; } return vid_stream->_skipFrame; } /* If we're already behind, don't check timing */ if ( vid_stream->_skipFrame > 0 ) { return --vid_stream->_skipFrame; } /* See if we need to skip frames, based on timing */ if ( vid_stream->rate_deal ) { static const double TIMESLICE = 0.01; // Seconds per OS timeslice double time_behind; /* Calculate the frame time relative to real time */ time_behind = CurrentTime(vid_stream) - Time();#ifdef DEBUG_MPEG_SCHEDULINGprintf("Frame %d: frame time: %f, real time: %f, time behind: %f\n", vid_stream->totNumFrames, Time(), CurrentTime(vid_stream), time_behind);#endif /* Allow up to MAX_FUDGE_TIME of delay in output */ if ( time_behind < -TIMESLICE ) { time_behind = -time_behind; vid_stream->_skipCount = 0;#ifdef DEBUG_MPEG_SCHEDULINGprintf("Ahead! Sleeping %f\n", time_behind-TIMESLICE);#endif SDL_Delay((Uint32)((time_behind-TIMESLICE)*1000)); } else if ( time_behind < FUDGE_TIME ) { if ( vid_stream->_skipCount > 0 ) { vid_stream->_skipCount /= 2; }#ifdef DEBUG_MPEG_SCHEDULINGprintf("Just right.\n");#endif } else if ( time_behind < MAX_FUDGE_TIME ) { if ( vid_stream->_skipCount > 0 ) { vid_stream->_skipCount--; } vid_stream->_skipFrame = 1+(int)(vid_stream->_skipCount/2);#ifdef DEBUG_MPEG_SCHEDULINGprintf("A little behind, skipping %d frames\n", vid_stream->_skipFrame);#endif } else { /* time_behind >= MAX_FUDGE_TIME */ if ( (time_behind > (MAX_FUDGE_TIME*2)) && (vid_stream->_skipCount == MAX_FRAME_SKIP) ) {#ifdef DEBUG_MPEG_SCHEDULINGprintf("Way too far behind, losing time sync...\n");#endif#if 0 // This results in smoother video, but sync's terribly on slow machines play_time = CurrentTime(vid_stream) - (MAX_FUDGE_TIME*2);#endif }#ifdef SLOW_START_SCHEDULING vid_stream->_skipCount += SLOW_START_INCREMENT;#else vid_stream->_skipCount += 1.0;#endif if( vid_stream->_skipCount > MAX_FRAME_SKIP ) { vid_stream->_skipCount = MAX_FRAME_SKIP; } vid_stream->_skipFrame = (int)(vid_stream->_skipCount+0.9);#ifdef DEBUG_MPEG_SCHEDULINGprintf("A lot behind, skipping %d frames\n", vid_stream->_skipFrame);#endif } } return(vid_stream->_skipFrame);}/* Do the hard work of copying from the video stream working buffer to the screen display and then calling the update callback.*/void MPEGvideo::DisplayFrame( VidStream * vid_stream ){ SMPEG_FilterInfo info; if ( _filter_mutex ) SDL_mutexP( _filter_mutex ); /* Get a pointer to _image pixels */ if ( SDL_LockYUVOverlay( _image ) ) { return; } /* Compute additionnal info for the filter */ if((_filter->flags & SMPEG_FILTER_INFO_PIXEL_ERROR) && vid_stream->current->mb_qscale) { register int x, y; register Uint16 * ptr; /* Compute quantization error for each pixel */ info.yuv_pixel_square_error = (Uint16 *) malloc(_w*_h*12/8*sizeof(Uint16)); ptr = info.yuv_pixel_square_error; for(y = 0; y < _h; y++) for(x = 0; x < _w; x++) *ptr++ = (Uint16) (((Uint32) vid_stream->noise_base_matrix[x & 7][y & 7] * vid_stream->current->mb_qscale[((y>>4) * (_w>>4)) + (x >> 4)]) >> 8); } if((_filter->flags & SMPEG_FILTER_INFO_MB_ERROR) && vid_stream->current->mb_qscale) { /* Retreive macroblock quantization error info */ info.yuv_mb_square_error = vid_stream->current->mb_qscale; } if( _filter ) { SDL_Overlay src; Uint16 pitches[3]; Uint8 *pixels[3]; /* Fill in an SDL YV12 overlay structure for the source */#ifdef USE_ATI vhar128_lockimage(vid_stream->ati_handle, vid_stream->current->image, &src);#else src.format = SDL_YV12_OVERLAY; src.w = _w; src.h = _h; src.planes = 3; pitches[0] = _w; pitches[1] = _w / 2; pitches[2] = _w / 2; src.pitches = pitches; pixels[0] = vid_stream->current->image; pixels[1] = vid_stream->current->image + pitches[0] * _h; pixels[2] = vid_stream->current->image + pitches[0] * _h + pitches[1] * _h / 2; src.pixels = pixels;#endif _filter->callback(_image, &src, &_srcrect, &info, _filter->data );#ifdef USE_ATI vhar128_unlockimage(vid_stream->ati_handle, vid_stream->current->image, &src);#endif } /* Now display the image */ if ( _mutex ) SDL_mutexP( _mutex ); SDL_DisplayYUVOverlay(_image, &_dstrect); if ( _callback ) _callback(_dst, _dstrect.x, _dstrect.y, _dstrect.w, _dstrect.h); SDL_UnlockYUVOverlay( _image ); if( _filter ) { if( _filter->flags & SMPEG_FILTER_INFO_PIXEL_ERROR ) free(info.yuv_pixel_square_error); } if ( _filter_mutex ) SDL_mutexV( _filter_mutex ); if ( _mutex ) SDL_mutexV( _mutex );}/* *-------------------------------------------------------------- * * ExecuteDisplay -- * * Actually displays display plane in previously created window. * * Results: * None. * * Side effects: * Updates video frame timing control * *-------------------------------------------------------------- */void MPEGvideo::ExecuteDisplay( VidStream* vid_stream ){ if( ! vid_stream->_skipFrame ) { DisplayFrame(vid_stream);#ifdef CALCULATE_FPS TimestampFPS(vid_stream);#endif } timeSync( vid_stream );}SMPEG_Filter *MPEGvideo:: Filter(SMPEG_Filter * filter){ SMPEG_Filter * old_filter; old_filter = _filter; if ( _filter_mutex ) SDL_mutexP( _filter_mutex ); _filter = filter; if ( _filter_mutex ) SDL_mutexV( _filter_mutex ); return(old_filter);}/* EOF */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -