]> git.sesse.net Git - vlc/blobdiff - modules/demux/avi/avi.c
All: string review (refs: #438)
[vlc] / modules / demux / avi / avi.c
index caad59b93124527ce9519f6a9229bd4e3f797b81..2efb5ea652e028907256180569900946654c4b89 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * avi.c : AVI file Stream input module for vlc
  *****************************************************************************
- * Copyright (C) 2001-2004 VideoLAN
+ * Copyright (C) 2001-2004 the VideoLAN team
  * $Id$
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *
@@ -17,7 +17,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
 /*****************************************************************************
@@ -28,6 +28,8 @@
 #include <vlc/vlc.h>
 #include <vlc/input.h>
 
+#include <vlc_interaction.h>
+
 #include "vlc_meta.h"
 #include "codecs.h"
 
  *****************************************************************************/
 
 #define INTERLEAVE_TEXT N_("Force interleaved method" )
-#define INTERLEAVE_LONGTEXT N_( "Force interleaved method" )
+#define INTERLEAVE_LONGTEXT N_( "Force interleaved method." )
 
 #define INDEX_TEXT N_("Force index creation")
 #define INDEX_LONGTEXT N_( \
-    "Recreate a index for the AVI file so we can seek trough it more reliably." )
+    "Recreate a index for the AVI file. Use this if your AVI file is damaged "\
+    "or incomplete (not seekable)." )
 
 static int  Open ( vlc_object_t * );
 static void Close( vlc_object_t * );
 
 vlc_module_begin();
+    set_shortname( "AVI" );
     set_description( _("AVI demuxer") );
     set_capability( "demux2", 212 );
+    set_category( CAT_INPUT );
+    set_subcategory( SUBCAT_INPUT_DEMUX );
 
     add_bool( "avi-interleaved", 0, NULL,
               INTERLEAVE_TEXT, INTERLEAVE_LONGTEXT, VLC_TRUE );
     add_bool( "avi-index", 0, NULL,
-              INDEX_TEXT, INDEX_LONGTEXT, VLC_TRUE );
+              INDEX_TEXT, INDEX_LONGTEXT, VLC_FALSE );
 
     set_callbacks( Open, Close );
 vlc_module_end();
@@ -138,6 +144,10 @@ struct demux_sys_t
 
     /* meta */
     vlc_meta_t  *meta;
+
+    /* Progress box */
+    mtime_t    last_update;
+    int        i_dialog_id;
 };
 
 static inline off_t __EVEN( off_t i )
@@ -194,6 +204,8 @@ static int Open( vlc_object_t * p_this )
     demux_t  *p_demux = (demux_t *)p_this;
     demux_sys_t     *p_sys;
 
+    vlc_bool_t       b_index = VLC_FALSE;
+
     avi_chunk_t         ck_riff;
     avi_chunk_list_t    *p_riff = (avi_chunk_list_t*)&ck_riff;
     avi_chunk_list_t    *p_hdrl, *p_movi;
@@ -204,24 +216,17 @@ static int Open( vlc_object_t * p_this )
 
     uint8_t  *p_peek;
 
-
     /* Is it an avi file ? */
-    if( stream_Peek( p_demux->s, &p_peek, 200 ) < 200 )
-    {
-        msg_Dbg( p_demux, "cannot peek()" );
-        return VLC_EGENERIC;
-    }
+    if( stream_Peek( p_demux->s, &p_peek, 200 ) < 200 ) return VLC_EGENERIC;
+
     for( i_peeker = 0; i_peeker < 188; i_peeker++ )
     {
-        if( !strncmp( &p_peek[0], "RIFF", 4 ) && !strncmp( &p_peek[8], "AVI ", 4 ) )
-        {
-            break;
-        }
+        if( !strncmp( (char *)&p_peek[0], "RIFF", 4 ) &&
+            !strncmp( (char *)&p_peek[8], "AVI ", 4 ) ) break;
         p_peek++;
     }
     if( i_peeker == 188 )
     {
-        msg_Warn( p_demux, "avi module discarded (invalid header)" );
         return VLC_EGENERIC;
     }
 
@@ -240,6 +245,7 @@ static int Open( vlc_object_t * p_this )
 
     p_demux->pf_control = Control;
     p_demux->pf_demux = Demux_Seekable;
+
     /* For unseekable stream, automaticaly use Demux_UnSeekable */
     if( !p_sys->b_seekable || config_GetInt( p_demux, "avi-interleaved" ) )
     {
@@ -248,7 +254,7 @@ static int Open( vlc_object_t * p_this )
 
     if( i_peeker > 0 )
     {
-       stream_Read( p_demux->s, NULL, i_peeker );
+        stream_Read( p_demux->s, NULL, i_peeker );
     }
 
     if( AVI_ChunkReadRoot( p_demux->s, &p_sys->ck_root ) )
@@ -329,6 +335,7 @@ static int Open( vlc_object_t * p_this )
         avi_track_t      *tk = malloc( sizeof( avi_track_t ) );
         avi_chunk_list_t *p_strl = AVI_ChunkFind( p_hdrl, AVIFOURCC_strl, i );
         avi_chunk_strh_t *p_strh = AVI_ChunkFind( p_strl, AVIFOURCC_strh, 0 );
+        avi_chunk_STRING_t *p_strn = AVI_ChunkFind( p_strl, AVIFOURCC_strn, 0 );
         avi_chunk_strf_auds_t *p_auds;
         avi_chunk_strf_vids_t *p_vids;
         es_format_t fmt;
@@ -437,13 +444,14 @@ static int Open( vlc_object_t * p_this )
                 fmt.video.i_width  = p_vids->p_bih->biWidth;
                 fmt.video.i_height = p_vids->p_bih->biHeight;
                 fmt.video.i_bits_per_pixel = p_vids->p_bih->biBitCount;
+                fmt.video.i_frame_rate = tk->i_rate;
+                fmt.video.i_frame_rate_base = tk->i_scale;
                 fmt.i_extra =
                     __MIN( p_vids->p_bih->biSize - sizeof( BITMAPINFOHEADER ),
                            p_vids->i_chunk_size - sizeof(BITMAPINFOHEADER) );
                 fmt.p_extra = &p_vids->p_bih[1];
                 msg_Dbg( p_demux, "stream[%d] video(%4.4s) %dx%d %dbpp %ffps",
-                        i,
-                         (char*)&p_vids->p_bih->biCompression,
+                         i, (char*)&p_vids->p_bih->biCompression,
                          p_vids->p_bih->biWidth,
                          p_vids->p_bih->biHeight,
                          p_vids->p_bih->biBitCount,
@@ -455,12 +463,50 @@ static int Open( vlc_object_t * p_this )
                     fmt.video.i_height =
                         (unsigned int)(-(int)p_vids->p_bih->biHeight);
                 }
+
+                /* Extract palette from extradata if bpp <= 8
+                 * (assumes that extradata contains only palette but appears
+                 *  to be true for all palettized codecs we support) */
+                if( fmt.i_extra && fmt.video.i_bits_per_pixel <= 8 &&
+                    fmt.video.i_bits_per_pixel > 0 )
+                {
+                    int i;
+
+                    fmt.video.p_palette = calloc( sizeof(video_palette_t), 1 );
+                    fmt.video.p_palette->i_entries = 1;
+
+                    /* Apparently this is necessary. But why ? */
+                    fmt.i_extra =
+                        p_vids->i_chunk_size - sizeof(BITMAPINFOHEADER);
+                    for( i = 0; i < __MIN(fmt.i_extra/4, 256); i++ )
+                    {
+                        ((uint32_t *)&fmt.video.p_palette->palette[0][0])[i] =
+                            GetDWLE((uint32_t*)fmt.p_extra + i);
+                    }
+                }
                 break;
+
+            case( AVIFOURCC_txts):
+                tk->i_cat   = SPU_ES;
+                tk->i_codec = VLC_FOURCC( 's', 'u', 'b', 't' );
+                msg_Dbg( p_demux, "stream[%d] subtitles", i );
+                es_format_Init( &fmt, SPU_ES, tk->i_codec );
+                break;
+
+            case( AVIFOURCC_mids):
+                msg_Dbg( p_demux, "stream[%d] midi is UNSUPPORTED", i );
+
             default:
                 msg_Warn( p_demux, "stream[%d] unknown type", i );
                 free( tk );
                 continue;
         }
+        if( p_strn )
+        {
+            /* The charset of p_strn is undefined */
+            EnsureUTF8( p_strn->p_str );
+            fmt.psz_description = strdup( p_strn->p_str );
+        }
         tk->p_es = es_out_Add( p_demux->out, &fmt );
         TAB_APPEND( p_sys->i_track, p_sys->track, tk );
     }
@@ -473,6 +519,7 @@ static int Open( vlc_object_t * p_this )
 
     if( config_GetInt( p_demux, "avi-index" ) )
     {
+aviindex:
         if( p_sys->b_seekable )
         {
             AVI_IndexCreate( p_demux );
@@ -494,8 +541,30 @@ static int Open( vlc_object_t * p_this )
                           (mtime_t)p_avih->i_microsecperframe /
                           (mtime_t)1000000 )
     {
-        msg_Warn( p_demux, "broken or missing index, 'seek' will be axproximative or will have strange behavour" );
+        msg_Warn( p_demux, "broken or missing index, 'seek' will be "
+                           "axproximative or will have strange behaviour" );
+        if( !b_index )
+        {
+            int i_create;
+            i_create = intf_UserYesNo( p_demux, _("AVI Index") ,
+                        _( "This AVI file is broken. Seeking will not "
+                        "work correctly.\nDo you want to "
+                        "try to repair it (this might take a long time) ?" ) );
+            if( i_create == DIALOG_OK_YES )
+            {
+                b_index = VLC_TRUE;
+                msg_Dbg( p_demux, "Fixing AVI index" );
+                goto aviindex;
+            }
+            else if( i_create == DIALOG_CANCELLED )
+            {
+                /* Kill input */
+                p_demux->p_parent->b_die = VLC_TRUE;
+                goto error;
+            }
+        }
     }
+
     /* fix some BeOS MediaKit generated file */
     for( i = 0 ; i < p_sys->i_track; i++ )
     {
@@ -860,7 +929,7 @@ static int Demux_Seekable( demux_t *p_demux )
 
         if( ( p_frame = stream_Block( p_demux->s, __EVEN( i_size ) ) )==NULL )
         {
-            msg_Warn( p_demux, "failled reading data" );
+            msg_Warn( p_demux, "failed reading data" );
             tk->b_activated = VLC_FALSE;
             toread[i_track].b_ok = VLC_FALSE;
             continue;
@@ -1098,8 +1167,8 @@ static int Seek( demux_t *p_demux, mtime_t i_date, int i_percent )
             int64_t i_pos;
 
             /* use i_percent to create a true i_date */
-            msg_Warn( p_demux, "mmh, seeking without index at %d%%"
-                      " work only for interleaved file", i_percent );
+            msg_Warn( p_demux, "seeking without index at %d%%"
+                      " only works for interleaved files", i_percent );
             if( i_percent >= 100 )
             {
                 msg_Warn( p_demux, "cannot seek so far !" );
@@ -1314,6 +1383,9 @@ static int    Control( demux_t *p_demux, int i_query, va_list args )
 
 static mtime_t AVI_PTSToChunk( avi_track_t *tk, mtime_t i_pts )
 {
+    if( !tk->i_scale )
+        return (mtime_t)0;
+
     return (mtime_t)((int64_t)i_pts *
                      (int64_t)tk->i_rate /
                      (int64_t)tk->i_scale /
@@ -1321,6 +1393,9 @@ static mtime_t AVI_PTSToChunk( avi_track_t *tk, mtime_t i_pts )
 }
 static mtime_t AVI_PTSToByte( avi_track_t *tk, mtime_t i_pts )
 {
+    if( !tk->i_scale || !tk->i_samplesize )
+        return (mtime_t)0;
+
     return (mtime_t)((int64_t)i_pts *
                      (int64_t)tk->i_rate /
                      (int64_t)tk->i_scale /
@@ -1330,7 +1405,10 @@ static mtime_t AVI_PTSToByte( avi_track_t *tk, mtime_t i_pts )
 
 static mtime_t AVI_GetDPTS( avi_track_t *tk, int64_t i_count )
 {
-    mtime_t i_dpts;
+    mtime_t i_dpts = 0;
+
+    if( !tk->i_rate )
+        return i_dpts;
 
     i_dpts = (mtime_t)( (int64_t)1000000 *
                         (int64_t)i_count *
@@ -1455,7 +1533,6 @@ static int AVI_StreamChunkFind( demux_t *p_demux, unsigned int i_stream )
     }
 }
 
-
 /* be sure that i_ck will be a valid index entry */
 static int AVI_StreamChunkSet( demux_t *p_demux, unsigned int i_stream,
                                unsigned int i_ck )
@@ -1483,7 +1560,6 @@ static int AVI_StreamChunkSet( demux_t *p_demux, unsigned int i_stream,
     return VLC_SUCCESS;
 }
 
-
 /* XXX FIXME up to now, we assume that all chunk are one after one */
 static int AVI_StreamBytesSet( demux_t    *p_demux,
                                unsigned int i_stream,
@@ -1846,6 +1922,7 @@ static int AVI_PacketNext( demux_t *p_demux )
     }
     return VLC_SUCCESS;
 }
+
 static int AVI_PacketRead( demux_t   *p_demux,
                            avi_packet_t     *p_pk,
                            block_t          **pp_frame )
@@ -2066,7 +2143,7 @@ static void __Parse_indx( demux_t    *p_demux,
     }
     else
     {
-        msg_Warn( p_demux, "unknow subtype index(0x%x)", p_indx->i_indexsubtype );
+        msg_Warn( p_demux, "unknown subtype index(0x%x)", p_indx->i_indexsubtype );
     }
 }
 
@@ -2093,7 +2170,8 @@ static void AVI_IndexLoad_indx( demux_t *p_demux )
 
         if( !p_indx )
         {
-            msg_Warn( p_demux, "cannot find indx (misdetect/broken OpenDML file?)" );
+            msg_Warn( p_demux, "cannot find indx (misdetect/broken OpenDML "
+                               "file?)" );
             continue;
         }
 
@@ -2103,7 +2181,7 @@ static void AVI_IndexLoad_indx( demux_t *p_demux )
         }
         else if( p_indx->i_indextype == AVI_INDEX_OF_INDEXES )
         {
-            avi_chunk_indx_t    ck_sub;
+            avi_chunk_t    ck_sub;
             for( i = 0; i < p_indx->i_entriesinuse; i++ )
             {
                 if( stream_Seek( p_demux->s, p_indx->idx.super[i].i_offset )||
@@ -2111,12 +2189,12 @@ static void AVI_IndexLoad_indx( demux_t *p_demux )
                 {
                     break;
                 }
-                __Parse_indx( p_demux, i_stream, &ck_sub );
+                __Parse_indx( p_demux, i_stream, &ck_sub.indx );
             }
         }
         else
         {
-            msg_Warn( p_demux, "unknow type index(0x%x)", p_indx->i_indextype );
+            msg_Warn( p_demux, "unknown type index(0x%x)", p_indx->i_indextype );
         }
 #undef p_stream
     }
@@ -2181,6 +2259,19 @@ static void AVI_IndexCreate( demux_t *p_demux )
 
     stream_Seek( p_demux->s, p_movi->i_chunk_pos + 12 );
     msg_Warn( p_demux, "creating index from LIST-movi, will take time !" );
+
+
+    /* Only show dialog if AVI is > 10MB */
+    p_demux->p_sys->i_dialog_id = -1;
+    if( stream_Size( p_demux->s ) > 10000000 )
+    {
+        p_demux->p_sys->i_dialog_id = intf_UserProgress( p_demux,
+                                        _( "Fixing AVI Index" ),
+                                        _( "Creating AVI Index ..." ),
+                                        0.0 );
+        p_demux->p_sys->last_update = mdate();
+    }
+
     for( ;; )
     {
         avi_packet_t pk;
@@ -2190,6 +2281,18 @@ static void AVI_IndexCreate( demux_t *p_demux )
             return;
         }
 
+        /* Don't update dialog too often */
+        if( p_demux->p_sys->i_dialog_id > 0 &&
+            mdate() - p_demux->p_sys->last_update > 100000 )
+        {
+            int64_t i_pos = stream_Tell( p_demux->s )* 100 /
+                            stream_Size( p_demux->s );
+            float f_pos = (float)i_pos;
+            p_demux->p_sys->last_update = mdate();
+            intf_UserProgressUpdate( p_demux, p_demux->p_sys->i_dialog_id,
+                                    _( "Creating AVI Index ..." ), f_pos );
+        }
+
         if( AVI_PacketGetHeader( p_demux, &pk ) )
         {
             break;
@@ -2247,6 +2350,11 @@ static void AVI_IndexCreate( demux_t *p_demux )
     }
 
 print_stat:
+    if( p_demux->p_sys->i_dialog_id > 0 )
+    {
+        intf_UserHide( p_demux, p_demux->p_sys->i_dialog_id );
+    }
+
     for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
     {
         msg_Dbg( p_demux,
@@ -2322,5 +2430,3 @@ static mtime_t  AVI_MovieGetLength( demux_t *p_demux )
 
     return i_maxlength;
 }
-
-