Re: real-time video in texture memory

New Message Reply Date view Thread view Subject view Author view

Wade Olsen (wade++at++fnord)
Fri, 3 Jun 1994 11:37:22 -0700


On Jun 3, 10:59am, Glen Fraser wrote:
> Subject: Re: real-time video in texture memory
> > Yes. How depends on where the video comes from:
> >
> > If the video comes from an external source (e.g. a camera, vcr...) and
you
> < stuff deleted >
>
> > If the video comes from memory, like little animation sequences, then
no
> < stuff deleted >
>
>
> What about if the video comes from disk? Is there some suitable way
> of getting long pre-generated animations from disk into texture memory
> in or near real-time? Is there an SGI animation format which would
> facilitate this?
>
> Thanks,
> Glen.

Video from disk is dealt with the same way as video from memory, with the
added task of reading the frames from disk to memory. There are a number
of tools availble to deal with video. Check out the dmedia (digital
media) development stuff. Unfortunatly, I don't know much about it. One
thing to think about when choosing how to store the data on disk is it
should be read into memory in the format expected by texdef2d or
subtexload (i.e. scanlines are padded to 4 bytes, see "pixmode" also).

The best way to do video from disk to graphics is to "sproc" another
process to do disk I/O or to use the asynchronous I/O commands (see "man
aio_init"). The disk process should be busy reading the next frame or
frames while the graphics process is using a frame that has already been
loaded. The processes could be synchronized using semaphores (see "man
usnewsema").

Here is a c++ library I used to do fast disk I/O for video. It sets up a
another process to read ahead:

----------------------------------file_io.h--------------------------------
class file_io
{
 public:
  file_io(char * file_name, int mode);
  ~file_io();

  virtual void read(void * buffer, int start_block, int num_blocks);
  virtual void write(void * buffer, int start_block, int num_blocks);

 protected:
  int file_handle;
  char * file_name;
};

class raw_file_io : public file_io
{
 public:
  raw_file_io(char * file_name, int mode, int first_block);

  virtual void read(void * buffer, int start_block, int num_blocks);
  virtual void write(void * buffer, int start_block, int num_blocks);

 private:
  int first_block;
};

file_io * open_a_file(char * name, int start_block);
file_io * create_a_file(char * name, int start_block);

----------------------------------file_io.c++------------------------------
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/syssgi.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>

#include "file_io.h"

#define BLOCKSIZE 512

static char * raw_name = "/dev/rdsk/";

file_io *
open_a_file(char * name, int start_block)
{
  file_io * f;
  if (strncmp(raw_name, name, strlen(raw_name)) == 0)
    f = new raw_file_io(name, O_RDONLY, start_block);
  else
    f = new file_io(name, O_RDONLY);

  return f;
}

file_io *
create_a_file(char * name, int start_block)
{
  file_io * f;
  if (strncmp(raw_name, name, strlen(raw_name)) == 0)
    f = new raw_file_io(name, O_WRONLY|O_CREAT, start_block);
  else
    f = new file_io(name, O_WRONLY|O_CREAT);

  return f;
}

file_io::file_io(char * name, int mode)
{
  file_name = name;
  file_handle = open(file_name, mode, 0644);
  if (file_handle < 0) {
    fprintf(stderr,
            "Can't open file %s: %s.\n",
            file_name,
            strerror(errno));
    exit(1);
  }
}

file_io::~file_io()
{
  close(file_handle);
}

raw_file_io::raw_file_io(char * name, int mode, int start)
     : file_io(name, mode)
{
  first_block = start;
}

void
file_io::read(void * buffer, int block, int blocks)
{
  long err = lseek(file_handle, block * BLOCKSIZE, SEEK_SET);
  if (err == -1)
    {
      fprintf(stderr,
              "Can't seek to block %0d in %s: %s.\n",
              block,
              file_name,
              strerror(errno));
      exit(1);
    }
  err = ::read(file_handle, buffer, blocks * BLOCKSIZE);
  if (err == -1)
    {
      fprintf(stderr,
              "Can't read from block %0d in %s: %s.\n",
              block,
              file_name,
              strerror(errno));
      exit(1);
    }
}

void
file_io::write(void * buffer, int block, int blocks)
{
  long err = lseek(file_handle, block * BLOCKSIZE, SEEK_SET);
  if (err == -1)
    {
      fprintf(stderr,
              "Can't seek to block %0d in %s: %s.\n",
              block,
              file_name,
              strerror(errno));
      exit(1);
    }
  err = ::write(file_handle, buffer, blocks * BLOCKSIZE);
  if (err == -1)
    {
      fprintf(stderr,
              "Can't write from block %0d in %s: %s.\n",
              block,
              file_name,
              strerror(errno));
      exit(1);
    }
}

void
raw_file_io::read(void * buffer, int block, int blocks)
{
  long err = syssgi(SGI_READB, file_handle, buffer,
                    block + first_block, blocks);
  if (err == -1)
    {
      fprintf(stderr,
              "Can't read to block %0d in %s: %s.\n",
              block,
              file_name,
              strerror(errno));
      exit(1);
    }
}

void
raw_file_io::write(void * buffer, int block, int blocks)
{
  long err = syssgi(SGI_WRITEB, file_handle, buffer,
                    block + first_block, blocks);
  if (err == -1)
    {
      fprintf(stderr,
              "Can't write to block %0d in %s: %s.\n",
              block,
              file_name,
              strerror(errno));
      exit(1);
    }
}
----------------------------------reader.h-------------------------------
#include <sys/types.h>
#include <task.h>
#include <ulocks.h>

#include "file_io.h"

class reader
{
  public:

    reader(int numbuffers, int buffer_size,
           file_io * file, int transfers);

    unsigned long * read();

  private:

    usema_t * produce_sema;
    usema_t * consume_sema;
    int produce_buffer;
    int consume_buffer;

    file_io * file_handle;
    int num_buffers;
    unsigned long ** buffers;

    void read_data();
    pid_t reader_task;
    pid_t parent_task;
    int transfers;

    // image buffer parameters
    int blocks_per_transfer;
};
-----------------------------------reader.c++------------------------------
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <sys/prctl.h>
#include <fcntl.h>
#include <sys/uio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <ulocks.h>
#include <math.h>
#include <libgen.h>
#include <X11/Intrinsic.h>
#include <sys/syssgi.h>

#include "reader.h"

reader::reader(int numbuffers, int buffer_size, file_io * file, int trans)
{
  transfers = trans;

  usptr_t * arena = usinit("/usr/tmp/raw_arena");
  produce_sema = usnewsema(arena, 0);
  consume_sema = usnewsema(arena, 0);
  produce_buffer = 0;
  consume_buffer = 0;

  file_handle = file;
  blocks_per_transfer = buffer_size;
  if (blocks_per_transfer == 0)
    {
      fprintf(stderr, "reader: transfer size is zero!\n");
      exit(1);
    }

  num_buffers = numbuffers;
  int bytes_per_transfer = blocks_per_transfer * 512;
  fprintf(stderr,
          "Allocating %0d buffers of %0d bytes\n",
          num_buffers, bytes_per_transfer);

  buffers = (unsigned long **)
    malloc(sizeof(unsigned long *) * num_buffers);
  for (int i = 0; i < num_buffers; i++)
    {
      buffers[i] = (unsigned long *)
        malloc(sizeof(unsigned long) * bytes_per_transfer);
      if (mpin (buffers[i], bytes_per_transfer))
        fprintf(stderr,
                "Can't pin %0d bytes for buffer %0d: %s\n",
                bytes_per_transfer,
                i,
                strerror(errno));
    }

  usinitsema(produce_sema, num_buffers -1);

  parent_task = getpid();
  reader_task = sproc((void (*)(void *))reader::read_data,
                      PR_SALL,
                      this);
}

unsigned long *
reader::read()
{
  if (ustestsema(produce_sema) == 0)
    fprintf(stderr, "Waiting for disk reader!\n");
  uspsema(consume_sema); /* Wait until the next buffer is
available. */

  unsigned long * buffer = buffers[consume_buffer];
  consume_buffer = (consume_buffer + 1) % num_buffers;
  usvsema(produce_sema); /* Wake the reader. */

  return buffer;
}

void
reader::read_data()
{
  prctl(PR_TERMCHILD);

  while (1)
    for (int i = 0; i < transfers; i++)
      {
        uspsema(produce_sema); /* Wait for an empty buffer. */

        int read_block = (i + 1) * blocks_per_transfer;
        file_handle->read(buffers[produce_buffer],
                          read_block, blocks_per_transfer);

        usvsema(consume_sema); /* Wake the consumer, the frame is ready.
*/

        produce_buffer = (produce_buffer +1) % num_buffers;
      }
}
---------------------------------------------------------------------------

Wade

-- 
-------------------------------------------------------------------------------
Wade Olsen, wade++at++sgi.com, 415-390-1023, Silicon Graphics Computer Systems

New Message Reply Date view Thread view Subject view Author view

This archive was generated by hypermail 2.0b2 on Mon Aug 10 1998 - 17:50:19 PDT

This message has been cleansed for anti-spam protection. Replace '++at++' in any mail addresses with the '@' symbol.