diff --git a/Makefile b/Makefile index ccf845e1a1..771b2a6245 100644 --- a/Makefile +++ b/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 diff --git a/configure b/configure index 9905394f6a..bc7199d70d 100755 --- a/configure +++ b/configure @@ -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 diff --git a/demux/demux.c b/demux/demux.c index b5934824dc..4e5f83f8ab 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -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, diff --git a/demux/demux_mng.c b/demux/demux_mng.c deleted file mode 100644 index f408687c1b..0000000000 --- a/demux/demux_mng.c +++ /dev/null @@ -1,572 +0,0 @@ -/* - * MNG file demuxer for MPlayer - * - * Copyright (C) 2008 Stefan Schuermans - * - * 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 -#include -#include - -#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 - -/** - * \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, -};