From 7a1396b6ca73d5db194dcc6cebc5ad92e9b22c89 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 16 Nov 2012 19:12:56 +0100 Subject: demux_mf: allow displaying single image files, various cleanups Enable autoprobing for demux_mf, so that image files can be directly displayed with e.g. "mpv file.jpg --pause". (The --pause switch is needed to prevent the window from closing immediately.) Since demux_mf doesn't have any real file format probing and goes by file extension only, move the demuxer down the demuxer list to ensure it's checked last. (ffmpeg's demux_mf equivalent, "image2", probes by file extensions too, and there doesn't seem to be anything that can probe typical image file formats from binary data.) Remove the --mf "w" and "h" suboptions. Don't pass the width/height to the video stream header. Both of these are useless, because the decoder reads the real image size at a later point from the file headers. Remove setting the BITMAPINFOHEADER as well, as vd_lavc doesn't need this. Enable --correct-pts by default. This fixes displaying a single image with vo_vdpau (as mentioned by uau). Keep around a pointer to the sh_video stream header instead of accessing demuxer->video->sh_video. Fixes a crash when deselecting the video track. Note that the format probing is incorrect when opening images from HTTP locations. File extensions don't have to match the actual file format. A correct implementation would require to check the MIME type, or to probe the binary data correctly. --- demux/demux.c | 3 +- demux/demux_mf.c | 190 +++++++++++++++++++++++++++++++++---------------------- demux/mf.c | 14 +++- demux/mf.h | 8 ++- 4 files changed, 132 insertions(+), 83 deletions(-) (limited to 'demux') diff --git a/demux/demux.c b/demux/demux.c index 889fbea409..e45335f2f8 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -80,7 +80,6 @@ const demuxer_desc_t *const demuxer_list[] = { #ifdef CONFIG_TV &demuxer_desc_tv, #endif - &demuxer_desc_mf, &demuxer_desc_lavf_preferred, &demuxer_desc_avi, &demuxer_desc_asf, @@ -99,6 +98,8 @@ const demuxer_desc_t *const demuxer_list[] = { &demuxer_desc_mpeg4_es, &demuxer_desc_h264_es, &demuxer_desc_mpeg_ts, + // auto-probe last, because it checks file-extensions only + &demuxer_desc_mf, /* Please do not add any new demuxers here. If you want to implement a new * demuxer, add it to libavformat, except for wrappers around external * libraries and demuxers requiring binary support. */ diff --git a/demux/demux_mf.c b/demux/demux_mf.c index fdfa21c4a3..911288badc 100644 --- a/demux/demux_mf.c +++ b/demux/demux_mf.c @@ -34,46 +34,64 @@ #include "stheader.h" #include "mf.h" +#define MF_MAX_FILE_SIZE (1024*1024*256) + +static void free_mf(mf_t *mf) +{ + if (mf) { + for (int n = 0; n < mf->nr_of_files; n++) + free(mf->names[n]); + free(mf->names); + free(mf->streams); + free(mf); + } +} + static void demux_seek_mf(demuxer_t *demuxer,float rel_seek_secs,float audio_delay,int flags){ mf_t * mf = (mf_t *)demuxer->priv; - sh_video_t * sh_video = demuxer->video->sh; int newpos = (flags & SEEK_ABSOLUTE)?0:mf->curr_frame - 1; if ( flags & SEEK_FACTOR ) newpos+=rel_seek_secs*(mf->nr_of_files - 1); - else newpos+=rel_seek_secs * sh_video->fps; + else newpos+=rel_seek_secs * mf->sh->fps; if ( newpos < 0 ) newpos=0; if( newpos >= mf->nr_of_files) newpos=mf->nr_of_files - 1; - demuxer->filepos=mf->curr_frame=newpos; + mf->curr_frame=newpos; } // return value: // 0 = EOF or no stream found // 1 = successfully read a packet static int demux_mf_fill_buffer(demuxer_t *demuxer, demux_stream_t *ds){ - mf_t * mf; - FILE * f; - - mf=(mf_t*)demuxer->priv; - if ( mf->curr_frame >= mf->nr_of_files ) return 0; - - if ( !( f=fopen( mf->names[mf->curr_frame],"rb" ) ) ) return 0; - { - sh_video_t * sh_video = demuxer->video->sh; - fseek(f, 0, SEEK_END); - long file_size = ftell(f); - fseek(f, 0, SEEK_SET); - demux_packet_t * dp = new_demux_packet( file_size ); - if ( !fread( dp->buffer,file_size,1,f ) ) return 0; - dp->pts=mf->curr_frame / sh_video->fps; - dp->pos=mf->curr_frame; - dp->keyframe = true; - // append packet to DS stream: - ds_add_packet( demuxer->video,dp ); - } - fclose( f ); + mf_t *mf = demuxer->priv; + if (mf->curr_frame >= mf->nr_of_files) + return 0; + + struct stream *entry_stream = NULL; + if (mf->streams) + entry_stream = mf->streams[mf->curr_frame]; + struct stream *stream = entry_stream; + if (!stream) + stream = open_stream(mf->names[mf->curr_frame], demuxer->opts, NULL); + + if (stream) { + stream_seek(stream, 0); + bstr data = stream_read_complete(stream, NULL, MF_MAX_FILE_SIZE, 0); + if (data.len) { + demux_packet_t *dp = new_demux_packet(data.len); + memcpy(dp->buffer, data.start, data.len); + dp->pts = mf->curr_frame / mf->sh->fps; + dp->pos = mf->curr_frame; + dp->keyframe = true; + ds_add_packet(demuxer->video, dp); + } + talloc_free(data.start); + } + + if (stream != entry_stream) + free_stream(stream); - demuxer->filepos=mf->curr_frame++; - return 1; + mf->curr_frame++; + return 1; } // force extension/type to have a fourcc @@ -112,29 +130,59 @@ static const struct { { NULL, 0 } }; -static demuxer_t* demux_open_mf(demuxer_t* demuxer){ - sh_video_t *sh_video = NULL; - mf_t *mf = NULL; - int i; +static uint32_t probe_format(mf_t *mf) +{ + if (mf->nr_of_files < 1) + return 0; + char *type = mf_type; + if (!type || !type[0]) { + char *p = strrchr(mf->names[0], '.'); + if (p) + type = p + 1; + } + if (!type || !type[0]) + return 0; + int i; + for (i = 0; type2format[i].type; i++) { + if (strcasecmp(type, type2format[i].type) == 0) + break; + } + return type2format[i].format; +} - if(!demuxer->stream->url) return NULL; - if(strncmp(demuxer->stream->url, "mf://", 5)) return NULL; +static mf_t *open_mf(demuxer_t *demuxer) +{ + if (!demuxer->stream->url) + return NULL; + + if (strncmp(demuxer->stream->url, "mf://", 5) == 0) { + return open_mf_pattern(demuxer->stream->url + 5); + } else { + mf_t *mf = open_mf_single(demuxer->stream->url); + mf->streams = calloc(1, sizeof(struct stream *)); + mf->streams[0] = demuxer->stream; + return mf; + } +} +static int demux_check_file(demuxer_t *demuxer) +{ + if (demuxer->stream->type == STREAMTYPE_MF) + return DEMUXER_TYPE_MF; + mf_t *mf = open_mf(demuxer); + bool ok = mf && probe_format(mf); + free_mf(mf); + return ok ? DEMUXER_TYPE_MF : 0; +} - mf=open_mf(demuxer->stream->url + 5); - if(!mf) return NULL; +static demuxer_t* demux_open_mf(demuxer_t* demuxer){ + sh_video_t *sh_video = NULL; - if(!mf_type){ - char* p=strrchr(mf->names[0],'.'); - if(!p){ - mp_msg(MSGT_DEMUX, MSGL_INFO, "[demux_mf] file type was not set! (try -mf type=xxx)\n" ); - free( mf ); return NULL; - } - mf_type = talloc_strdup(NULL, p+1); - mp_msg(MSGT_DEMUX, MSGL_INFO, "[demux_mf] file type was not set! trying 'type=%s'...\n", mf_type); - } + mf_t *mf = open_mf(demuxer); + if (!mf) + goto error; - demuxer->filepos=mf->curr_frame=0; + mf->curr_frame = 0; demuxer->movi_start = 0; demuxer->movi_end = mf->nr_of_files - 1; @@ -145,63 +193,53 @@ static demuxer_t* demux_open_mf(demuxer_t* demuxer){ // (even though new_sh_video() ought to take care of it) demuxer->video->sh = sh_video; + sh_video->format = probe_format(mf); + if (!sh_video->format) { + mp_msg(MSGT_DEMUX, MSGL_INFO, "[demux_mf] file type was not set! (try -mf type=ext)\n" ); + goto error; + } + // make sure that the video demuxer stream header knows about its // parent video demuxer stream (this is getting wacky), or else // video_read_properties() will choke sh_video->ds = demuxer->video; - for (i = 0; type2format[i].type; i++) - if (strcasecmp(mf_type, type2format[i].type) == 0) - break; - if (!type2format[i].type) { - mp_msg(MSGT_DEMUX, MSGL_INFO, "[demux_mf] unknown input file type.\n" ); - free(mf); - return NULL; - } - sh_video->format = type2format[i].format; - - sh_video->disp_w = mf_w; - sh_video->disp_h = mf_h; + sh_video->disp_w = 0; + sh_video->disp_h = 0; sh_video->fps = mf_fps; sh_video->frametime = 1 / sh_video->fps; - // emulate BITMAPINFOHEADER: - sh_video->bih=calloc(1, sizeof(*sh_video->bih)); - sh_video->bih->biSize=40; - sh_video->bih->biWidth = mf_w; - sh_video->bih->biHeight = mf_h; - sh_video->bih->biPlanes=1; - sh_video->bih->biBitCount=24; - sh_video->bih->biCompression=sh_video->format; - sh_video->bih->biSizeImage=sh_video->bih->biWidth*sh_video->bih->biHeight*3; - - /* disable seeking */ -// demuxer->seekable = 0; - + mf->sh = sh_video; demuxer->priv=(void*)mf; return demuxer; + +error: + free_mf(mf); + return NULL; } static void demux_close_mf(demuxer_t* demuxer) { mf_t *mf = demuxer->priv; - free(mf); + free_mf(mf); } static int demux_control_mf(demuxer_t *demuxer, int cmd, void *arg) { mf_t *mf = (mf_t *)demuxer->priv; - sh_video_t *sh_video = demuxer->video->sh; switch(cmd) { case DEMUXER_CTRL_GET_TIME_LENGTH: - *((double *)arg) = (double)mf->nr_of_files / sh_video->fps; + *((double *)arg) = (double)mf->nr_of_files / mf->sh->fps; return DEMUXER_CTRL_OK; case DEMUXER_CTRL_GET_PERCENT_POS: - if (mf->nr_of_files <= 1) + if (mf->nr_of_files < 1) return DEMUXER_CTRL_DONTKNOW; - *((int *)arg) = 100 * mf->curr_frame / (mf->nr_of_files - 1); + *((int *)arg) = 100 * mf->curr_frame / mf->nr_of_files; + return DEMUXER_CTRL_OK; + + case DEMUXER_CTRL_CORRECT_PTS: return DEMUXER_CTRL_OK; default: @@ -216,8 +254,8 @@ const demuxer_desc_t demuxer_desc_mf = { "?", "multiframe?, pictures demuxer", DEMUXER_TYPE_MF, - 0, // no autodetect - NULL, + 1, + demux_check_file, demux_mf_fill_buffer, demux_open_mf, demux_close_mf, diff --git a/demux/mf.c b/demux/mf.c index 440156087e..6ab23b36e9 100644 --- a/demux/mf.c +++ b/demux/mf.c @@ -43,12 +43,11 @@ #include "mf.h" -int mf_w = 0; //352; // let codecs to detect it -int mf_h = 0; //288; double mf_fps = 25.0; char * mf_type = NULL; //"jpg"; -mf_t* open_mf(char * filename){ +mf_t* open_mf_pattern(char * filename) +{ #if defined(HAVE_GLOB) || defined(__MINGW32__) glob_t gg; int i; @@ -169,3 +168,12 @@ exit_mf: return 0; #endif } + +mf_t* open_mf_single(char * filename) +{ + mf_t *mf = calloc(1, sizeof(mf_t)); + mf->nr_of_files = 1; + mf->names = calloc(1, sizeof(char *)); + mf->names[0] = strdup(filename); + return mf; +} diff --git a/demux/mf.h b/demux/mf.h index dd461bc97c..bcf758db5b 100644 --- a/demux/mf.h +++ b/demux/mf.h @@ -19,18 +19,20 @@ #ifndef MPLAYER_MF_H #define MPLAYER_MF_H -extern int mf_w; -extern int mf_h; extern double mf_fps; extern char * mf_type; typedef struct { + struct sh_video *sh; int curr_frame; int nr_of_files; char ** names; + // optional + struct stream **streams; } mf_t; -mf_t* open_mf(char * filename); +mf_t* open_mf_pattern(char * filename); +mf_t* open_mf_single(char * filename); #endif /* MPLAYER_MF_H */ -- cgit v1.2.3