void Client::send(uint8_t* packet, int size, bool last_packet) {
    if (_state == REQUEST && !(_streamer->source()->encoder_type() == H264 && _streamer->frame_type() != 's')
        && !(_streamer->source()->encoder_type() == MPEG4 && !_streamer->is_mpeg4_starter_frame())) {
        SBL_MSG(MSG::STREAMER, "Client %d, starting to play", id());
        _state = PLAY;
    }
    if (_state != PLAY)
        return;
    if (skip_frame(_streamer->frame_index())) {
        SBL_MSG(MSG::STREAMER, "Client %d, filtering out frame %d, current level is %d",
                id(), _streamer->frame_index(), _temporal_level);
        return;
    }
    // This implements packet gap
    application()->rtsp_server()->packet_wait();
    packet[Streamer::RTP_SEQ_NUM]     = _seq_number >> 8;
    packet[Streamer::RTP_SEQ_NUM + 1] = _seq_number;

    SBL_MSG(MSG::STREAMER, "Client %d, send packet size %d", id(), size);
    if (_socket.send(packet - _offs, size + _offs, false)) {
        _seq_number++;
        _total_bytes += size;
        _total_packets++;
        uint32_t ts = timestamp();
        if (last_packet && ts - _last_rtcp_packet > RTCP_INTERVAL) {
            send_sender_rtcp();
            _last_rtcp_packet = ts;
        }
    } else {
        _state = STOP;
        SBL_WARN("Switching off client %d due to socket error", id());
    }
}
Beispiel #2
0
void detection_thread<T>::execute() {
  try {
    bool	display        = false;
#ifdef __GUI__
    display = conf.exists_true("display")
        && conf.exists_true("display_threads");
    bool	mindisplay     = conf.exists_true("minimal_display");
    bool       save_video     = conf.exists_true("save_video");
    bool	display_states = conf.exists_true("display_states");
    uint       wid	       = 0;	// window id
    uint       wid_states     = 0;	// window id
#endif
    uint	display_sleep  = conf.try_get_uint("display_sleep", 0);
    //      if (!display && save_video) {
    //        // we still want to output images but not show them
    //        display = true;
    // #ifdef __GUI__
    //        set_gui_silent();
    // #endif
    //      }
    // load network and weights in a forward-only parameter
    parameter<T> theparam;
    theparam.set_forward_only();
    idx<ubyte> classes(1,1);
    //try { // try loading classes names but do not stop upon failure
    load_matrix<ubyte>(classes, conf.get_cstring("classes"));
    // } catch(std::string &err) {
    //   merr << "warning: " << err;
    //   merr << std::endl;
    // }
    std::vector<std::string> sclasses = ubyteidx_to_stringvector(classes);
    answer_module<T> *ans = create_answer<T,T,T>(conf, classes.dim(0));
    uint noutputs = ans->get_nfeatures();
    intg thick = -1;
    module_1_1<T> *net = create_network<T>(theparam, conf, thick, noutputs,
                                           "arch", this->_id);
    // loading weights
    if (conf.exists("weights")) { // manual weights
      // concatenate weights if multiple ones
      std::vector<std::string> w =
          string_to_stringvector(conf.get_string("weights"));
      mout << "Loading weights from: " << w << std::endl;
      theparam.load_x(w);
      // permute weights by blocks
      if (conf.exists("weights_permutation")) {
        std::string sblocks = conf.get_string("weights_blocks");
        std::string spermut = conf.get_string("weights_permutation");
        std::vector<intg> blocks = string_to_intgvector(sblocks.c_str());
        std::vector<uint> permut = string_to_uintvector(spermut.c_str());
        theparam.permute_x(blocks, permut);
      }
    } else {
      if (conf.exists_true("manual_load")) { // manual load
        eblwarn("\"weights\" variable not defined, loading manually "
                << "if manual_load defined");
        manually_load_network(*((layers<T>*)net), conf);
      } else { // random weights
        int seed = dynamic_init_drand();
        eblwarn("No weights to load, randomizing weights with seed " << seed);
        forget_param_linear fgp(1, 0.5, seed);
        net->forget(fgp);
      }
    }
    DEBUGMEM_PRETTY("before detection");
    // detector
    detector<T> detect(*net, sclasses, ans, NULL, NULL, mout, merr);
    init_detector(detect, conf, outdir, silent);
    // keep pointer to detector
    pdetect = &detect;
    bootstrapping<T> boot(conf);

    // when a bbox file is given, ignore the processing, load the pre-computed
    // bboxes and feed them to the nms (non-maximum suppression).
    bboxes boxes(bbox_all, NULL, mout, merr);
    boxes.print_saving_type(); // inform user how we save boxes
    bool precomputed_boxes = false;
    if (conf.exists("bbox_file")) {
      precomputed_boxes = true;
      std::string bbfile = conf.get_string("bbox_file");
      boxes.load_eblearn(bbfile);
    }
    bool bmask_class = false;
    if (conf.exists("mask_class"))
      bmask_class = detect.set_mask_class(conf.get_cstring("mask_class"));

    std::string viddir = outdir;
    viddir += "video/";
    mkdir_full(viddir);
    // gui
#ifdef __GUI__
    uint display_wmax = conf.try_get_uint("display_max_width", 3000);
    T display_min = (T) conf.try_get_double("display_min", -1.7);
    T display_max = (T) conf.try_get_double("display_max", 1.7);
    T display_in_max = (T) conf.try_get_double("display_in_max", 255);
    T display_in_min = (T) conf.try_get_double("display_in_min", 0);
    float display_transp = conf.try_get_float("display_bb_transparency", 0);
    uint qstep1 = conf.try_get_uint("qstep1", 0);
    uint qheight1 = conf.try_get_uint("qheight1", 0);
    uint qwidth1 = conf.try_get_uint("qwidth1", 0);
    uint qstep2 = conf.try_get_uint("qstep2", 0);
    uint qheight2 = conf.try_get_uint("qheight2", 0);
    uint qwidth2 = conf.try_get_uint("qwidth2", 0);
    module_1_1_gui	netgui;
    wid_states  = display_states ? new_window("network states"):0;
    night_mode();
    std::string title = "EBLearn detector: ";
    title += _name;
    if (display) {
      wid = new_window(title.c_str());
      mout << "displaying in window " << wid << std::endl;
      night_mode();
    }
    float zoom = conf.try_get_float("display_zoom", 1);
    bool bbox_show_conf = !conf.exists_false("bbox_show_conf");
    bool bbox_show_class = !conf.exists_false("bbox_show_class");
    detector_gui<T>
        dgui(conf.try_get_uint("show_extracted", 0),
             conf.exists_bool("queue1"), qstep1, qheight1,
             qwidth1, conf.exists_bool("queue2"), qstep2, qheight2, qwidth2,
             bbox_show_class, bbox_show_conf);
    if (bmask_class)
      dgui.set_mask_class(conf.get_cstring("mask_class"),
                          (T) conf.try_get_double("mask_threshold", 0));
#endif
    // timing variables
    timer tpass, toverall;
    long ms;
    // loop
    toverall.start();
    // we're ready
    bavailable = true;
    while(!this->_stop) {
      // wait until a new image is made available
      while (!in_updated && !_stop) {
        millisleep(1);
      }
      tpass.restart();
      if (_stop) break ;
      // we got a new frame, reset new frame flag
      in_updated = false; // no need to lock mutex
      // check if this frame should be skipped
      if (boot.skip_frame(frame_name)) {
        skip_frame();
        continue ;
      } else if (!frame_loaded) {
        uframe = load_image<ubyte>(frame_fullname);
        mout << "loaded image " << frame_fullname << std::endl;
      }
      if (!silent) mout << "processing " << frame_name << std::endl;
      // check frame is correctly allocated, if not, allocate.
      if (frame.order() != uframe.order())
        frame = idx<T>(uframe.get_idxdim());
      else if (frame.get_idxdim() != uframe.get_idxdim())
        frame.resize(uframe.get_idxdim());
      // copy frame
      idx_copy(uframe, frame);
      // run detector
      if (!display) { // fprop without display
        if (precomputed_boxes) {
          try {
            bboxes *bb = boxes.get_group(frame_name);
            idxdim d = boxes.get_group_dims(frame_name);
            d.insert_dim(0, 1);
            bboxes pruned;
            detect.init(d);
            detect.fprop_nms(*bb, pruned);
            copy_bboxes(pruned); // make a copy of bounding boxes
            // resize frame so that caller knows the size of the frame
            idxdim framedim = frame.get_idxdim();
            if (d.dim(1) == -1 || d.dim(2) == -1)
              eblerror("pre-computed boxes must contain full image size, "
                       << "but found: " << d);
            framedim.setdim(0, d.dim(1));
            framedim.setdim(1, d.dim(2));
            frame.resize(framedim);
          } catch(eblexception &e) {
#ifdef __NOEXCEPTIONS__
            merr << "exception" << std::endl;
#else
            merr << e << std::endl;
#endif
          }
        } else {
          try {
            mout << "starting processing of frame " << frame_name << std::endl;
            bboxes &bb = detect.fprop(frame, frame_name.c_str(), frame_id);
            copy_bboxes(bb); // make a copy of bounding boxes
          } catch(ebl::eblexception &e) { // detection failed
#ifdef __NOEXCEPTIONS__
            eblwarn("detection failed");
#else
            eblwarn("detection failed: " << e);
#endif
            clear_bboxes();
          }
        }
      }
#ifdef __GUI__
      else { // fprop and display
        if (precomputed_boxes) eblerror("not implemented for nms only (TODO)");
        disable_window_updates();
        select_window(wid);
        clear_window();
        std::string title = _name;
        title << ": " << frame_name;
        set_window_title(title.c_str());
        //	 clear_resize_window();
        try {
          if (mindisplay) {
            bboxes &bb =
                dgui.display(detect, frame, frame_name.c_str(), frame_id,
                             0, 0, zoom, display_min, display_max,
                             wid, _name.c_str(), display_transp);
            copy_bboxes(bb); // make a copy of bounding boxes
          } else {
            // extract & display boxes
            bboxes &bb =
                dgui.display_inputs_outputs(detect, frame, frame_name.c_str(),
                                            frame_id, 0, 0, zoom,
                                            display_min, display_max, wid,
                                            _name.c_str(),
                                            display_in_min, display_in_max,
                                            display_transp, display_wmax);
            // make a copy of bounding boxes
            copy_bboxes(bb);
          }
        } catch(ebl::eblexception &e) { // detection failed
          eblwarn("detection failed: " << e);
          clear_bboxes();
        }
        enable_window_updates();
      }
      if (display_states) {
        dgui.display_current(detect, frame, wid_states, NULL, zoom);
        select_window(wid);
      }
      if (save_video && display) {
        std::string fname = viddir;
        fname += frame_name;
        save_window(fname.c_str());
        if (!silent) mout << "saved " << fname << std::endl;
      }
#endif
      if (!silent)
        mout << "processing done for frame " << frame_name << std::endl;
      // bootstrapping
      if (conf.exists_true("bootstrapping")) {
        boot.fprop(detect, frame_name);
        // add multiple scales if positives and scales are defined
        if (conf.exists("gt_scales") && boot.extract_positives()) {
          std::vector<double> scales =
              string_to_doublevector(conf.get_cstring("gt_scales"));
          for (uint s = 0; s < scales.size(); ++s) {
            double f = scales[s];
            // downsample input by f
            detect.set_resolution(f);
            detect.init(frame.get_idxdim(), frame_name.c_str());
            detect.fprop(frame, frame_name.c_str(), frame_id);
            boot.fprop(detect, frame_name, false, f);
          }
          detect.set_scaling_original();
          detect.init(frame.get_idxdim(), frame_name.c_str());
        }
        copy_bootstrapping(boot.get_all(), boot.get_bball());
#ifdef __GUI__
        // display groundtruth
        if (conf.exists_true("display_bootstrapping"))
          dgui.display_groundtruth(detect, frame, boot.get_gtall(),
                                   boot.get_gtclean(), boot.get_gtrest(),
                                   boot.get_bbpos(), boot.get_bbneg(),
                                   boot.get_pos(), boot.get_neg(), 0, 0, zoom,
                                   display_min, display_max);
#endif
      }
      total_saved = detect.get_total_saved();
      ms = tpass.elapsed_milliseconds();
      if (!silent) {
        mout << bbs.pretty_short(detect.get_labels());
        mout << "processing=" << ms << " ms ("
             << tpass.elapsed() << ")" << std::endl;
      }
      DEBUGMEM_PRETTY("after detection");
      // switch 'updated' flag on to warn we just added new data
      set_out_updated();
      // display sleep
      if (display_sleep > 0) {
        mout << "sleeping for " << display_sleep << "ms." << std::endl;
        millisleep(display_sleep);
      }
      if (conf.exists("save_max") &&
          detect.get_total_saved() > conf.get_uint("save_max"))
        break ; // limit number of detection saves
    }
    mout << "detection finished. Execution time: " << toverall.elapsed()<<std::endl;
    // free variables
    if (net) delete net;
    if (ans) delete ans;
  } eblcatcherror();
}
/*-----------------------------------------------------------------------------------*/
u8_t
cs8900a_poll(void)
{
  /* Check receiver event register to see if there are any valid
     unicast frames avaliable.  */
  /* PACKETPP = 0x0124;
     if(PPDATA & 0x000d == 0x0000) {
       return 0;
     }
  */
  asm("lda #$24");
  asm("sta %v", cs8900a_packetpp);
  asm("lda #$01");
  asm("sta %v+1", cs8900a_packetpp);
  asm("lda %v+1", cs8900a_ppdata);
  asm("and #$0d");
  asm("cmp #$00");
  asm("bne noreturn");
  /* No frame ready. */
  return 0;
  
  asm("noreturn:");
  /* Process the incoming frame. */
  
  /* Read receiver event and discard it. */
  /* dummy = RXTXREG; */
     
  asm("lda %v+1", cs8900a_rxtxreg);
  asm("sta _len+1");
  asm("lda %v", cs8900a_rxtxreg);
  asm("sta _len");
  
  /* Read frame length. */
  /* len = uip_len = RXTXREG; */
  asm("lda %v+1", cs8900a_rxtxreg);
  asm("sta _len+1");
  asm("sta _uip_len+1");
  asm("lda %v", cs8900a_rxtxreg);
  asm("sta _len");
  asm("sta _uip_len");

  
  if(len > UIP_BUFSIZE) {
    skip_frame();
    return 0;
  }
  
  /* Read bytes into uip_buf. */
  asm("lda ptr1");
  asm("pha");
  asm("lda ptr1+1");
  asm("pha");
  
  asm("lda #<_uip_buf");
  asm("sta ptr1");
  asm("lda #>_uip_buf");
  asm("sta ptr1+1");  
  
  asm("lda _len+1");
  asm("beq read256");
  
    /* Read first 256*n bytes. */
  asm("ldy #0");
  asm("read256loop:");
  asm("lda %v", cs8900a_rxtxreg);
  asm("sta (ptr1),y");
  asm("iny");
  asm("lda %v+1", cs8900a_rxtxreg);
  asm("sta (ptr1),y");
  asm("iny");
  asm("bne read256loop");
  asm("inc ptr1+1");
  
  asm("dec _len+1");
  asm("bne read256loop");
  
  /* Read last 255 or less bytes. */
  asm("read256:");
  asm("lda _len");
  asm("lsr");
  asm("bcc noinc");
  asm("inc _len");
  asm("noinc:");
  asm("ldy #$0");
  asm("readloop:");
  asm("lda %v", cs8900a_rxtxreg);
  asm("sta (ptr1),y");
  asm("iny");
  asm("lda %v+1", cs8900a_rxtxreg);
  asm("sta (ptr1),y");
  asm("iny");
  asm("cpy _len");
  asm("bne readloop");

  asm("pla");
  asm("sta ptr1+1");
  asm("pla");
  asm("sta ptr1");
  return len;
}
Beispiel #4
0
int main(int argc, char **argv)
{
  int num_queued;
  time_t start_time;
  double t;
  long num_frames, fast_skip = 200, fast_rewind = 200;
  unsigned int width, height;
  XEvent xevent;
  const char *prgname = argv[0];
  const char *classname = "XLndmovie";
  char *pixel_file_name = NULL;
  FILE *pixel_file;
  unsigned char *buffer = NULL, *huff = NULL;
  XImage *shm_image;
  XShmSegmentInfo shminfo;
  int shm_major, shm_minor;
  Bool shm_pixmaps;
  int ShmCompletionType;
  int shmtransfer_completed;
  int i, count, step_key = 0;
  char xkey[32];
  KeySym keysym;
  XComposeStatus compose;
  int oc;
  extern int optind;
  extern char *optarg;


  init_signal_handling();
  display = xwin_init(NULL, prgname, classname, argc, argv, &screen_no, &width, &height);
  fixed_font = XLoadQueryFont(display, "fixed");
  mit_shm = XShmQueryVersion(display, &shm_major, &shm_minor, &shm_pixmaps);
  mit_shm = XShmQueryExtension(display);
  if (mit_shm == True)
  {
    /* printf("Shared memory extension used (found V %d.%d)\n", shm_major, shm_minor); */
    ShmCompletionType = XShmGetEventBase(display) + ShmCompletion;
  }
/*
  else
    printf("Standard Xlib used, no shared memory\n");
*/
  while ((oc = getopt(argc, argv, "c:f:r:h")) != -1)
  {
    switch (oc)
    {
    case 'c':
      cell_boxsize = strtol(optarg, NULL, 10);
      break;
    case 'f':
      fast_skip = strtol(optarg, NULL, 10);
      if (fast_skip < 1)
	fast_skip = 200;
      break;
    case 'r':
      fast_rewind = strtol(optarg, NULL, 10);
      if (fast_rewind < 1)
	fast_rewind = 200;
      break;
    default:
      fprintf(stderr, "Unknown option \'-%c\' -- ignored\n", oc);
      break;
    }
  }
  if (optind < argc)
    pixel_file_name = argv[optind++];
  else
  {
    fprintf(stderr, "No pixel file specified -- exit\n");
    exit (EXIT_FAILURE);
  }
  pixel_file = fopen(pixel_file_name, "rb");
  if (pixel_file == NULL)
  {
    fprintf(stderr, "Failed to open pixel file \"%s\" -- exit\n", pixel_file_name);
    exit (EXIT_FAILURE);
  }
  read_pixheader(pixel_file);
  if ((cell_boxsize <= 0) || ((width / world_width) < cell_boxsize))
    cell_boxsize = width / world_width;
  if ((height / world_height) < cell_boxsize)
    cell_boxsize = height / world_height;
  if (cell_boxsize <= 0)
    cell_boxsize = 1;
  if ((height / world_height) < cell_boxsize)
    cell_boxsize = height / world_height;
  window_width = world_width * cell_boxsize;
  pixmap_height = world_height * cell_boxsize;
  if (fixed_font)
    window_height = pixmap_height + fixed_font->ascent + fixed_font->descent + 5;
  else
    window_height = pixmap_height;
  buffer = (unsigned char *) malloc(world_width * world_height * sizeof(char));
  if (buffer == NULL)
  {
    fprintf(stderr, "Failed to allocate internal buffer\n");
    exit (EXIT_FAILURE);
  }
  huff = (unsigned char *) malloc(world_width * world_height * sizeof(char));
  if (buffer == NULL)
  {
    fprintf(stderr, "Failed to allocate internal buffer\n");
    free(buffer);
    exit (EXIT_FAILURE);
  }
  window = create_window(MOVER | FULLER | CLOSER | RTARROW | LFARROW | UPARROW | DNARROW,
	  window_width, window_height, redraw_pixworld, close_pixwindow, 100, 100, window_width, window_height);
  XSelectInput(display, window, WH_EVENTMASK | WH_SELECTMASK);
  map_window(window);
  if (create_lndgcs(lnd_gc, lndx_gc, background_gc, &text_gc))
  {
    fprintf(stderr, "Failed to create necessary GCs (insufficient colors?)\n");
    free(buffer);
    free(huff);
    exit (EXIT_FAILURE);
  }
  if (mit_shm)
  {
    shm_image = XShmCreateImage(display, DefaultVisual(display, screen_no),
	    DefaultDepth(display, screen_no), ZPixmap, NULL, &shminfo, window_width, pixmap_height);
/*
    printf("XImage Structure:\n");
    printf("width = %d, height = %d, depth = %d\n", shm_image->width, shm_image->height, shm_image->depth);
    printf("format: ");
    switch (shm_image->format)
    {
    case XYBitmap:
      printf("XYBitmap\n");
      break;
    case XYPixmap:
      printf("XYPixmap\n");
      break;
    case ZPixmap:
      printf("ZPixmap\n");
      break;
    default:
      printf("UNKNOWN (%d)\n", shm_image->format);
      break;
    }
    printf("%d bytes per line, %d bits per pixel\n", shm_image->bytes_per_line, shm_image->bits_per_pixel);
    switch (shm_image->byte_order)
    {
    case MSBFirst:
      printf("byte order: MSBFirst\n");
      break;
    case LSBFirst:
      printf("byte order: LSBFirst\n");
      break;
    default:
      printf("byte order UNKNOWN (%d)\n", shm_image->byte_order);
      break;
    }
    switch (shm_image->bitmap_bit_order)
    {
    case MSBFirst:
      printf("bitmap bit order: MSBFirst\n");
      break;
    case LSBFirst:
      printf("bitmap bit order: LSBFirst\n");
      break;
    default:
      printf("bitmap bit order UNKNOWN (%d)\n", shm_image->bitmap_bit_order);
      break;
    }
*/
    shminfo.shmid = shmget(IPC_PRIVATE, shm_image->bytes_per_line * shm_image->height, IPC_CREAT | 0777);
    if (shminfo.shmid == -1)
    {
      fprintf(stderr, "Failed to get shared memory segment, falling back to standard Xlib\n");
      mit_shm = 0;
    }
    else
    {
      shminfo.shmaddr = shmat(shminfo.shmid, 0, 0);
      shm_image->data = shminfo.shmaddr;
      shminfo.readOnly = False;
      if (XShmAttach(display, &shminfo))
	; /* printf("Shared mem successfully attached to server\n"); */
      else
      {
	mit_shm = 0;
	XDestroyImage(shm_image);
	shmdt(shminfo.shmaddr);
	shmctl(shminfo.shmid, IPC_RMID, 0);
	printf("Shared memory released\n");
      }
    }
  }
  if (!mit_shm)
  {
    paint_pixmap = XCreatePixmap(display, window, window_width, pixmap_height, DefaultDepth(display, screen_no));
    XFillRectangle(display, paint_pixmap, background_gc[15], 0, 0, window_width, pixmap_height);
  }
  redraw_pixmap = XCreatePixmap(display, window, window_width, pixmap_height, DefaultDepth(display, screen_no));
  XFillRectangle(display, redraw_pixmap, background_gc[15], 0, 0, window_width, pixmap_height);
/*
  for (i = 0; i < 6; i++)
  {
    XPutPixel(shm_image, 0, 0, lnd_pixel[i]);
    printf("lnd_pixel[%d]=%08lx -> data=%02x\n", i, lnd_pixel[i], shm_image->data[0]);
    XPutPixel(shm_image, 0, 0, lndx_pixel[i]);
    printf("lndx_pixel[%d]=%08lx -> data=%02x\n", i, lndx_pixel[i], shm_image->data[0]);
  }
  XPutPixel(shm_image, 0, 0, back_pixel);
  printf("back_pixel=%08lx -> data=%02x\n", back_pixel, shm_image->data[0]);
*/
  do
  {
    XNextEvent(display, &xevent);
    num_queued = XEventsQueued(display, QueuedAfterFlush);
    process_xevent(&xevent);
  }
  while (!((xevent.type == Expose) && (xevent.xexpose.window == window)));
  shmtransfer_completed = 1;
  start_time = time(NULL);
  num_frames = 0;
  while (!game_over)
  {
    if(feof(pixel_file) || ferror(pixel_file))
    {
      if (resume_fpos != -1)
      {
	mode = SINGLE_STEP;
	/* printf("switched to single step due to feof / ferror\n"); */
	step_key = 0;
	/*
	printf("rewinding to resume pos %ld\n", resume_fpos);
	fseek(pixel_file, resume_fpos, SEEK_SET);
	*/
      }
      else
      {
	fprintf(stderr, "Encountered EOF without finding any entry point -- quitting\n");
	game_over = 1;
      }
    }
    num_queued = XEventsQueued(display, QueuedAfterFlush);
    while ((num_queued) || ((mode == SINGLE_STEP) && !step_key))
    {
      XNextEvent(display, &xevent);
      num_queued = XEventsQueued(display, QueuedAfterFlush);
      /* printf("received event: %s, window: %d\n", event_name[xevent.type], (int) xevent.xany.window); */
      if (process_xevent(&xevent))
	continue;
      if (xevent.type == ShmCompletionType)
      {
        /* printf("shm transfer completed\n"); */
	shmtransfer_completed = 1;
      }
      if (xevent.type == KeyPress)
      {
        count = XLookupString(&(xevent.xkey), xkey, 32, &keysym, &compose);
	if (count)
	{
	  switch(xkey[0])
	  {
	  case 'f':
	    /* printf("fast forward\n"); */
	    /* printf("rewind position: %ld\n", resume_fpos); */
	    mode = FAST_FORWARD;
	    break;
	  case 'r':
	    /* printf("fast rewind\n"); */
	    /* printf("rewind position: %ld\n", resume_fpos); */
	    mode = FAST_REWIND;
	    break;
	  case 'b':
	    /* printf("backward play\n"); */
	    /* printf("rewind position: %ld\n", resume_fpos); */
	    mode = BACKWARD_PLAY;
	    rewind_generation(pixel_file);
	    break;
	  case 's':
	    /* printf("single step\n"); */
	    mode = SINGLE_STEP;
	    step_key = 0;
	    break;
	  case 'n':
	    /* printf("normal play\n"); */
	    /* printf("rewind position: %ld\n", resume_fpos); */
	    mode = NORMAL_PLAY;
	    break;
	  case 'q': case 'Q':
	    /* printf("game over, bye bye\n"); */
            mode = NORMAL_PLAY;
            step_key = 1;
	    game_over = 1;
	    break;
	  default:
	    step_key = 1;
	    break;
	  }
	}
      }
    }
    if ((mode == NORMAL_PLAY) || (mode == BACKWARD_PLAY) || ((mode == SINGLE_STEP) && step_key)
            || ((mode == FAST_FORWARD) && ((generation % fast_skip) == (fast_skip - 1)))
            || ((mode == FAST_REWIND) && ((generation % fast_rewind) == 1)))
    {
      if (mit_shm && shmtransfer_completed)
      {
	if (shm_draw_generation(pixel_file, shm_image, buffer, huff))
	{
	  mode = SINGLE_STEP;
	  /* printf("switched to single step after shm_draw_generation\n"); */
	  step_key = 0;
	}
	else
	{
	  if (window != BadValue)
	    XShmPutImage(display, window, background_gc[15], shm_image, 0, 0, 0, window_height - pixmap_height, window_width, pixmap_height, True);
	  if (redraw_pixmap != BadValue)
	  XShmPutImage(display, redraw_pixmap, background_gc[15], shm_image, 0, 0, 0, 0, window_width, pixmap_height, True);
	  shmtransfer_completed = 0;
	  num_frames++;
	}
      }
      else
      {
	if (draw_generation(pixel_file, paint_pixmap, buffer, huff))
	{
	  mode = SINGLE_STEP;
	  /* printf("switched to single step after draw_generation\n"); */
	  step_key = 0;
	}
	else
	{
	  if (window != BadValue)
	    XCopyArea(display, paint_pixmap, window, background_gc[15], 0, 0, window_width, pixmap_height, 0, window_height - pixmap_height);
	  if (redraw_pixmap != BadValue)
	    XCopyArea(display, paint_pixmap, redraw_pixmap, background_gc[15], 0, 0, window_width, pixmap_height, 0, 0);
	  num_frames++;
	}
      }
      redraw_text();
      if (mode == FAST_REWIND)
      {
	if (rewind_generation(pixel_file))
	{
	  mode = SINGLE_STEP;
	  /* printf("switched to single step after rewind_generation\n"); */
	  step_key = 0;
	}
      }
      step_key = 0;
    }
    switch (mode)
    {
    case BACKWARD_PLAY:
      if (rewind_generation(pixel_file))
      {
	mode = SINGLE_STEP;
	/* printf("switched to single step after rewind_generation\n"); */
	step_key = 0;
      }
      /* fall through */
    case FAST_REWIND:
      if (rewind_generation(pixel_file))
      {
	mode = SINGLE_STEP;
	/* printf("switched to single step after rewind_generation\n"); */
	step_key = 0;
      }
      redraw_text();
      break;
    case FAST_FORWARD:
      if (skip_frame(pixel_file))
      {
	mode = SINGLE_STEP;
	/* printf("switched to single step after skip_frame\n"); */
	step_key = 0;
      }
      redraw_text();
      break;
    }
  }
  t = difftime(time(NULL), start_time);
  /* printf("%ld frames in %f seconds (%f frames/sec)\n", num_frames, t, num_frames / t); */
  if (mit_shm)
  {
    XShmDetach(display, &shminfo);
    XDestroyImage(shm_image);
    shmdt(shminfo.shmaddr);
    shmctl(shminfo.shmid, IPC_RMID, 0);
    printf("Shared memory released\n");
  }
  free_lndgcs();
  if (window != BadValue)
    remove_window(window);
  if (redraw_pixmap != BadValue)
    XFreePixmap(display, redraw_pixmap);
  if (paint_pixmap != BadValue)
    XFreePixmap(display, paint_pixmap);
  free(buffer);
  free(huff);
  return (EXIT_SUCCESS);
}