From 8580ca5c5ff48b8aaa1c3f9686fb6ab3bc7e75e8 Mon Sep 17 00:00:00 2001 From: michael Date: Sun, 11 Apr 2004 14:26:04 +0000 Subject: demux_lavf git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@12165 b3059339-0415-0410-9bf9-f77b7e298cf2 --- libmpdemux/Makefile | 7 +- libmpdemux/demux_lavf.c | 333 ++++++++++++++++++++++++++++++++++++++++++++++++ libmpdemux/demuxer.c | 41 +++++- libmpdemux/demuxer.h | 3 +- 4 files changed, 380 insertions(+), 4 deletions(-) create mode 100644 libmpdemux/demux_lavf.c (limited to 'libmpdemux') diff --git a/libmpdemux/Makefile b/libmpdemux/Makefile index 743266fe88..224acdc55e 100644 --- a/libmpdemux/Makefile +++ b/libmpdemux/Makefile @@ -3,7 +3,7 @@ LIBNAME = libmpdemux.a include ../config.mak -SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c muxer.c muxer_avi.c muxer_mpeg.c demux_asf.c demux_avi.c demux_mov.c parse_mp4.c demux_mpg.c demux_ty.c demux_ty_osd.c demux_pva.c demux_viv.c demuxer.c dvdnav_stream.c open.c parse_es.c stream.c stream_file.c stream_netstream.c stream_vcd.c stream_null.c stream_ftp.c tv.c tvi_dummy.c tvi_v4l.c tvi_v4l2.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c demux_ogg.c demux_bmp.c cdda.c demux_rawaudio.c demux_rawvideo.c cddb.c cdinfo.c demux_rawdv.c ai_alsa.c ai_alsa1x.c ai_oss.c audio_in.c demux_smjpeg.c demux_lmlm4.c cue_read.c extension.c demux_gif.c demux_ts.c demux_realaud.c url.c muxer_rawvideo.c +SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c muxer.c muxer_avi.c muxer_mpeg.c demux_asf.c demux_avi.c demux_mov.c parse_mp4.c demux_mpg.c demux_ty.c demux_ty_osd.c demux_pva.c demux_viv.c demuxer.c dvdnav_stream.c open.c parse_es.c stream.c stream_file.c stream_netstream.c stream_vcd.c stream_null.c stream_ftp.c tv.c tvi_dummy.c tvi_v4l.c tvi_v4l2.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c demux_ogg.c demux_bmp.c cdda.c demux_rawaudio.c demux_rawvideo.c cddb.c cdinfo.c demux_rawdv.c ai_alsa.c ai_alsa1x.c ai_oss.c audio_in.c demux_smjpeg.c demux_lmlm4.c cue_read.c extension.c demux_gif.c demux_ts.c demux_realaud.c url.c muxer_rawvideo.c demux_lavf.c ifeq ($(XMMS_PLUGINS),yes) SRCS += demux_xmms.c endif @@ -33,10 +33,13 @@ ifeq ($(MATROSKA_EXTERNAL),yes) CPLUSPLUSSRCS += demux_mkv_old.cpp endif +ifeq ($(CONFIG_LIBAVFORMAT),yes) +LIBAV_INC = -I../libavcodec -I../libavformat +endif OBJS = $(SRCS:.c=.o) OBJS += $(CPLUSPLUSSRCS:.cpp=.o) -INCLUDE = -I../loader $(CSS_INC) $(EXTRA_INC) +INCLUDE = -I../loader $(CSS_INC) $(EXTRA_INC) $(LIBAV_INC) CFLAGS = $(OPTFLAGS) $(INCLUDE) $(XMMS_CFLAGS) $(CDPARANOIA_INC) $(DVB_INC) CPLUSPLUSFLAGS = $(CFLAGS) $(CPLUSPLUSINCLUDE) CPLUSPLUS = $(CC) diff --git a/libmpdemux/demux_lavf.c b/libmpdemux/demux_lavf.c new file mode 100644 index 0000000000..3ea46f13fb --- /dev/null +++ b/libmpdemux/demux_lavf.c @@ -0,0 +1,333 @@ +/* + Copyright (C) 2004 Michael Niedermayer + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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-1307 USA +*/ + +// #include +#include +// #include + +#include "config.h" +#include "mp_msg.h" +// #include "help_mp.h" + +#include "stream.h" +#include "demuxer.h" +#include "stheader.h" + +#ifdef USE_LIBAVFORMAT + +#include "avformat.h" +#include "avi.h" + +#define PROBE_BUF_SIZE 2048 +//#define IO_BUFFER_SIZE 32768 + +typedef struct lavf_priv_t{ + AVInputFormat *avif; + AVFormatContext *avfc; + ByteIOContext pb; + int audio_streams; + int video_streams; +}lavf_priv_t; + +extern void print_wave_header(WAVEFORMATEX *h); +extern void print_video_header(BITMAPINFOHEADER *h); + +static int mp_open(URLContext *h, const char *filename, int flags){ + return 0; +} + +static int mp_read(URLContext *h, unsigned char *buf, int size){ + stream_t *stream = (stream_t*)h->priv_data; + if(stream_eof(stream)) //needed? + return -1; + return stream_read(stream, buf, size); +} + +static int mp_write(URLContext *h, unsigned char *buf, int size){ + return -1; +} + +static offset_t mp_seek(URLContext *h, offset_t pos, int whence){ + stream_t *stream = (stream_t*)h->priv_data; +mp_msg(MSGT_HEADER,MSGL_DBG2,"file_seek(%p, %d, %d)\n", h, (int)pos, whence); + if(whence == SEEK_CUR) + pos +=stream_tell(stream); + else if(whence == SEEK_END) + pos += stream->end_pos; + else if(whence != SEEK_SET) + return -1; + + if(stream_seek(stream, pos)==0) + return -1; + return pos; +} + +static int mp_close(URLContext *h){ + return 0; +} + +static URLProtocol mp_protocol = { + "mp", + mp_open, + mp_read, + mp_write, + mp_seek, + mp_close, +}; + +int lavf_check_file(demuxer_t *demuxer){ + AVProbeData avpd; + uint8_t buf[PROBE_BUF_SIZE]; + lavf_priv_t *priv; + + if(!demuxer->priv) + demuxer->priv=calloc(sizeof(lavf_priv_t),1); + priv= demuxer->priv; + + av_register_all(); + + stream_read(demuxer->stream, buf, PROBE_BUF_SIZE); + avpd.filename= demuxer->stream->url; + avpd.buf= buf; + avpd.buf_size= PROBE_BUF_SIZE; + + priv->avif= av_probe_input_format(&avpd, 1); + if(!priv->avif){ + mp_msg(MSGT_HEADER,MSGL_V,"LAVF_check: no clue about this gibberish!\n"); + return 0; + }else + mp_msg(MSGT_HEADER,MSGL_V,"LAVF_check: %s\n", priv->avif->long_name); + + return 1; +} + +int demux_open_lavf(demuxer_t *demuxer){ + AVFormatContext *avfc; + AVFormatParameters ap; + lavf_priv_t *priv= demuxer->priv; + int i; + char mp_filename[256]="mp:"; + + memset(&ap, 0, sizeof(AVFormatParameters)); + + stream_seek(demuxer->stream, 0); + + register_protocol(&mp_protocol); + + strncpy(mp_filename + 3, demuxer->stream->url, sizeof(mp_filename)-3); + + url_fopen(&priv->pb, mp_filename, URL_RDONLY); + + ((URLContext*)(priv->pb.opaque))->priv_data= demuxer->stream; + + if(av_open_input_stream(&avfc, &priv->pb, mp_filename, priv->avif, &ap)<0){ + mp_msg(MSGT_HEADER,MSGL_ERR,"LAVF_header: av_open_input_stream() failed\n"); + return 0; + } + + priv->avfc= avfc; + + if(av_find_stream_info(avfc) < 0){ + mp_msg(MSGT_HEADER,MSGL_ERR,"LAVF_header: av_find_stream_info() failed\n"); + return 0; + } + +//demux_info_add(demuxer, "author", string); ... + + for(i=0; inb_streams; i++){ + AVStream *st= avfc->streams[i]; + AVCodecContext *codec= &st->codec; + + switch(codec->codec_type){ + case CODEC_TYPE_AUDIO:{ + WAVEFORMATEX *wf= calloc(sizeof(WAVEFORMATEX) + codec->extradata_size, 1); + sh_audio_t* sh_audio=new_sh_audio(demuxer, i); + priv->audio_streams++; + if(!codec->codec_tag) + codec->codec_tag= codec_get_wav_tag(codec->codec_id); + wf->wFormatTag= codec->codec_tag; + wf->nChannels= codec->channels; + wf->nSamplesPerSec= codec->sample_rate; + wf->nAvgBytesPerSec= codec->bit_rate/8; + wf->nBlockAlign= codec->block_align; + wf->wBitsPerSample= codec->bits_per_sample; + wf->cbSize= codec->extradata_size; + if(codec->extradata_size){ + memcpy( + wf + 1, + codec->extradata, + codec->extradata_size); + } + sh_audio->wf= wf; + sh_audio->ds= demuxer->audio; + sh_audio->format= codec->codec_tag; + sh_audio->channels= codec->channels; + sh_audio->samplerate= codec->sample_rate; + if(verbose>=1) print_wave_header(sh_audio->wf); + demuxer->audio->id=i; + demuxer->audio->sh= demuxer->a_streams[i]; + break;} + case CODEC_TYPE_VIDEO:{ + BITMAPINFOHEADER *bih=calloc(sizeof(BITMAPINFOHEADER) + codec->extradata_size,1); + sh_video_t* sh_video=new_sh_video(demuxer, i); + + priv->video_streams++; + if(!codec->codec_tag) + codec->codec_tag= codec_get_bmp_tag(codec->codec_id); + bih->biSize= sizeof(BITMAPINFOHEADER) + codec->extradata_size; + bih->biWidth= codec->width; + bih->biHeight= codec->height; + bih->biBitCount= codec->bits_per_sample; + bih->biSizeImage = bih->biWidth * bih->biHeight * bih->biBitCount/8; + bih->biCompression= codec->codec_tag; + sh_video->bih= bih; + sh_video->disp_w= codec->width; + sh_video->disp_h= codec->height; + sh_video->video.dwRate= codec->frame_rate; + sh_video->video.dwScale= codec->frame_rate_base; + sh_video->fps=(float)sh_video->video.dwRate/(float)sh_video->video.dwScale; + sh_video->frametime=(float)sh_video->video.dwScale/(float)sh_video->video.dwRate; + sh_video->format = bih->biCompression; + sh_video->ds= demuxer->video; + if(codec->extradata_size) + memcpy(sh_video->bih + 1, codec->extradata, codec->extradata_size); + if(verbose>=1) print_video_header(sh_video->bih); +/* short biPlanes; + int biXPelsPerMeter; + int biYPelsPerMeter; + int biClrUsed; + int biClrImportant;*/ + demuxer->video->id=i; + demuxer->video->sh= demuxer->v_streams[i]; + break;} + } + } + + mp_msg(MSGT_HEADER,MSGL_V,"LAVF: %d audio and %d video streams found\n",priv->audio_streams,priv->video_streams); + if(!priv->audio_streams) demuxer->audio->id=-2; // nosound +// else if(best_audio > 0 && demuxer->audio->id == -1) demuxer->audio->id=best_audio; + if(!priv->video_streams){ + if(!priv->audio_streams){ + mp_msg(MSGT_HEADER,MSGL_ERR,"LAVF: no audio or video headers found - broken file?\n"); + return 0; + } + demuxer->video->id=-2; // audio-only + } //else if (best_video > 0 && demuxer->video->id == -1) demuxer->video->id = best_video; + + return 1; +} + +int demux_lavf_fill_buffer(demuxer_t *demux){ + lavf_priv_t *priv= demux->priv; + AVPacket pkt; + demux_packet_t *dp; + demux_stream_t *ds; + int id; + mp_msg(MSGT_DEMUX,MSGL_DBG2,"demux_lavf_fill_buffer()\n"); + + demux->filepos=stream_tell(demux->stream); + + if(stream_eof(demux->stream)){ +// demuxre->stream->eof=1; + return 0; + } + + if(av_read_frame(priv->avfc, &pkt) < 0) + return 0; + + id= pkt.stream_index; + + if(id==demux->audio->id){ + // audio + ds=demux->audio; + if(!ds->sh){ + ds->sh=demux->a_streams[id]; + mp_msg(MSGT_DEMUX,MSGL_V,"Auto-selected LAVF audio ID = %d\n",ds->id); + } + } else if(id==demux->video->id){ + // video + ds=demux->video; + if(!ds->sh){ + ds->sh=demux->v_streams[id]; + mp_msg(MSGT_DEMUX,MSGL_V,"Auto-selected LAVF video ID = %d\n",ds->id); + } + } else + ds= NULL; + + if(0/*pkt.destruct == av_destruct_packet*/){ + //ok kids, dont try this at home :) + dp=(demux_packet_t*)malloc(sizeof(demux_packet_t)); + dp->len=pkt.size; + dp->next=NULL; + dp->refcount=1; + dp->master=NULL; + dp->buffer=pkt.data; + pkt.destruct= NULL; + }else{ + dp=new_demux_packet(pkt.size); + memcpy(dp->buffer, pkt.data, pkt.size); + av_free_packet(&pkt); + } + + dp->pts=pkt.pts / (float)AV_TIME_BASE; + dp->pos=demux->filepos; + dp->flags= !!(pkt.flags&PKT_FLAG_KEY); + // append packet to DS stream: + ds_add_packet(ds,dp); + return 1; +} + +void demux_seek_lavf(demuxer_t *demuxer, float rel_seek_secs, int flags){ + mp_msg(MSGT_DEMUX,MSGL_DBG2,"demux_seek_lavf()\n"); +} + +int demux_lavf_control(demuxer_t *demuxer, int cmd, void *arg) +{ + lavf_priv_t *priv = demuxer->priv; + + switch (cmd) { +/* case DEMUXER_CTRL_GET_TIME_LENGTH: + if (priv->duration == 0) + return DEMUXER_CTRL_DONTKNOW; + + *((unsigned long *)arg) = priv->duration; + return DEMUXER_CTRL_OK; + + case DEMUXER_CTRL_GET_PERCENT_POS: + if (priv->duration == 0) + return DEMUXER_CTRL_DONTKNOW; + + *((int *)arg) = (int)(100 * lastpts / priv->duration); + return DEMUXER_CTRL_OK;*/ + + default: + return DEMUXER_CTRL_NOTIMPL; + } +} + +void demux_close_lavf(demuxer_t *demuxer) +{ + lavf_priv_t* priv = demuxer->priv; + + if (priv){ + av_close_input_file(priv->avfc); priv->avfc= NULL; + free(priv); demuxer->priv= NULL; + } +} + +#endif // USE_LIBAVFORMAT diff --git a/libmpdemux/demuxer.c b/libmpdemux/demuxer.c index fb56183e2c..fceb8990b9 100644 --- a/libmpdemux/demuxer.c +++ b/libmpdemux/demuxer.c @@ -139,6 +139,7 @@ extern void demux_close_ts(demuxer_t* demuxer); extern void demux_close_mkv(demuxer_t* demuxer); extern void demux_close_ra(demuxer_t* demuxer); extern void demux_close_ty(demuxer_t* demuxer); +extern void demux_close_lavf(demuxer_t* demuxer); #ifdef USE_TV @@ -223,7 +224,10 @@ void free_demuxer(demuxer_t *demuxer){ demux_close_ts(demuxer); break; case DEMUXER_TYPE_REALAUDIO: demux_close_ra(demuxer); break; - +#ifdef USE_LIBAVFORMAT + case DEMUXER_TYPE_LAVF: + demux_close_lavf(demuxer); break; +#endif } // free streams: for(i=0;i<256;i++){ @@ -313,6 +317,7 @@ extern int demux_rawvideo_fill_buffer(demuxer_t* demuxer, demux_stream_t *ds); extern int demux_smjpeg_fill_buffer(demuxer_t* demux); extern int demux_lmlm4_fill_buffer(demuxer_t* demux); extern int demux_mkv_fill_buffer(demuxer_t *d); +extern int demux_lavf_fill_buffer(demuxer_t *d); int demux_fill_buffer(demuxer_t *demux,demux_stream_t *ds){ // Note: parameter 'ds' can be NULL! @@ -369,6 +374,9 @@ int demux_fill_buffer(demuxer_t *demux,demux_stream_t *ds){ case DEMUXER_TYPE_MPEG4_IN_TS: return demux_ts_fill_buffer(demux); case DEMUXER_TYPE_REALAUDIO: return demux_ra_fill_buffer(demux); +#ifdef USE_LIBAVFORMAT + case DEMUXER_TYPE_LAVF: return demux_lavf_fill_buffer(demux); +#endif } return 0; } @@ -612,6 +620,8 @@ extern int demux_open_ra(demuxer_t* demuxer); #ifdef HAVE_MATROSKA extern int demux_mkv_open(demuxer_t *demuxer); #endif +extern int lavf_check_file(demuxer_t *demuxer); +extern int demux_open_lavf(demuxer_t* demuxer); extern demuxer_t* init_avi_with_ogg(demuxer_t* demuxer); @@ -1078,6 +1088,19 @@ if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_MPEG_TY) if(file_format==DEMUXER_TYPE_RTP) { demuxer=new_demuxer(stream,DEMUXER_TYPE_RTP,audio_id,video_id,dvdsub_id); } +//=============== Try to open with LAVF: ================= +#ifdef USE_LIBAVFORMAT + if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_LAVF){ + demuxer=new_demuxer(stream,DEMUXER_TYPE_LAVF,audio_id,video_id,dvdsub_id); + if(lavf_check_file(demuxer)){ + mp_msg(MSGT_DEMUXER,MSGL_INFO,MSGTR_Detected_XXX_FileFormat,"libavformat"); //FIXME print format + file_format=DEMUXER_TYPE_LAVF; + } else { + free_demuxer(demuxer); + demuxer = NULL; + } +} +#endif //=============== Unknown, exiting... =========================== if(file_format==DEMUXER_TYPE_UNKNOWN || demuxer == NULL){ //mp_msg(MSGT_DEMUXER,MSGL_ERR,MSGTR_FormatNotRecognized); // will be done by mplayer.c after fallback to playlist-parsing @@ -1311,6 +1334,12 @@ switch(file_format){ if (!demux_open_ra(demuxer)) return NULL; break; } +#ifdef USE_LIBAVFORMAT + case DEMUXER_TYPE_LAVF: { + if (!demux_open_lavf(demuxer)) return NULL; + break; + } +#endif } // switch(file_format) pts_from_bps=0; // !!! return demuxer; @@ -1397,6 +1426,7 @@ void demux_seek_mov(demuxer_t *demuxer,float pts,int flags); int demux_seek_real(demuxer_t *demuxer,float rel_seek_secs,int flags); int demux_seek_pva(demuxer_t *demuxer,float rel_seek_secs,int flags); int demux_seek_ts(demuxer_t *demuxer,float rel_seek_secs,int flags); +int demux_seek_lavf(demuxer_t *demuxer,float rel_seek_secs,int flags); #ifdef HAVE_LIBDV095 int demux_seek_rawdv(demuxer_t *demuxer, float pts, int flags); @@ -1508,6 +1538,10 @@ switch(demuxer->file_format){ case DEMUXER_TYPE_MPEG_TS: case DEMUXER_TYPE_MPEG4_IN_TS: demux_seek_ts(demuxer,rel_seek_secs,flags); break; + #ifdef USE_LIBAVFORMAT + case DEMUXER_TYPE_LAVF: + demux_seek_lavf(demuxer,rel_seek_secs,flags); break; + #endif } // switch(demuxer->file_format) @@ -1573,6 +1607,7 @@ extern int demux_mkv_control(demuxer_t *demuxer, int cmd, void *arg); extern int demux_audio_control(demuxer_t *demuxer, int cmd, void *arg); extern int demux_ogg_control(demuxer_t *demuxer, int cmd, void *arg); extern int demux_real_control(demuxer_t *demuxer, int cmd, void *arg); +extern int demux_lavf_control(demuxer_t *demuxer, int cmd, void *arg); int demux_control(demuxer_t *demuxer, int cmd, void *arg) { switch(demuxer->type) { @@ -1606,6 +1641,10 @@ int demux_control(demuxer_t *demuxer, int cmd, void *arg) { #endif case DEMUXER_TYPE_REAL: return demux_real_control(demuxer, cmd, arg); +#ifdef USE_LIBAVFORMAT + case DEMUXER_TYPE_LAVF: + return demux_lavf_control(demuxer, cmd, arg); +#endif default: return DEMUXER_CTRL_NOTIMPL; diff --git a/libmpdemux/demuxer.h b/libmpdemux/demuxer.h index 6a97fe7967..256138b2b5 100644 --- a/libmpdemux/demuxer.h +++ b/libmpdemux/demuxer.h @@ -43,11 +43,12 @@ #define DEMUXER_TYPE_REALAUDIO 32 #define DEMUXER_TYPE_MPEG_TY 33 #define DEMUXER_TYPE_LMLM4 34 +#define DEMUXER_TYPE_LAVF 35 // This should always match the higest demuxer type number. // Unless you want to disallow users to force the demuxer to some types #define DEMUXER_TYPE_MIN 0 -#define DEMUXER_TYPE_MAX 34 +#define DEMUXER_TYPE_MAX 35 #define DEMUXER_TYPE_DEMUXERS (1<<16) // A virtual demuxer type for the network code -- cgit v1.2.3