X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fdemux%2Favformat%2Fdemux.c;h=60c9941387c34bfd76fc21922842ab328995a983;hb=88041dfe447b0239779f0af66e212e04a1d14da8;hp=16a9cb04718bb52ed7877c007648fbfc453391d2;hpb=4b44912ce0888ed40d35aa5d782cd17cbf7e9c6b;p=vlc diff --git a/modules/demux/avformat/demux.c b/modules/demux/avformat/demux.c index 16a9cb0471..60c9941387 100644 --- a/modules/demux/avformat/demux.c +++ b/modules/demux/avformat/demux.c @@ -1,7 +1,7 @@ /***************************************************************************** * demux.c: demuxer using ffmpeg (libavformat). ***************************************************************************** - * Copyright (C) 2004-2007 the VideoLAN team + * Copyright (C) 2004-2009 the VideoLAN team * $Id$ * * Authors: Laurent Aimar @@ -47,6 +47,7 @@ #include "../../codec/avcodec/avcodec.h" #include "avformat.h" +#include "../xiph.h" #include "../vobsub.h" //#define AVFORMAT_DEBUG 1 @@ -58,10 +59,6 @@ # define HAVE_FFMPEG_CODEC_ATTACHMENT 1 #endif -#if (LIBAVFORMAT_VERSION_INT >= ((52<<16)+(15<<8)+0) ) -# define HAVE_FFMPEG_CHAPTERS 1 -#endif - /***************************************************************************** * demux_sys_t: demux descriptor *****************************************************************************/ @@ -83,6 +80,8 @@ struct demux_sys_t int64_t i_pcr_inc; int i_pcr_tk; + unsigned i_ssa_order; + int i_attachments; input_attachment_t **attachments; @@ -99,6 +98,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args ); static int IORead( void *opaque, uint8_t *buf, int buf_size ); static int64_t IOSeek( void *opaque, int64_t offset, int whence ); +static block_t *BuildSsaFrame( const AVPacket *p_pkt, unsigned i_order ); static void UpdateSeekPoint( demux_t *p_demux, int64_t i_time ); /***************************************************************************** @@ -111,23 +111,36 @@ int OpenDemux( vlc_object_t *p_this ) AVProbeData pd; AVInputFormat *fmt; unsigned int i; - bool b_avfmt_nofile; int64_t i_start_time = -1; + bool b_can_seek; + char *psz_url; + if( p_demux->psz_file ) + psz_url = strdup( p_demux->psz_file ); + else + { + if( asprintf( &psz_url, "%s://%s", p_demux->psz_access, p_demux->psz_location ) == -1) + return VLC_ENOMEM; + } + msg_Dbg( p_demux, "trying url: %s", psz_url ); /* Init Probe data */ - pd.filename = p_demux->psz_path; - if( ( pd.buf_size = stream_Peek( p_demux->s, &pd.buf, 2048 ) ) <= 0 ) + pd.filename = psz_url; + if( ( pd.buf_size = stream_Peek( p_demux->s, &pd.buf, 2048 + 213 ) ) <= 0 ) { + free( psz_url ); msg_Warn( p_demux, "cannot peek" ); return VLC_EGENERIC; } + vlc_avcodec_lock(); av_register_all(); /* Can be called several times */ + vlc_avcodec_unlock(); /* Guess format */ if( !( fmt = av_probe_input_format( &pd, 1 ) ) ) { msg_Dbg( p_demux, "couldn't guess format" ); + free( psz_url ); return VLC_EGENERIC; } @@ -141,6 +154,7 @@ int OpenDemux( vlc_object_t *p_this ) !strcmp( fmt->name, "redir" ) || !strcmp( fmt->name, "sdp" ) ) ) { + free( psz_url ); return VLC_EGENERIC; } @@ -149,15 +163,24 @@ int OpenDemux( vlc_object_t *p_this ) { int i_len; - if( !p_demux->psz_path ) return VLC_EGENERIC; + if( !p_demux->psz_file ) + { + free( psz_url ); + return VLC_EGENERIC; + } - i_len = strlen( p_demux->psz_path ); - if( i_len < 4 ) return VLC_EGENERIC; + i_len = strlen( p_demux->psz_file ); + if( i_len < 4 ) + { + free( psz_url ); + return VLC_EGENERIC; + } - if( strcasecmp( &p_demux->psz_path[i_len - 4], ".str" ) && - strcasecmp( &p_demux->psz_path[i_len - 4], ".xai" ) && - strcasecmp( &p_demux->psz_path[i_len - 3], ".xa" ) ) + if( strcasecmp( &p_demux->psz_file[i_len - 4], ".str" ) && + strcasecmp( &p_demux->psz_file[i_len - 4], ".xai" ) && + strcasecmp( &p_demux->psz_file[i_len - 3], ".xa" ) ) { + free( psz_url ); return VLC_EGENERIC; } } @@ -174,6 +197,7 @@ int OpenDemux( vlc_object_t *p_this ) p_sys->tk = NULL; p_sys->i_pcr_tk = -1; p_sys->i_pcr = -1; + p_sys->i_ssa_order = 0; TAB_INIT( p_sys->i_attachments, p_sys->attachments); p_sys->p_title = NULL; @@ -194,34 +218,42 @@ int OpenDemux( vlc_object_t *p_this ) init_put_byte( &p_sys->io, p_sys->io_buffer, p_sys->io_buffer_size, 0, &p_sys->url, IORead, NULL, IOSeek ); - b_avfmt_nofile = p_sys->fmt->flags & AVFMT_NOFILE; - p_sys->fmt->flags |= AVFMT_NOFILE; /* libavformat must not fopen/fclose */ + stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_can_seek ); + if( !b_can_seek ) + { + /* Tell avformat that input is stream, so it doesn't get stuck + when trying av_find_stream_info() trying to seek all the wrong places + init_put_byte defaults io.is_streamed=0, so thats why we set them after it + */ + p_sys->url.is_streamed = 1; + p_sys->io.is_streamed = 1; + } + /* Open it */ - if( av_open_input_stream( &p_sys->ic, &p_sys->io, p_demux->psz_path, + if( av_open_input_stream( &p_sys->ic, &p_sys->io, psz_url, p_sys->fmt, NULL ) ) { msg_Err( p_demux, "av_open_input_stream failed" ); - if( !b_avfmt_nofile ) p_sys->fmt->flags ^= AVFMT_NOFILE; + free( psz_url ); CloseDemux( p_this ); return VLC_EGENERIC; } + free( psz_url ); + psz_url = NULL; vlc_avcodec_lock(); /* avformat calls avcodec behind our back!!! */ if( av_find_stream_info( p_sys->ic ) < 0 ) { - vlc_avcodec_unlock(); - msg_Err( p_demux, "av_find_stream_info failed" ); - if( !b_avfmt_nofile ) p_sys->fmt->flags ^= AVFMT_NOFILE; - CloseDemux( p_this ); - return VLC_EGENERIC; + msg_Warn( p_demux, "av_find_stream_info failed" ); } vlc_avcodec_unlock(); - if( !b_avfmt_nofile ) p_sys->fmt->flags ^= AVFMT_NOFILE; for( i = 0; i < p_sys->ic->nb_streams; i++ ) { - AVCodecContext *cc = p_sys->ic->streams[i]->codec; + AVStream *s = p_sys->ic->streams[i]; + AVCodecContext *cc = s->codec; + es_out_id_t *es; es_format_t fmt; vlc_fourcc_t fcc; @@ -234,13 +266,10 @@ int OpenDemux( vlc_object_t *p_this ) { case CODEC_TYPE_AUDIO: es_format_Init( &fmt, AUDIO_ES, fcc ); + fmt.i_bitrate = cc->bit_rate; fmt.audio.i_channels = cc->channels; fmt.audio.i_rate = cc->sample_rate; -#if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0) - fmt.audio.i_bitspersample = cc->bits_per_sample; -#else fmt.audio.i_bitspersample = cc->bits_per_coded_sample; -#endif fmt.audio.i_blockalign = cc->block_align; psz_type = "audio"; break; @@ -259,6 +288,10 @@ int OpenDemux( vlc_object_t *p_this ) else fmt.i_codec = fmt.video.i_chroma; } + /* We need this for the h264 packetizer */ + else if( cc->codec_id == CODEC_ID_H264 && ( !strcmp( p_sys->fmt->name, "flv" ) || + !strcmp( p_sys->fmt->name, "matroska" ) || !strcmp( p_sys->fmt->name, "mp4" ) ) ) + fmt.i_original_fourcc = VLC_FOURCC( 'a', 'v', 'c', '1' ); fmt.video.i_width = cc->width; fmt.video.i_height = cc->height; @@ -268,6 +301,8 @@ int OpenDemux( vlc_object_t *p_this ) *fmt.video.p_palette = *(video_palette_t *)cc->palctrl; } psz_type = "video"; + fmt.video.i_frame_rate = cc->time_base.den; + fmt.video.i_frame_rate_base = cc->time_base.num; break; case CODEC_TYPE_SUBTITLE: @@ -326,7 +361,7 @@ int OpenDemux( vlc_object_t *p_this ) psz_type = "attachment"; if( cc->codec_id == CODEC_ID_TTF ) { - p_attachment = vlc_input_attachment_New( p_sys->ic->streams[i]->filename, "application/x-truetype-font", NULL, + p_attachment = vlc_input_attachment_New( s->filename, "application/x-truetype-font", NULL, cc->extradata, (int)cc->extradata_size ); TAB_APPEND( p_sys->i_attachments, p_sys->attachments, p_attachment ); } @@ -341,16 +376,78 @@ int OpenDemux( vlc_object_t *p_this ) msg_Warn( p_demux, "unsupported track type in ffmpeg demux" ); break; } - fmt.psz_language = p_sys->ic->streams[i]->language; + fmt.psz_language = strdup( s->language ); + if( s->disposition & AV_DISPOSITION_DEFAULT ) + fmt.i_priority = 1000; #ifdef HAVE_FFMPEG_CODEC_ATTACHMENT if( cc->codec_type != CODEC_TYPE_ATTACHMENT ) #endif { - fmt.i_extra = cc->extradata_size; - fmt.p_extra = cc->extradata; + const bool b_ogg = !strcmp( p_sys->fmt->name, "ogg" ); + const uint8_t *p_extra = cc->extradata; + unsigned i_extra = cc->extradata_size; + + if( cc->codec_id == CODEC_ID_THEORA && b_ogg ) + { + unsigned pi_size[3]; + void *pp_data[3]; + unsigned i_count; + for( i_count = 0; i_count < 3; i_count++ ) + { + if( i_extra < 2 ) + break; + pi_size[i_count] = GetWBE( p_extra ); + pp_data[i_count] = (uint8_t*)&p_extra[2]; + if( i_extra < pi_size[i_count] + 2 ) + break; + + p_extra += 2 + pi_size[i_count]; + i_extra -= 2 + pi_size[i_count]; + } + if( i_count > 0 && xiph_PackHeaders( &fmt.i_extra, &fmt.p_extra, + pi_size, pp_data, i_count ) ) + { + fmt.i_extra = 0; + fmt.p_extra = NULL; + } + } + else if( cc->codec_id == CODEC_ID_SPEEX && b_ogg ) + { + uint8_t p_dummy_comment[] = { + 0, 0, 0, 0, + 0, 0, 0, 0, + }; + unsigned pi_size[2]; + void *pp_data[2]; + + pi_size[0] = i_extra; + pp_data[0] = (uint8_t*)p_extra; + + pi_size[1] = sizeof(p_dummy_comment); + pp_data[1] = p_dummy_comment; + + if( pi_size[0] > 0 && xiph_PackHeaders( &fmt.i_extra, &fmt.p_extra, + pi_size, pp_data, 2 ) ) + { + fmt.i_extra = 0; + fmt.p_extra = NULL; + } + } + else if( cc->extradata_size > 0 ) + { + fmt.p_extra = malloc( i_extra ); + if( fmt.p_extra ) + { + fmt.i_extra = i_extra; + memcpy( fmt.p_extra, p_extra, i_extra ); + } + } } es = es_out_Add( p_demux->out, &fmt ); + if( s->disposition & AV_DISPOSITION_DEFAULT ) + es_out_Control( p_demux->out, ES_OUT_SET_ES_DEFAULT, es ); + es_format_Clean( &fmt ); msg_Dbg( p_demux, "adding es: %s codec = %4.4s", psz_type, (char*)&fcc ); @@ -367,7 +464,6 @@ int OpenDemux( vlc_object_t *p_this ) ( p_sys->ic->duration != (int64_t)AV_NOPTS_VALUE ) ? p_sys->ic->duration * 1000000 / AV_TIME_BASE : -1 ); -#ifdef HAVE_FFMPEG_CHAPTERS if( p_sys->ic->nb_chapters > 0 ) p_sys->p_title = vlc_input_title_New(); for( i = 0; i < p_sys->ic->nb_chapters; i++ ) @@ -386,7 +482,6 @@ int OpenDemux( vlc_object_t *p_this ) (i_start_time != -1 ? i_start_time : 0 ); TAB_APPEND( p_sys->p_title->i_seekpoint, p_sys->p_title->seekpoint, s ); } -#endif return VLC_SUCCESS; } @@ -398,14 +493,10 @@ void CloseDemux( vlc_object_t *p_this ) { demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys = p_demux->p_sys; - bool b_avfmt_nofile; FREENULL( p_sys->tk ); - b_avfmt_nofile = p_sys->fmt->flags & AVFMT_NOFILE; - p_sys->fmt->flags |= AVFMT_NOFILE; /* libavformat must not fopen/fclose */ - if( p_sys->ic ) av_close_input_file( p_sys->ic ); - if( !b_avfmt_nofile ) p_sys->fmt->flags ^= AVFMT_NOFILE; + if( p_sys->ic ) av_close_input_stream( p_sys->ic ); for( int i = 0; i < p_sys->i_attachments; i++ ) free( p_sys->attachments[i] ); @@ -438,12 +529,31 @@ static int Demux( demux_t *p_demux ) av_free_packet( &pkt ); return 1; } - if( ( p_frame = block_New( p_demux, pkt.size ) ) == NULL ) + const AVStream *p_stream = p_sys->ic->streams[pkt.stream_index]; + if( p_stream->time_base.den <= 0 ) { - return 0; + msg_Warn( p_demux, "Invalid time base for the stream %d", pkt.stream_index ); + av_free_packet( &pkt ); + return 1; + } + if( p_stream->codec->codec_id == CODEC_ID_SSA ) + { + p_frame = BuildSsaFrame( &pkt, p_sys->i_ssa_order++ ); + if( !p_frame ) + { + av_free_packet( &pkt ); + return 1; + } + } + else + { + if( ( p_frame = block_New( p_demux, pkt.size ) ) == NULL ) + { + av_free_packet( &pkt ); + return 0; + } + memcpy( p_frame->p_buffer, pkt.data, pkt.size ); } - - memcpy( p_frame->p_buffer, pkt.data, pkt.size ); if( pkt.flags & PKT_FLAG_KEY ) p_frame->i_flags |= BLOCK_FLAG_TYPE_I; @@ -452,24 +562,31 @@ static int Demux( demux_t *p_demux ) ( p_sys->ic->start_time * 1000000 / AV_TIME_BASE ) : 0; p_frame->i_dts = ( pkt.dts == (int64_t)AV_NOPTS_VALUE ) ? - 0 : (pkt.dts) * 1000000 * - p_sys->ic->streams[pkt.stream_index]->time_base.num / - p_sys->ic->streams[pkt.stream_index]->time_base.den - i_start_time; + VLC_TS_INVALID : (pkt.dts) * 1000000 * + p_stream->time_base.num / + p_stream->time_base.den - i_start_time + VLC_TS_0; p_frame->i_pts = ( pkt.pts == (int64_t)AV_NOPTS_VALUE ) ? - 0 : (pkt.pts) * 1000000 * - p_sys->ic->streams[pkt.stream_index]->time_base.num / - p_sys->ic->streams[pkt.stream_index]->time_base.den - i_start_time; - if( pkt.duration > 0 ) + VLC_TS_INVALID : (pkt.pts) * 1000000 * + p_stream->time_base.num / + p_stream->time_base.den - i_start_time + VLC_TS_0; + if( pkt.duration > 0 && p_frame->i_length <= 0 ) p_frame->i_length = pkt.duration * 1000000 * - p_sys->ic->streams[pkt.stream_index]->time_base.num / - p_sys->ic->streams[pkt.stream_index]->time_base.den - i_start_time; + p_stream->time_base.num / + p_stream->time_base.den; + if( pkt.dts != AV_NOPTS_VALUE && pkt.dts == pkt.pts && + p_stream->codec->codec_type == CODEC_TYPE_VIDEO ) + { + /* Add here notoriously bugged file formats/samples regarding PTS */ + if( !strcmp( p_sys->fmt->name, "flv" ) ) + p_frame->i_pts = VLC_TS_INVALID; + } #ifdef AVFORMAT_DEBUG msg_Dbg( p_demux, "tk[%d] dts=%"PRId64" pts=%"PRId64, pkt.stream_index, p_frame->i_dts, p_frame->i_pts ); #endif - if( pkt.dts > 0 && + if( p_frame->i_dts > VLC_TS_INVALID && ( pkt.stream_index == p_sys->i_pcr_tk || p_sys->i_pcr_tk < 0 ) ) { p_sys->i_pcr_tk = pkt.stream_index; @@ -507,6 +624,40 @@ static void UpdateSeekPoint( demux_t *p_demux, int64_t i_time ) } } +static block_t *BuildSsaFrame( const AVPacket *p_pkt, unsigned i_order ) +{ + if( p_pkt->size <= 0 ) + return NULL; + + char buffer[256]; + const size_t i_buffer_size = __MIN( sizeof(buffer) - 1, p_pkt->size ); + memcpy( buffer, p_pkt->data, i_buffer_size ); + buffer[i_buffer_size] = '\0'; + + /* */ + int i_layer; + int h0, m0, s0, c0; + int h1, m1, s1, c1; + int i_position = 0; + if( sscanf( buffer, "Dialogue: %d,%d:%d:%d.%d,%d:%d:%d.%d,%n", &i_layer, + &h0, &m0, &s0, &c0, &h1, &m1, &s1, &c1, &i_position ) < 9 ) + return NULL; + if( i_position <= 0 || i_position >= i_buffer_size ) + return NULL; + + char *p; + if( asprintf( &p, "%u,%d,%.*s", i_order, i_layer, p_pkt->size - i_position, p_pkt->data + i_position ) < 0 ) + return NULL; + + block_t *p_frame = block_heap_Alloc( p, p, strlen(p) + 1 ); + if( p_frame ) + p_frame->i_length = CLOCK_FREQ * ((h1 - h1) * 3600 + + (m1-m0) * 60 + + (s1-s0) * 1) + + CLOCK_FREQ * (c1-c0) / 100; + return p_frame; +} + /***************************************************************************** * Control: *****************************************************************************/ @@ -523,7 +674,8 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) i64 = stream_Size( p_demux->s ); if( i64 > 0 ) { - *pf = (double)stream_Tell( p_demux->s ) / (double)i64; + double current = stream_Tell( p_demux->s ); + *pf = current / (double)i64; } if( (p_sys->ic->duration != (int64_t)AV_NOPTS_VALUE) && (p_sys->i_pcr > 0) ) @@ -535,7 +687,6 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) case DEMUX_SET_POSITION: f = (double) va_arg( args, double ); - i64 = stream_Tell( p_demux->s ); if( p_sys->i_pcr > 0 ) { i64 = p_sys->ic->duration * f; @@ -550,12 +701,16 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) (av_seek_frame( p_sys->ic, -1, i64, 0 ) < 0) ) { int64_t i_size = stream_Size( p_demux->s ); + i64 = (i_size * f); msg_Warn( p_demux, "DEMUX_SET_BYTE_POSITION: %"PRId64, i64 ); - if( av_seek_frame( p_sys->ic, -1, (i_size * f), AVSEEK_FLAG_BYTE ) < 0 ) + if( av_seek_frame( p_sys->ic, -1, i64, AVSEEK_FLAG_BYTE ) < 0 ) return VLC_EGENERIC; } - UpdateSeekPoint( p_demux, i64 ); + else + { + UpdateSeekPoint( p_demux, i64 ); + } p_sys->i_pcr = -1; /* Invalidate time display */ } return VLC_SUCCESS; @@ -563,10 +718,9 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) case DEMUX_GET_LENGTH: pi64 = (int64_t*)va_arg( args, int64_t * ); if( p_sys->ic->duration != (int64_t)AV_NOPTS_VALUE ) - { - *pi64 = p_sys->ic->duration; - } - else *pi64 = 0; + *pi64 = p_sys->ic->duration * 1000000 / AV_TIME_BASE; + else + *pi64 = 0; return VLC_SUCCESS; case DEMUX_GET_TIME: @@ -602,13 +756,6 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) { vlc_meta_t *p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t* ); - if( !p_sys->ic->title[0] || !p_sys->ic->author[0] || - !p_sys->ic->copyright[0] || !p_sys->ic->comment[0] || - /*!p_sys->ic->album[0] ||*/ !p_sys->ic->genre[0] ) - { - return VLC_EGENERIC; - } - if( p_sys->ic->title[0] ) vlc_meta_SetTitle( p_meta, p_sys->ic->title ); if( p_sys->ic->author[0] ) @@ -706,7 +853,7 @@ static int64_t IOSeek( void *opaque, int64_t offset, int whence ) { URLContext *p_url = opaque; demux_t *p_demux = p_url->priv_data; - int64_t i_absolute = (int64_t)offset; + int64_t i_absolute; int64_t i_size = stream_Size( p_demux->s ); #ifdef AVFORMAT_DEBUG