/*****************************************************************************
* 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>
*
*
* 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.
*****************************************************************************/
/*****************************************************************************
#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();
/* meta */
vlc_meta_t *meta;
+
+ /* Progress box */
+ mtime_t last_update;
+ int i_dialog_id;
};
static inline off_t __EVEN( off_t i )
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;
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;
}
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" ) )
{
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 ) )
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;
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,
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 );
}
if( config_GetInt( p_demux, "avi-index" ) )
{
+aviindex:
if( p_sys->b_seekable )
{
AVI_IndexCreate( p_demux );
(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++ )
{
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;
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 !" );
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 /
}
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 /
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 *
}
}
-
/* 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 )
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,
}
return VLC_SUCCESS;
}
+
static int AVI_PacketRead( demux_t *p_demux,
avi_packet_t *p_pk,
block_t **pp_frame )
}
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 );
}
}
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;
}
}
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 )||
{
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
}
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;
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;
}
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,
return i_maxlength;
}
-
-