/* * Copyright (c) 1994 Friedrich-Alexander Universitaet Erlangen-Nuernberg (FAU) * All rights reserved. * * Copyright (c) 1993-1994 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and the Network Research Group at * Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ // Description: // Framegrabber modul for SlicVideo SBus framegrabber card for sparc. // Written 1995 for vic-2.7 by toerless.eckert@informatik.uni-erlangen.de, // based on the grabber-vigra module. // // The SlicVideo framegrabber is a dump framegrabber for SBus, very similar // to the Vigrapix framegrabber card. It uses a different SBus interface // chip, the Motorola SLIC (MC92005) and has 2 * FBAS and 1 Y/C input. // Besides the grabber library used in this module the SlicVideo framegrabber // also supports XIL under SunOS 5.x. Currently tested only with SunOS 5.x. // // This module supports yuv411 and yuv422 framgrabbing in any size, // including cif. When using cif the images will be centered and probably // cropped, depending on the video signal. Both PAL and NTSC video signal // have been tested. The module will search for installed SlicVideo boards // upon startup. Also supported are commands to change attribute of the // video signal: luma brightness/contrast, chroma gain/saturation, hue. // // Speed // Measured on a SS20/502, SunOS 5.4, vic-2.7a22, no preview, still image: // // All numbers in fps NTSC NTSC NTSC PAL PAL PAL QCIF CIF QCIF CIF // 1/16 1/4 1/1 1/16 1/4 1/1 PAL PAL NTSC NTSC // // SlicVideo, NV: 30 27 3.5 25 20 2.5 - - - - // SlicVideo, H261: - - - - - - 25 22 30 28 // // SunVideo/RTVC, NV: 25* 25* 10 25 23 C - - - - // SunVideo/RTVC, H261: - - - - - - 25 25 25* 30 // // C means that vic crashed when trying this resolution. // * seems to be a bug in vic. // // It should always kept in mind that these numbers turn out to be much worse // for the SlicVideo (or any other dump framegrabber) on a slower machine, // whereas the SunVideo RTVC driver probably keeps some work on the DSP // on the SunVideo itself, so it's more likely independant of CPU speed. // // Remarks: // This module SHOULD be compiled with the highest optimization possible // with your compiler, otherwise the framegrabbing will be _slow_. // The difference between -O and -O2 with gcc is about 40% speed. // // Todo: // Grabbing full size frames requires the grabbing of two fields. It seems // to be quite tricky to get two matching fields (one even, one odd) from the // same frame. That code should be improved to use interrupts. static const char rcsid[] = "@(#) $Id: grabber-slv.cpp,v 1.1 1999/09/09 12:52:54 piers Exp $ (FAU)"; #include #include #include #include #include "grabber.h" #include "module.h" #include "vic_tcl.h" #include "device-input.h" // Configurable variables: // // Utilizing the external api introduces one // further step of copying because there is no function // in the external api to pass data out in the format needed by vic // This is about 20% slower, but is left in the code // to act as a fallback if there is a bug in the implementation // of the grabbing routines utilizing the internal api. static const int use_internal_api = 1; static const int slv_debug = 0; // SlicVideo specific declarations extern "C" { #include extern int slv_bytespp[]; /* forgotten in */ } #include static int slv_read_frame_yuv(SLV *slvptr, int is411, u_char *yp, int y_stride, u_char *up, int u_stride, u_char *vp, int v_stride); static int slv_read_field_yuv(SLV *slvptr, int is411, u_char *yp, int y_stride, u_char *up, int u_stride, u_char *vp, int v_stride); static int slv_copyin_yuv(SLV *slvptr, u_int fbuf, int is411, u_char *yp, int y_stride, u_char *up, int u_stride, u_char *vp, int v_stride); static const int f_411 = 0; static const int f_422 = 1; static const int f_cif = 2; //**************************************************************************** //* Interfaces //**************************************************************************** class SlicVideoGrabber : public Grabber { public: SlicVideoGrabber(const char* name, const char* format); virtual ~SlicVideoGrabber(); virtual void start(); protected: virtual int command(int argc, const char*const* argv); virtual int capture(); virtual int grab(); virtual void reformat(); virtual void slv_assert(char* desc, int command); // initialized by the constructor routine const char *name_; SLV *handle_; int video_format_; int coder_format_; int port_; u_int decimate_; // initialised by reformat(). Output size of frames grabbed. int x_output_size_, y_output_size_, x_output_border_, y_output_border_; char *fbuf_; int fbufl_; }; class SlicVideoDevice : public InputDevice { public: SlicVideoDevice(const char* nickname, const char *devname, int free); virtual int command(int argc, const char*const* argv); protected: const char *name_; }; class SlicVideoScanner { public: SlicVideoScanner(const int n); }; static SlicVideoScanner find_slv_devices(4); //*************************************************************************** //* Implementation of class SlicVideoDevice / SlicVideoScanner //*************************************************************************** SlicVideoScanner::SlicVideoScanner(const int n) { // scan for SlicVideo devices and instanciate // an appropriate number of "SlicVideoDevice" InputDevices. int i; SLV *slv; char *devname_template = "/dev/slv%d"; char *nickname_template = "slicvideo-%d"; for(i = 0; i < n; i++) { char *nickname = new char[strlen(nickname_template) + 3]; char *devname = new char[strlen(devname_template) + 3]; sprintf(nickname, nickname_template, i + 1); sprintf(devname, devname_template, i); if ((access(devname, R_OK) == 0) && (access(devname, W_OK) == 0)) { // Device may exist slv = slv_open(devname, SLV_PORT1, SLV_AUTO_INPUT, SLV_EVEN_FIELDS_OUTPUT, SLV_YUV422_OUTPUT); if((int)(slv)) { slv_close(slv); new SlicVideoDevice(nickname, devname, 1); } else { new SlicVideoDevice(nickname, devname, 0); } } else { delete nickname; delete devname; } } } SlicVideoDevice::SlicVideoDevice(const char* nickname, const char* devname, int free) : InputDevice(nickname), name_(devname) { if(free) attributes_ = "\ format { 411 422 } \ size { small large cif } \ port { Composite-1 Composite-2 S-Video}"; else attributes_ = "disabled"; } int SlicVideoDevice::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if ((argc == 3) && (strcmp(argv[1], "open") == 0)) { TclObject* o = 0; o = new SlicVideoGrabber(name_, argv[2]); if (o != 0) tcl.result(o->name()); return (TCL_OK); } return (InputDevice::command(argc, argv)); } //*************************************************************************** //* Implementation of class SlicVideoGrabber //*************************************************************************** SlicVideoGrabber::SlicVideoGrabber(const char* name, const char* format) { // initialize format_ variable. // this is later used when converting grabed frames // into the format needed by vic if(slv_debug) fprintf(stderr, "slv: new grabber %s, %s\n", name, format); coder_format_ = -1; if(!strcmp(format,"411")) coder_format_ = f_411; if(!strcmp(format,"422")) coder_format_ = f_422; if(!strcmp(format,"cif")) coder_format_ = f_cif; if(coder_format_ == -1) { fprintf(stderr, "vic: SlicVideoGrabber: unsupported format \"%s\"\n", coder_format_); abort(); } decimate_ = 2; port_ = SLV_PORT1; fbuf_ = NULL; handle_ = slv_open((char *) name, port_, SLV_AUTO_INPUT, SLV_EVEN_FIELDS_OUTPUT, SLV_YUV422_OUTPUT); if (handle_ == 0) { status_ = -1; return; } } SlicVideoGrabber::~SlicVideoGrabber() { if(slv_debug) fprintf(stderr, "slv: close grabber\n"); if (handle_ != 0) { slv_assert("slv_close", slv_close(handle_)); handle_ = 0; } } void SlicVideoGrabber::reformat() { int vformat_xsize, vformat_ysize, vformat_xstart, vformat_ystart; int size_x, size_y; int x_input_start, x_input_count, y_input_count, y_input_start; // Resync video signal and determine current input video size. slv_assert("slv set INPUT_PORT", slv_set(handle_, "INPUT_PORT", (void*) port_)); slv_assert("slv set INPUT_FORMAT", slv_set(handle_, "INPUT_FORMAT", (void*) SLV_AUTO_INPUT)); slv_assert("slv get INPUT_FORMAT", slv_get(handle_, "INPUT_FORMAT", (void**) &video_format_)); switch(video_format_) { case SLV_PAL_INPUT: case SLV_SECAM_INPUT: vformat_xsize = SLV_PAL_X_SIZE; vformat_ysize = SLV_PAL_Y_SIZE * 2; vformat_xstart = SLV_PAL_X_START; vformat_ystart = SLV_PAL_Y_START; break; default: case SLV_NTSC_INPUT: vformat_xsize = SLV_NTSC_X_SIZE; vformat_ysize = SLV_NTSC_Y_SIZE * 2; vformat_xstart = SLV_NTSC_X_START; vformat_ystart = SLV_NTSC_Y_START; break; } // Determine output sizes: // size_x and size_y are the frame size we actually // want to have, due to the video format sizes and the selected // decimate_. Usually they will be taken. An exception is // cif format which has fixed dimensions. These dimensions are // determined by the set_size_XXX methods called below and stored // in the outw_ and outh_ instance variables. size_x = vformat_xsize / decimate_; size_y = vformat_ysize / decimate_; switch(coder_format_) { case f_411: set_size_411(size_x , size_y); break; case f_422: set_size_422(size_x , size_y); break; case f_cif: set_size_cif(size_x , size_y); break; default: fprintf(stderr, "vic: SlicVideoGrabber::reformat: illegal coder_format (%d) detected\n", coder_format_); abort(); break; } allocref(); // allocates reference frame memory // According to size_x, size_y, outh_ and outw_ // the scaler of the SlicVideo board is initialised. // If the format is not cif there will be no cropping or // borders, otherwise these necessary artifacts have to be // taken into account. The input window will take care of // cropping, the output window of the borders. if(outw_ >= size_x) { // x borders x_input_start = 0; x_input_count = vformat_xsize; x_output_border_ = (outw_ - size_x) / 2; x_output_size_ = size_x; } else { // x cropping x_input_start = (size_x - outw_) / 2 * decimate_; x_input_count = vformat_xsize - x_input_start * 2; x_output_border_ = 0; x_output_size_ = outw_; } if(outh_ >= size_y) { // y borders y_input_start = 0; y_input_count = vformat_ysize; y_output_border_ = (outh_ - size_y) / 2; y_output_size_ = size_y; } else { // y cropping y_input_start = (size_y - outh_) / 2 * decimate_; y_input_count = vformat_ysize - y_input_start * 2; y_output_border_ = 0; y_output_size_ = outh_; } // The SlicVideo library uses field size dimensions so // everything in y is off by a factor of 2 slv_input_size(handle_, x_input_start + vformat_xstart, x_input_count, y_input_start / 2 + vformat_ystart, y_input_count / 2); slv_output_size(handle_, x_output_size_, (decimate_ > 1) ? y_output_size_ : y_output_size_ / 2); if(slv_debug) { char *fmt[] = {"411", "422", "cif"}; fprintf(stderr, "slv: reformat:\n"); fprintf(stderr, " input window: %d X %d (offset: %d + %d, %d + %d)\n", x_input_count, y_input_count / 2, x_input_start, vformat_xstart, y_input_start / 2, vformat_ystart); fprintf(stderr, " output window: %d X %d (offset: %d, %d)\n", x_output_size_, (decimate_ > 1) ? y_output_size_ : y_output_size_ / 2, x_output_border_, y_output_border_); fprintf(stderr, " vic buffer: %d X %d\n", outw_, outh_); fprintf(stderr, " coder_format = %s\n", fmt[coder_format_]); } slv_assert("slv_set OUTPUT_MODE", slv_set(handle_, "OUTPUT_MODE", (decimate_ > 1) ? (void*) SLV_EVEN_FIELDS_OUTPUT : (void*) SLV_INTERLACE_OUTPUT)); // MCT = 0 will make the grabbed UV color signals unsigned slv_assert("slv_set MCT", slv_set(handle_, "MCT", (void*) 0)); slv_assert("slv_set DEGAMMA", slv_set(handle_, "DEGAMMA", (void*) 1)); slv_flush(handle_, 0); if(! use_internal_api) { if(!fbuf_) { fbufl_ = SLV_PAL_X_COUNT * SLV_PAL_Y_COUNT * 2; fbuf_ = new char[fbufl_]; } memset(fbuf_, 0x80, fbufl_); } } void SlicVideoGrabber::start() { if (running_) return; reformat(); Grabber::start(); } int SlicVideoGrabber::command(int argc, const char*const* argv) { if(slv_debug) fprintf(stderr, "vic: slicvideo command: %s\n", argv[1]); if ((argc == 4) && !strcmp(argv[1], "set")) { char *argv2 = (char *) argv[2]; char *argv3 = (char *) argv[3]; slv_assert(argv2, slv_set(handle_, argv2, (void*)(atoi(argv3)))); return (TCL_OK); } else if ((argc == 3) && !strcmp(argv[1], "decimate")) { int dec = atoi(argv[2]); Tcl& tcl = Tcl::instance(); if (dec <= 0) { tcl.resultf("%s: divide by zero", argv[0]); return (TCL_ERROR); } if (dec != decimate_) { decimate_ = dec; reformat(); } return (TCL_OK); } else if ((argc == 3) && !strcmp(argv[1], "port")) { const char* name = argv[2]; int port = SLV_PORT1; if (!strcasecmp(name, "composite-2")) port = SLV_PORT2; if (!strcasecmp(name, "s-video")) port = SLV_PORT0; if (port != port_) { port_ = port; reformat(); } return (TCL_OK); } else if ((argc == 3) && !strcmp(argv[1], "contrast")) { contrast(atof(argv[2])); return (TCL_OK); } else if ((argc == 3) && !strcmp(argv[1], "luma-contrast")) { return (TCL_OK); } else if ((argc == 2) && !strcmp(argv[1], "format")) { int vformat = -1; Tcl& tcl = Tcl::instance(); slv_assert("slv_get X_INPUT_FORMAT", slv_get(handle_, "INPUT_FORMAT", (void**) &vformat)); switch (vformat) { case SLV_NTSC_INPUT: tcl.result("ntsc"); break; case SLV_PAL_INPUT: tcl.result("pal"); break; case SLV_SECAM_INPUT: tcl.result("secam"); break; default: tcl.result("no-lock"); break; } return (TCL_OK); } return (Grabber::command(argc, argv)); } int SlicVideoGrabber::grab() { if (capture() < 0) return (0); suppress(frame_); saveblks(frame_); YuvFrame f(media_ts(), frame_, crvec_, outw_, outh_); return (target_->consume(&f)); } // Capture a frame. int SlicVideoGrabber::capture() { if(use_internal_api) { int y_stride, y_offset, uv_stride, uv_offset, is411; u_char *y_ptr, *u_ptr, *v_ptr; // grab a frame or field of dimensions // (x_output_size_ X y_output_size_) into a buffer of dimensions // (outw_ X outh_). Calculate offsets so that the frame/field will // be centered. If decimate_ == 1 we need to call a routine to // grab a whole frame consisting of two interleced fields, // otherwise we will grab only the odd fields. if(coder_format_ == f_422) { y_stride = outw_; y_offset = x_output_border_ + y_output_border_ * y_stride; uv_stride = outw_ / 2; uv_offset = x_output_border_/2 + y_output_border_ * uv_stride; y_ptr = frame_ + y_offset; u_ptr = frame_ + framesize_ + uv_offset; v_ptr = frame_ + framesize_ * 3 / 2 + uv_offset; is411 = 0; } else { y_stride = outw_; y_offset = x_output_border_ + y_output_border_ * y_stride; uv_stride = outw_ / 2; uv_offset = x_output_border_/2 + y_output_border_/2 * uv_stride; y_ptr = frame_ + y_offset; u_ptr = frame_ + framesize_ + uv_offset; v_ptr = frame_ + framesize_ * 5 / 4 + uv_offset; is411 = 1; } if(decimate_ == 1) { slv_read_frame_yuv(handle_, is411, y_ptr, y_stride, u_ptr, uv_stride, v_ptr, uv_stride); } else { slv_read_field_yuv(handle_, is411, y_ptr, y_stride, u_ptr, uv_stride, v_ptr, uv_stride); } return (0); } else { // ! use_internal_api u_char *yp, *up, *vp; u_int *fbufp, v; int i, h, w; char *ptr; int offset, stride, len; // grab a frame or field of dimensions // (x_output_size_ X y_output_size_) into a buffer of dimensions // (outw_ X outh_). Calculate offsets so that the frame/field will // be centered. If decimate_ == 1 we need to call a routine to // grab a whole frame consisting of two interleced fields, // otherwise we will grab only the odd fields. // offset in bytes, 2 bytes hold one pixel offset = 2 * (x_output_border_ + y_output_border_ * outw_); stride = outw_ * 2; ptr = fbuf_ + offset; len = fbufl_ - offset; if(decimate_ == 1) { slv_assert("slv_read_frame", slv_read_frame(handle_, ptr, len, stride)); } else { slv_assert("slv_read_field", slv_read_field(handle_, ptr, len, (char *) 0, 0, stride)); } // Last step is to convert the frame format as retrieved // by the SlicVideo external API calls into the format // required by vic. The API provides only calls to retrieve // byte interleaved data (UYVY), whereas vic needs separate // buffers. // This additional step of copying is ugly so it's not a big deal // to also convert the borders (unnecessarily). fbufp = (u_int *) fbuf_; if(coder_format_ == f_422) { yp = frame_; up = yp + framesize_; vp = up + (framesize_ >> 1); for (int k = framesize_; k > 0; ) { // MSB LSB - Sun Byteorder // U Y0 V Y1 - Sun Byteorder v = *fbufp++; *yp++ = v >> 16; *yp++ = v; *up++ = v >> 24; *vp++ = v >> 8; k -= 2; } } else { yp = frame_; up = yp + framesize_; vp = up + (framesize_ >> 2); for (h = outh_ / 2; --h >= 0; ) { for (w = outw_ / 2; --w >= 0; ) { v = *fbufp++; *yp++ = v >> 16; *yp++ = v; *up++ = v >> 24; *vp++ = v >> 8; } // Skip color information on every second line for (w = outw_ / 2; --w >= 0; ) { v = *fbufp++; *yp++ = v >> 16; *yp++ = v; } } } return (0); } } // Check exit status of slv_library commands void SlicVideoGrabber::slv_assert(char* desc, int command) { if(command != SLV_SUCCESS) { char *msg1, *msg2; msg1 = "slv: %s failed:"; msg2 = new char[strlen(msg1)+strlen(desc)+1]; sprintf(msg2, msg1, desc); perror(msg2); } } //*************************************************************************** //* A faster field reading routing //* Taken from the SLIC-Video User's Guide and modified //* to transfer data out in VIC format //* Should actually be part of the SlicVideo API, so it's kept separate. //*************************************************************************** // Try to help the compiler a little bit // 4 longwords contain 4 U values, 4 V values and 8 Y values inline void copy(volatile u_long * &source, u_char * &yp, u_char * &up, u_char * &vp) { u_int v; v = *source; *yp++ = v >> 16; *yp++ = v; *up++ = v >> 24; *vp++ = v >> 8; } inline void copy4_inc(volatile u_long * &source, u_char * &yp, u_char * &up, u_char * &vp) { u_int s1, s2, s3, s4; // MSB LSB - Sun Byteorder // U Y0 V Y1 - Sun Byteorder s1 = *source++; s2 = *source++; s3 = *source++; s4 = *source++; *((u_long *)yp)++ = ((s1>>16)&0xff)<<24 | (s1&0xff)<<16 | ((s2>>16)&0xff)<< 8 | (s2&0xff) ; *((u_long *)yp)++ = ((s3>>16)&0xff)<<24 | (s3&0xff)<<16 | ((s4>>16)&0xff)<< 8 | (s4&0xff) ; *((u_long *)up)++ = ((s1>>24)&0xff)<<24 | ((s2>>24)&0xff)<<16 | ((s3>>24)&0xff)<< 8 | ((s4>>24)&0xff) ; *((u_long *)vp)++ = ((s1>> 8)&0xff)<<24 | ((s2>> 8)&0xff)<<16 | ((s3>> 8)&0xff)<< 8 | ((s4>> 8)&0xff) ; } static int slv_read_frame_yuv(SLV *slvptr, int is411, u_char *yp, int y_stride, u_char *up, int u_stride, u_char *vp, int v_stride) { u_int fbuf_e, fbuf_o; int deltat, last, prev, waiting; struct slv_info slv_info; int status = SLV_FAILURE; // Grabbing a frame requires to find two out of three buffers // containing both fields of a frame. The information which kind // of frame is contained in a buffer is only set at the interrupt // indicating the completion of a buffer fill. Somehow it seems // as if this interrupts gets lost quite often, so this routine // sometimes loops around for a while... waiting = 1; while(waiting) { slv_disb_FRAM_intr(slvptr); slv_getstat(slvptr, &slv_info); last = ( slv_info.last_csr & SLV_CSR_VALID_M & ~slv_info.prev_csr); prev = ( slv_info.last_csr & SLV_CSR_VALID_M & ~last); deltat = slv_info.last_time.tv_usec - slv_info.prev_time.tv_usec; if(deltat < 0) deltat += 1000000; if( !(slv_info.last_csr & SLV_CSR_INLOCK_M) && (slv_info.prev_csr & SLV_CSR_INLOCK_M) && (deltat > 0) && (deltat < 30000) ) { // we've found two buffers which are part of one frame // (1/50 second for PAL, 1/60 for NTSC) fbuf_e = last >> SLV_CSR_VALID_S; fbuf_o = prev >> SLV_CSR_VALID_S; slv_acquire_fbufs(slvptr, fbuf_e | fbuf_o); slv_enb_FRAM_intr(slvptr); waiting = 0; } else { slv_enb_FRAM_intr(slvptr); } } status = slv_copyin_yuv(slvptr, fbuf_o, is411, yp, y_stride * 2, up, u_stride * 2, vp, v_stride * 2); slv_release_fbufs(slvptr, fbuf_o); status = slv_copyin_yuv(slvptr, fbuf_e, is411, yp + y_stride, y_stride * 2, up + u_stride, u_stride * 2, vp + v_stride, v_stride * 2); slv_release_fbufs(slvptr, fbuf_e); return(SLV_SUCCESS); } static int slv_read_field_yuv(SLV *slvptr, int is411, u_char *yp, int y_stride, u_char *up, int u_stride, u_char *vp, int v_stride) { u_int fbuf; int status = SLV_FAILURE; fbuf = slv_acquire_next_fbuf(slvptr); if(fbuf != 0) { status = slv_copyin_yuv(slvptr, fbuf, is411, yp, y_stride, up, u_stride, vp, v_stride); slv_release_fbufs(slvptr, fbuf); } return(status); } static int slv_copyin_yuv(SLV *slvptr, u_int fbuf, int is411, u_char *yp, int y_stride, u_char *up, int u_stride, u_char *vp, int v_stride) { u_int i, j; u_int leftover; int fram_index; int linebytes; u_long v; volatile u_long *framp; slv_pipe_begin(slvptr); // Read a buffer (unrolled, double-buffered, and // pipelined prefetch). linebytes = (slvptr->dst_x * slv_bytespp[slvptr->output_format]); switch (fbuf) { case SLV_FRAM_BUF0: fram_index = 0; break; case SLV_FRAM_BUF1: fram_index = 1; break; case SLV_FRAM_BUF2: fram_index = 2; break; default:slv_pipe_end(slvptr); goto failure; } framp = slvptr->fram[fram_index]; for(i = 0; i < slvptr->dst_y; i++) { // Issue prefetch on both channel's buffers. if( linebytes > 16*4) { slv_prefetch_chan(slvptr, fbuf, SLV_CHAN_A); slv_wait_chan(slvptr, SLV_CHAN_A); } j = linebytes; for(; j >= (32 * 4); j -= (32 * 4)) { volatile u_long *channelA = slvptr->slic->bufA; volatile u_long *channelB = slvptr->slic->bufB; slv_prefetch_chan(slvptr, fbuf, SLV_CHAN_B); copy4_inc(channelA, yp, up, vp); copy4_inc(channelA, yp, up, vp); copy4_inc(channelA, yp, up, vp); copy4_inc(channelA, yp, up, vp); slv_wait_chan(slvptr, SLV_CHAN_B); if(j >= ((32*4)+(16*4))) { // Issue prefetch on A channel's buffer. slv_prefetch_chan(slvptr, fbuf, SLV_CHAN_A); } copy4_inc(channelB, yp, up, vp); copy4_inc(channelB, yp, up, vp); copy4_inc(channelB, yp, up, vp); copy4_inc(channelB, yp, up, vp); slv_wait_chan(slvptr, SLV_CHAN_A); } // Do the leftover bit. if(j >= (16*4)) { volatile u_long *channelA = slvptr->slic->bufA; copy4_inc(channelA, yp, up, vp); copy4_inc(channelA, yp, up, vp); copy4_inc(channelA, yp, up, vp); copy4_inc(channelA, yp, up, vp); j -= (16*4); } // Clear both channels of the SLIC state machine. slvptr->slic->statusA = 0; slvptr->slic->statusB = 0; // Read the last bit from the FRAM for(; j > 0; j -= 4) { // read (un-prefetched) from FRAM copy(framp, yp, up, vp); } // Skip to next line. yp += y_stride - linebytes / 2; up += u_stride - linebytes / 4; vp += v_stride - linebytes / 4; if(is411 && !(i & 0x1)) { up -= u_stride; vp -= v_stride; } // Every few lines, we should call slv_pipe_update if ((i&3) == 3) slv_pipe_update(slvptr); } slv_pipe_end(slvptr); return(SLV_SUCCESS); failure: return(SLV_FAILURE); }