Logo Search packages:      
Sourcecode: xawtv version File versions  Download package

ttv.c

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <pthread.h>
#include <aalib.h>

#include "grab-ng.h"
#include "capture.h"
#include "channel.h"
#include "commands.h"
#include "frequencies.h"
#include "parseconfig.h"
#include "sound.h"

/* ---------------------------------------------------------------------- */
/* capture stuff                                                          */

static struct aa_hardware_params params;
static aa_renderparams render;
static aa_context *context;
char *framebuffer;
static int signaled;

static char title[256];
static char message[256];
static time_t mtime;
static struct ng_video_fmt   fmt,gfmt;
static struct ng_video_conv  *conv;
static struct ng_convert_handle *ch;
static int fast;

static void
grabber_init(void)
{
    drv = ng_vid_open(ng_dev.video,NULL,NULL,0,&h_drv);
    if (NULL == drv) {
      fprintf(stderr,"no grabber device available\n");
      exit(1);
    }
    f_drv = drv->capabilities(h_drv);
    add_attrs(drv->list_attrs(h_drv));
}

static void
new_title(char *txt)
{
    strcpy(title,txt);
}

static void
new_message(char *txt)
{
    mtime = time(NULL);
    strcpy(message,txt);
}

static void do_capture(int from, int to, int tmp_switch)
{
    /* off */
    switch (from) {
    case CAPTURE_GRABDISPLAY:
      if (f_drv & CAN_CAPTURE)
          drv->stopvideo(h_drv);
      break;
    }

    /* on */
    switch (to) {
    case CAPTURE_GRABDISPLAY:
      /* try native */
      fmt.fmtid  = VIDEO_GRAY;
      fmt.width  = aa_imgwidth(context);
      fmt.height = aa_imgheight(context);
      if (0 != ng_grabber_setformat(&fmt,1)) {
          gfmt = fmt;
          if (NULL == (conv = ng_grabber_findconv(&gfmt,0))) {
            fprintf(stderr,"can't capture gray data\n");
            exit(1);
          }
          ch = ng_convert_alloc(conv,&gfmt,&fmt);
          ng_convert_init(ch);
      }
      if (f_drv & CAN_CAPTURE)
          drv->startvideo(h_drv,-1,2);
      break;
    }
}

static void blitframe(struct ng_video_buf *buf)
{
    int w,h,y;
    char *s,*d;

#if 0
    /* debug */
    fprintf(stdout,"P5\n%d %d\n255\n",buf->fmt.width,buf->fmt.height);
    fwrite(buf->data,buf->fmt.width,buf->fmt.height,stdout);
    exit(1);
#endif
    if (buf->fmt.width  == aa_imgwidth(context) &&
      buf->fmt.height == aa_imgheight(context)) {
      memcpy(framebuffer,buf->data,buf->fmt.width*buf->fmt.height);
    } else {
      s = buf->data;
      d = framebuffer;
      if (buf->fmt.height < aa_imgheight(context)) {
          h  = buf->fmt.height;
          d += (aa_imgheight(context)-buf->fmt.height)/2 *
            aa_imgwidth(context);
      } else {
          h = aa_imgheight(context);
          s += (buf->fmt.height-aa_imgheight(context))/2 *
            buf->fmt.width;
      }
      if (buf->fmt.width < aa_imgwidth(context)) {
          w  = buf->fmt.width;
          d += (aa_imgwidth(context)-buf->fmt.width)/2;
      } else {
          w  = aa_imgwidth(context);
          s += (buf->fmt.width-aa_imgwidth(context))/2;
      }
      for (y = 0; y < h; y++) {
          memcpy(d,s,w);
          s += buf->fmt.width;
          d += aa_imgwidth(context);
      }
    }
}

/* ----------------------------------------------------------------------- */

static void aa_cleanup(void)
{
    aa_uninitkbd(context);
    aa_close(context);
}

static void
ctrlc(int signal)
{
    signaled++;
}

static void
usage(void)
{
    printf("ttv -- watch tv on a ascii terminal using aalib\n"
         "\n"
         "ttv options:\n"
         "  -h             print this text\n"
         "  -f             use fast aalib render function\n"
         "  -c <device>    video device [%s]\n"
         "\n"
         "aalib options:\n"
         "%s",
         ng_dev.video,aa_help);
    exit(1);
}

int
main(int argc, char **argv)
{
    struct ng_video_buf *buf;
    unsigned long freq;
    int c,i,key,frames,fps;
    time_t now,last;
    struct tm *t;

    ng_init();
    params = aa_defparams;
    render = aa_defrenderparams;
    if (!aa_parseoptions (&params, &render, &argc, argv))
      usage();
    for (;;) {
      c = getopt(argc, argv, "vfhc:");
      if (c == -1)
          break;
      switch (c) {
      case 'v':
          debug++;
          ng_debug++;
          break;
      case 'f':
          fast++;
          break;
      case 'c':
          ng_dev.video = optarg;
          break;
      case 'h':
      default:
          usage();
          break;
      }
    }

    /* init aalib */
    context = aa_autoinit(&params);
    if (context == NULL) {
      printf("Failed to initialize aalib\n");
      exit (1);
    }
    aa_autoinitkbd(context,0);
    atexit(aa_cleanup);
    framebuffer = aa_image(context);

    /* init v4l */
    grabber_init();
    freq_init();
    read_config(NULL,NULL,NULL);
    ng_ratio_x = 0;
    ng_ratio_y = 0;

    /* init mixer */
    if (0 != strlen(mixerdev)) {
      struct ng_attribute *attr;
      if (NULL != (attr = ng_mix_init(mixerdev,mixerctl)))
          add_attrs(attr);
    }

    /* set hooks (command.c) */
    update_title      = new_title;
    display_message   = new_message;
    set_capture_hook  = do_capture;

    /* init hardware */
    attr_init();
    audio_on();
    audio_init();

    /* build channel list */
    parse_config();
    do_va_cmd(2,"setfreqtab",(-1 != chantab)
              ? chanlist_names[chantab].str : "europe-west");
    cur_capture = 0;
    do_va_cmd(2,"capture","grabdisplay");
    if (optind+1 == argc) {
      do_va_cmd(2,"setstation",argv[optind]);
    } else {
      if ((f_drv & CAN_TUNE) && 0 != (freq = drv->getfreq(h_drv))) {
          for (i = 0; i < chancount; i++)
            if (chanlist[i].freq == freq*1000/16) {
                do_va_cmd(2,"setchannel",chanlist[i].name);
                break;
            }
      }
      if (-1 == cur_channel) {
          if (count > 0)
            do_va_cmd(2,"setstation","0");
          else
            set_defaults();
      }
    }
    
    /* catch ^C */
    signal(SIGINT,ctrlc);
    signal(SIGTERM,ctrlc);
    signal(SIGQUIT,ctrlc);

    /* main loop */
    last = now = time(NULL);
    frames = fps = 0;
    for (;!signaled;) {
      /* time + performance */
      now = time(NULL);
      t = localtime(&now);
      frames++;
      if (now - last >= 5) {
          fps = frames * 10 / (now-last);
          last = now;
          frames = 0;
      }
      
      /* grab + convert frame */
      if (NULL == (buf = ng_grabber_grab_image(0))) {
          fprintf(stderr,"capturing image failed\n");
          exit(1);
      }
      if (ch)
          buf = ng_convert_frame(ch,NULL,buf);

      /* blit frame */
      blitframe(buf);
      ng_release_video_buf(buf);
      if (fast)
          aa_fastrender(context, 0, 0,
                    aa_scrwidth (context), aa_scrheight (context));
      else
          aa_render(context, &render, 0, 0,
                  aa_scrwidth (context), aa_scrheight (context));
      if (now - mtime < 6) {
          aa_printf(context,0,0,AA_NORMAL,"[ %s ] ",
                  message);
      } else {
          aa_printf(context,0,0,AA_NORMAL,"[ %s - %d.%d fps - %02d:%02d ] ",
                  title,fps/10,fps%10,t->tm_hour,t->tm_min);
      }
      aa_flush(context);

      /* check for keys */
      key = aa_getkey(context,0);
      switch (key) {
      case 'q':
      case 'Q':
      case 'e':
      case 'E':
      case 'x':
      case 'X':
          audio_off();
          signaled++;
          break;
      case 'd':
      case 'D':
          mtime = time(NULL);
          sprintf(message,"debug: scr=%dx%d / img=%dx%d / cap=%dx%d",
                aa_scrwidth(context),aa_scrheight(context),
                aa_imgwidth(context),aa_imgheight(context),
                fmt.width,fmt.height);
          break;
      case '+':
          do_va_cmd(2,"volume","inc");
          break;
      case '-':
          do_va_cmd(2,"volume","dec");
          break;
      case 10:
      case 13:
          do_va_cmd(2,"volume","mute");
          break;
      case AA_UP:
          do_va_cmd(2,"setchannel","next");
          break;
      case AA_DOWN:
          do_va_cmd(2,"setchannel","prev");
          break;
      case AA_RIGHT:
          do_va_cmd(2,"setchannel","fine_up");
          break;
      case AA_LEFT:
          do_va_cmd(2,"setchannel","fine_down");
          break;
      case ' ':
          do_va_cmd(2,"setstation","next");
          break;
      default:
          /* nothing */
          break;
      }
    }
    exit(0);
}

Generated by  Doxygen 1.6.0   Back to index