[vlc-devel] [PATCH] demux: ogg: add skeleton index seeking

Denis Charmet typx at dinauz.org
Wed Sep 18 19:37:20 CEST 2013


Hi,

I don't know ogg so here are a few questions:

Le mercredi 18 septembre 2013 à 06:22:29, Francois Cartegnie a écrit :
> ---
>  modules/demux/ogg.c | 442 +++++++++++++++++++++++++++++++++++++++++++++++-----
>  modules/demux/ogg.h |  25 +++
>  modules/mux/ogg.c   |   2 +
>  3 files changed, 427 insertions(+), 42 deletions(-)
> 
> diff --git a/modules/demux/ogg.c b/modules/demux/ogg.c
> index d6ced62..b52c673 100644
> --- a/modules/demux/ogg.c
> +++ b/modules/demux/ogg.c
> @@ -145,6 +145,18 @@ static void Ogg_ReadKateHeader( logical_stream_t *, ogg_packet * );
>  static void Ogg_ReadFlacHeader( demux_t *, logical_stream_t *, ogg_packet * );
>  static void Ogg_ReadAnnodexHeader( demux_t *, logical_stream_t *, ogg_packet * );
>  static bool Ogg_ReadDiracHeader( logical_stream_t *, ogg_packet * );
> +static void Ogg_ReadSkeletonHeader( demux_t *, logical_stream_t *, ogg_packet * );
> +
> +/* Skeleton */
> +static void Ogg_ReadSkeletonBones( demux_t *, ogg_packet * );
> +static void Ogg_ReadSkeletonIndex( demux_t *, ogg_packet * );
> +static void Ogg_FreeSkeleton( ogg_skeleton_t * );
> +static void Ogg_ApplySkeleton( logical_stream_t * );
> +static bool Ogg_SeekUsingSkeletonIndex( demux_t *, int64_t );
> +
> +unsigned const char * Read7BitsVariableLE( unsigned const char *,
> +                                           unsigned const char const *,
> +                                           ogg_int64_t * );
>  
>  static void fill_channels_info(audio_format_t *audio)
>  {
> @@ -243,7 +255,6 @@ static int Demux( demux_t * p_demux )
>      int         i_stream;
>      bool b_skipping = false;
>  
> -
>      if( p_sys->i_eos == p_sys->i_streams )
>      {
>          if( p_sys->i_eos )
> @@ -266,7 +277,6 @@ static int Demux( demux_t * p_demux )
>          msg_Dbg( p_demux, "beginning of a group of logical streams" );
>          es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 );
>      }
> -
>      /*
>       * The first data page of a physical stream is stored in the relevant logical stream
>       * in Ogg_FindLogicalStreams. Therefore, we must not read a page and only update the
> @@ -291,10 +301,29 @@ static int Demux( demux_t * p_demux )
>  
>          /* Test for End of Stream */
>          if( ogg_page_eos( &p_sys->current_page ) )
> +        {
> +            /* If we delayed restarting encoders/SET_ES_FMT for more
> +             * skeleton provided configuration */
> +            if ( p_sys->p_skelstream && p_sys->p_skelstream->i_serial_no == ogg_page_serialno(&p_sys->current_page) )
> +            {
> +                msg_Dbg( p_demux, "End of Skeleton" );
> +                for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
> +                {
> +                    logical_stream_t *p_stream = p_sys->pp_stream[i_stream];
> +                    if ( p_stream->b_have_updated_format  )
> +                    {
> +                        p_stream->b_have_updated_format = false;
> +                        if ( p_stream->p_skel ) Ogg_ApplySkeleton( p_stream );
> +                        msg_Dbg( p_demux, "Resetting format for stream %d", i_stream );
> +                        es_out_Control( p_demux->out, ES_OUT_SET_ES_FMT,
> +                                        p_stream->p_es, &p_stream->fmt );
> +                    }
> +                }
> +            }
>              p_sys->i_eos++;
> +        }
>      }
>  
> -
>      for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
>      {
>          logical_stream_t *p_stream = p_sys->pp_stream[i_stream];
> @@ -471,7 +500,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
>  {
>      demux_sys_t *p_sys  = p_demux->p_sys;
>      vlc_meta_t *p_meta;
> -    int64_t *pi64;
> +    int64_t *pi64, i64;
>      bool *pb_bool;
>  
>      switch( i_query )
> @@ -493,6 +522,9 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
>              return VLC_SUCCESS;
>  
>          case DEMUX_SET_TIME:
> +            i64 = (int64_t)va_arg( args, int64_t );
> +            if ( Ogg_SeekUsingSkeletonIndex( p_demux, i64 ) )
> +                return VLC_SUCCESS;
>              return VLC_EGENERIC;

It cannot apply to DEMUX_SET_POSITION?
>  
>          case DEMUX_GET_ATTACHMENTS:
> @@ -521,8 +553,10 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
>              }
>  
>              Ogg_ResetStreamHelper( p_sys );
> +
>              return demux_vaControlHelper( p_demux->s, 0, -1, p_sys->i_bitrate,
>                                            1, i_query, args );
> +
>          case DEMUX_GET_LENGTH:
>              if ( p_sys->i_length < 0 )
>                  return demux_vaControlHelper( p_demux->s, 0, -1, p_sys->i_bitrate,
> @@ -562,11 +596,18 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
>          case DEMUX_SET_SEEKPOINT:
>          {
>              const int i_seekpoint = (int)va_arg( args, int );
> -            if( i_seekpoint > p_sys->i_seekpoints )
> +            if( i_seekpoint > p_sys->i_seekpoints || p_sys->i_bos > 0 )
>                  return VLC_EGENERIC;
> -            if( p_sys->i_bos > 0 )
> +
> +            /* First try our skeleton index. Will save a bisect search or
> +             * directly hit keyframes.
> +            */
> +            if ( Ogg_SeekUsingSkeletonIndex( p_demux,
> +                 p_sys->pp_seekpoints[i_seekpoint]->i_time_offset ) )
>              {
> -                return VLC_EGENERIC;
> +                p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
> +                p_demux->info.i_seekpoint = i_seekpoint;
> +                return VLC_SUCCESS;
>              }
>  
>              Ogg_ResetStreamHelper( p_sys );
> @@ -575,7 +616,6 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
>              {
>                  /* we won't be able to find block by time
>                   * we'll need to bisect search from here
> -                 * or use skeleton index if any (FIXME)
>                  */
>                  if ( p_sys->pp_stream[0]->fmt.i_codec == VLC_CODEC_OPUS )
>                  {
> @@ -745,6 +785,18 @@ static void Ogg_DecodePacket( demux_t *p_demux,
>          /* it's an AnxData packet -- skip it (do nothing) */
>          return;
>      }
> +    else if( p_oggpacket->bytes >= 8 &&
> +        ! memcmp ( p_oggpacket->packet, "fisbone\0", 8 ) )
Aren't you missing an 'h'? btw "" already appends a '\0'.

> +    {
> +        Ogg_ReadSkeletonBones( p_demux, p_oggpacket );
> +        return;
> +    }
> +    else if( p_oggpacket->bytes >= 6 &&
> +        ! memcmp ( p_oggpacket->packet, "index\0", 6 ) )
> +    {
> +        Ogg_ReadSkeletonIndex( p_demux, p_oggpacket );
> +        return;
> +    }
>  
>      if( p_stream->fmt.i_codec == VLC_CODEC_SUBT && p_oggpacket->bytes > 0 &&
>          p_oggpacket->packet[0] & PACKET_TYPE_BITS ) return;
> @@ -844,8 +896,23 @@ static void Ogg_DecodePacket( demux_t *p_demux,
>                      p_stream->fmt.i_extra = 0;
>  
>                  if( Ogg_LogicalStreamResetEsFormat( p_demux, p_stream ) )
> -                    es_out_Control( p_demux->out, ES_OUT_SET_ES_FMT,
> -                                    p_stream->p_es, &p_stream->fmt );
> +                {
> +                    if ( p_ogg->p_skelstream )
> +                    {
> +                        /* We delay until eos is reached on skeleton.
> +                         * There should only be headers, as no data page is
> +                         * allowed before skeleton's eos.
> +                         * Skeleton data is appended to fmt on skeleton eos.
> +                         */
> +                        p_stream->b_have_updated_format = true;
> +                    }
> +                    else
> +                    {
> +                        /* Otherwhise we set config from first headers */
> +                        es_out_Control( p_demux->out, ES_OUT_SET_ES_FMT,
> +                                        p_stream->p_es, &p_stream->fmt );
> +                    }
> +                }
>  
>                  if( p_stream->i_headers > 0 )
>                      Ogg_ExtractMeta( p_demux, & p_stream->fmt,
> @@ -1542,14 +1609,14 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
>                          p_ogg->i_streams--;
>                      }
>                  }
> -                else if( oggpacket.bytes >= 7 &&
> -                             ! memcmp( oggpacket.packet, "fishead", 7 ) )
> +                else if( oggpacket.bytes >= 8 &&
> +                             ! memcmp( oggpacket.packet, "fishead\0", 8 ) )
>  
>                  {
>                      /* Skeleton */
>                      msg_Dbg( p_demux, "stream %d is a skeleton",
>                                  p_ogg->i_streams-1 );
> -                    /* FIXME: https://trac.videolan.org/vlc/ticket/1412 */
> +                    Ogg_ReadSkeletonHeader( p_demux, p_stream, &oggpacket );
>                  }
>                  else
>                  {
> @@ -1696,6 +1763,8 @@ static void Ogg_EndOfStream( demux_t *p_demux )
>      p_ogg->i_bitrate = 0;
>      p_ogg->i_streams = 0;
>      p_ogg->pp_stream = NULL;
> +    p_ogg->skeleton.major = 0;
> +    p_ogg->skeleton.minor = 0;
>  
>      /* */
>      if( p_ogg->p_meta )
> @@ -1722,6 +1791,11 @@ static void Ogg_LogicalStreamDelete( demux_t *p_demux, logical_stream_t *p_strea
>          oggseek_index_entries_free( p_stream->idx );
>      }
>  
> +    Ogg_FreeSkeleton( p_stream->p_skel );
> +    p_stream->p_skel = NULL;
> +    if ( p_demux->p_sys->p_skelstream == p_stream )
> +        p_demux->p_sys->p_skelstream = NULL;
> +
>      free( p_stream );
>  }
>  /**
> @@ -2231,6 +2305,76 @@ static void Ogg_ReadKateHeader( logical_stream_t *p_stream,
>      }
>  }
>  
> +static void Ogg_ApplyContentType( logical_stream_t *p_stream, const char* psz_value,
> +                                  bool *b_force_backup, bool *b_packet_out )
> +{
Is it normal that there is no default value for b_force_backup or
b_packet_out?
> +    if( !strncmp(psz_value, "audio/x-wav", 11) )
> +    {
> +        /* n.b. WAVs are unsupported right now */
> +        p_stream->fmt.i_cat = UNKNOWN_ES;
> +        free( p_stream->fmt.psz_description );
> +        p_stream->fmt.psz_description = strdup("WAV Audio (Unsupported)");
> +    }
> +    else if( !strncmp(psz_value, "audio/x-vorbis", 14) ||
> +             !strncmp(psz_value, "audio/vorbis", 12) )
> +    {
> +        p_stream->fmt.i_cat = AUDIO_ES;
> +        p_stream->fmt.i_codec = VLC_CODEC_VORBIS;
> +
> +        *b_force_backup = true;
> +    }
> +    else if( !strncmp(psz_value, "audio/x-speex", 13) ||
> +             !strncmp(psz_value, "audio/speex", 11) )
> +    {
> +        p_stream->fmt.i_cat = AUDIO_ES;
> +        p_stream->fmt.i_codec = VLC_CODEC_SPEEX;
> +
> +        *b_force_backup = true;
> +    }
> +    else if( !strncmp(psz_value, "audio/flac", 10) )
> +    {
> +        p_stream->fmt.i_cat = AUDIO_ES;
> +        p_stream->fmt.i_codec = VLC_CODEC_FLAC;
> +
> +        *b_force_backup = true;
> +    }
> +    else if( !strncmp(psz_value, "video/x-theora", 14) ||
> +             !strncmp(psz_value, "video/theora", 12) )
> +    {
> +        p_stream->fmt.i_cat = VIDEO_ES;
> +        p_stream->fmt.i_codec = VLC_CODEC_THEORA;
> +
> +        *b_force_backup = true;
> +    }
> +    else if( !strncmp(psz_value, "video/x-xvid", 12) )
> +    {
> +        p_stream->fmt.i_cat = VIDEO_ES;
> +        p_stream->fmt.i_codec = VLC_FOURCC( 'x','v','i','d' );
> +
> +        *b_force_backup = true;
> +    }
> +    else if( !strncmp(psz_value, "video/mpeg", 10) )
> +    {
> +        /* n.b. MPEG streams are unsupported right now */
> +        p_stream->fmt.i_cat = VIDEO_ES;
> +        p_stream->fmt.i_codec = VLC_CODEC_MPGV;
> +    }
> +    else if( !strncmp(psz_value, "text/x-cmml", 11) ||
> +             !strncmp(psz_value, "text/cmml", 9) )
> +    {
> +        p_stream->fmt.i_cat = SPU_ES;
> +        p_stream->fmt.i_codec = VLC_CODEC_CMML;
> +        *b_packet_out = true;
> +    }
> +    else if( !strncmp(psz_value, "application/kate", 16) )
> +    {
> +        /* ??? */
> +        p_stream->fmt.i_cat = UNKNOWN_ES;
> +        free( p_stream->fmt.psz_description );
> +        p_stream->fmt.psz_description = strdup("OGG Kate Overlay (Unsupported)");
> +    }
no else for unknown value so far?
> +}
> +
>  static void Ogg_ReadAnnodexHeader( demux_t *p_demux,
>                                     logical_stream_t *p_stream,
>                                     ogg_packet *p_oggpacket )
> @@ -2295,52 +2439,266 @@ static void Ogg_ReadAnnodexHeader( demux_t *p_demux,
>          /* What type of file do we have?
>           * strcmp is safe to use here because we've extracted
>           * content_type_string from the stream manually */
> -        if( !strncmp(content_type_string, "audio/x-wav", 11) )
> +        bool b_dopacketout = false;
> +        Ogg_ApplyContentType( p_stream, content_type_string,
> +                              &p_stream->b_force_backup, &b_dopacketout );
> +        if ( b_dopacketout ) ogg_stream_packetout( &p_stream->os, p_oggpacket );
> +    }
> +}
> +
> +static void Ogg_ReadSkeletonHeader( demux_t *p_demux, logical_stream_t *p_stream,
> +                                    ogg_packet *p_oggpacket )
> +{
> +    p_demux->p_sys->p_skelstream = p_stream;
> +    /* There can be only 1 skeleton for streams */
> +    p_demux->p_sys->skeleton.major = GetWLE( &p_oggpacket->packet[8] );
> +    p_demux->p_sys->skeleton.minor = GetWLE( &p_oggpacket->packet[10] );
> +    if ( asprintf( & p_stream->fmt.psz_description,
> +                        "OGG Skeleton version %" PRIu16 ".%" PRIu16,
> +                        p_demux->p_sys->skeleton.major,
> +                        p_demux->p_sys->skeleton.minor ) < 0 )
> +        p_stream->fmt.psz_description = NULL;
> +}
> +
> +static void Ogg_ReadSkeletonBones( demux_t *p_demux, ogg_packet *p_oggpacket )
> +{
> +    if ( p_demux->p_sys->skeleton.major < 3 || p_oggpacket->bytes < 52 ) return;
> +
> +    /* Find the matching stream for this skeleton data */
> +    ogg_int32_t i_serialno = GetDWLE( &p_oggpacket->packet[12] );
> +    logical_stream_t *p_target_stream = NULL;
> +    for ( int i=0; i< p_demux->p_sys->i_streams; i++ )
> +    {
> +        if ( p_demux->p_sys->pp_stream[i]->i_serial_no == i_serialno )
>          {
> -            /* n.b. WAVs are unsupported right now */
> -            p_stream->fmt.i_cat = UNKNOWN_ES;
> +            p_target_stream = p_demux->p_sys->pp_stream[i];
> +            break;
>          }
> -        else if( !strncmp(content_type_string, "audio/x-vorbis", 14) )
> -        {
> -            p_stream->fmt.i_cat = AUDIO_ES;
> -            p_stream->fmt.i_codec = VLC_CODEC_VORBIS;
> +    }
> +    if ( !p_target_stream ) return;
> +
> +    ogg_skeleton_t *p_skel = p_target_stream->p_skel;
> +    if ( !p_skel )
> +    {
> +        p_skel = malloc( sizeof( ogg_skeleton_t ) );
> +        if ( !p_skel ) return;
> +        TAB_INIT( p_skel->i_messages, p_skel->pppsz_messages );
> +        p_target_stream->p_skel = p_skel;
> +    }
>  
> -            p_stream->b_force_backup = true;
> +    const unsigned char *p_messages = 8 + p_oggpacket->packet + GetDWLE( &p_oggpacket->packet[8] );
Beware of offsets coming from the file especially with possible
overflows the boundary test may not be enough.
> +    const unsigned char *p_boundary = p_oggpacket->packet + p_oggpacket->bytes;
> +    const unsigned char *p = p_messages;
> +    while ( p <= p_boundary - 1 )
> +    {
> +        if ( *p == 0x0D && *(p+1) == 0x0A )
> +        {
> +            char *psz_message = strndup( (const char *) p_messages,
> +                                         p - p_messages );
> +            if ( psz_message )
> +            {
> +                psz_message[ p - p_messages ] = 0;
strndup should have taken care of that itself.
> +                msg_Dbg( p_demux, "stream %" PRId32 " [%s]", i_serialno, psz_message );
> +                TAB_APPEND( p_skel->i_messages, p_skel->pppsz_messages, psz_message );
> +            }
> +            if ( p < p_boundary - 1 ) p_messages = p + 2;
>          }
> -        else if( !strncmp(content_type_string, "audio/x-speex", 13) )
> +        p++;
> +    }
> +
> +}
> +
> +/* Unpacks the 7bit variable encoding used in skeleton indexes */
> +unsigned const char * Read7BitsVariableLE( unsigned const char *p_begin,
> +                                           unsigned const char const *p_end,
> +                                           ogg_int64_t *pi_value )
> +{
> +    int i_shift = 0;
> +    ogg_int64_t i_read = 0;
> +    *pi_value = 0;
> +
> +    while ( p_begin < p_end )
> +    {
> +        i_read = *p_begin & 0x7F; /* High bit is start of integer */
> +        *pi_value = *pi_value | ( i_read << i_shift );
> +        i_shift += 7;
> +        if ( (*p_begin++ & 0x80) == 0x80 ) break; /* see prev */
> +    }
> +
> +    *pi_value = GetQWLE( pi_value );
> +    return p_begin;
> +}
> +
> +static void Ogg_ReadSkeletonIndex( demux_t *p_demux, ogg_packet *p_oggpacket )
> +{
> +    if ( p_demux->p_sys->skeleton.major < 4
> +         || p_oggpacket->bytes < 44 /* Need at least 1 index value (42+1+1) */
> +    ) return;
> +
> +    /* Find the matching stream for this skeleton data */
> +    ogg_int32_t i_serialno = GetDWLE( &p_oggpacket->packet[6] );
> +    logical_stream_t *p_stream = NULL;
> +    for ( int i=0; i< p_demux->p_sys->i_streams; i++ )
> +    {
> +        if ( p_demux->p_sys->pp_stream[i]->i_serial_no == i_serialno )
>          {
> -            p_stream->fmt.i_cat = AUDIO_ES;
> -            p_stream->fmt.i_codec = VLC_CODEC_SPEEX;
> +            p_stream = p_demux->p_sys->pp_stream[i];
> +            break;
> +        }
> +    }
> +    if ( !p_stream ) return;
> +    ogg_int64_t i_keypoints = GetQWLE( &p_oggpacket->packet[10] );
> +    msg_Dbg( p_demux, "%" PRIi64 " index data for %" PRIi32, i_keypoints, i_serialno );
> +    if ( !i_keypoints ) return;
> +
> +    p_stream->p_skel->i_indexstampden = GetQWLE( &p_oggpacket->packet[18] );
> +    p_stream->p_skel->i_indexfirstnum = GetQWLE( &p_oggpacket->packet[24] );
> +    p_stream->p_skel->i_indexlastnum = GetQWLE( &p_oggpacket->packet[32] );
> +    unsigned const char *p_fwdbyte = &p_oggpacket->packet[42];
> +    unsigned const char const *p_boundary = p_oggpacket->packet + p_oggpacket->bytes;
> +    ogg_int64_t i_offset = 0;
> +    ogg_int64_t i_time = 0;
> +    ogg_int64_t i_keypoints_found = 0;
> +
> +    while( p_fwdbyte < p_boundary && i_keypoints_found < i_keypoints )
> +    {
> +        ogg_int64_t i_val;
> +        p_fwdbyte = Read7BitsVariableLE( p_fwdbyte, p_boundary, &i_val );
> +        i_offset += i_val;
> +        p_fwdbyte = Read7BitsVariableLE( p_fwdbyte, p_boundary, &i_val );
> +        i_time += i_val * p_stream->p_skel->i_indexstampden;
> +        i_keypoints_found++;
> +#if 0
> +        msg_Dbg( p_demux, "index -- byte %"PRIi64" time %"PRIi64, i_offset, i_time );
> +#endif
> +    }
> +
> +    if ( i_keypoints_found != i_keypoints )
> +    {
> +        msg_Warn( p_demux, "Invalid Index: missing entries" );
> +        return;
> +    }
> +
> +    p_stream->p_skel->p_index = malloc( p_oggpacket->bytes - 42 );
> +    if ( !p_stream->p_skel->p_index ) return;
> +    memcpy( p_stream->p_skel->p_index, &p_oggpacket->packet[42],
> +            p_oggpacket->bytes - 42 );
> +    p_stream->p_skel->i_index = i_keypoints_found;
> +    p_stream->p_skel->i_index_size = p_oggpacket->bytes - 42;
> +}
>  
> -            p_stream->b_force_backup = true;
> +static void Ogg_FreeSkeleton( ogg_skeleton_t *p_skel )
> +{
> +    if ( !p_skel ) return;
> +    for ( int i=0; i< p_skel->i_messages; i++ )
> +        free( p_skel->pppsz_messages[i] );
> +    TAB_CLEAN( p_skel->i_messages, p_skel->pppsz_messages );
> +    free( p_skel->p_index );
> +    free( p_skel );
> +}
> +
> +static void Ogg_ApplySkeleton( logical_stream_t *p_stream )
> +{
> +    if ( !p_stream->p_skel ) return;
> +    for ( int i=0; i< p_stream->p_skel->i_messages; i++ )
> +    {
> +        const char *psz_message = p_stream->p_skel->pppsz_messages[i];
> +        if ( ! strncmp( "Name: ", psz_message, 6 ) )
> +        {
> +            free( p_stream->fmt.psz_description );
> +            p_stream->fmt.psz_description = strdup( psz_message + 6 );
>          }
> -        else if( !strncmp(content_type_string, "video/x-theora", 14) )
> +        else if ( ! strncmp("Content-Type: ", psz_message, 14 ) )
>          {
> -            p_stream->fmt.i_cat = VIDEO_ES;
> -            p_stream->fmt.i_codec = VLC_CODEC_THEORA;
> -
> -            p_stream->b_force_backup = true;
> +            bool b_foo;
> +            Ogg_ApplyContentType( p_stream, psz_message + 14, &b_foo, &b_foo );
>          }
> -        else if( !strncmp(content_type_string, "video/x-xvid", 12) )
> +    }
> +}
> +
> +bool Ogg_SeekUsingSkeletonIndex( demux_t *p_demux, int64_t i_time )
> +{
> +    logical_stream_t *p_stream = NULL;
> +    demux_sys_t *p_sys = p_demux->p_sys;
> +
> +    /* Select one stream with index */
> +    for( int i=0; i<p_sys->i_streams; i++ )
> +    {
> +        logical_stream_t *p_candidate = p_sys->pp_stream[i];
> +        if ( ! p_candidate->p_skel ) continue;
> +
> +        bool b_selected = false;
> +        es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE,
> +                        p_candidate->p_es, &b_selected );
> +        if ( !b_selected ) continue;
> +
> +        if ( !p_stream && p_candidate->fmt.i_cat == AUDIO_ES )
>          {
> -            p_stream->fmt.i_cat = VIDEO_ES;
> -            p_stream->fmt.i_codec = VLC_FOURCC( 'x','v','i','d' );
> +            p_stream = p_candidate;
> +            continue; /* Try to find video instead */
> +        }
>  
> -            p_stream->b_force_backup = true;
> +        if ( p_candidate->fmt.i_cat == VIDEO_ES )
> +        {
> +            p_stream = p_candidate;
> +            break;
>          }
> -        else if( !strncmp(content_type_string, "video/mpeg", 10) )
> +
> +    }
> +    if ( !p_stream ) return false;
> +
> +    /* Validate range */
> +    if ( i_time < p_stream->p_skel->i_indexfirstnum
> +                * p_stream->p_skel->i_indexstampden ||
> +         i_time > p_stream->p_skel->i_indexlastnum
> +                * p_stream->p_skel->i_indexstampden ) return false;
> +
> +    /* Then Lookup its index */
> +    unsigned const char *p_fwdbyte = p_stream->p_skel->p_index;
> +    struct
> +    {
> +        ogg_int64_t i_offset;
> +        ogg_int64_t i_time;
> +    } current = { 0, 0 }, prev = { -1, -1 };
> +
> +    uint64_t i_keypoints_found = 0;
> +
> +    while( p_fwdbyte < p_fwdbyte + p_stream->p_skel->i_index_size
> +           && i_keypoints_found < p_stream->p_skel->i_index )
> +    {
> +        ogg_int64_t i_val;
> +        p_fwdbyte = Read7BitsVariableLE( p_fwdbyte,
> +                        p_fwdbyte + p_stream->p_skel->i_index_size, &i_val );
> +        current.i_offset += i_val;
> +        p_fwdbyte = Read7BitsVariableLE( p_fwdbyte,
> +                        p_fwdbyte + p_stream->p_skel->i_index_size, &i_val );
> +        current.i_time += i_val * p_stream->p_skel->i_indexstampden;
> +        i_keypoints_found++;
> +
> +        if ( i_time == current.i_time )
>          {
> -            /* n.b. MPEG streams are unsupported right now */
> -            p_stream->fmt.i_cat = VIDEO_ES;
> -            p_stream->fmt.i_codec = VLC_CODEC_MPGV;
> +            Ogg_ResetStreamHelper( p_sys );
> +            stream_Seek( p_demux->s, current.i_offset );
> +            return true;
>          }
> -        else if( !strncmp(content_type_string, "text/x-cmml", 11) )
> +        else if ( i_time < current.i_time && prev.i_offset != -1 )
>          {
> -            ogg_stream_packetout( &p_stream->os, p_oggpacket );
> -            p_stream->fmt.i_cat = SPU_ES;
> -            p_stream->fmt.i_codec = VLC_CODEC_CMML;
> +            Ogg_ResetStreamHelper( p_sys );
> +            stream_Seek( p_demux->s, prev.i_offset );
> +            return true;
>          }
> +        prev = current;
> +    }
> +
> +    /* Last keypoint */
> +    if ( i_time > current.i_time && prev.i_offset != -1 )
> +    {
> +        Ogg_ResetStreamHelper( p_sys );
> +        stream_Seek( p_demux->s, current.i_offset );
> +        return true;
>      }
> +
> +    return false;
>  }
>  
>  static uint32_t dirac_uint( bs_t *p_bs )
> diff --git a/modules/demux/ogg.h b/modules/demux/ogg.h
> index 606282c..bebe66e 100644
> --- a/modules/demux/ogg.h
> +++ b/modules/demux/ogg.h
> @@ -27,6 +27,7 @@
>   *****************************************************************************/
>  
>  typedef struct oggseek_index_entry demux_index_entry_t;
> +typedef struct ogg_skeleton_t ogg_skeleton_t;
>  
>  typedef struct logical_stream_s
>  {
> @@ -44,6 +45,7 @@ typedef struct logical_stream_s
>       * them to the decoder. */
>      bool             b_force_backup;
>      int              i_packets_backup;
> +    bool             b_have_updated_format;
>      void             *p_headers;
>      int              i_headers;
>      ogg_int64_t      i_previous_granulepos;
> @@ -69,6 +71,9 @@ typedef struct logical_stream_s
>      /* keyframe index for seeking, created as we discover keyframes */
>      demux_index_entry_t *idx;
>  
> +    /* Skeleton data */
> +    ogg_skeleton_t *p_skel;
> +
>      /* skip some frames after a seek */
>      int i_skip_frames;
>  
> @@ -83,12 +88,25 @@ typedef struct logical_stream_s
>  
>  } logical_stream_t;
>  
> +struct ogg_skeleton_t
> +{
> +    int            i_messages;
> +    char         **pppsz_messages;
<nitpicking> 2 stars 3 'p' ? :) </nitpicking>

> +    unsigned char *p_index;
> +    uint64_t       i_index;
> +    uint64_t       i_index_size;
> +    int64_t        i_indexstampden;/* time denominator */
> +    int64_t        i_indexfirstnum;/* first sample time numerator */
> +    int64_t        i_indexlastnum;
> +};
> +
>  struct demux_sys_t
>  {
>      ogg_sync_state oy;        /* sync and verify incoming physical bitstream */
>  
>      int i_streams;                           /* number of logical bitstreams */
>      logical_stream_t **pp_stream;  /* pointer to an array of logical streams */
> +    logical_stream_t *p_skelstream; /* pointer to skeleton stream if any */
>  
>      logical_stream_t *p_old_stream; /* pointer to a old logical stream to avoid recreating it */
>  
> @@ -124,6 +142,13 @@ struct demux_sys_t
>      int                 i_seekpoints;
>      seekpoint_t         **pp_seekpoints;
>  
> +    /* skeleton */
> +    struct
> +    {
> +        uint16_t major;
> +        uint16_t minor;
> +    } skeleton;
> +
>      /* */
>      int                 i_attachments;
>      input_attachment_t  **attachments;
> diff --git a/modules/mux/ogg.c b/modules/mux/ogg.c
> index 99252b0..9e529cf 100644
> --- a/modules/mux/ogg.c
> +++ b/modules/mux/ogg.c
> @@ -289,6 +289,8 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
>  
>      p_stream->p_oggds_header = 0;
>  
> +    /* FIXME: https://trac.videolan.org/vlc/ticket/1412 */
> +
>      switch( p_input->p_fmt->i_cat )
>      {
>      case VIDEO_ES:
> -- 
> 1.8.1.4
> 
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel

Regards,

-- 
Denis Charmet - TypX
Le mauvais esprit est un art de vivre



More information about the vlc-devel mailing list