Changeset 3751

Show
Ignore:
Timestamp:
2008-10-29 04:06:26 (2 months ago)
Author:
conrad
Message:

anx_import_ogg: replace scan/seek algorithm with one-pass accumulation,
like oggz-chop but on a packet basis

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • libannodex/trunk/src/importers/anx_import_ogg.c

    r3750 r3751  
    8686typedef enum { 
    8787  STATE_HEADERS, 
     88  STATE_GLUE, 
     89#if 0 
    8890  STATE_GRANULEINFO, 
    8991  STATE_FILTER, 
     92#endif 
    9093  STATE_DATA 
    9194} state_t; 
     
    112115struct _AnxOggTrack { 
    113116  AnxSourceTrack source_track; 
     117  int nr_headers_remaining; 
     118 
     119  /* Queue of packets corresponding to the last GOP of the 
     120   * glue section for this track. */ 
     121  AnxList * glue_packets; 
     122 
    114123  int need_keygranule; 
    115124  ogg_int64_t keygranule; 
    116125  double keygranule_time; 
    117126  int filter_got_keygranule; 
    118   int nr_headers_remaining; 
    119127}; 
    120128 
     
    137145  int got_skeleton_eos; 
    138146 
    139   long nr_headers_remaining; 
    140   long headers_unread; 
     147  int nr_headers_remaining; 
     148  int headers_unread; 
    141149 
    142150  int use_granule_seek; 
     
    147155 
    148156  /* Maintain a list of AnxOggTracks */ 
    149   OggzTable * logicals; 
    150  
     157  OggzTable * tracks; 
     158 
     159  /* Packet queues */ 
     160  AnxList * header_queue; 
    151161  AnxList * delivery_queue; 
     162 
    152163  long current_offset; /* offset into current packet */ 
    153164 
     
    288299  aop->eos = op->e_o_s; 
    289300 
     301  memcpy (aop->data, op->packet, op->bytes); 
     302 
    290303  return aop; 
    291304} 
     
    312325                     void * user_data) 
    313326{ 
    314   unsigned char * header = op->packet; 
    315327  AnxOggData * aod = (AnxOggData *)user_data; 
    316328  AnxOggTrack * aot = NULL; 
     329  AnxOggPacket * aop = NULL; 
    317330  AnxSource * m = aod->anx_source; 
    318331  AnxSourceTrack * track = NULL; 
     
    321334  int got_headers = 0; 
    322335 
    323   aot = (AnxOggTrack *) oggz_table_lookup (aod->logicals, serialno); 
     336  aot = (AnxOggTrack *) oggz_table_lookup (aod->tracks, serialno); 
    324337  if (aot != NULL) { 
    325338    need_insert = 0; 
    326339  } 
    327340 
     341  content = oggz_stream_get_content (oggz, serialno); 
     342 
    328343  if (op->b_o_s) { 
    329     content = oggz_stream_get_content (oggz, serialno); 
    330344 
    331345    if (content == OGGZ_CONTENT_CMML) { 
     
    398412 
    399413      if (need_insert) { 
    400         oggz_table_insert (aod->logicals, serialno, aot); 
     414        oggz_table_insert (aod->tracks, serialno, aot); 
    401415      } 
    402416 
     
    432446    } 
    433447 
     448    if (content != OGGZ_CONTENT_CMML) { 
     449      aot = (AnxOggTrack *) oggz_table_lookup (aod->tracks, serialno); 
     450      track = &(aot->source_track); 
     451    } 
     452 
    434453    aod->got_non_bos = 1; 
    435454  } 
     
    445464  } 
    446465   
     466  /* Add this packet to the headers_queue */ 
     467  if (track) { 
     468    aop = anxogg_packet_new (op, track, 0.0); 
     469    aod->header_queue = anx_list_append (aod->header_queue, aop); 
     470  } 
     471 
    447472  if (got_headers) { 
     473#if 0 
    448474    if (m->start_time != 0.0) { 
    449475      if (oggz_seek_units (oggz, 0, SEEK_CUR) >= 0) { 
    450476        oggz_set_data_start (oggz, oggz_tell (oggz)); 
    451         if (aod->use_granule_seek) aod->state = STATE_GRANULEINFO; 
     477        if (aod->use_granule_seek) 
     478          aod->state = STATE_GRANULEINFO; 
    452479      } 
    453480    } else { 
    454481      aod->state = STATE_DATA; 
    455482    } 
     483#else 
     484    aod->state = STATE_GLUE; 
     485    aod->headers_unread = anx_list_length (aod->header_queue); 
     486#endif 
    456487    return OGGZ_STOP_OK; 
    457488  } 
     
    460491} 
    461492 
     493/* 
     494 * OggzReadPacket read_packet_glue 
     495 * 
     496 * Parse Ogg packets up to the start point. 
     497 */ 
     498static int 
     499read_packet_glue (OGGZ * oggz, ogg_packet * op, long serialno, 
     500                  void * user_data) 
     501{ 
     502  AnxOggData * aod = (AnxOggData *)user_data; 
     503  AnxOggTrack * aot = NULL; 
     504  AnxSourceTrack * track = NULL; 
     505  AnxOggPacket * aop; 
     506  int granuleshift, iframe; 
     507  double start_time, at_time; 
     508 
     509  aot = (AnxOggTrack *) oggz_table_lookup (aod->tracks, serialno); 
     510 
     511  /* If this track is not in the table, ignore it. */ 
     512  if (aot == NULL) return OGGZ_CONTINUE; 
     513 
     514  track = &(aot->source_track); 
     515 
     516  /* If we are past the start time, then queue this packet for delivery 
     517   * and set state to STATE_DATA */ 
     518  start_time = aod->anx_source->start_time; 
     519  at_time = gp_to_time (aod->oggz, serialno, op->granulepos); 
     520  if (at_time >= start_time) { 
     521    aop = anxogg_packet_new (op, track, at_time); 
     522    aod->delivery_queue = anx_list_append (aod->delivery_queue, aop); 
     523    aod->state = STATE_DATA; 
     524    return OGGZ_STOP_OK; 
     525  } 
     526 
     527  granuleshift = oggz_get_granuleshift(oggz, serialno); 
     528  /* No need to cache packets of tracks without granuleshift */ 
     529  if (granuleshift == 0) return OGGZ_CONTINUE; 
     530 
     531  /* If this is a keyframe, clear the glue_packets queue for this track */ 
     532  iframe = op->granulepos >> granuleshift; 
     533  if (op->granulepos != -1 && (iframe << granuleshift) == op->granulepos) { 
     534    anx_list_free_with (aot->glue_packets, anxogg_packet_free); 
     535    aot->glue_packets = NULL; 
     536  } 
     537 
     538  /* Append this packet to this track's list of glue_packets */ 
     539  aop = anxogg_packet_new (op, track, at_time); 
     540  aot->glue_packets = anx_list_append (aot->glue_packets, aop); 
     541 
     542  return OGGZ_CONTINUE; 
     543} 
     544 
     545/* 
     546 * Create a single list containing all the glue packets from all 
     547 * tracks, in time order. 
     548 */ 
     549static AnxList * 
     550merge_glue (AnxOggData * aod) 
     551{ 
     552  AnxList * glued = NULL, * candidates = NULL, * c, * min_aot_l, * min_aop_l; 
     553  AnxOggTrack * aot = NULL, * min_aot; 
     554  AnxOggPacket * aop = NULL; 
     555  int i, ntracks, ncandidates=0; 
     556  long serialno; 
     557  double at_time, min_time; 
     558 
     559  /* Prime candidates */ 
     560  ntracks = oggz_table_size (aod->tracks); 
     561  for (i=0; i < ntracks; i++) { 
     562    aot = oggz_table_nth (aod->tracks, i, &serialno); 
     563    if (aot != NULL && aot->glue_packets != NULL) { 
     564      candidates = anx_list_append (candidates, aot); 
     565    } 
     566  } 
     567 
     568  /* Merge candidates */ 
     569  while (candidates != NULL) { 
     570    /* Find minimum time packet in all glue buffers */ 
     571    min_time = 10e100; 
     572    min_aot_l = NULL; 
     573    for (c = candidates; c; c = c->next) { 
     574      aot = (AnxOggTrack *)c->data; 
     575      aop = (AnxOggPacket *)aot->glue_packets->data; 
     576      if (aop->current_time < min_time) { 
     577        /* This is the min so far ... */ 
     578        min_time = aop->current_time; 
     579        min_aot_l = c; 
     580      } 
     581    } 
     582 
     583    /* Got min_aot */ 
     584    min_aot = min_aot_l->data; 
     585 
     586    /* Stash the AnxList* containing the minimum glue packet */ 
     587    min_aop_l = min_aot->glue_packets; 
     588 
     589    /* Set that track's glue_packets to it's own tail */ 
     590    min_aot->glue_packets = min_aop_l->next; 
     591    if (min_aot->glue_packets) { 
     592      /* If packets are remaining, clear the head's prev pointer */ 
     593      min_aot->glue_packets->prev = NULL; 
     594    } else { 
     595      /* Otherwise, we can remove this track from future candidates */ 
     596      candidates = anx_list_remove (candidates, min_aot_l); 
     597      /* Free the min_aot_l container (but not its AnxOggTrack data) */ 
     598      anx_free (min_aot_l); 
     599    } 
     600     
     601    /* Append the min_aop to the list of glued packets we are building */ 
     602    glued = anx_list_append (glued, min_aop_l->data); 
     603 
     604    /* Free the min_aop_l container (but not it's AnxOggPacket data) */ 
     605    anx_free (min_aop_l); 
     606  } 
     607 
     608  return glued; 
     609} 
     610 
     611static int 
     612init_delivery_queue (AnxOggData * aod, AnxList * glued) 
     613{ 
     614  AnxList * queue = NULL, * tail; 
     615 
     616  queue = aod->header_queue; 
     617  tail = anx_list_tail (queue); 
     618 
     619  /* If there packets glued, join them to the header queue */ 
     620  if (glued != NULL) { 
     621    tail->next = glued; 
     622    glued->prev = tail; 
     623 
     624    /* Advance tail to the tail of (glued)queue */ 
     625    tail = anx_list_tail (glued); 
     626  } 
     627 
     628  /* If there's any packets already queued for delivery during gluing, 
     629   * join them too. */ 
     630  if (aod->delivery_queue != NULL) { 
     631    tail->next = aod->delivery_queue; 
     632    aod->delivery_queue->prev = tail; 
     633  } 
     634 
     635  /* Now queue points to the original headers++glued++delivery, so 
     636   * mark that for delivery */ 
     637  aod->delivery_queue = queue; 
     638 
     639  /* And clear the header_queue pointer as it is no longer needed */ 
     640  aod->header_queue = NULL; 
     641 
     642  return 0; 
     643} 
     644 
     645#if 0 
    462646static int 
    463647granuleinfo_update_state (AnxOggData * aod) 
     
    466650  int i, n; 
    467651 
    468 #ifdef DEBUG 
    469   //fprintf (aod->df, "anxogg::granuleinfo_update_state cmml %010ld %s\n", 
    470         //   aod->cmml_serialno, 
    471         //   aod->cmml_need_keygranule ? "needs keygranule" : "no keygranule"); 
    472 #endif 
    473  
    474652  if (aod->cmml_serialno != -1 && aod->cmml_need_keygranule) return 0; 
    475653 
    476   n = oggz_table_size (aod->logicals); 
    477  
    478 #ifdef DEBUG 
    479   fprintf (aod->df, "anxogg::granuleinfo_update_state %d logicals\n", n); 
     654  n = oggz_table_size (aod->tracks); 
     655 
     656#ifdef DEBUG 
     657  fprintf (aod->df, "anxogg::granuleinfo_update_state %d tracks\n", n); 
    480658#endif 
    481659 
    482660  for (i = 0; i < n; i++) { 
    483     aot = (AnxOggTrack *)oggz_table_nth (aod->logicals, i, NULL); 
     661    aot = (AnxOggTrack *)oggz_table_nth (aod->tracks, i, NULL); 
    484662    if (aot->need_keygranule) { 
    485663#ifdef DEBUG 
     
    560738  } else { 
    561739 
    562     aot = (AnxOggTrack *) oggz_table_lookup (aod->logicals, serialno); 
     740    aot = (AnxOggTrack *) oggz_table_lookup (aod->tracks, serialno); 
    563741    if (aot == NULL) { 
    564742      /* If this track is not in the table, ignore it. */ 
     
    618796  return OGGZ_STOP_OK; 
    619797} 
     798#endif 
    620799 
    621800static int 
    622801anxogg_setup (AnxOggData * aod) 
    623802{ 
     803  AnxList * glued; 
    624804  long n; 
    625805  double start_time = 0.0, end_time = -1.0; 
     
    643823#endif 
    644824 
     825  /* Slurp glue section */ 
     826  oggz_set_read_callback (aod->oggz, -1, read_packet_glue, aod); 
     827  while (aod->state == STATE_GLUE && 
     828         (n = oggz_read (aod->oggz, 1024)) != 0); 
     829 
     830  /* Now merge the glue section, and build the initial delivery queue */ 
     831  glued = merge_glue (aod); 
     832  init_delivery_queue (aod, glued); 
     833 
     834#if 0 
    645835  /* Find bitrate info */ 
    646836  start_time = aod->anx_source->start_time; 
     
    724914  oggz_seek (aod->oggz, 0, SEEK_SET); 
    725915  aod->nr_headers_remaining = aod->headers_unread; 
     916#endif 
    726917 
    727918  return 0; 
     
    732923 */ 
    733924 
     925#if 0 
    734926static double 
    735927anxogg_seek_update (AnxSource * source) 
     
    785977  return offset; 
    786978} 
     979#endif 
    787980 
    788981static long 
     
    791984  AnxOggData * aod = (AnxOggData *)media->custom_data; 
    792985 
    793  do_read: 
     986 //do_read: 
    794987 
    795988  while ((aod->delivery_queue == NULL) && (oggz_read (aod->oggz, 1024)) != 0); 
    796989 
     990#if 0 
    797991  if (aod->need_seek == NEED_SEEK && aod->nr_headers_remaining == 0) { 
    798992    anxogg_seek_update (media); 
    799993    goto do_read; 
    800994  } 
     995#endif 
    801996 
    802997  return 0; 
    803998} 
    804999 
     1000#if 0 
    8051001/*********************************************************** 
    8061002 * A filter predicate, used between the min seek granule 
     
    8901086#endif 
    8911087} 
     1088#endif 
    8921089 
    8931090/* 
     
    9151112 
    9161113  if (!(aod->cmml_serialno != -1 && serialno == aod->cmml_serialno)) { 
    917     aot = (AnxOggTrack *) oggz_table_lookup (aod->logicals, serialno); 
     1114    aot = (AnxOggTrack *) oggz_table_lookup (aod->tracks, serialno); 
    9181115    if (aot == NULL) { 
    9191116#ifdef DEBUG 
     
    9911188 
    9921189#ifdef DEBUG 
    993   fprintf (aod->df, "anxogg::read_packet: Filter? (%s)\n",  
    994            aod->state == STATE_FILTER ? "USE_FN" : "NO_FN"); 
    995 #endif 
    996  
    997   if (!aod->ignore_media && !aod->got_end && 
    998       (aod->state != STATE_FILTER || filter (aod, aot, serialno, op))) { 
     1190  //fprintf (aod->df, "anxogg::read_packet: Filter? (%s)\n",  
     1191   //        aod->state == STATE_FILTER ? "USE_FN" : "NO_FN"); 
     1192#endif 
     1193 
     1194  if (!aod->ignore_media && !aod->got_end) { 
     1195      // && 
     1196      //(aod->state != STATE_FILTER || filter (aod, aot, serialno, op))) { 
    9991197#ifdef DEBUG 
    10001198    fprintf (aod->df, "anxogg::read_packet_data: no, copy out\n"); 
     
    10031201    aop = anxogg_packet_new (op, track, 
    10041202                             ((double)oggz_tell_units(oggz)) / SUBSECONDS); 
    1005     memcpy (aop->data, op->packet, op->bytes); 
    1006      
    10071203    aod->delivery_queue = anx_list_append (aod->delivery_queue, aop); 
    10081204     
     1205#if 0 
    10091206    if (aot->nr_headers_remaining > 0) { 
    10101207      aod->nr_headers_remaining--; 
     
    10281225      } 
    10291226    } 
     1227#endif 
    10301228  } 
    10311229 
     
    10731271  /* If that's finished this media packet, advance to the next one */ 
    10741272  if (aod->current_offset >= aop->length) { 
     1273 
    10751274    aod->delivery_queue = anx_list_remove (aod->delivery_queue, head); 
    10761275 
     
    11541353  aod->need_seek = NEED_SEEK_PENDING; 
    11551354  aod->got_end = 0; 
    1156   aod->logicals = oggz_table_new (); 
     1355  aod->tracks = oggz_table_new (); 
     1356 
     1357  aod->header_queue = NULL; 
    11571358 
    11581359  aod->delivery_queue = NULL; 
     
    12431444  anx_list_free_with (aod->delivery_queue, (AnxFreeFunc)anxogg_packet_free); 
    12441445 
    1245   n = oggz_table_size (aod->logicals); 
     1446  n = oggz_table_size (aod->tracks); 
    12461447  for (i = 0; i < n; i++) { 
    1247     aot = (AnxOggTrack *)oggz_table_nth (aod->logicals, i, NULL); 
     1448    aot = (AnxOggTrack *)oggz_table_nth (aod->tracks, i, NULL); 
    12481449    if (aot) { 
    12491450      track = &(aot->source_track); 
     
    12541455  } 
    12551456 
    1256   oggz_table_delete (aod->logicals); 
     1457  oggz_table_delete (aod->tracks); 
    12571458 
    12581459#ifdef DEBUG