[PATCH] bin/cue-support

Fabian Franz <[email protected]>
Newsgroups gmane.comp.video.mplayer.g2.devel
Message-ID <[email protected]>
hi,

attached is simply the reworked file, ported from main-tree.

I also removed all globals so it is a more clean approach than before.

It could also be backported to main as the g2-specific stuff is easy to see 
:-)

Btw. I love this new stream-architecture. It is sooo nice to use :-))

cu

Fabian

_______________________________________________
MPlayer-G2-dev mailing list
[email protected]
http://mplayerhq.hu/mailman/listinfo/mplayer-g2-dev
stream_cue.c (text/x-csrc, 15 KB)
//=================== VideoCD BinCue ==========================

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

#include "../config.h"
#include "../mp_msg.h"
#include "../help_mp.h"

#include "stream.h"

//#include "cue_read.h"

#define byte    unsigned char
#define SIZERAW 2352
#define SIZEISO_MODE1 2048
#define SIZEISO_MODE2_RAW 2352
#define SIZEISO_MODE2_FORM1 2048
#define SIZEISO_MODE2_FORM2 2336
#define AUDIO 0
#define MODE1 1
#define MODE2 2
#define MODE1_2352 10
#define MODE2_2352 20
#define MODE1_2048 30
#define MODE2_2336 40
#define UNKNOWN -1

//static int fd_bin = 0;

typedef struct track
{
   unsigned short mode;
   unsigned short minute;
   unsigned short second;
   unsigned short frame;

   /* (min*60 + sec) * 75 + fps   */

   unsigned long start_sector;

   /* = the sizes in bytes off all tracks bevor this one */
   /* its needed if there are mode1 tracks befor the mpeg tracks */
   unsigned long start_offset;

   /*   unsigned char num[3]; */
} tTrack;

/* max 99 tracks on a cd */
//static tTrack tracks[100];

static struct cue_track_pos {
  int track;
  unsigned short mode;
  unsigned short minute;
  unsigned short second;
  unsigned short frame;
} cue_curr_pos;//cue_current_pos;

static struct cue_priv_s
{
  int fd_bin;
  /* max 99 tracks on a cd */
  tTrack tracks[100];
  
  struct cue_track_pos cue_current_pos;
  /* number of tracks on the cd */
  int nTracks;
} cue_priv_st;

typedef struct cue_priv_s cue_priv_t;

/* number of tracks on the cd */
//static int nTracks = 0;

/* presumes Line is preloaded with the "current" line of the file */
int cue_getTrackinfo(char *Line, tTrack *track, FILE* fd_cue)
{
  char inum[3];
  char min;
  char sec;
  char fps;
  int already_set = 0;

  /* Get the 'mode' */
  if (strncmp(&Line[2], "TRACK ", 6)==0)
  {
/*    strncpy(track->num, &Line[8], 2); track->num[2] = '\0'; */

    track->mode = UNKNOWN;
    if(strncmp(&Line[11], "AUDIO", 5)==0) track->mode = AUDIO;
    if(strncmp(&Line[11], "MODE1/2352", 10)==0) track->mode = MODE1_2352;
    if(strncmp(&Line[11], "MODE1/2048", 10)==0) track->mode = MODE1_2048;
    if(strncmp(&Line[11], "MODE2/2352", 10)==0) track->mode = MODE2_2352;
    if(strncmp(&Line[11], "MODE2/2336", 10)==0) track->mode = MODE2_2336;
  }
  else return(1);

  /* Get the track indexes */
  while(1) {
    if(! fgets( Line, 256, fd_cue ) ) { break;}

    if (strncmp(&Line[2], "TRACK ", 6)==0)
    {
      /* next track starting */
      break;
    }

    /* Track 0 or 1, take the first an get fill the values*/
    if (strncmp(&Line[4], "INDEX ", 6)==0)
    {
      /* check stuff here so if the answer is false the else stuff below won't be executed */
      strncpy(inum, &Line[10], 2); inum[2] = '\0';
      if ((already_set == 0) &&
          ((strcmp(inum, "00")==0) || (strcmp(inum, "01")==0)))
      {
        already_set = 1;

        min = ((Line[13]-'0')<<4) | (Line[14]-'0');
        sec = ((Line[16]-'0')<<4) | (Line[17]-'0');
        fps = ((Line[19]-'0')<<4) | (Line[20]-'0');

        track->minute = (((min>>4)*10) + (min&0xf));
        track->second = (((sec>>4)*10) + (sec&0xf));
        track->frame  = (((fps>>4)*10) + (fps&0xf));
      }
    }
    else if (strncmp(&Line[4], "PREGAP ", 7)==0) { ; /* ignore */ }
    else if (strncmp(&Line[4], "FLAGS ", 6)==0)  { ; /* ignore */ }
    else mp_msg (MSGT_OPEN,MSGL_INFO,
                 "[bincue] Unexpected cuefile line: %s\n", Line);
  }
  return(0);
}



int cue_find_bin (char *firstline, char* cue_filename, char* bincue_path) {
  int i,j;
  char s[256];
  char t[256];
  char bin_filename[256];
  int fd_bin;

  /* get the filename out of that */
  /*                      12345 6  */
  if (strncmp(firstline, "FILE \"",6)==0)
  {
    i = 0;
    j = 0;
    while ( firstline[6 + i] != '"')
    {
      bin_filename[j] = firstline[6 + i];

      /* if I found a path info, than delete all bevor it */
      switch (bin_filename[j])
      {
        case '\\':
          j = 0;
          break;

        case '/':
          j = 0;
          break;

        default:
          j++;
      }
      i++;
    }
    bin_filename[j+1] = '\0';

  }

  /* now try to open that file, without path */
  fd_bin = open (bin_filename, O_RDONLY);
  if (fd_bin == -1)
  {
    mp_msg(MSGT_OPEN,MSGL_STATUS, "[bincue] bin filename tested: %s\n",
           bin_filename);

    /* now try to find it with the path of the cue file */
    sprintf(s,"%s/%s",bincue_path, bin_filename);
    fd_bin = open (s, O_RDONLY);
    if (fd_bin == -1)
    {
      mp_msg(MSGT_OPEN,MSGL_STATUS,
             "[bincue] bin filename tested: %s\n", s);
      /* now I would say the whole filename is shit, build our own */
      strncpy(s, cue_filename, strlen(cue_filename) - 3 );
      s[strlen(cue_filename) - 3] = '\0';
      strcat(s, "bin");
      fd_bin = open (s, O_RDONLY);
      if (fd_bin == -1)
      {
        mp_msg(MSGT_OPEN,MSGL_STATUS,
               "[bincue] bin filename tested: %s\n", s);

        /* ok try it with path */
        sprintf(t,"%s/%s",bincue_path, s);
        fd_bin = open (t, O_RDONLY);
        if (fd_bin == -1)
        {
          mp_msg(MSGT_OPEN,MSGL_STATUS,
                 "[bincue] bin filename tested: %s\n",t);
          /* now I would say the whole filename is shit, build our own */
          strncpy(s, cue_filename, strlen(cue_filename) - 3 );
          s[strlen(cue_filename) - 3] = '\0';
          strcat(s, "img");
          fd_bin = open (s, O_RDONLY);
          if (fd_bin == -1)
          {
            mp_msg(MSGT_OPEN,MSGL_STATUS,
                   "[bincue] bin filename tested: %s \n", s);
            /* ok try it with path */
            sprintf(t,"%s/%s",bincue_path, s);
            fd_bin = open (t, O_RDONLY);
            if (fd_bin == -1)
            {
              mp_msg(MSGT_OPEN,MSGL_STATUS,
                     "[bincue] bin filename tested: %s\n", s);

              /* I'll give up */
              mp_msg(MSGT_OPEN,MSGL_ERR,
                     "[bincue] couldn't find the bin file - giving up\n");
              return -1;
            }
          }
        } else strcpy(bin_filename, t);

      } else strcpy(bin_filename, s);

    } else strcpy(bin_filename, s);

  }

  mp_msg(MSGT_OPEN,MSGL_INFO,
         "[bincue] using bin file %s\n", bin_filename);
  return fd_bin;
}

static inline int cue_msf_2_sector(int minute, int second, int frame) {
 return frame + (second + minute * 60 ) * 75;
}

static inline int cue_get_msf(cue_priv_t* cue) {
  return cue_msf_2_sector (cue->cue_current_pos.minute,
                           cue->cue_current_pos.second,
                           cue->cue_current_pos.frame);
}

inline void cue_set_msf(cue_priv_t* cue, unsigned int sect){
  cue->cue_current_pos.frame=sect%75;
  sect=sect/75;
  cue->cue_current_pos.second=sect%60;
  sect=sect/60;
  cue->cue_current_pos.minute=sect;
}

static inline int cue_mode_2_sector_size(int mode)
{
  switch (mode)
  {
    case AUDIO:      return AUDIO;
    case MODE1_2352: return SIZERAW;
    case MODE1_2048: return SIZEISO_MODE1;
    case MODE2_2352: return SIZEISO_MODE2_RAW;
    case MODE2_2336: return SIZEISO_MODE2_FORM2;

    default:
      mp_msg(MSGT_OPEN,MSGL_FATAL,
             "[bincue] unknown mode for binfile. should not happen. aborting\n");
      abort();
  }

}


cue_priv_t* cue_read_cue (char *in_cue_filename)
{
  struct stat filestat;
  char sLine[256];
  char cue_filename[256];
  char bincue_path[256];
  unsigned int sect;
  char *s,*t;
  int i;
  FILE* fd_cue;
  cue_priv_t cue; 
  cue_priv_t* cue_p=NULL; 

  /* we have no tracks at the beginning */
  cue.nTracks = 0;

  cue.fd_bin = 0;

  /* split the filename into a path and filename part */
  s = strdup(in_cue_filename);
  t = strrchr(s, '/');
  if (t == (char *)NULL)
     t = ".";
  else {
     *t = '\0';
     t = s;
     if (*t == '\0')
       strcpy(t, "/");
  }
  printf ("dirname: %s\n", t);
  strcpy(bincue_path,t);


  /* no path at all? */
  if (strcmp(bincue_path, ".") == 0) {
    //printf ("bincue_path: %s\n", bincue_path); //FF: unneccessary printf - should imho be removed in main too
    strcpy(cue_filename,in_cue_filename);
  } else {
    strcpy(cue_filename,in_cue_filename + strlen(bincue_path) + 1);
  }



  /* open the cue file */
  fd_cue = fopen (in_cue_filename, "r");
  if (fd_cue == NULL)
  {
    mp_msg(MSGT_OPEN,MSGL_ERR,
           "[bincue] cannot open %s\n", in_cue_filename);
    return 0;
  }

  /* read the first line and hand it to find_bin, which will
     test more than one possible name of the file */

  if(! fgets( sLine, 256, fd_cue ) )
  {
    mp_msg(MSGT_OPEN,MSGL_ERR,
           "[bincue] error reading from  %s\n", in_cue_filename);
    fclose (fd_cue);
    return 0;
  }
  cue.fd_bin=cue_find_bin(sLine, cue_filename, bincue_path);
  if (cue.fd_bin < 0) {
    fclose (fd_cue);
    return 0;
  }


  /* now build the track list */
  /* red the next line and call our track finder */
  if(! fgets( sLine, 256, fd_cue ) )
  {
    mp_msg(MSGT_OPEN,MSGL_ERR,
           "[bincue] error reading from  %s\n", in_cue_filename);
    fclose (fd_cue);
    return 0;
  }

  while(!feof(fd_cue))
  {
    if (cue_getTrackinfo(sLine, &cue.tracks[cue.nTracks++], fd_cue) != 0)
    {
      mp_msg(MSGT_OPEN,MSGL_ERR,
             "[bincue] error reading from  %s\n", in_cue_filename);
      fclose (fd_cue);
      return 0;
    }
  }

  /* make a fake track with stands for the Lead out */
  if (fstat (cue.fd_bin, &filestat) == -1) {
    mp_msg(MSGT_OPEN,MSGL_ERR,
           "[bincue] error getting size of bin file\n");
    fclose (fd_cue);
    return 0;
  }

  sect = filestat.st_size / 2352;

  cue.tracks[cue.nTracks].frame = sect%75;
  sect=sect/75;
  cue.tracks[cue.nTracks].second = sect%60;
  sect=sect/60;
  cue.tracks[cue.nTracks].minute = sect;


  /* lets calculate the start sectors and offsets */
  for(i = 0; i <= cue.nTracks; i++)
  {
    cue.tracks[i].start_sector = cue_msf_2_sector(cue.tracks[i].minute,
                                              cue.tracks[cue.nTracks].second,
                                              cue.tracks[cue.nTracks].frame);

    /* if we're the first track we don't need to offset of the one befor */
    if (i == 0)
    {
      /* was always 0 on my svcds, but who knows */
      cue.tracks[0].start_offset = cue.tracks[0].start_sector *
        cue_mode_2_sector_size(cue.tracks[0].mode);
    } else
    {
      cue.tracks[i].start_offset = cue.tracks[i-1].start_offset +
        (cue.tracks[i].start_sector - cue.tracks[i-1].start_sector) *
        cue_mode_2_sector_size(cue.tracks[i-1].mode);
    }
  }

  fclose (fd_cue);

  cue_p = malloc(sizeof(cue_priv_t));
  memcpy(cue_p, &cue, sizeof(cue_priv_t));

  return cue_p;
}




int cue_read_toc_entry(cue_priv_t* cue) {

  int track = cue->cue_current_pos.track - 1;

  /* check if its a valid track, if not return -1 */
  if (track >= cue->nTracks)
    return -1;


  switch (cue->tracks[track].mode)
  {
    case AUDIO:
      cue->cue_current_pos.mode = AUDIO;
      break;
    case MODE1_2352:
      cue->cue_current_pos.mode = MODE1;
      break;
    case MODE1_2048:
      cue->cue_current_pos.mode = MODE1;
      break;
    default: /* MODE2_2352 and MODE2_2336 */
      cue->cue_current_pos.mode = MODE2;
  }
  cue->cue_current_pos.minute = cue->tracks[track].minute;
  cue->cue_current_pos.second = cue->tracks[track].second;
  cue->cue_current_pos.frame = cue->tracks[track].frame;

  return 0;
}

int cue_read_raw(cue_priv_t* cue,char *buf) {
  int position;
  int track = cue->cue_current_pos.track - 1;

  /* get the mode of the bin file part and calc the positon */
  position = cue->tracks[track].start_offset +
             (cue_msf_2_sector(cue->cue_current_pos.minute,
                               cue->cue_current_pos.second,
                               cue->cue_current_pos.frame) -
              cue->tracks[track].start_sector)
             * cue_mode_2_sector_size(cue->tracks[track].mode);

  /* check if the track is at its end*/
  if (position >= cue->tracks[track+1].start_offset)
    return -1;

  if (lseek (cue->fd_bin, position, SEEK_SET) == -1) {
    mp_msg(MSGT_OPEN,MSGL_ERR,
           "[bincue] unexpected end of bin file\n");
    return -1;
  }

  if (!read (cue->fd_bin, buf, VCD_SECTOR_SIZE))
    return -1;
  else
    return VCD_SECTOR_DATA;
}



int cue_vcd_seek_to_track (cue_priv_t* cue,int track){
  cue->cue_current_pos.track  = track;

  if (cue_read_toc_entry (cue))
    return -1;

  return VCD_SECTOR_DATA * cue_get_msf(cue);
}

int cue_vcd_get_track_end (cue_priv_t* cue,int track){
  cue->cue_current_pos.frame = cue->tracks[track].frame;
  cue->cue_current_pos.second = cue->tracks[track].second;
  cue->cue_current_pos.minute = cue->tracks[track].minute;

  return VCD_SECTOR_DATA * cue_get_msf(cue);
}

void cue_vcd_read_toc(cue_priv_t* cue){
  int i;
  for (i = 0; i < cue->nTracks; ++i) {

    mp_msg(MSGT_OPEN,MSGL_INFO,
           "track %02d:  format=%d  %02d:%02d:%02d\n",
           i,
           cue->tracks[i].mode,
           cue->tracks[i].minute,
           cue->tracks[i].second,
           cue->tracks[i].frame
           );
  }
}


static char vcd_buf[VCD_SECTOR_SIZE];

int cue_vcd_read(cue_priv_t* cue,char *mem){

  if (cue_read_raw(cue,vcd_buf)==-1) return 0; // EOF?

  memcpy(mem,&vcd_buf[VCD_SECTOR_OFFS],VCD_SECTOR_DATA);

  cue->cue_current_pos.frame++;
  if (cue->cue_current_pos.frame==75){
    cue->cue_current_pos.frame=0;
    cue->cue_current_pos.second++;
    if (cue->cue_current_pos.second==60){
      cue->cue_current_pos.second=0;
      cue->cue_current_pos.minute++;
    }
  }

  return VCD_SECTOR_DATA;
}

// Driver dependent part
//

static int driver_open(stream_t *stream) {
  int vcd_track;
  int vcd_last_track;
  int ret,ret2,f;
  cue_priv_t* cue;
  
  url_parse_range(stream->url, &vcd_track, &vcd_last_track, &cdrom_device);
  if(!vcd_track) vcd_track=1;

  cue=cue_read_cue (stream->url->url+6); // cue://
  if(cue==NULL){ 
    return 0;
  }

  cue_vcd_read_toc(cue);
  f=cue->fd_bin;
  
  ret2=cue_vcd_get_track_end(cue,vcd_last_track ? vcd_last_track : vcd_track); // FF: So Right ?
  if(ret2<0){
    mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_ErrTrackSelect " (get)\n");
    close(f);
    free(cue);
    return 0;
  }
  ret=cue_vcd_seek_to_track(cue,vcd_track);
  if(ret<0){
    mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_ErrTrackSelect " (seek)\n");
    close(f);
    free(cue);
    return 0;
  }
  mp_msg(MSGT_OPEN,MSGL_V,"VCD start byte position: 0x%X  end: 0x%X\n",ret,ret2);

  stream->fd = f;
  stream->buf_size = VCD_SECTOR_DATA;
  stream->start_pos=ret;
  stream->end_pos=ret2;
  stream->priv = (struct stream_priv_s*)cue;

  return 1;
}

static int driver_fill(stream_t *s){
  return cue_vcd_read((cue_priv_t*)s->priv,s->buffer);
}

static int driver_seek(stream_t *s,off_t pos) {
  s->pos=(pos/VCD_SECTOR_DATA)*VCD_SECTOR_DATA;
  cue_set_msf((cue_priv_t*)s->priv,s->pos/VCD_SECTOR_DATA);
  return 1;
}

static int driver_free(stream_t *stream) {
  if (stream->priv)
    free(stream->priv);
  return 1;
}

stream_driver_t stream_driver_cue = {
    "cue",
    "VideoCD/SVCD/XCD driver for cue/bin-files",
    "ported from main + cleanup by Fabian Franz",
    driver_open,
    NULL, //reset,
    driver_fill,
    driver_seek,
    driver_free
};
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.