diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | audio/decode/ad_lavc.c | 34 | ||||
-rw-r--r-- | audio/out/ao_lavc.c | 77 | ||||
-rwxr-xr-x | configure | 19 | ||||
-rw-r--r-- | demux/codec_tags.c | 1 | ||||
-rw-r--r-- | demux/demux.c | 4 | ||||
-rw-r--r-- | demux/demux_mf.c | 209 | ||||
-rw-r--r-- | demux/demux_mkv.c | 5 | ||||
-rw-r--r-- | demux/demux_mng.c | 572 | ||||
-rw-r--r-- | demux/matroska.h | 1 | ||||
-rw-r--r-- | demux/mf.c | 211 | ||||
-rw-r--r-- | demux/mf.h | 19 | ||||
-rw-r--r-- | video/out/vo_lavc.c | 4 | ||||
-rw-r--r-- | video/out/wayland_common.c | 12 |
14 files changed, 247 insertions, 922 deletions
@@ -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/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c index c42c430850..2e0cade8c5 100644 --- a/audio/decode/ad_lavc.c +++ b/audio/decode/ad_lavc.c @@ -63,12 +63,10 @@ const m_option_t ad_lavc_decode_opts_conf[] = { struct pcm_map { int tag; - const char *codecs[5]; // {any, 1byte, 2bytes, 3bytes, 4bytes} + const char *codecs[6]; // {any, 1byte, 2bytes, 3bytes, 4bytes, 8bytes} }; -// NOTE: some of these are needed to make rawaudio with demux_mkv and others -// work. ffmpeg does similar mapping internally, not part of the public -// API. Some of these might be dead leftovers for demux_mov support. +// NOTE: these are needed to make rawaudio with demux_mkv work. static const struct pcm_map tag_map[] = { // Microsoft PCM {0x0, {NULL, "pcm_u8", "pcm_s16le", "pcm_s24le", "pcm_s32le"}}, @@ -76,26 +74,12 @@ static const struct pcm_map tag_map[] = { // MS PCM, Extended {0xfffe, {NULL, "pcm_u8", "pcm_s16le", "pcm_s24le", "pcm_s32le"}}, // IEEE float - {0x3, {"pcm_f32le"}}, + {0x3, {"pcm_f32le", [5] = "pcm_f64le"}}, // 'raw ' {0x20776172, {"pcm_s16be", [1] = "pcm_u8"}}, - // 'twos'/'sowt' - {0x736F7774, {"pcm_s16be", [1] = "pcm_s8"}}, - {0x74776F73, {"pcm_s16be", [1] = "pcm_s8"}}, - // 'fl32'/'FL32' - {0x32336c66, {"pcm_f32be"}}, - {0x32334C46, {"pcm_f32be"}}, - // '23lf'/'lpcm' - {0x666c3332, {"pcm_f32le"}}, - {0x6D63706C, {"pcm_f32le"}}, - // 'in24', bigendian int24 - {0x34326e69, {"pcm_s24be"}}, - // '42ni', little endian int24, MPlayer internal fourCC - {0x696e3234, {"pcm_s24le"}}, - // 'in32', bigendian int32 - {0x32336e69, {"pcm_s32be"}}, - // '23ni', little endian int32, MPlayer internal fourCC - {0x696e3332, {"pcm_s32le"}}, + // 'twos', used by demux_mkv.c internally + {MKTAG('t', 'w', 'o', 's'), + {NULL, "pcm_s8", "pcm_s16be", "pcm_s24be", "pcm_s32be"}}, {-1}, }; @@ -118,6 +102,8 @@ static const struct pcm_map af_map[] = { {AF_FORMAT_S32_BE, {"pcm_s32be"}}, {AF_FORMAT_FLOAT_LE, {"pcm_f32le"}}, {AF_FORMAT_FLOAT_BE, {"pcm_f32be"}}, + {AF_FORMAT_DOUBLE_LE, {"pcm_f64le"}}, + {AF_FORMAT_DOUBLE_BE, {"pcm_f64be"}}, {-1}, }; @@ -125,11 +111,13 @@ static const char *find_pcm_decoder(const struct pcm_map *map, int format, int bits_per_sample) { int bytes = (bits_per_sample + 7) / 8; + if (bytes == 8) + bytes = 5; // 64 bit entry for (int n = 0; map[n].tag != -1; n++) { const struct pcm_map *entry = &map[n]; if (entry->tag == format) { const char *dec = NULL; - if (bytes >= 1 && bytes <= 4) + if (bytes >= 1 && bytes <= 5) dec = entry->codecs[bytes]; if (!dec) dec = entry->codecs[0]; diff --git a/audio/out/ao_lavc.c b/audio/out/ao_lavc.c index 9be3a7b6ae..c1fce6a715 100644 --- a/audio/out/ao_lavc.c +++ b/audio/out/ao_lavc.c @@ -50,8 +50,6 @@ struct priv { int pcmhack; int aframesize; int aframecount; - int offset; - int offset_left; int64_t savepts; int framecount; int64_t lastpts; @@ -271,9 +269,6 @@ out_takefirst: ac->savepts = MP_NOPTS_VALUE; ac->lastpts = MP_NOPTS_VALUE; - ac->offset = ac->stream->codec->sample_rate * - encode_lavc_getoffset(ao->encode_lavc_ctx, ac->stream); - ac->offset_left = ac->offset; ao->untimed = true; ao->priv = ac; @@ -450,7 +445,6 @@ static int play(struct ao *ao, void **ni_data, int samples, int flags) struct priv *ac = ao->priv; struct encode_lavc_context *ectx = ao->encode_lavc_ctx; int bufpos = 0; - int64_t ptsoffset; void *paddingbuf = NULL; double nextpts; double pts = ao->pts; @@ -542,63 +536,10 @@ static int play(struct ao *ao, void **ni_data, int samples, int flags) // Absurd, as this range MUST contain at least one multiple of B. } - ptsoffset = ac->offset; - // this basically just edits ao->apts for syncing purposes - - if (ectx->options->copyts || ectx->options->rawts) { - // we do not send time sync data to the video side, - // but we always need the exact pts, even if zero - } else { - // here we must "simulate" the pts editing - // 1. if we have to skip stuff, we skip it - // 2. if we have to add samples, we add them - // 3. we must still adjust ptsoffset appropriately for AV sync! - // invariant: - // if no partial skipping is done, the first frame gets ao->apts passed as pts! - - if (ac->offset_left < 0) { - if (ac->offset_left <= -len) { - // skip whole frame - ac->offset_left += len; - return len; - } else { - // skip part of this frame, buffer/encode the rest - bufpos -= ac->offset_left; - ptsoffset += ac->offset_left; - ac->offset_left = 0; - } - } else if (ac->offset_left > 0) { - // make a temporary buffer, filled with zeroes at the start - // (don't worry, only happens once) - - paddingbuf = talloc_size(ac, ac->sample_size * ao->channels.num * - (ac->offset_left + len)); - fill_with_padding(paddingbuf, ac->offset_left, ac->sample_size, - ac->sample_padding); - data = (char *) paddingbuf + ac->sample_size * ao->channels.num * - ac->offset_left; - bufpos -= ac->offset_left; // yes, negative! - ptsoffset += ac->offset_left; - ac->offset_left = 0; - - // now adjust the bufpos so the final value of bufpos is positive! - /* - int cnt = (len - bufpos) / ac->aframesize; - int finalbufpos = bufpos + cnt * ac->aframesize; - */ - int finalbufpos = len - (len - bufpos) % ac->aframesize; - if (finalbufpos < 0) { - MP_WARN(ao, "cannot attain the " - "exact requested audio sync; shifting by %d frames\n", - -finalbufpos); - bufpos -= finalbufpos; - } - } - } - + // Fix and apply the discontinuity pts offset. if (!ectx->options->rawts && ectx->options->copyts) { // fix the discontinuity pts offset - nextpts = pts + ptsoffset / (double) ao->samplerate; + nextpts = pts; if (ectx->discontinuity_pts_offset == MP_NOPTS_VALUE) { ectx->discontinuity_pts_offset = ectx->next_in_pts - nextpts; } @@ -611,23 +552,27 @@ static int play(struct ao *ao, void **ni_data, int samples, int flags) outpts = pts + ectx->discontinuity_pts_offset; } - else + else { outpts = pts; + } + + // Shift pts by the pts offset first. + outpts += encode_lavc_getoffset(ectx, ac->stream); while (len - bufpos >= ac->aframesize) { encode(ao, - outpts + (bufpos + ptsoffset) / (double) ao->samplerate + encode_lavc_getoffset(ectx, ac->stream), + outpts + bufpos / (double) ao->samplerate, (char *) data + ac->sample_size * bufpos * ao->channels.num); bufpos += ac->aframesize; } talloc_free(paddingbuf); - // calculate expected pts of next audio frame - ac->expected_next_pts = pts + (bufpos + ptsoffset) / (double) ao->samplerate; + // Calculate expected pts of next audio frame (input side). + ac->expected_next_pts = pts + bufpos / (double) ao->samplerate; + // Set next allowed input pts value (input side). if (!ectx->options->rawts && ectx->options->copyts) { - // set next allowed output pts value nextpts = ac->expected_next_pts + ectx->discontinuity_pts_offset; if (nextpts > ectx->next_in_pts) ectx->next_in_pts = nextpts; @@ -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 @@ -3316,7 +3299,6 @@ LIBQUVI = $_libquvi4 LIBQUVI9 = $_libquvi9 LIBGUESS = $_libguess LIRC = $_lirc -MNG = $_mng MPG123 = $_mpg123 OPENAL = $_openal OSS = $_ossaudio @@ -3513,7 +3495,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/codec_tags.c b/demux/codec_tags.c index 66489aae03..dbf384fdbd 100644 --- a/demux/codec_tags.c +++ b/demux/codec_tags.c @@ -132,7 +132,6 @@ static const struct mp_codec_tag mp_audio_codec_tags[] = { {MKTAG('B', 'P', 'C', 'M'), "pcm_bluray"}, {MKTAG('P', 'L', 'X', 'F'), "pcm_lxf"}, {MKTAG('T', 'W', 'I', '2'), "twinvq"}, - {0x20776172, "pcm"}, // demux_mpg.c dvdpcm {0}, }; diff --git a/demux/demux.c b/demux/demux.c index ded0dd895e..da5957efdd 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_mf.c b/demux/demux_mf.c index 50888f59ad..6042771241 100644 --- a/demux/demux_mf.c +++ b/demux/demux_mf.c @@ -28,35 +28,29 @@ #include "talloc.h" #include "config.h" #include "mpvcore/mp_msg.h" +#include "mpvcore/mp_talloc.h" #include "stream/stream.h" #include "demux.h" #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); - } -} +#define MF_MAX_FILE_SIZE (1024 * 1024 * 256) static void demux_seek_mf(demuxer_t *demuxer, float rel_seek_secs, int flags) { - mf_t * mf = (mf_t *)demuxer->priv; - 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 * mf->sh->fps; - if ( newpos < 0 ) newpos=0; - if( newpos >= mf->nr_of_files) newpos=mf->nr_of_files - 1; - mf->curr_frame=newpos; + mf_t *mf = demuxer->priv; + 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 * mf->sh->fps; + if (newpos < 0) + newpos = 0; + if (newpos >= mf->nr_of_files) + newpos = mf->nr_of_files - 1; + mf->curr_frame = newpos; } // return value: @@ -101,52 +95,52 @@ static int demux_mf_fill_buffer(demuxer_t *demuxer) // map file extension/type to a codec name static const struct { - const char *type; - const char *codec; + const char *type; + const char *codec; } type2format[] = { - { "bmp", "bmp" }, - { "dpx", "dpx" }, - { "j2c", "jpeg2000" }, - { "j2k", "jpeg2000" }, - { "jp2", "jpeg2000" }, - { "jpc", "jpeg2000" }, - { "jpeg", "mjpeg" }, - { "jpg", "mjpeg" }, - { "jps", "mjpeg" }, - { "jls", "ljpeg" }, - { "thm", "mjpeg" }, - { "db", "mjpeg" }, - { "pcx", "pcx" }, - { "png", "png" }, - { "pns", "png" }, - { "ptx", "ptx" }, - { "tga", "targa" }, - { "tif", "tiff" }, - { "tiff", "tiff" }, - { "sgi", "sgi" }, - { "sun", "sunrast" }, - { "ras", "sunrast" }, - { "rs", "sunrast" }, - { "ra", "sunrast" }, - { "im1", "sunrast" }, - { "im8", "sunrast" }, - { "im24", "sunrast" }, - { "im32", "sunrast" }, - { "sunras", "sunrast" }, - { "xbm", "xbm" }, - { "pam", "pam" }, - { "pbm", "pbm" }, - { "pgm", "pgm" }, - { "pgmyuv", "pgmyuv" }, - { "ppm", "ppm" }, - { "pnm", "ppm" }, - { "gif", "gif" }, // usually handled by demux_lavf - { "pix", "brender_pix" }, - { "exr", "exr" }, - { "pic", "pictor" }, - { "xface", "xface" }, - { "xwd", "xwd" }, - {0} + { "bmp", "bmp" }, + { "dpx", "dpx" }, + { "j2c", "jpeg2000" }, + { "j2k", "jpeg2000" }, + { "jp2", "jpeg2000" }, + { "jpc", "jpeg2000" }, + { "jpeg", "mjpeg" }, + { "jpg", "mjpeg" }, + { "jps", "mjpeg" }, + { "jls", "ljpeg" }, + { "thm", "mjpeg" }, + { "db", "mjpeg" }, + { "pcx", "pcx" }, + { "png", "png" }, + { "pns", "png" }, + { "ptx", "ptx" }, + { "tga", "targa" }, + { "tif", "tiff" }, + { "tiff", "tiff" }, + { "sgi", "sgi" }, + { "sun", "sunrast" }, + { "ras", "sunrast" }, + { "rs", "sunrast" }, + { "ra", "sunrast" }, + { "im1", "sunrast" }, + { "im8", "sunrast" }, + { "im24", "sunrast" }, + { "im32", "sunrast" }, + { "sunras", "sunrast" }, + { "xbm", "xbm" }, + { "pam", "pam" }, + { "pbm", "pbm" }, + { "pgm", "pgm" }, + { "pgmyuv", "pgmyuv" }, + { "ppm", "ppm" }, + { "pnm", "ppm" }, + { "gif", "gif" }, // usually handled by demux_lavf + { "pix", "brender_pix" }, + { "exr", "exr" }, + { "pic", "pictor" }, + { "xface", "xface" }, + { "xwd", "xwd" }, + {0} }; static const char *probe_format(mf_t *mf, enum demux_check check) @@ -167,7 +161,7 @@ static const char *probe_format(mf_t *mf, enum demux_check check) if (!mf_type) { mp_msg(MSGT_DEMUX, MSGL_ERR, "[demux_mf] file type was not set! (try --mf-type=ext)\n"); - } else { + } else { mp_msg(MSGT_DEMUX, MSGL_ERR, "[demux_mf] --mf-type set to an unknown codec!\n"); } @@ -175,67 +169,64 @@ static const char *probe_format(mf_t *mf, enum demux_check check) return NULL; } -static int demux_open_mf(demuxer_t* demuxer, enum demux_check check) +static int demux_open_mf(demuxer_t *demuxer, enum demux_check check) { - sh_video_t *sh_video = NULL; - mf_t *mf; - - if (strncmp(demuxer->stream->url, "mf://", 5) == 0 && - demuxer->stream->type == STREAMTYPE_MF) - { - mf = open_mf_pattern(demuxer->stream->url + 5); - } else { - mf = open_mf_single(demuxer->stream->url); - mf->streams = calloc(1, sizeof(struct stream *)); - mf->streams[0] = demuxer->stream; - } + sh_video_t *sh_video = NULL; + mf_t *mf; + + if (strncmp(demuxer->stream->url, "mf://", 5) == 0 && + demuxer->stream->type == STREAMTYPE_MF) + mf = open_mf_pattern(demuxer, demuxer->stream->url + 5); + else { + mf = open_mf_single(demuxer, demuxer->stream->url); + int bog = 0; + MP_TARRAY_APPEND(mf, mf->streams, bog, demuxer->stream); + } - if (!mf || mf->nr_of_files < 1) - goto error; + if (!mf || mf->nr_of_files < 1) + goto error; - const char *codec = probe_format(mf, check); - if (!codec) - goto error; + const char *codec = probe_format(mf, check); + if (!codec) + goto error; - mf->curr_frame = 0; + mf->curr_frame = 0; - // create a new video stream header - struct sh_stream *sh = new_sh_stream(demuxer, STREAM_VIDEO); - sh_video = sh->video; + // create a new video stream header + struct sh_stream *sh = new_sh_stream(demuxer, STREAM_VIDEO); + sh_video = sh->video; - sh_video->gsh->codec = codec; - sh_video->disp_w = 0; - sh_video->disp_h = 0; - sh_video->fps = mf_fps; + sh_video->gsh->codec = codec; + sh_video->disp_w = 0; + sh_video->disp_h = 0; + sh_video->fps = mf_fps; - mf->sh = sh_video; - demuxer->priv=(void*)mf; - demuxer->seekable = true; + mf->sh = sh_video; + demuxer->priv = (void *)mf; + demuxer->seekable = true; - return 0; + return 0; error: - free_mf(mf); - return -1; + return -1; } -static void demux_close_mf(demuxer_t* demuxer) { - mf_t *mf = demuxer->priv; - - free_mf(mf); +static void demux_close_mf(demuxer_t *demuxer) +{ } -static int demux_control_mf(demuxer_t *demuxer, int cmd, void *arg) { - mf_t *mf = (mf_t *)demuxer->priv; +static int demux_control_mf(demuxer_t *demuxer, int cmd, void *arg) +{ + mf_t *mf = demuxer->priv; - switch(cmd) { + switch (cmd) { case DEMUXER_CTRL_GET_TIME_LENGTH: - *((double *)arg) = (double)mf->nr_of_files / mf->sh->fps; - return DEMUXER_CTRL_OK; + *((double *)arg) = (double)mf->nr_of_files / mf->sh->fps; + return DEMUXER_CTRL_OK; default: - return DEMUXER_CTRL_NOTIMPL; - } + return DEMUXER_CTRL_NOTIMPL; + } } const demuxer_desc_t demuxer_desc_mf = { diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index 7a9aaa0f87..7a30721e66 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -1355,6 +1355,7 @@ static struct mkv_audio_tag { { MKV_A_DTS, 0, 0x2001 }, { MKV_A_PCM, 0, 0x0001 }, { MKV_A_PCM_BE, 0, 0x0001 }, + { MKV_A_PCM_FLT, 0, 0x0003 }, { MKV_A_AAC_2MAIN, 0, MP_FOURCC('M', 'P', '4', 'A') }, { MKV_A_AAC_2LC, 1, MP_FOURCC('M', 'P', '4', 'A') }, { MKV_A_AAC_2SSR, 0, MP_FOURCC('M', 'P', '4', 'A') }, @@ -1464,10 +1465,10 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track) free(sh_a->wf); sh_a->wf = NULL; } else if (track->a_formattag == 0x0001) { /* PCM || PCM_BE */ - sh_a->wf->nAvgBytesPerSec = sh_a->channels.num * sh_a->samplerate * 2; - sh_a->wf->nBlockAlign = sh_a->wf->nAvgBytesPerSec; if (!strcmp(track->codec_id, MKV_A_PCM_BE)) sh_a->format = MP_FOURCC('t', 'w', 'o', 's'); + } else if (track->a_formattag == 0x0003) { /* PCM_FLT */ + /* ok */ } else if (!strcmp(track->codec_id, MKV_A_QDMC) || !strcmp(track->codec_id, MKV_A_QDMC2)) { sh_a->wf->nAvgBytesPerSec = 16000; 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 <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, |