[vlc-devel] [PATCH] Handling prefered language in AsfSelectStream Better, bitrate sort and select algo Tested with asf containing 3, Videos and 24 Lang...

Rémi Denis-Courmont remi at remlab.net
Tue Jul 16 18:20:02 CEST 2013


Please consider posting inline. Reviewing attachments is a PITA in my opinion.

>From d2c60889af4c05bab7ced9ad60d17575a560b0f2 Mon Sep 17 00:00:00 2001
From: Alain Degreffe <eczema at ecze.com>
Date: Tue, 16 Jul 2013 16:47:38 +0200
Subject: [PATCH] Handling prefered language in AsfSelectStream Better,
 bitrate sort and select algo Tested with asf containing  3,
 Videos and 24 Lang..

First line is a 72-characters summary. Add more paragraphs and wrap if you 
need to.

---
 modules/access/mms/asf.c   |  233 
++++++++++++++++++++++++++++++++------------
 modules/access/mms/asf.h   |   18 +++-
 modules/access/mms/mms.c   |    1 +
 modules/access/mms/mmsh.c  |   12 ++-
 modules/access/mms/mmstu.c |    6 +-
 5 files changed, 203 insertions(+), 67 deletions(-)

diff --git a/modules/access/mms/asf.c b/modules/access/mms/asf.c
index d353bfd..3005315 100644
--- a/modules/access/mms/asf.c
+++ b/modules/access/mms/asf.c
@@ -46,6 +46,8 @@ void  asf_HeaderParse ( asf_header_t *hdr,
     var_buffer_t buffer;
     guid_t      guid;
     uint64_t    i_size;
+    uint16_t    stream_number;
+    uint16_t    lang_ID;
 
     hdr->i_file_size = 0;
     hdr->i_data_packets_count = 0;
@@ -55,6 +57,7 @@ void  asf_HeaderParse ( asf_header_t *hdr,
         hdr->stream[i].i_cat = ASF_CODEC_TYPE_UNKNOWN;
         hdr->stream[i].i_selected = 0;
         hdr->stream[i].i_bitrate = -1;
+        hdr->stream[i].i_lang_id = -1;
     }
 
     var_buffer_initread( &buffer, p_header, i_header );
@@ -93,8 +96,15 @@ void  asf_HeaderParse ( asf_header_t *hdr,
             int16_t i_count1, i_count2;
             int i_subsize;
 
-            var_buffer_getmemory( &buffer, NULL, 84 - 24 );
+            var_buffer_getmemory( &buffer, NULL, 72 - 24 );
 
+            stream_number = var_buffer_get16( &buffer );
+            lang_ID = var_buffer_get16( &buffer );
+            
+            hdr->stream[stream_number].i_lang_id = lang_ID;
+            
+            var_buffer_getmemory( &buffer, NULL, 8 );
+            
             i_count1 = var_buffer_get16( &buffer );
             i_count2 = var_buffer_get16( &buffer );
 
@@ -167,6 +177,48 @@ void  asf_HeaderParse ( asf_header_t *hdr,
             }
             var_buffer_getmemory( &buffer, NULL, i_size - 24 );
         }
+        else if( guidcmp( &guid, &asf_object_language_list ) )
+        {
+            int      i_count;
+            uint64_t i_langid_len;
+            int      i_lang_str_len;
+            uint8_t  *pi_ws_lang_str;
+            char     *psz_lang_str;
+            int      i_current_id;
+
+            i_count = var_buffer_get16( &buffer );
+
+            for( i_current_id = 0 ; i_current_id < i_count ; i_current_id++ )
+            {
+                i_langid_len = var_buffer_get8( &buffer );
+                i_lang_str_len = i_langid_len / 2;
+
+                psz_lang_str = malloc( i_lang_str_len );
+                pi_ws_lang_str  = malloc( i_langid_len );
+
+                if( !psz_lang_str || !pi_ws_lang_str )
+                { 
+                    /* Malloc problem - Zap the remaining bytes of object */
+                    var_buffer_getmemory( &buffer, NULL, i_langid_len );
+                    free( psz_lang_str );
+                    free( pi_ws_lang_str );
+                    continue ;
+                }
+
+		var_buffer_getmemory( &buffer, pi_ws_lang_str , i_langid_len );
+		asf_wstr2str( psz_lang_str, pi_ws_lang_str,i_langid_len );
+
+                hdr->ppsz_tablang[i_current_id] = malloc( i_lang_str_len );
+                if( hdr->ppsz_tablang[i_current_id] )
+                {
+                    memcpy( hdr->ppsz_tablang[i_current_id],
+                            psz_lang_str, i_lang_str_len );
+                }

strndup() ?

And I cannot see where the table content is free()d.

+                free( psz_lang_str );
+		free( pi_ws_lang_str );
+            }
+        }    
+
         else
         {
             // skip unknown guid
@@ -178,21 +230,44 @@ void  asf_HeaderParse ( asf_header_t *hdr,
     }
 }
 
-void  asf_StreamSelect  ( asf_header_t *hdr,
-                              int i_bitrate_max,
-                              bool b_all, bool b_audio, bool b_video )
+void asf_ClearCandidate ( asf_candidate_t *cell )
+{
+    asf_candidate_t * tmp;
+    while( cell->next )
+    {
+        tmp = cell ; 
+        cell = tmp->next;
+        free(tmp);
+    }
+    free(cell); 
+}
+
+asf_candidate_t * asf_AddCandidate( asf_candidate_t *work_Candidate,
+                                    int stream_candidate_id )
+{
+    work_Candidate->value = stream_candidate_id;
+    work_Candidate->next  = malloc( sizeof( asf_candidate_t ) );
+    if( !work_Candidate->next ) return work_Candidate;
+    work_Candidate = work_Candidate->next;
+    work_Candidate->next = NULL;
+    return work_Candidate;
+} 
+
+void  asf_StreamSelect ( asf_header_t *hdr,
+                         int i_bitrate_max,
+                         bool b_all,
+                         bool b_audio,
+                         bool b_video, 
+                         const char * psz_lang )
 {
     /* XXX FIXME use mututal eclusion information */
     unsigned i;
     int i_audio, i_video;
-    int i_bitrate_total;
+    int i_bitrate_var, i_bitrate_total;
 #if 0
     char *psz_stream;
 #endif
 
-    i_audio = 0;
-    i_video = 0;
-    i_bitrate_total = 0;
     if( b_all )
     {
         /* select all valid stream */
@@ -214,78 +289,110 @@ void  asf_StreamSelect  ( asf_header_t *hdr,
         }
     }
 
-    /* big test:
-     * select a stream if
-     *    - no audio nor video stream
-     *    - or:
-     *         - if i_bitrate_max not set keep the highest bitrate
-     *         - if i_bitrate_max is set, keep stream that make we used best
-     *           quality regarding i_bitrate_max
-     *
-     * XXX: little buggy:
-     *        - it doesn't use mutual exclusion info..
-     *        - when selecting a better stream we could select
-     *        something that make i_bitrate_total> i_bitrate_max
-     */
-    for( i = 1; i < 128; i++ )
+    i_audio = -1;
+    i_video = -1;
+    i_bitrate_total = 0;
+    i_bitrate_var = 0;
+
+    asf_candidate_t  * head_Candidatefavlang, * courant_Candidatefavlang;
+    asf_candidate_t  * head_Candidateotherlang,  * 
courant_Candidateotherlang;
+    asf_candidate_t  * head_CandidateVideo, * courant_CandidateVideo;
+    asf_candidate_t  * work_Candidate;
+
+    head_Candidatefavlang = malloc( sizeof( asf_candidate_t ) );
+    head_Candidateotherlang = malloc( sizeof( asf_candidate_t ) );
+    head_CandidateVideo = malloc( sizeof( asf_candidate_t ) );
+
+    if( !head_Candidatefavlang || !head_Candidatefavlang ||
+        !head_Candidatefavlang )
+    {
+        free( head_Candidatefavlang );
+        free( head_Candidatefavlang );
+        free( head_Candidatefavlang );
+        return;
+    }
+
+    head_Candidatefavlang->next = NULL;
+    courant_Candidatefavlang = head_Candidatefavlang;
+    
+    head_Candidateotherlang->next = NULL;
+    courant_Candidateotherlang = head_Candidateotherlang;
+
+    head_CandidateVideo->next = NULL;
+    courant_CandidateVideo = head_CandidateVideo;
+
+    for( i = 1 ; i < 128 ; i++ )
     {
         if( hdr->stream[i].i_cat == ASF_CODEC_TYPE_UNKNOWN )
         {
             continue;
         }
-        else if( hdr->stream[i].i_cat == ASF_CODEC_TYPE_AUDIO && b_audio &&
-                 ( i_audio <= 0 ||
-                    ( ( ( hdr->stream[i].i_bitrate > hdr-
>stream[i_audio].i_bitrate &&
-                          ( i_bitrate_total + hdr->stream[i].i_bitrate - hdr-
>stream[i_audio].i_bitrate
-                                            < i_bitrate_max || 
!i_bitrate_max) ) ||
-                        ( hdr->stream[i].i_bitrate < hdr-
>stream[i_audio].i_bitrate &&
-                              i_bitrate_max != 0 && i_bitrate_total > 
i_bitrate_max )
-                      ) )  ) )
+      
+        /* audio */ 
+        if( hdr->stream[i].i_cat == ASF_CODEC_TYPE_AUDIO && b_audio &&
+              ( hdr->stream[i].i_bitrate < i_bitrate_max || !i_bitrate_max ) 
)
         {
-            /* unselect old stream */
-            if( i_audio > 0 )
+            if( psz_lang != NULL &&
+                strcmp( hdr->ppsz_tablang[hdr->stream[i].i_lang_id], psz_lang 
) == 0 )
             {
-                hdr->stream[i_audio].i_selected = 0;
-                if( hdr->stream[i_audio].i_bitrate> 0 )
-                {
-                    i_bitrate_total -= hdr->stream[i_audio].i_bitrate;
-                }
+                courant_Candidatefavlang = 
asf_AddCandidate(courant_Candidatefavlang, i);
             }
-
-            hdr->stream[i].i_selected = 1;
-            if( hdr->stream[i].i_bitrate> 0 )
+            else
             {
-                i_bitrate_total += hdr->stream[i].i_bitrate;
+                courant_Candidateotherlang = 
asf_AddCandidate(courant_Candidateotherlang, i);
             }
-            i_audio = i;
         }
+        /* video */
         else if( hdr->stream[i].i_cat == ASF_CODEC_TYPE_VIDEO && b_video &&
-                 ( i_video <= 0 ||
-                    (
-                        ( ( hdr->stream[i].i_bitrate > hdr-
>stream[i_video].i_bitrate &&
-                            ( i_bitrate_total + hdr->stream[i].i_bitrate - 
hdr->stream[i_video].i_bitrate
-                                            < i_bitrate_max || 
!i_bitrate_max) ) ||
-                          ( hdr->stream[i].i_bitrate < hdr-
>stream[i_video].i_bitrate &&
-                            i_bitrate_max != 0 && i_bitrate_total > 
i_bitrate_max )
-                        ) ) )  )
+                 ( hdr->stream[i].i_bitrate < i_bitrate_max || !i_bitrate_max 
) )
         {
-            /* unselect old stream */
-            if( i_video > 0 )
-            {
-                hdr->stream[i_video].i_selected = 0;
-                if( hdr->stream[i_video].i_bitrate> 0 )
-                {
-                    i_bitrate_total -= hdr->stream[i_video].i_bitrate;
-                }
-            }
+            courant_CandidateVideo = asf_AddCandidate(courant_CandidateVideo, 
i);
+        }
+    }
+    
+    if( head_Candidatefavlang->next )
+    {
+        work_Candidate = head_Candidatefavlang;
+    }
+    else
+    {
+        work_Candidate = head_Candidateotherlang;
+    }
+
+    courant_CandidateVideo = head_CandidateVideo;
 
-            hdr->stream[i].i_selected = 1;
-            if( hdr->stream[i].i_bitrate> 0 )
+    while( work_Candidate->next )
+    {
+        while( courant_CandidateVideo->next )
+        {
+            i_bitrate_var = hdr->stream[work_Candidate->value].i_bitrate
+                            + hdr->stream[courant_CandidateVideo-
>value].i_bitrate;
+            if( i_bitrate_var > i_bitrate_total &&
+               ( !i_bitrate_max  || i_bitrate_var < i_bitrate_max ) )
             {
-                i_bitrate_total += hdr->stream[i].i_bitrate;
+                i_audio = work_Candidate->value;
+                i_video = courant_CandidateVideo->value;
+                i_bitrate_total = i_bitrate_var;
             }
-            i_video = i;
+            courant_CandidateVideo = courant_CandidateVideo->next;
         }
 
+        i_bitrate_var = hdr->stream[work_Candidate->value].i_bitrate;
+        if( i_bitrate_var > i_bitrate_total &&
+           ( !i_bitrate_max || i_bitrate_var < i_bitrate_max ) )
+        {
+            i_audio = work_Candidate->value;
+            i_bitrate_total = i_bitrate_var;
+        }
+        work_Candidate = work_Candidate->next;
     }
+ 
+    /* select stream */
+    if( i_audio != -1 ) hdr->stream[i_audio].i_selected = 1;
+    if( i_video != -1 ) hdr->stream[i_video].i_selected = 1;
+   
+    /* clear structures */
+    asf_ClearCandidate( head_Candidatefavlang );
+    asf_ClearCandidate( head_Candidateotherlang );
+    asf_ClearCandidate( head_CandidateVideo );
 }
diff --git a/modules/access/mms/asf.h b/modules/access/mms/asf.h
index f15b90d..a7d0725 100644
--- a/modules/access/mms/asf.h
+++ b/modules/access/mms/asf.h
@@ -42,6 +42,7 @@ typedef struct
     int i_cat;      /* ASF_CODEC_TYPE_VIDEO, ASF_CODEC_TYPE_AUDIO, */
     int i_bitrate;  /* -1 if unknown */
     int i_selected;
+    int i_lang_id;
 } asf_stream_t;
 
 typedef struct
@@ -49,16 +50,31 @@ typedef struct
     int64_t      i_file_size;
     int64_t      i_data_packets_count;
     int32_t      i_min_data_packet_size;
+    char *       ppsz_tablang[128];
 
     asf_stream_t stream[128];
 
 } asf_header_t;
 
+typedef struct asf_candidate_t
+{
+    int value ;
+    struct asf_candidate_t *next;
+} asf_candidate_t;
 
 void  GenerateGuid      ( guid_t * );
+asf_candidate_t *  asf_AddCandidate( asf_candidate_t *, int );
+void  asf_ClearCandidate ( asf_candidate_t *);
 void  asf_HeaderParse   ( asf_header_t *, uint8_t *, int );
 void  asf_StreamSelect  ( asf_header_t *,
                               int i_bitrate_max, bool b_all, bool b_audio,
-                              bool b_video );
+                              bool b_video , const char * psz_preflang );
 
+static inline void asf_wstr2str( char * dst, uint8_t * src , int inlen )
+{
+    for( int i = 0 ; i <  inlen ; i += 2 )
+       {
+           dst[i/2] = GetWLE( &src[i] );
+       }
+};
 #endif
diff --git a/modules/access/mms/mms.c b/modules/access/mms/mms.c
index 5633c10..591315e 100644
--- a/modules/access/mms/mms.c
+++ b/modules/access/mms/mms.c
@@ -77,6 +77,7 @@ vlc_module_begin ()
     add_bool( "mms-all", false, ALL_TEXT, ALL_LONGTEXT, true )
     add_integer( "mms-maxbitrate", 0, BITRATE_TEXT, BITRATE_LONGTEXT ,
                  false )
+        change_safe()
     add_string( "mmsh-proxy", NULL, PROXY_TEXT, PROXY_LONGTEXT,
                     false )
 
diff --git a/modules/access/mms/mmsh.c b/modules/access/mms/mmsh.c
index 2a36670..5a0743f 100644
--- a/modules/access/mms/mmsh.c
+++ b/modules/access/mms/mmsh.c
@@ -440,6 +440,7 @@ static int Reset( access_t *p_access )
     access_sys_t *p_sys = p_access->p_sys;
     asf_header_t old_asfh = p_sys->asfh;
     int i;
+    char * psz_preflang;
 
     msg_Dbg( p_access, "Reset the stream" );
     p_sys->i_start = p_access->info.i_pos;
@@ -461,11 +462,14 @@ static int Reset( access_t *p_access )
              p_sys->asfh.i_data_packets_count,
              p_sys->asfh.i_min_data_packet_size );
 
+    psz_preflang = var_InheritString( p_access->p_parent, "audio-language" );

Why are you accessing p_parent here??
Furthermore, why do you use the default audio track language here?

If you want to hint the server about the user locale, then the language 
identifier is _("C") instead. On the other hand, if you want to filter tracks to 
save bandwidth, then you should add a control query from the ASF demux to the 
MMS access (like betweem MPEG-TS demux and DTV access).

If you force filtering at the access level, next month users will whine that 
they cannot override the track selection from the UI anymore...

     asf_StreamSelect( &p_sys->asfh,
                        var_InheritInteger( p_access, "mms-maxbitrate" ),
                        var_InheritBool( p_access, "mms-all" ),
                        var_InheritBool( p_access, "audio" ),
-                       var_InheritBool( p_access, "video" ) );
+                       var_InheritBool( p_access, "video" ),
+                       psz_preflang );
+    free (psz_preflang);
 
     /* Check we have comptible asfh */
     for( i = 1; i < 128; i++ )
@@ -552,6 +556,7 @@ static int Describe( access_t  *p_access, char 
**ppsz_location )
     bool         b_keepalive = false;
     char         *psz;
     int          i_code;
+    char         *psz_preflang;
 
     /* Reinit context */
     p_sys->b_broadcast = true;
@@ -714,11 +719,14 @@ static int Describe( access_t  *p_access, char 
**ppsz_location )
     if( p_sys->asfh.i_min_data_packet_size <= 0 )
         goto error;
 
+    psz_preflang = var_InheritString( p_access->p_parent, "audio-language" );
     asf_StreamSelect( &p_sys->asfh,
                        var_InheritInteger( p_access, "mms-maxbitrate" ),
                        var_InheritBool( p_access, "mms-all" ),
                        var_InheritBool( p_access, "audio" ),
-                       var_InheritBool( p_access, "video" ) );
+                       var_InheritBool( p_access, "video" ),
+                       psz_preflang );
+    free( psz_preflang );
     return VLC_SUCCESS;
 
 error:
diff --git a/modules/access/mms/mmstu.c b/modules/access/mms/mmstu.c
index 932c59f..dbb3fe5 100644
--- a/modules/access/mms/mmstu.c
+++ b/modules/access/mms/mmstu.c
@@ -467,6 +467,7 @@ static int MMSOpen( access_t  *p_access, vlc_url_t *p_url, 
int  i_proto )
     int          i_streams;
     int          i_first;
     char         *mediapath;
+    char         *psz_preflang;
 
 
     /* *** Open a TCP connection with server *** */
@@ -788,11 +789,14 @@ static int MMSOpen( access_t  *p_access, vlc_url_t 
*p_url, int  i_proto )
      *        and bitrate mutual exclusion(optional) */
      asf_HeaderParse ( &p_sys->asfh,
                            p_sys->p_header, p_sys->i_header );
+     psz_preflang = var_InheritString( p_access->p_parent, "audio-language" );
      asf_StreamSelect( &p_sys->asfh,
                            var_InheritInteger( p_access, "mms-maxbitrate" ),
                            var_InheritBool( p_access, "mms-all" ),
                            var_InheritBool( p_access, "audio" ),
-                           var_InheritBool( p_access, "video" ) );
+                           var_InheritBool( p_access, "video" ),
+                           psz_preflang );
+     free( psz_preflang );

Same remark as above.

 
     /* *** now select stream we want to receive *** */
     /* TODO take care of stream bitrate TODO */
-- 
1.7.9.5


-- 
Rémi Denis-Courmont
http://www.remlab.net/




More information about the vlc-devel mailing list