mirror of
https://github.com/mpv-player/mpv
synced 2025-03-21 10:51:51 +00:00
demux: kill libmng support
It's a dead format that was never used anywhere.
This commit is contained in:
parent
2f92056e2a
commit
84dcb76f27
1
Makefile
1
Makefile
@ -54,7 +54,6 @@ SOURCES-$(COCOA) += video/out/cocoa/view.m \
|
||||
osdep/ar/HIDRemote.m \
|
||||
osdep/path-macosx.m
|
||||
|
||||
SOURCES-$(MNG) += demux/demux_mng.c
|
||||
SOURCES-$(MPG123) += audio/decode/ad_mpg123.c
|
||||
|
||||
SOURCES-$(NEED_GETTIMEOFDAY) += osdep/gettimeofday.c
|
||||
|
19
configure
vendored
19
configure
vendored
@ -330,7 +330,6 @@ Optional features:
|
||||
--disable-af-lavfi disable af_lavfi libavfilter bridge [audodetect]
|
||||
|
||||
Codecs:
|
||||
--enable-mng enable MNG input support [autodetect]
|
||||
--enable-jpeg enable JPEG input/output support [autodetect]
|
||||
--enable-libcdio enable libcdio support [autodetect]
|
||||
--enable-libav skip Libav autodetection [autodetect]
|
||||
@ -432,7 +431,6 @@ _sdl=no
|
||||
_sdl2=no
|
||||
_dsound=auto
|
||||
_wasapi=auto
|
||||
_mng=auto
|
||||
_jpeg=auto
|
||||
_gl=auto
|
||||
_aa=auto
|
||||
@ -601,8 +599,6 @@ for ac_option do
|
||||
--disable-dsound) _dsound=no ;;
|
||||
--enable-wasapi) _wasapi=yes ;;
|
||||
--disable-wasapi) _wasapi=no ;;
|
||||
--enable-mng) _mng=yes ;;
|
||||
--disable-mng) _mng=no ;;
|
||||
--enable-jpeg) _jpeg=yes ;;
|
||||
--disable-jpeg) _jpeg=no ;;
|
||||
--enable-gl) _gl=yes ;;
|
||||
@ -1998,19 +1994,6 @@ else
|
||||
fi
|
||||
|
||||
|
||||
echocheck "MNG support"
|
||||
if test "$_mng" = auto ; then
|
||||
_mng=no
|
||||
return_statement_check libmng.h 'const char * p_ver = mng_version_text()' '!p_ver || p_ver[0] == 0' -lmng -lz $_ld_lm && _mng=yes
|
||||
fi
|
||||
echores "$_mng"
|
||||
if test "$_mng" = yes ; then
|
||||
def_mng='#define HAVE_MNG 1'
|
||||
libs_mplayer="$libs_mplayer -lmng -lz"
|
||||
else
|
||||
def_mng='#define HAVE_MNG 0'
|
||||
fi
|
||||
|
||||
echocheck "JPEG support"
|
||||
if test "$_jpeg" = auto ; then
|
||||
_jpeg=no
|
||||
@ -3318,7 +3301,6 @@ LIBQUVI = $_libquvi4
|
||||
LIBQUVI9 = $_libquvi9
|
||||
LIBGUESS = $_libguess
|
||||
LIRC = $_lirc
|
||||
MNG = $_mng
|
||||
MPG123 = $_mpg123
|
||||
OPENAL = $_openal
|
||||
OSS = $_ossaudio
|
||||
@ -3515,7 +3497,6 @@ $def_gl_win32
|
||||
$def_gl_x11
|
||||
$def_gl_wayland
|
||||
$def_jpeg
|
||||
$def_mng
|
||||
$def_v4l2
|
||||
$def_vdpau
|
||||
$def_vdpau_dec
|
||||
|
@ -56,7 +56,6 @@ extern const demuxer_desc_t demuxer_desc_tv;
|
||||
extern const demuxer_desc_t demuxer_desc_mf;
|
||||
extern const demuxer_desc_t demuxer_desc_matroska;
|
||||
extern const demuxer_desc_t demuxer_desc_lavf;
|
||||
extern const demuxer_desc_t demuxer_desc_mng;
|
||||
extern const demuxer_desc_t demuxer_desc_libass;
|
||||
extern const demuxer_desc_t demuxer_desc_subreader;
|
||||
extern const demuxer_desc_t demuxer_desc_playlist;
|
||||
@ -79,9 +78,6 @@ const demuxer_desc_t *const demuxer_list[] = {
|
||||
&demuxer_desc_matroska,
|
||||
&demuxer_desc_lavf,
|
||||
&demuxer_desc_mf,
|
||||
#if HAVE_MNG
|
||||
&demuxer_desc_mng,
|
||||
#endif
|
||||
&demuxer_desc_playlist,
|
||||
// Pretty aggressive, so should be last.
|
||||
&demuxer_desc_subreader,
|
||||
|
@ -1,572 +0,0 @@
|
||||
/*
|
||||
* MNG file demuxer for MPlayer
|
||||
*
|
||||
* Copyright (C) 2008 Stefan Schuermans <stefan blinkenarea org>
|
||||
*
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* MPlayer 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.
|
||||
*
|
||||
* MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "mpvcore/mp_msg.h"
|
||||
|
||||
#include "stream/stream.h"
|
||||
#include "demux.h"
|
||||
#include "stheader.h"
|
||||
#include "video/img_fourcc.h"
|
||||
|
||||
#define MNG_SUPPORT_READ
|
||||
#define MNG_SUPPORT_DISPLAY
|
||||
#include <libmng.h>
|
||||
|
||||
/**
|
||||
* \brief private context structure
|
||||
*
|
||||
* This structure is used as private data for MPlayer demuxer
|
||||
* and also as private data for the MNG library.
|
||||
*
|
||||
* All members ending in \p _ms are in milliseconds
|
||||
*/
|
||||
typedef struct {
|
||||
stream_t * stream; ///< pointer to MNG data input stream
|
||||
mng_handle h_mng; ///< MNG library image handle
|
||||
int header_processed; ///< if MNG image header is processed
|
||||
mng_uint32 width; ///< MNG image width
|
||||
mng_uint32 height; ///< MNG image height
|
||||
int total_time_ms; ///< total MNG animation time
|
||||
unsigned char * canvas; /**< \brief canvas to draw the image onto
|
||||
* \details
|
||||
* \li lines top-down
|
||||
* \li pixels left-to-right
|
||||
* \li channels RGB
|
||||
* \li no padding
|
||||
* \li NULL if no canvas yet
|
||||
*/
|
||||
int displaying; /**< \brief if displaying already,
|
||||
* i.e. if mng_display has
|
||||
* already been called
|
||||
*/
|
||||
int finished; ///< if animation is finished
|
||||
int global_time_ms; ///< current global time for MNG library
|
||||
int anim_cur_time_ms; ///< current frame time in MNG animation
|
||||
int anim_frame_duration_ms; ///< current frame duration in MNG animation
|
||||
int show_cur_time_ms; /**< \brief current time in the show process,
|
||||
* i.e. time of last demux packet
|
||||
*/
|
||||
int show_next_time_ms; /**< \brief next time in the show process,
|
||||
* i.e. time of next demux packet
|
||||
*/
|
||||
int timer_ms; /**< \brief number of milliseconds after which
|
||||
* libmng wants to be called again
|
||||
*/
|
||||
} mng_priv_t;
|
||||
|
||||
/**
|
||||
* \brief MNG library callback: Allocate a new zero-filled memory block.
|
||||
* \param[in] size memory block size
|
||||
* \return pointer to new memory block
|
||||
*/
|
||||
static mng_ptr demux_mng_alloc(mng_size_t size)
|
||||
{
|
||||
return calloc(1, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief MNG library callback: Free memory block.
|
||||
* \param[in] ptr pointer to memory block
|
||||
* \param[in] size memory block size
|
||||
*/
|
||||
static void demux_mng_free(mng_ptr ptr, mng_size_t size)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief MNG library callback: Open MNG stream.
|
||||
* \param[in] h_mng MNG library image handle
|
||||
* \return \p MNG_TRUE on success, \p MNG_FALSE on error (never happens)
|
||||
*/
|
||||
static mng_bool demux_mng_openstream(mng_handle h_mng)
|
||||
{
|
||||
mng_priv_t * mng_priv = mng_get_userdata(h_mng);
|
||||
stream_t * stream = mng_priv->stream;
|
||||
|
||||
// rewind stream to the beginning
|
||||
stream_seek(stream, stream->start_pos);
|
||||
|
||||
return MNG_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief MNG library callback: Close MNG stream.
|
||||
* \param[in] h_mng MNG library image handle
|
||||
* \return \p MNG_TRUE on success, \p MNG_FALSE on error (never happens)
|
||||
*/
|
||||
static mng_bool demux_mng_closestream(mng_handle h_mng)
|
||||
{
|
||||
return MNG_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief MNG library callback: Read data from stream.
|
||||
* \param[in] h_mng MNG library image handle
|
||||
* \param[in] buf pointer to buffer to fill with data
|
||||
* \param[in] size size of buffer
|
||||
* \param[out] read number of bytes read from stream
|
||||
* \return \p MNG_TRUE on success, \p MNG_FALSE on error (never happens)
|
||||
*/
|
||||
static mng_bool demux_mng_readdata(mng_handle h_mng, mng_ptr buf,
|
||||
mng_uint32 size, mng_uint32 * read)
|
||||
{
|
||||
mng_priv_t * mng_priv = mng_get_userdata(h_mng);
|
||||
stream_t * stream = mng_priv->stream;
|
||||
|
||||
// simply read data from stream and return number of bytes or error
|
||||
*read = stream_read(stream, buf, size);
|
||||
|
||||
return MNG_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief MNG library callback: Header information is processed now.
|
||||
* \param[in] h_mng MNG library image handle
|
||||
* \param[in] width image width
|
||||
* \param[in] height image height
|
||||
* \return \p MNG_TRUE on success, \p MNG_FALSE on error
|
||||
*/
|
||||
static mng_bool demux_mng_processheader(mng_handle h_mng, mng_uint32 width,
|
||||
mng_uint32 height)
|
||||
{
|
||||
mng_priv_t * mng_priv = mng_get_userdata(h_mng);
|
||||
|
||||
// remember size in private data
|
||||
mng_priv->header_processed = 1;
|
||||
mng_priv->width = width;
|
||||
mng_priv->height = height;
|
||||
|
||||
// get total animation time
|
||||
mng_priv->total_time_ms = mng_get_playtime(h_mng);
|
||||
|
||||
// allocate canvas
|
||||
mng_priv->canvas = malloc(height * width * 4);
|
||||
if (!mng_priv->canvas) {
|
||||
mp_msg(MSGT_DEMUX, MSGL_ERR,
|
||||
"demux_mng: could not allocate canvas of size %dx%d\n",
|
||||
width, height);
|
||||
return MNG_FALSE;
|
||||
}
|
||||
|
||||
return MNG_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief MNG library callback: Get access to a canvas line.
|
||||
* \param[in] h_mng MNG library image handle
|
||||
* \param[in] line y coordinate of line to access
|
||||
* \return pointer to line on success, \p MNG_NULL on error
|
||||
*/
|
||||
static mng_ptr demux_mng_getcanvasline(mng_handle h_mng, mng_uint32 line)
|
||||
{
|
||||
mng_priv_t * mng_priv = mng_get_userdata(h_mng);
|
||||
|
||||
// return pointer to canvas line
|
||||
if (line < mng_priv->height && mng_priv->canvas)
|
||||
return (mng_ptr)(mng_priv->canvas + line * mng_priv->width * 4);
|
||||
else
|
||||
return (mng_ptr)MNG_NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief MNG library callback: A part of the canvas should be shown.
|
||||
*
|
||||
* This function is called by libmng whenever it thinks a
|
||||
* rectangular part of the display should be updated. This
|
||||
* can happen multiple times for a frame and/or a single time
|
||||
* for a frame. Only the the part of the display occupied by
|
||||
* the rectangle defined by x, y, width, height is to be updated.
|
||||
* It is possible that some parts of the display are not updated
|
||||
* for many frames. There is no chance here to find out if the
|
||||
* current frame is completed with this update or not.
|
||||
*
|
||||
* This mechanism does not match MPlayer's demuxer architecture,
|
||||
* so it will not be used exactly as intended by libmng.
|
||||
* A new frame is generated in the demux_mng_fill_buffer() function
|
||||
* whenever libmng tells us to wait for some time.
|
||||
*
|
||||
* \param[in] h_mng MNG library image handle
|
||||
* \param[in] x rectangle's left edge
|
||||
* \param[in] y rectangle's top edge
|
||||
* \param[in] width rectangle's width
|
||||
* \param[in] height rectangle's heigt
|
||||
* \return \p MNG_TRUE on success, \p MNG_FALSE on error (never happens)
|
||||
*/
|
||||
static mng_bool demux_mng_refresh(mng_handle h_mng, mng_uint32 x, mng_uint32 y,
|
||||
mng_uint32 width, mng_uint32 height)
|
||||
{
|
||||
// nothing to do here, the image data is already on the canvas
|
||||
return MNG_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief MNG library callback: Get how many milliseconds have passed.
|
||||
* \param[in] h_mng MNG library image handle
|
||||
* \return global time in milliseconds
|
||||
*/
|
||||
static mng_uint32 demux_mng_gettickcount(mng_handle h_mng)
|
||||
{
|
||||
mng_priv_t * mng_priv = mng_get_userdata(h_mng);
|
||||
|
||||
// return current global time
|
||||
return mng_priv->global_time_ms;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief MNG library callback: Please call again after some milliseconds.
|
||||
* \param[in] h_mng MNG library image handle
|
||||
* \param[in] msecs number of milliseconds after which to call again
|
||||
* \return \p MNG_TRUE on success, \p MNG_FALSE on error (never happens)
|
||||
*/
|
||||
static mng_bool demux_mng_settimer(mng_handle h_mng, mng_uint32 msecs)
|
||||
{
|
||||
mng_priv_t * mng_priv = mng_get_userdata(h_mng);
|
||||
|
||||
// Save number of milliseconds after which to call the MNG library again
|
||||
// in private data.
|
||||
mng_priv->timer_ms = msecs;
|
||||
return MNG_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief MPlayer callback: Fill buffer from MNG stream.
|
||||
* \param[in] demuxer demuxer structure
|
||||
* \return \p 1 on success, \p 0 on error
|
||||
*/
|
||||
static int demux_mng_fill_buffer(demuxer_t * demuxer)
|
||||
{
|
||||
mng_priv_t * mng_priv = demuxer->priv;
|
||||
mng_handle h_mng = mng_priv->h_mng;
|
||||
mng_retcode mng_ret;
|
||||
demux_packet_t * dp;
|
||||
|
||||
// exit if animation is finished
|
||||
if (mng_priv->finished)
|
||||
return 0;
|
||||
|
||||
// advance animation to requested next show time
|
||||
while (mng_priv->anim_cur_time_ms + mng_priv->anim_frame_duration_ms
|
||||
<= mng_priv->show_next_time_ms && !mng_priv->finished) {
|
||||
|
||||
// advance global and animation time
|
||||
mng_priv->global_time_ms += mng_priv->anim_frame_duration_ms;
|
||||
mng_priv->anim_cur_time_ms += mng_priv->anim_frame_duration_ms;
|
||||
|
||||
// Clear variable MNG library will write number of milliseconds to
|
||||
// (via settimer callback).
|
||||
mng_priv->timer_ms = 0;
|
||||
|
||||
// get next image from MNG library
|
||||
if (mng_priv->displaying)
|
||||
mng_ret = mng_display_resume(h_mng); // resume displaying MNG data
|
||||
// to canvas
|
||||
else
|
||||
mng_ret = mng_display(h_mng); // start displaying MNG data to canvas
|
||||
if (mng_ret && mng_ret != MNG_NEEDTIMERWAIT) {
|
||||
mp_msg(MSGT_DEMUX, MSGL_ERR,
|
||||
"demux_mng: could not display MNG data to canvas: "
|
||||
"mng_retcode %d\n", mng_ret);
|
||||
return 0;
|
||||
}
|
||||
mng_priv->displaying = 1; // mng_display() has been called now
|
||||
mng_priv->finished = mng_ret == 0; // animation is finished iff
|
||||
// mng_display() returned 0
|
||||
|
||||
// save current frame duration
|
||||
mng_priv->anim_frame_duration_ms = mng_priv->timer_ms < 1
|
||||
? 1 : mng_priv->timer_ms;
|
||||
|
||||
} // while (mng_priv->anim_cur_time_ms + ...
|
||||
|
||||
// create a new demuxer packet
|
||||
dp = new_demux_packet(mng_priv->height * mng_priv->width * 4);
|
||||
|
||||
// copy image data into demuxer packet
|
||||
memcpy(dp->buffer, mng_priv->canvas,
|
||||
mng_priv->height * mng_priv->width * 4);
|
||||
|
||||
// set current show time to requested show time
|
||||
mng_priv->show_cur_time_ms = mng_priv->show_next_time_ms;
|
||||
|
||||
// get time of next frame to show
|
||||
mng_priv->show_next_time_ms = mng_priv->anim_cur_time_ms
|
||||
+ mng_priv->anim_frame_duration_ms;
|
||||
|
||||
// Set position and timing information in demuxer video and demuxer packet.
|
||||
// - Time must be time of next frame and always be > 0 for the variable
|
||||
// frame time mechanism (GIF, MATROSKA, MNG) in video.c to work.
|
||||
dp->pts = (float)mng_priv->show_next_time_ms / 1000.0f;
|
||||
dp->pos = stream_tell(demuxer->stream);
|
||||
demuxer_add_packet(demuxer, demuxer->streams[0], dp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int demux_mng_open(demuxer_t * demuxer, enum demux_check check)
|
||||
{
|
||||
mng_priv_t * mng_priv;
|
||||
mng_handle h_mng;
|
||||
mng_retcode mng_ret;
|
||||
sh_video_t * sh_video;
|
||||
|
||||
if (check > DEMUX_CHECK_REQUEST)
|
||||
return -1; // check too unsafe
|
||||
if (check > DEMUX_CHECK_FORCE) {
|
||||
char buf[4];
|
||||
if (stream_read(demuxer->stream, buf, 4) != 4)
|
||||
return -1;
|
||||
if (memcmp(buf, "\x8AMNG", 4))
|
||||
return -1;
|
||||
stream_seek(demuxer->stream, demuxer->stream->start_pos);
|
||||
}
|
||||
|
||||
// create private data structure
|
||||
mng_priv = calloc(1, sizeof(mng_priv_t));
|
||||
|
||||
//stream pointer into private data
|
||||
mng_priv->stream = demuxer->stream;
|
||||
|
||||
// initialize MNG image instance
|
||||
h_mng = mng_initialize((mng_ptr)mng_priv, demux_mng_alloc,
|
||||
demux_mng_free, MNG_NULL);
|
||||
if (!h_mng) {
|
||||
mp_msg(MSGT_DEMUX, MSGL_ERR,
|
||||
"demux_mng: could not initialize MNG image instance\n");
|
||||
free(mng_priv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// MNG image handle into private data
|
||||
mng_priv->h_mng = h_mng;
|
||||
|
||||
// set required MNG callbacks
|
||||
if (mng_setcb_openstream(h_mng, demux_mng_openstream) ||
|
||||
mng_setcb_closestream(h_mng, demux_mng_closestream) ||
|
||||
mng_setcb_readdata(h_mng, demux_mng_readdata) ||
|
||||
mng_setcb_processheader(h_mng, demux_mng_processheader) ||
|
||||
mng_setcb_getcanvasline(h_mng, demux_mng_getcanvasline) ||
|
||||
mng_setcb_refresh(h_mng, demux_mng_refresh) ||
|
||||
mng_setcb_gettickcount(h_mng, demux_mng_gettickcount) ||
|
||||
mng_setcb_settimer(h_mng, demux_mng_settimer) ||
|
||||
mng_set_canvasstyle(h_mng, MNG_CANVAS_RGBA8)) {
|
||||
mp_msg(MSGT_DEMUX, MSGL_ERR,
|
||||
"demux_mng: could not set MNG callbacks\n");
|
||||
mng_cleanup(&h_mng);
|
||||
free(mng_priv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// start reading MNG data
|
||||
mng_ret = mng_read(h_mng);
|
||||
if (mng_ret) {
|
||||
mp_msg(MSGT_DEMUX, MSGL_ERR,
|
||||
"demux_mng: could not start reading MNG data: "
|
||||
"mng_retcode %d\n", mng_ret);
|
||||
mng_cleanup(&h_mng);
|
||||
free(mng_priv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// check that MNG header is processed now
|
||||
if (!mng_priv->header_processed) {
|
||||
mp_msg(MSGT_DEMUX, MSGL_ERR,
|
||||
"demux_mng: internal error: header not processed\n");
|
||||
mng_cleanup(&h_mng);
|
||||
free(mng_priv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// create a new video stream header
|
||||
struct sh_stream *sh = new_sh_stream(demuxer, STREAM_VIDEO);
|
||||
sh_video = sh->video;
|
||||
|
||||
// set format of pixels in video packets
|
||||
sh_video->gsh->codec = "rawvideo";
|
||||
sh_video->format = MP_FOURCC_RGB32;
|
||||
|
||||
// set framerate to some value (MNG does not have a fixed framerate)
|
||||
sh_video->fps = 5.0f;
|
||||
|
||||
// set video frame parameters
|
||||
sh_video->bih = calloc(1, sizeof(*sh_video->bih));
|
||||
sh_video->bih->biCompression = sh_video->format;
|
||||
sh_video->bih->biWidth = mng_priv->width;
|
||||
sh_video->bih->biHeight = mng_priv->height;
|
||||
sh_video->bih->biBitCount = 32;
|
||||
sh_video->bih->biPlanes = 1;
|
||||
|
||||
// weirdly broken
|
||||
demuxer->accurate_seek = false;
|
||||
|
||||
// set private data in demuxer and return demuxer
|
||||
demuxer->priv = mng_priv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief MPlayer callback: Close MNG stream.
|
||||
* \param[in] demuxer demuxer structure
|
||||
*/
|
||||
static void demux_mng_close(demuxer_t* demuxer)
|
||||
{
|
||||
mng_priv_t * mng_priv = demuxer->priv;
|
||||
|
||||
if (mng_priv) {
|
||||
|
||||
// shutdown MNG image instance
|
||||
if (mng_priv->h_mng)
|
||||
mng_cleanup(&mng_priv->h_mng);
|
||||
|
||||
// free private data
|
||||
free(mng_priv->canvas);
|
||||
|
||||
free(mng_priv);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief MPlayer callback: Seek in MNG stream.
|
||||
* \param[in] demuxer demuxer structure
|
||||
* \param[in] rel_seek_secs relative seek time in seconds
|
||||
* \param[in] audio_delay unused, MNG does not contain audio
|
||||
* \param[in] flags bit flags, \p 1: absolute, \p 2: fractional position
|
||||
*/
|
||||
static void demux_mng_seek(demuxer_t * demuxer, float rel_seek_secs, int flags)
|
||||
{
|
||||
mng_priv_t * mng_priv = demuxer->priv;
|
||||
mng_handle h_mng = mng_priv->h_mng;
|
||||
mng_retcode mng_ret;
|
||||
int seek_ms, pos_ms;
|
||||
|
||||
// exit if not ready to seek (header not yet read or not yet displaying)
|
||||
if (!mng_priv->header_processed || !mng_priv->displaying)
|
||||
return;
|
||||
|
||||
// get number of milliseconds to seek to
|
||||
if (flags & 2) // seek by fractional position (0.0 ... 1.0)
|
||||
seek_ms = (int)(rel_seek_secs * (float)mng_priv->total_time_ms);
|
||||
else // seek by time in seconds
|
||||
seek_ms = (int)(rel_seek_secs * 1000.0f + 0.5f);
|
||||
|
||||
// get new position in milliseconds
|
||||
if (flags & 1) // absolute
|
||||
pos_ms = seek_ms;
|
||||
else // relative
|
||||
pos_ms = mng_priv->show_cur_time_ms + seek_ms;
|
||||
|
||||
// fix position
|
||||
if (pos_ms < 0)
|
||||
pos_ms = 0;
|
||||
if (pos_ms > mng_priv->total_time_ms)
|
||||
pos_ms = mng_priv->total_time_ms;
|
||||
|
||||
// FIXME
|
||||
// In principle there is a function to seek in MNG: mng_display_gotime().
|
||||
// - Using it did not work out (documentation is very brief,
|
||||
// example code does not exist?).
|
||||
// - The following code works, but its performance is quite bad.
|
||||
|
||||
// seeking forward
|
||||
if (pos_ms >= mng_priv->show_cur_time_ms) {
|
||||
|
||||
// Simply advance show time to seek position.
|
||||
// - Everything else will be handled in demux_mng_fill_buffer().
|
||||
mng_priv->show_next_time_ms = pos_ms;
|
||||
|
||||
} // if (pos_ms > mng_priv->show_time_ms)
|
||||
|
||||
// seeking backward
|
||||
else { // if (pos_ms > mng_priv->show_time_ms)
|
||||
|
||||
// Clear variable MNG library will write number of milliseconds to
|
||||
// (via settimer callback).
|
||||
mng_priv->timer_ms = 0;
|
||||
|
||||
// Restart displaying and advance show time to seek position.
|
||||
// - Everything else will be handled in demux_mng_fill_buffer().
|
||||
mng_ret = mng_display_reset(h_mng);
|
||||
// If a timer wait is needed, fool libmng that requested time
|
||||
// passed and try again.
|
||||
if (mng_ret == MNG_NEEDTIMERWAIT) {
|
||||
mng_priv->global_time_ms += mng_priv->timer_ms;
|
||||
mng_ret = mng_display_reset(h_mng);
|
||||
}
|
||||
if (mng_ret) {
|
||||
mp_msg(MSGT_DEMUX, MSGL_ERR,
|
||||
"demux_mng: could not reset MNG display state: "
|
||||
"mng_retcode %d\n", mng_ret);
|
||||
return;
|
||||
}
|
||||
mng_priv->displaying = 0;
|
||||
mng_priv->finished = 0;
|
||||
mng_priv->anim_cur_time_ms = 0;
|
||||
mng_priv->anim_frame_duration_ms = 0;
|
||||
mng_priv->show_next_time_ms = pos_ms;
|
||||
|
||||
} // if (pos_ms > mng_priv->show_time_ms) ... else
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief MPlayer callback: Control MNG stream.
|
||||
* \param[in] demuxer demuxer structure
|
||||
* \param[in] cmd code of control command to perform
|
||||
* \param[in,out] arg command argument
|
||||
* \return demuxer control response code
|
||||
*/
|
||||
static int demux_mng_control(demuxer_t * demuxer, int cmd, void * arg)
|
||||
{
|
||||
mng_priv_t * mng_priv = demuxer->priv;
|
||||
|
||||
switch(cmd) {
|
||||
|
||||
// get total movie length
|
||||
case DEMUXER_CTRL_GET_TIME_LENGTH:
|
||||
if (mng_priv->header_processed) {
|
||||
*(double *)arg = (double)mng_priv->total_time_ms / 1000.0;
|
||||
return DEMUXER_CTRL_OK;
|
||||
} else {
|
||||
return DEMUXER_CTRL_DONTKNOW;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return DEMUXER_CTRL_NOTIMPL;
|
||||
|
||||
} // switch (cmd)
|
||||
}
|
||||
|
||||
const demuxer_desc_t demuxer_desc_mng = {
|
||||
.name = "mng",
|
||||
.desc = "MNG",
|
||||
.fill_buffer = demux_mng_fill_buffer,
|
||||
.open = demux_mng_open,
|
||||
.close = demux_mng_close,
|
||||
.seek = demux_mng_seek,
|
||||
.control = demux_mng_control,
|
||||
};
|
Loading…
Reference in New Issue
Block a user