Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

demux.c

00001 /*****************************************************************************
00002  * demux.c: demuxer using ffmpeg (libavformat).
00003  *****************************************************************************
00004  * Copyright (C) 2004 the VideoLAN team
00005  * $Id: demux.c 13101 2005-11-02 18:16:58Z gbazin $
00006  *
00007  * Authors: Laurent Aimar <[email protected]>
00008  *          Gildas Bazin <[email protected]>
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00023  *****************************************************************************/
00024 
00025 /*****************************************************************************
00026  * Preamble
00027  *****************************************************************************/
00028 #include <stdlib.h>                                      /* malloc(), free() */
00029 
00030 #include <vlc/vlc.h>
00031 #include <vlc/input.h>
00032 #include "vlc_meta.h"
00033 
00034 /* ffmpeg header */
00035 #ifdef HAVE_FFMPEG_AVCODEC_H
00036 #   include <ffmpeg/avformat.h>
00037 #else
00038 #   include <avformat.h>
00039 #endif
00040 
00041 #include "ffmpeg.h"
00042 
00043 //#define AVFORMAT_DEBUG 1
00044 
00045 /* Version checking */
00046 #if (LIBAVFORMAT_BUILD >= 4629) && defined(HAVE_LIBAVFORMAT)
00047 
00048 /*****************************************************************************
00049  * demux_sys_t: demux descriptor
00050  *****************************************************************************/
00051 struct demux_sys_t
00052 {
00053     ByteIOContext   io;
00054     int             io_buffer_size;
00055     uint8_t        *io_buffer;
00056 
00057     AVInputFormat  *fmt;
00058     AVFormatContext *ic;
00059     URLContext     url;
00060     URLProtocol    prot;
00061 
00062     int             i_tk;
00063     es_out_id_t     **tk;
00064 
00065     int64_t     i_pcr;
00066     int64_t     i_pcr_inc;
00067     int         i_pcr_tk;
00068 };
00069 
00070 /*****************************************************************************
00071  * Local prototypes
00072  *****************************************************************************/
00073 static int Demux  ( demux_t *p_demux );
00074 static int Control( demux_t *p_demux, int i_query, va_list args );
00075 
00076 static int IORead( void *opaque, uint8_t *buf, int buf_size );
00077 static int IOSeek( void *opaque, offset_t offset, int whence );
00078 
00079 /*****************************************************************************
00080  * Open
00081  *****************************************************************************/
00082 int E_(OpenDemux)( vlc_object_t *p_this )
00083 {
00084     demux_t       *p_demux = (demux_t*)p_this;
00085     demux_sys_t   *p_sys;
00086     AVProbeData   pd;
00087     AVInputFormat *fmt;
00088     int i;
00089 
00090     /* Init Probe data */
00091     pd.filename = p_demux->psz_path;
00092     if( ( pd.buf_size = stream_Peek( p_demux->s, &pd.buf, 2048 ) ) <= 0 )
00093     {
00094         msg_Warn( p_demux, "cannot peek" );
00095         return VLC_EGENERIC;
00096     }
00097 
00098     av_register_all(); /* Can be called several times */
00099 
00100     /* Guess format */
00101     if( !( fmt = av_probe_input_format( &pd, 1 ) ) )
00102     {
00103         msg_Dbg( p_demux, "couldn't guess format" );
00104         return VLC_EGENERIC;
00105     }
00106 
00107     /* Don't try to handle MPEG unless forced */
00108     if( !p_demux->b_force &&
00109         ( !strcmp( fmt->name, "mpeg" ) ||
00110           !strcmp( fmt->name, "vcd" ) ||
00111           !strcmp( fmt->name, "vob" ) ||
00112           !strcmp( fmt->name, "mpegts" ) ||
00113           /* libavformat's redirector won't work */
00114           !strcmp( fmt->name, "redir" ) ||
00115           !strcmp( fmt->name, "sdp" ) ) )
00116     {
00117         return VLC_EGENERIC;
00118     }
00119 
00120     /* Don't trigger false alarms on bin files */
00121     if( !p_demux->b_force && !strcmp( fmt->name, "psxstr" ) )
00122     {
00123         int i_len;
00124 
00125         if( !p_demux->psz_path ) return VLC_EGENERIC;
00126 
00127         i_len = strlen( p_demux->psz_path );
00128         if( i_len < 4 ) return VLC_EGENERIC;
00129 
00130         if( strcasecmp( &p_demux->psz_path[i_len - 4], ".str" ) &&
00131             strcasecmp( &p_demux->psz_path[i_len - 4], ".xai" ) &&
00132             strcasecmp( &p_demux->psz_path[i_len - 3], ".xa" ) )
00133         {
00134             return VLC_EGENERIC;
00135         }
00136     }
00137 
00138     msg_Dbg( p_demux, "detected format: %s", fmt->name );
00139 
00140     /* Fill p_demux fields */
00141     p_demux->pf_demux = Demux;
00142     p_demux->pf_control = Control;
00143     p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
00144     p_sys->ic = 0;
00145     p_sys->fmt = fmt;
00146     p_sys->i_tk = 0;
00147     p_sys->tk = NULL;
00148     p_sys->i_pcr_tk = -1;
00149     p_sys->i_pcr = -1;
00150 
00151     /* Create I/O wrapper */
00152     p_sys->io_buffer_size = 32768;  /* FIXME */
00153     p_sys->io_buffer = malloc( p_sys->io_buffer_size );
00154     p_sys->url.priv_data = p_demux;
00155     p_sys->url.prot = &p_sys->prot;
00156     p_sys->url.prot->name = "VLC I/O wrapper";
00157     p_sys->url.prot->url_open = 0;
00158     p_sys->url.prot->url_read =
00159                     (int (*) (URLContext *, unsigned char *, int))IORead;
00160     p_sys->url.prot->url_write = 0;
00161     p_sys->url.prot->url_seek =
00162                     (offset_t (*) (URLContext *, offset_t, int))IOSeek;
00163     p_sys->url.prot->url_close = 0;
00164     p_sys->url.prot->next = 0;
00165     init_put_byte( &p_sys->io, p_sys->io_buffer, p_sys->io_buffer_size,
00166                    0, &p_sys->url, IORead, NULL, IOSeek );
00167 
00168     p_sys->fmt->flags |= AVFMT_NOFILE; /* libavformat must not fopen/fclose */
00169 
00170     /* Open it */
00171     if( av_open_input_stream( &p_sys->ic, &p_sys->io, p_demux->psz_path,
00172                               p_sys->fmt, NULL ) )
00173     {
00174         msg_Err( p_demux, "av_open_input_stream failed" );
00175         E_(CloseDemux)( p_this );
00176         return VLC_EGENERIC;
00177     }
00178 
00179     if( av_find_stream_info( p_sys->ic ) < 0 )
00180     {
00181         msg_Err( p_demux, "av_find_stream_info failed" );
00182         E_(CloseDemux)( p_this );
00183         return VLC_EGENERIC;
00184     }
00185 
00186     for( i = 0; i < p_sys->ic->nb_streams; i++ )
00187     {
00188         AVCodecContext *cc = p_sys->ic->streams[i]->codec;
00189         es_out_id_t  *es;
00190         es_format_t  fmt;
00191         vlc_fourcc_t fcc;
00192 
00193         if( !E_(GetVlcFourcc)( cc->codec_id, NULL, &fcc, NULL ) )
00194         {
00195             fcc = VLC_FOURCC( 'u', 'n', 'd', 'f' );
00196 
00197             /* Special case for raw video data */
00198             if( cc->codec_id == CODEC_ID_RAWVIDEO )
00199             {
00200                 msg_Dbg( p_demux, "raw video, pixel format: %i", cc->pix_fmt );
00201                 fcc = E_(GetVlcChroma)( cc->pix_fmt );
00202             }
00203         }
00204 
00205         switch( cc->codec_type )
00206         {
00207         case CODEC_TYPE_AUDIO:
00208             es_format_Init( &fmt, AUDIO_ES, fcc );
00209             fmt.audio.i_channels = cc->channels;
00210             fmt.audio.i_rate = cc->sample_rate;
00211             fmt.audio.i_bitspersample = cc->bits_per_sample;
00212             fmt.audio.i_blockalign = cc->block_align;
00213             break;
00214         case CODEC_TYPE_VIDEO:
00215             es_format_Init( &fmt, VIDEO_ES, fcc );
00216             fmt.video.i_width = cc->width;
00217             fmt.video.i_height = cc->height;
00218             if( cc->palctrl )
00219             {
00220                 fmt.video.p_palette = malloc( sizeof(video_palette_t) );
00221                 *fmt.video.p_palette = *(video_palette_t *)cc->palctrl;
00222             }
00223             break;
00224         default:
00225             break;
00226         }
00227 
00228         fmt.i_extra = cc->extradata_size;
00229         fmt.p_extra = cc->extradata;
00230         es = es_out_Add( p_demux->out, &fmt );
00231 
00232         msg_Dbg( p_demux, "adding es: %s codec = %4.4s",
00233                  cc->codec_type == CODEC_TYPE_AUDIO ? "audio" : "video",
00234                  (char*)&fcc );
00235         TAB_APPEND( p_sys->i_tk, p_sys->tk, es );
00236     }
00237 
00238     msg_Dbg( p_demux, "AVFormat supported stream" );
00239     msg_Dbg( p_demux, "    - format = %s (%s)",
00240              p_sys->fmt->name, p_sys->fmt->long_name );
00241     msg_Dbg( p_demux, "    - start time = "I64Fd,
00242              ( p_sys->ic->start_time != AV_NOPTS_VALUE ) ?
00243              p_sys->ic->start_time * 1000000 / AV_TIME_BASE : -1 );
00244     msg_Dbg( p_demux, "    - duration = "I64Fd,
00245              ( p_sys->ic->duration != AV_NOPTS_VALUE ) ?
00246              p_sys->ic->duration * 1000000 / AV_TIME_BASE : -1 );
00247 
00248     return VLC_SUCCESS;
00249 }
00250 
00251 /*****************************************************************************
00252  * Close
00253  *****************************************************************************/
00254 void E_(CloseDemux)( vlc_object_t *p_this )
00255 {
00256     demux_t     *p_demux = (demux_t*)p_this;
00257     demux_sys_t *p_sys = p_demux->p_sys;
00258 
00259     if( p_sys->ic ) av_close_input_file( p_sys->ic );
00260     if( p_sys->io_buffer ) free( p_sys->io_buffer );
00261     free( p_sys );
00262 }
00263 
00264 /*****************************************************************************
00265  * Demux:
00266  *****************************************************************************/
00267 static int Demux( demux_t *p_demux )
00268 {
00269     demux_sys_t *p_sys = p_demux->p_sys;
00270     AVPacket    pkt;
00271     block_t     *p_frame;
00272     int64_t     i_start_time;
00273 
00274     /* Read a frame */
00275     if( av_read_frame( p_sys->ic, &pkt ) )
00276     {
00277         return 0;
00278     }
00279     if( pkt.stream_index < 0 || pkt.stream_index >= p_sys->i_tk )
00280     {
00281         av_free_packet( &pkt );
00282         return 1;
00283     }
00284     if( ( p_frame = block_New( p_demux, pkt.size ) ) == NULL )
00285     {
00286         return 0;
00287     }
00288 
00289     memcpy( p_frame->p_buffer, pkt.data, pkt.size );
00290 
00291     i_start_time = ( p_sys->ic->start_time != AV_NOPTS_VALUE ) ?
00292         p_sys->ic->start_time : 0;
00293 
00294     p_frame->i_dts = ( pkt.dts == AV_NOPTS_VALUE ) ?
00295         0 : (pkt.dts - i_start_time) * 1000000 *
00296         p_sys->ic->streams[pkt.stream_index]->time_base.num /
00297         p_sys->ic->streams[pkt.stream_index]->time_base.den;
00298     p_frame->i_pts = ( pkt.pts == AV_NOPTS_VALUE ) ?
00299         0 : (pkt.pts - i_start_time) * 1000000 *
00300         p_sys->ic->streams[pkt.stream_index]->time_base.num /
00301         p_sys->ic->streams[pkt.stream_index]->time_base.den;
00302 
00303 #ifdef AVFORMAT_DEBUG
00304     msg_Dbg( p_demux, "tk[%d] dts="I64Fd" pts="I64Fd,
00305              pkt.stream_index, p_frame->i_dts, p_frame->i_pts );
00306 #endif
00307 
00308     if( pkt.dts > 0  &&
00309         ( pkt.stream_index == p_sys->i_pcr_tk || p_sys->i_pcr_tk < 0 ) )
00310     {    
00311         p_sys->i_pcr_tk = pkt.stream_index;
00312         p_sys->i_pcr = p_frame->i_dts;
00313 
00314         es_out_Control( p_demux->out, ES_OUT_SET_PCR, (int64_t)p_sys->i_pcr );
00315     }
00316 
00317     es_out_Send( p_demux->out, p_sys->tk[pkt.stream_index], p_frame );
00318     av_free_packet( &pkt );
00319     return 1;
00320 }
00321 
00322 /*****************************************************************************
00323  * Control:
00324  *****************************************************************************/
00325 static int Control( demux_t *p_demux, int i_query, va_list args )
00326 {
00327     demux_sys_t *p_sys = p_demux->p_sys;
00328     double f, *pf;
00329     int64_t i64, *pi64;
00330 
00331     switch( i_query )
00332     {
00333         case DEMUX_GET_POSITION:
00334             pf = (double*) va_arg( args, double* ); *pf = 0.0;
00335             i64 = stream_Size( p_demux->s );
00336             if( i64 > 0 )
00337             {
00338                 *pf = (double)stream_Tell( p_demux->s ) / (double)i64;
00339             }
00340 
00341             if( p_sys->ic->duration != AV_NOPTS_VALUE && p_sys->i_pcr > 0 )
00342             {
00343                 *pf = (double)p_sys->i_pcr / (double)p_sys->ic->duration;
00344             }
00345 
00346             return VLC_SUCCESS;
00347 
00348         case DEMUX_SET_POSITION:
00349             f = (double) va_arg( args, double );
00350             i64 = stream_Tell( p_demux->s );
00351             if( i64 && p_sys->i_pcr > 0 )
00352             {
00353                 int64_t i_size = stream_Size( p_demux->s );
00354 
00355                 i64 = p_sys->i_pcr * i_size / i64 * f;
00356                 if( p_sys->ic->start_time != AV_NOPTS_VALUE )
00357                     i64 += p_sys->ic->start_time;
00358 
00359                 if( p_sys->ic->duration != AV_NOPTS_VALUE )
00360                     i64 = p_sys->ic->duration * f;
00361 
00362                 msg_Warn( p_demux, "DEMUX_SET_POSITION: "I64Fd, i64 );
00363 
00364                 if( av_seek_frame( p_sys->ic, -1, i64, 0 ) < 0 )
00365                 {
00366                     return VLC_EGENERIC;
00367                 }
00368                 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
00369                 p_sys->i_pcr = -1; /* Invalidate time display */
00370             }
00371             return VLC_SUCCESS;
00372 
00373         case DEMUX_GET_LENGTH:
00374             pi64 = (int64_t*)va_arg( args, int64_t * );
00375             if( p_sys->ic->duration != AV_NOPTS_VALUE )
00376             {
00377                 *pi64 = p_sys->ic->duration;
00378             }
00379             else *pi64 = 0;
00380             return VLC_SUCCESS;
00381 
00382         case DEMUX_GET_TIME:
00383             pi64 = (int64_t*)va_arg( args, int64_t * );
00384             *pi64 = p_sys->i_pcr;
00385             return VLC_SUCCESS;
00386 
00387         case DEMUX_SET_TIME:
00388             i64 = (int64_t)va_arg( args, int64_t );
00389             if( p_sys->ic->start_time != AV_NOPTS_VALUE )
00390                 i64 += p_sys->ic->start_time;
00391 
00392             msg_Warn( p_demux, "DEMUX_SET_TIME: "I64Fd, i64 );
00393 
00394             if( av_seek_frame( p_sys->ic, -1, i64, 0 ) < 0 )
00395             {
00396                 return VLC_EGENERIC;
00397             }
00398             es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
00399             p_sys->i_pcr = -1; /* Invalidate time display */
00400             return VLC_SUCCESS;
00401 
00402         case DEMUX_GET_META:
00403         {
00404             vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
00405             vlc_meta_t *meta;
00406 
00407             if( !p_sys->ic->title[0] || !p_sys->ic->author[0] ||
00408                 !p_sys->ic->copyright[0] || !p_sys->ic->comment[0] || !p_sys->ic->genre[0] )
00410             {
00411                 return VLC_EGENERIC;
00412             }
00413 
00414             *pp_meta = meta = vlc_meta_New();
00415 
00416             if( p_sys->ic->title[0] )
00417                 vlc_meta_Add( meta, VLC_META_TITLE, p_sys->ic->title );
00418             if( p_sys->ic->author[0] )
00419                 vlc_meta_Add( meta, VLC_META_AUTHOR, p_sys->ic->author );
00420             if( p_sys->ic->copyright[0] )
00421                 vlc_meta_Add( meta, VLC_META_COPYRIGHT, p_sys->ic->copyright );
00422             if( p_sys->ic->comment[0] )
00423                 vlc_meta_Add( meta, VLC_META_DESCRIPTION, p_sys->ic->comment );
00424             if( p_sys->ic->genre[0] )
00425                 vlc_meta_Add( meta, VLC_META_GENRE, p_sys->ic->genre );
00426             return VLC_SUCCESS;
00427         }
00428 
00429         default:
00430             return VLC_EGENERIC;
00431     }
00432 }
00433 
00434 /*****************************************************************************
00435  * I/O wrappers for libavformat
00436  *****************************************************************************/
00437 static int IORead( void *opaque, uint8_t *buf, int buf_size )
00438 {
00439     URLContext *p_url = opaque;
00440     demux_t *p_demux = p_url->priv_data;
00441     int i_ret = stream_Read( p_demux->s, buf, buf_size );
00442     return i_ret ? i_ret : -1;
00443 }
00444 
00445 static int IOSeek( void *opaque, offset_t offset, int whence )
00446 {
00447     URLContext *p_url = opaque;
00448     demux_t *p_demux = p_url->priv_data;
00449     int64_t i_absolute;
00450 
00451 #ifdef AVFORMAT_DEBUG
00452     msg_Warn( p_demux, "IOSeek offset: "I64Fd", whence: %i", offset, whence );
00453 #endif
00454 
00455     switch( whence )
00456     {
00457         case SEEK_SET:
00458             i_absolute = offset;
00459             break;
00460         case SEEK_CUR:
00461             i_absolute = stream_Tell( p_demux->s ) + offset;
00462             break;
00463         case SEEK_END:
00464             i_absolute = stream_Size( p_demux->s ) - offset;
00465             break;
00466         default:
00467             return -1;
00468 
00469     }
00470 
00471     if( stream_Seek( p_demux->s, i_absolute ) )
00472     {
00473         return -1;
00474     }
00475 
00476     return 0;
00477 }
00478 
00479 #else /* LIBAVFORMAT_BUILD >= 4611 */
00480 
00481 int E_(OpenDemux)( vlc_object_t *p_this )
00482 {
00483     return VLC_EGENERIC;
00484 }
00485 
00486 void E_(CloseDemux)( vlc_object_t *p_this )
00487 {
00488 }
00489 
00490 #endif /* LIBAVFORMAT_BUILD >= 4629 */

Generated on Tue Dec 20 10:14:29 2005 for vlc-0.8.4a by  doxygen 1.4.2