00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <stdlib.h>
00029
00030 #include <vlc/vlc.h>
00031 #include <vlc/input.h>
00032 #include "vlc_meta.h"
00033
00034
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
00044
00045
00046 #if (LIBAVFORMAT_BUILD >= 4629) && defined(HAVE_LIBAVFORMAT)
00047
00048
00049
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
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
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
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();
00099
00100
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
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
00114 !strcmp( fmt->name, "redir" ) ||
00115 !strcmp( fmt->name, "sdp" ) ) )
00116 {
00117 return VLC_EGENERIC;
00118 }
00119
00120
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
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
00152 p_sys->io_buffer_size = 32768;
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;
00169
00170
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
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
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
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
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
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;
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;
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
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
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