X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fdemux%2Favformat%2Fdemux.c;h=1841ce5576ff37bd768d9953330000af81acb7bd;hb=5754275dff94623be34ec22bbf1792635ef2ea41;hp=3cac99d36c002ab22eb989132fabc2d5b9c2a4d0;hpb=491d41862114b95b7b35c79ee8d506ee7f9a1d71;p=vlc diff --git a/modules/demux/avformat/demux.c b/modules/demux/avformat/demux.c index 3cac99d36c..1841ce5576 100644 --- a/modules/demux/avformat/demux.c +++ b/modules/demux/avformat/demux.c @@ -34,6 +34,8 @@ #include #include #include +#include +#include /* ffmpeg header */ #if defined(HAVE_LIBAVFORMAT_AVFORMAT_H) @@ -42,8 +44,7 @@ # include #endif -#include "../../codec/avcodec/fourcc.h" -#include "../../codec/avcodec/chroma.h" +#include "../../codec/avcodec/avcodec.h" #include "avformat.h" //#define AVFORMAT_DEBUG 1 @@ -55,6 +56,10 @@ # 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 *****************************************************************************/ @@ -75,6 +80,12 @@ struct demux_sys_t int64_t i_pcr; int64_t i_pcr_inc; int i_pcr_tk; + + int i_attachments; + input_attachment_t **attachments; + + /* Only one title with seekpoints possible atm. */ + input_title_t *p_title; }; /***************************************************************************** @@ -84,7 +95,9 @@ static int Demux ( demux_t *p_demux ); 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 offset_t IOSeek( void *opaque, offset_t offset, int whence ); +static int64_t IOSeek( void *opaque, int64_t offset, int whence ); + +static void UpdateSeekPoint( demux_t *p_demux, int64_t i_time ); /***************************************************************************** * Open @@ -95,8 +108,9 @@ int OpenDemux( vlc_object_t *p_this ) demux_sys_t *p_sys; AVProbeData pd; AVInputFormat *fmt; - unsigned int i; - bool b_avfmt_nofile; + unsigned int i; + bool b_avfmt_nofile; + int64_t i_start_time = -1; /* Init Probe data */ pd.filename = p_demux->psz_path; @@ -158,6 +172,8 @@ int OpenDemux( vlc_object_t *p_this ) p_sys->tk = NULL; p_sys->i_pcr_tk = -1; p_sys->i_pcr = -1; + TAB_INIT( p_sys->i_attachments, p_sys->attachments); + p_sys->p_title = NULL; /* Create I/O wrapper */ p_sys->io_buffer_size = 32768; /* FIXME */ @@ -170,7 +186,7 @@ int OpenDemux( vlc_object_t *p_this ) (int (*) (URLContext *, unsigned char *, int))IORead; p_sys->url.prot->url_write = 0; p_sys->url.prot->url_seek = - (offset_t (*) (URLContext *, offset_t, int))IOSeek; + (int64_t (*) (URLContext *, int64_t, int))IOSeek; p_sys->url.prot->url_close = 0; p_sys->url.prot->next = 0; init_put_byte( &p_sys->io, p_sys->io_buffer, p_sys->io_buffer_size, @@ -207,29 +223,38 @@ int OpenDemux( vlc_object_t *p_this ) const char *psz_type = "unknown"; if( !GetVlcFourcc( cc->codec_id, NULL, &fcc, NULL ) ) - { fcc = VLC_FOURCC( 'u', 'n', 'd', 'f' ); - /* Special case for raw video data */ - if( cc->codec_id == CODEC_ID_RAWVIDEO ) - { - msg_Dbg( p_demux, "raw video, pixel format: %i", cc->pix_fmt ); - fcc = GetVlcChroma( cc->pix_fmt ); - } - } - switch( cc->codec_type ) { case CODEC_TYPE_AUDIO: es_format_Init( &fmt, AUDIO_ES, fcc ); 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; + case CODEC_TYPE_VIDEO: es_format_Init( &fmt, VIDEO_ES, fcc ); + + /* Special case for raw video data */ + if( cc->codec_id == CODEC_ID_RAWVIDEO ) + { + msg_Dbg( p_demux, "raw video, pixel format: %i", cc->pix_fmt ); + if( GetVlcChroma( &fmt.video, cc->pix_fmt ) != VLC_SUCCESS) + { + msg_Err( p_demux, "was unable to find a FourCC match for raw video" ); + } + else + fmt.i_codec = fmt.video.i_chroma; + } + fmt.video.i_width = cc->width; fmt.video.i_height = cc->height; if( cc->palctrl ) @@ -239,6 +264,7 @@ int OpenDemux( vlc_object_t *p_this ) } psz_type = "video"; break; + case CODEC_TYPE_SUBTITLE: es_format_Init( &fmt, SPU_ES, fcc ); psz_type = "subtitle"; @@ -246,36 +272,74 @@ int OpenDemux( vlc_object_t *p_this ) default: es_format_Init( &fmt, UNKNOWN_ES, 0 ); - if( cc->codec_type == CODEC_TYPE_DATA ) - psz_type = "data"; #ifdef HAVE_FFMPEG_CODEC_ATTACHMENT - else if( cc->codec_type == CODEC_TYPE_ATTACHMENT ) + if( cc->codec_type == CODEC_TYPE_ATTACHMENT ) + { + input_attachment_t *p_attachment; 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, + cc->extradata, (int)cc->extradata_size ); + TAB_APPEND( p_sys->i_attachments, p_sys->attachments, p_attachment ); + } + else msg_Warn( p_demux, "unsupported attachment type in ffmpeg demux" ); + } + break; #endif + + if( cc->codec_type == CODEC_TYPE_DATA ) + psz_type = "data"; + msg_Warn( p_demux, "unsupported track type in ffmpeg demux" ); break; } - fmt.psz_language = strdup( p_sys->ic->streams[i]->language ); - fmt.i_extra = cc->extradata_size; - fmt.p_extra = cc->extradata; + +#ifdef HAVE_FFMPEG_CODEC_ATTACHMENT + if( cc->codec_type != CODEC_TYPE_ATTACHMENT ) +#endif + { + fmt.i_extra = cc->extradata_size; + fmt.p_extra = cc->extradata; + } es = es_out_Add( p_demux->out, &fmt ); msg_Dbg( p_demux, "adding es: %s codec = %4.4s", psz_type, (char*)&fcc ); TAB_APPEND( p_sys->i_tk, p_sys->tk, es ); } + if( p_sys->ic->start_time != (int64_t)AV_NOPTS_VALUE ) + i_start_time = p_sys->ic->start_time * 1000000 / AV_TIME_BASE; msg_Dbg( p_demux, "AVFormat supported stream" ); msg_Dbg( p_demux, " - format = %s (%s)", p_sys->fmt->name, p_sys->fmt->long_name ); - msg_Dbg( p_demux, " - start time = %"PRId64, - ( p_sys->ic->start_time != (int64_t)AV_NOPTS_VALUE ) ? - p_sys->ic->start_time * 1000000 / AV_TIME_BASE : -1 ); + msg_Dbg( p_demux, " - start time = %"PRId64, i_start_time ); msg_Dbg( p_demux, " - duration = %"PRId64, ( p_sys->ic->duration != (int64_t)AV_NOPTS_VALUE ) ? p_sys->ic->duration * 1000000 / AV_TIME_BASE : -1 ); +#ifdef HAVE_FFMPEG_CHAPTERS + p_sys->p_title = vlc_input_title_New(); + for( i = 0; i < p_sys->ic->nb_chapters; i++ ) + { + seekpoint_t *s = vlc_seekpoint_New(); + + if( p_sys->ic->chapters[i]->title ) + { + s->psz_name = strdup( p_sys->ic->chapters[i]->title ); + EnsureUTF8( s->psz_name ); + msg_Dbg( p_demux, " - chapter %d: %s", i, s->psz_name ); + } + s->i_time_offset = p_sys->ic->chapters[i]->start * 1000000 * + p_sys->ic->chapters[i]->time_base.num / + p_sys->ic->chapters[i]->time_base.den - + (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; } @@ -295,6 +359,13 @@ void CloseDemux( vlc_object_t *p_this ) if( p_sys->ic ) av_close_input_file( p_sys->ic ); if( !b_avfmt_nofile ) p_sys->fmt->flags ^= AVFMT_NOFILE; + for( int i = 0; i < p_sys->i_attachments; i++ ) + free( p_sys->attachments[i] ); + TAB_CLEAN( p_sys->i_attachments, p_sys->attachments); + + if( p_sys->p_title ) + vlc_input_title_Delete( p_sys->p_title ); + free( p_sys->io_buffer ); free( p_sys ); } @@ -340,6 +411,10 @@ static int Demux( demux_t *p_demux ) 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 ) + 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; #ifdef AVFORMAT_DEBUG msg_Dbg( p_demux, "tk[%d] dts=%"PRId64" pts=%"PRId64, @@ -356,10 +431,34 @@ static int Demux( demux_t *p_demux ) } es_out_Send( p_demux->out, p_sys->tk[pkt.stream_index], p_frame ); + + UpdateSeekPoint( p_demux, p_sys->i_pcr); av_free_packet( &pkt ); return 1; } +static void UpdateSeekPoint( demux_t *p_demux, int64_t i_time ) +{ + demux_sys_t *p_sys = p_demux->p_sys; + int i; + + if( !p_sys->p_title ) + return; + + for( i = 0; i < p_sys->p_title->i_seekpoint; i++ ) + { + if( i_time < p_sys->p_title->seekpoint[i]->i_time_offset ) + break; + } + i--; + + if( i != p_demux->info.i_seekpoint && i >= 0 ) + { + p_demux->info.i_seekpoint = i; + p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT; + } +} + /***************************************************************************** * Control: *****************************************************************************/ @@ -403,13 +502,12 @@ 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 = (int64_t)i_size * f; msg_Warn( p_demux, "DEMUX_SET_BYTE_POSITION: %"PRId64, i64 ); - if( av_seek_frame( p_sys->ic, -1, i64, AVSEEK_FLAG_BYTE ) < 0 ) + if( av_seek_frame( p_sys->ic, -1, (i_size * f), AVSEEK_FLAG_BYTE ) < 0 ) return VLC_EGENERIC; } - es_out_Control( p_demux->out, ES_OUT_RESET_PCR ); + UpdateSeekPoint( p_demux, i64 ); p_sys->i_pcr = -1; /* Invalidate time display */ } return VLC_SUCCESS; @@ -440,8 +538,8 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) { return VLC_EGENERIC; } - es_out_Control( p_demux->out, ES_OUT_RESET_PCR ); p_sys->i_pcr = -1; /* Invalidate time display */ + UpdateSeekPoint( p_demux, i64 ); return VLC_SUCCESS; case DEMUX_GET_META: @@ -468,6 +566,69 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) return VLC_SUCCESS; } + case DEMUX_GET_ATTACHMENTS: + { + input_attachment_t ***ppp_attach = + (input_attachment_t***)va_arg( args, input_attachment_t*** ); + int *pi_int = (int*)va_arg( args, int * ); + int i; + + if( p_sys->i_attachments <= 0 ) + return VLC_EGENERIC; + + *pi_int = p_sys->i_attachments;; + *ppp_attach = malloc( sizeof(input_attachment_t**) * p_sys->i_attachments ); + for( i = 0; i < p_sys->i_attachments; i++ ) + (*ppp_attach)[i] = vlc_input_attachment_Duplicate( p_sys->attachments[i] ); + return VLC_SUCCESS; + } + + case DEMUX_GET_TITLE_INFO: + { + input_title_t ***ppp_title = (input_title_t***)va_arg( args, input_title_t*** ); + int *pi_int = (int*)va_arg( args, int* ); + int *pi_title_offset = (int*)va_arg( args, int* ); + int *pi_seekpoint_offset = (int*)va_arg( args, int* ); + + if( !p_sys->p_title ) + return VLC_EGENERIC; + + *pi_int = 1; + *ppp_title = malloc( sizeof( input_title_t**) ); + (*ppp_title)[0] = vlc_input_title_Duplicate( p_sys->p_title ); + *pi_title_offset = 0; + *pi_seekpoint_offset = 0; + return VLC_SUCCESS; + } + case DEMUX_SET_TITLE: + { + const int i_title = (int)va_arg( args, int ); + if( !p_sys->p_title || i_title != 0 ) + return VLC_EGENERIC; + return VLC_SUCCESS; + } + case DEMUX_SET_SEEKPOINT: + { + const int i_seekpoint = (int)va_arg( args, int ); + if( !p_sys->p_title ) + return VLC_EGENERIC; + + i64 = p_sys->p_title->seekpoint[i_seekpoint]->i_time_offset *AV_TIME_BASE / 1000000; + if( p_sys->ic->start_time != (int64_t)AV_NOPTS_VALUE ) + i64 += p_sys->ic->start_time; + + msg_Warn( p_demux, "DEMUX_SET_TIME: %"PRId64, i64 ); + + if( av_seek_frame( p_sys->ic, -1, i64, 0 ) < 0 ) + { + return VLC_EGENERIC; + } + p_sys->i_pcr = -1; /* Invalidate time display */ + UpdateSeekPoint( p_demux, i64 ); + return VLC_SUCCESS; + } + + default: return VLC_EGENERIC; } @@ -480,11 +641,12 @@ static int IORead( void *opaque, uint8_t *buf, int buf_size ) { URLContext *p_url = opaque; demux_t *p_demux = p_url->priv_data; + if( buf_size < 0 ) return -1; int i_ret = stream_Read( p_demux->s, buf, buf_size ); return i_ret ? i_ret : -1; } -static offset_t IOSeek( void *opaque, offset_t offset, int whence ) +static int64_t IOSeek( void *opaque, int64_t offset, int whence ) { URLContext *p_url = opaque; demux_t *p_demux = p_url->priv_data;