mirror of
https://github.com/mpv-player/mpv.git
synced 2024-09-20 03:52:22 +02:00
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.
This commit is contained in:
parent
f7163c8065
commit
7a1396b6ca
@ -1088,12 +1088,10 @@
|
||||
Maximum A-V sync correction per frame (in seconds)
|
||||
|
||||
--mf=<option1:option2:...>
|
||||
Used when decoding from multiple PNG or JPEG files.
|
||||
Used when decoding from multiple PNG or JPEG files with ``mf://``.
|
||||
|
||||
Available options are:
|
||||
|
||||
:w=<value>: input file width (default: autodetect)
|
||||
:h=<value>: input file height (default: autodetect)
|
||||
:fps=<value>: output fps (default: 25)
|
||||
:type=<value>: input file type (available: jpeg, png, tga, sgi)
|
||||
|
||||
|
@ -190,15 +190,11 @@ const m_option_t scaler_filter_conf[]={
|
||||
|
||||
extern char *dvd_device, *cdrom_device;
|
||||
|
||||
extern int mf_w;
|
||||
extern int mf_h;
|
||||
extern double mf_fps;
|
||||
extern char * mf_type;
|
||||
extern m_obj_list_t vf_obj_list;
|
||||
|
||||
const m_option_t mfopts_conf[]={
|
||||
{"w", &mf_w, CONF_TYPE_INT, 0, 0, 0, NULL},
|
||||
{"h", &mf_h, CONF_TYPE_INT, 0, 0, 0, NULL},
|
||||
{"fps", &mf_fps, CONF_TYPE_DOUBLE, 0, 0, 0, NULL},
|
||||
{"type", &mf_type, CONF_TYPE_STRING, 0, 0, 0, NULL},
|
||||
{NULL, NULL, 0, 0, 0, 0, NULL}
|
||||
|
@ -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. */
|
||||
|
188
demux/demux_mf.c
188
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_t *mf = demuxer->priv;
|
||||
if (mf->curr_frame >= mf->nr_of_files)
|
||||
return 0;
|
||||
|
||||
mf=(mf_t*)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 ( !( 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 );
|
||||
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);
|
||||
}
|
||||
|
||||
demuxer->filepos=mf->curr_frame++;
|
||||
return 1;
|
||||
if (stream != entry_stream)
|
||||
free_stream(stream);
|
||||
|
||||
mf->curr_frame++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// force extension/type to have a fourcc
|
||||
@ -112,29 +130,59 @@ static const struct {
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static demuxer_t* demux_open_mf(demuxer_t* demuxer){
|
||||
sh_video_t *sh_video = NULL;
|
||||
mf_t *mf = NULL;
|
||||
int i;
|
||||
|
||||
if(!demuxer->stream->url) return NULL;
|
||||
if(strncmp(demuxer->stream->url, "mf://", 5)) return NULL;
|
||||
mf_t *mf = open_mf(demuxer);
|
||||
if (!mf)
|
||||
goto error;
|
||||
|
||||
|
||||
mf=open_mf(demuxer->stream->url + 5);
|
||||
if(!mf) return 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);
|
||||
}
|
||||
|
||||
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,
|
||||
|
14
demux/mf.c
14
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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user