mirror of
https://github.com/mpv-player/mpv
synced 2024-08-24 07:21:49 +02:00
Remove some demuxers and decoders
Most of these demuxers and decoders are provided in better form by libav, while the mplayer builtin ones are essentially unmaintained. The only legimitate use case for not using the libav ones was working around libav bugs or bugs related to the way mplayer uses libav. Instead of trying to keep dead code alive, development effort should go into improving libav or the mplayer libav glue code. Note that the libav demuxer have been preferred over the mplayer builtin ones for a while in mplayer2. There were some exceptions: playing DVDs with dvdnav or playing network sources. (That's because some stream modules and network.c requested explicit file formats, such as DEMUXER_TYPE_MPEG_PS, which mapped to builtin demuxers.) With this commit, they are switched to use libav. One caveat is that the requested format is not passed to libavformat, instead we rely on the auto probing to select the correct libav demuxer (see code in demux_open_stream()).
This commit is contained in:
parent
17b69493b7
commit
1fde09db6f
30
Makefile
30
Makefile
@ -88,11 +88,9 @@ SRCS_COMMON-$(LIBMAD) += libmpcodecs/ad_libmad.c
|
||||
|
||||
SRCS_COMMON-$(LIBNEMESI) += libmpdemux/demux_nemesi.c \
|
||||
stream/stream_nemesi.c
|
||||
SRCS_COMMON-$(LIBNUT) += libmpdemux/demux_nut.c
|
||||
SRCS_COMMON-$(LIBPOSTPROC) += libmpcodecs/vf_pp.c
|
||||
SRCS_COMMON-$(LIBSMBCLIENT) += stream/stream_smb.c
|
||||
|
||||
SRCS_COMMON-$(LIBTHEORA) += libmpcodecs/vd_theora.c
|
||||
SRCS_COMMON-$(LIVE555) += libmpdemux/demux_rtp.cpp \
|
||||
libmpdemux/demux_rtp_codec.cpp \
|
||||
stream/stream_live555.c
|
||||
@ -103,8 +101,6 @@ SRCS_COMMON-$(COCOA) += libvo/osx_common.c \
|
||||
SRCS_COMMON-$(MNG) += libmpdemux/demux_mng.c
|
||||
SRCS_COMMON-$(MPG123) += libmpcodecs/ad_mpg123.c
|
||||
|
||||
SRCS_COMMON-$(MUSEPACK) += libmpcodecs/ad_mpc.c \
|
||||
libmpdemux/demux_mpc.c
|
||||
SRCS_COMMON-$(NATIVE_RTSP) += stream/stream_rtsp.c \
|
||||
stream/freesdp/common.c \
|
||||
stream/freesdp/errorlist.c \
|
||||
@ -148,7 +144,6 @@ SRCS_COMMON-$(RADIO) += stream/stream_radio.c
|
||||
SRCS_COMMON-$(RADIO_CAPTURE) += stream/audio_in.c
|
||||
SRCS_COMMON-$(REAL_CODECS) += libmpcodecs/ad_realaud.c \
|
||||
libmpcodecs/vd_realvid.c
|
||||
SRCS_COMMON-$(SPEEX) += libmpcodecs/ad_speex.c
|
||||
SRCS_COMMON-$(STREAM_CACHE) += stream/cache2.c
|
||||
|
||||
SRCS_COMMON-$(TV) += stream/stream_tv.c stream/tv.c \
|
||||
@ -161,8 +156,6 @@ SRCS_COMMON-$(TV_DSHOW) += stream/tvi_dshow.c \
|
||||
SRCS_COMMON-$(TV_V4L1) += stream/tvi_v4l.c stream/audio_in.c
|
||||
SRCS_COMMON-$(TV_V4L2) += stream/tvi_v4l2.c stream/audio_in.c
|
||||
SRCS_COMMON-$(VCD) += stream/stream_vcd.c
|
||||
SRCS_COMMON-$(VORBIS) += libmpcodecs/ad_libvorbis.c \
|
||||
libmpdemux/demux_ogg.c
|
||||
SRCS_COMMON-$(VSTREAM) += stream/stream_vstream.c
|
||||
SRCS_QTX_EMULATION += loader/wrapper.S
|
||||
SRCS_COMMON-$(QTX_EMULATION) += $(SRCS_QTX_EMULATION)
|
||||
@ -181,7 +174,6 @@ SRCS_COMMON-$(WIN32_EMULATION) += $(SRCS_WIN32_EMULATION)
|
||||
SRCS_COMMON-$(WIN32DLL) += libmpcodecs/ad_acm.c \
|
||||
libmpcodecs/ad_dmo.c \
|
||||
libmpcodecs/ad_dshow.c \
|
||||
libmpcodecs/ad_twin.c \
|
||||
libmpcodecs/vd_dmo.c \
|
||||
libmpcodecs/vd_dshow.c \
|
||||
libmpcodecs/vd_vfw.c \
|
||||
@ -207,7 +199,6 @@ SRCS_COMMON-$(WIN32DLL) += libmpcodecs/ad_acm.c \
|
||||
loader/dmo/dmo_guids.c \
|
||||
|
||||
SRCS_COMMON-$(XANIM_CODECS) += libmpcodecs/vd_xanim.c
|
||||
SRCS_COMMON-$(XVID4) += libmpcodecs/vd_xvid4.c
|
||||
|
||||
SRCS_COMMON-$(DUMMY_OSD) += sub/osd_dummy.c
|
||||
SRCS_COMMON-$(LIBASS_OSD) += sub/osd_libass.c
|
||||
@ -262,7 +253,6 @@ SRCS_COMMON = asxparser.c \
|
||||
libaf/window.c \
|
||||
libmpcodecs/ad.c \
|
||||
libmpcodecs/ad_alaw.c \
|
||||
libmpcodecs/ad_dk3adpcm.c \
|
||||
libmpcodecs/ad_dvdpcm.c \
|
||||
libmpcodecs/ad_ffmpeg.c \
|
||||
libmpcodecs/ad_hwac3.c \
|
||||
@ -280,11 +270,9 @@ SRCS_COMMON = asxparser.c \
|
||||
libmpcodecs/vd_ffmpeg.c \
|
||||
libmpcodecs/vd_hmblck.c \
|
||||
libmpcodecs/vd_lzo.c \
|
||||
libmpcodecs/vd_mpegpes.c \
|
||||
libmpcodecs/vd_mtga.c \
|
||||
libmpcodecs/vd_null.c \
|
||||
libmpcodecs/vd_raw.c \
|
||||
libmpcodecs/vd_sgi.c \
|
||||
libmpcodecs/vf.c \
|
||||
libmpcodecs/vf_1bpp.c \
|
||||
libmpcodecs/vf_2xsai.c \
|
||||
@ -357,48 +345,30 @@ SRCS_COMMON = asxparser.c \
|
||||
libmpcodecs/vf_yadif.c \
|
||||
libmpcodecs/vf_yuvcsp.c \
|
||||
libmpcodecs/vf_yvu9.c \
|
||||
libmpdemux/aac_hdr.c \
|
||||
libmpdemux/asfheader.c \
|
||||
libmpdemux/aviheader.c \
|
||||
libmpdemux/aviprint.c \
|
||||
libmpdemux/demuxer.c \
|
||||
libmpdemux/demux_aac.c \
|
||||
libmpdemux/demux_asf.c \
|
||||
libmpdemux/demux_audio.c \
|
||||
libmpdemux/demux_avi.c \
|
||||
libmpdemux/demux_demuxers.c \
|
||||
libmpdemux/demux_edl.c \
|
||||
libmpdemux/demux_cue.c \
|
||||
libmpdemux/demux_film.c \
|
||||
libmpdemux/demux_fli.c \
|
||||
libmpdemux/demux_lavf.c \
|
||||
libmpdemux/demux_lmlm4.c \
|
||||
libmpdemux/demux_mf.c \
|
||||
libmpdemux/demux_mkv.c \
|
||||
libmpdemux/demux_mov.c \
|
||||
libmpdemux/demux_mpg.c \
|
||||
libmpdemux/demux_nsv.c \
|
||||
libmpdemux/demux_pva.c \
|
||||
libmpdemux/demux_rawaudio.c \
|
||||
libmpdemux/demux_rawvideo.c \
|
||||
libmpdemux/demux_realaud.c \
|
||||
libmpdemux/demux_real.c \
|
||||
libmpdemux/demux_roq.c \
|
||||
libmpdemux/demux_smjpeg.c \
|
||||
libmpdemux/demux_ts.c \
|
||||
libmpdemux/demux_ty.c \
|
||||
libmpdemux/demux_viv.c \
|
||||
libmpdemux/demux_vqf.c \
|
||||
libmpdemux/demux_y4m.c \
|
||||
libmpdemux/ebml.c \
|
||||
libmpdemux/extension.c \
|
||||
libmpdemux/mf.c \
|
||||
libmpdemux/mp3_hdr.c \
|
||||
libmpdemux/mp_taglists.c \
|
||||
libmpdemux/mpeg_hdr.c \
|
||||
libmpdemux/mpeg_packetizer.c \
|
||||
libmpdemux/parse_es.c \
|
||||
libmpdemux/parse_mp4.c \
|
||||
libmpdemux/video.c \
|
||||
libmpdemux/yuv4mpeg.c \
|
||||
libmpdemux/yuv4mpeg_ratio.c \
|
||||
|
@ -30,7 +30,6 @@
|
||||
#include "config.h"
|
||||
#include "m_config.h"
|
||||
#include "m_option.h"
|
||||
#include "libmpdemux/demux_ts.h"
|
||||
#include "stream/tv.h"
|
||||
#include "stream/stream_radio.h"
|
||||
#include "libvo/csputils.h"
|
||||
@ -77,12 +76,6 @@ extern const m_option_t demux_rawaudio_opts[];
|
||||
extern const m_option_t demux_rawvideo_opts[];
|
||||
extern const m_option_t cdda_opts[];
|
||||
|
||||
extern int ts_prog;
|
||||
extern int ts_keep_broken;
|
||||
extern off_t ts_probe;
|
||||
extern int audio_substream_id;
|
||||
extern off_t ps_probe;
|
||||
|
||||
extern int sws_flags;
|
||||
extern const char pp_help[];
|
||||
|
||||
@ -465,7 +458,6 @@ const m_option_t common_opts[] = {
|
||||
|
||||
// select audio/video/subtitle stream
|
||||
OPT_INTRANGE("aid", audio_id, 0, -2, 8190),
|
||||
{"ausid", &audio_substream_id, CONF_TYPE_INT, 0, 0, 0, NULL},
|
||||
OPT_INTRANGE("vid", video_id, 0, -2, 8190),
|
||||
OPT_INTRANGE("sid", sub_id, 0, -2, 8190),
|
||||
OPT_FLAG_CONSTANTS("no-sub", sub_id, 0, -1, -2),
|
||||
@ -566,10 +558,6 @@ const m_option_t common_opts[] = {
|
||||
|
||||
OPT_FLAG_CONSTANTS("flip", flip, 0, -1, 1),
|
||||
OPT_FLAG_CONSTANTS("no-flip", flip, 0, -1, 0),
|
||||
{"tsprog", &ts_prog, CONF_TYPE_INT, CONF_RANGE, 0, 65534, NULL},
|
||||
{"tsprobe", &ts_probe, CONF_TYPE_POSITION, 0, 0, TS_MAX_PROBE_SIZE, NULL},
|
||||
{"psprobe", &ps_probe, CONF_TYPE_POSITION, 0, 0, TS_MAX_PROBE_SIZE, NULL},
|
||||
{"tskeepbroken", &ts_keep_broken, CONF_TYPE_FLAG, 0, 0, 1, NULL},
|
||||
|
||||
// draw by slices or whole frame (useful with libmpeg2/libavcodec)
|
||||
OPT_MAKE_FLAGS("slices", vd_use_slices, 0),
|
||||
|
@ -1610,8 +1610,7 @@ static int mp_property_sub(m_option_t *prop, int action, void *arg,
|
||||
|
||||
if ((d_sub->demuxer->type == DEMUXER_TYPE_MATROSKA
|
||||
|| d_sub->demuxer->type == DEMUXER_TYPE_LAVF
|
||||
|| d_sub->demuxer->type == DEMUXER_TYPE_LAVF_PREFERRED
|
||||
|| d_sub->demuxer->type == DEMUXER_TYPE_OGG)
|
||||
|| d_sub->demuxer->type == DEMUXER_TYPE_LAVF_PREFERRED)
|
||||
&& d_sub->sh && opts->sub_id >= 0) {
|
||||
struct sh_sub *sh = d_sub->sh;
|
||||
char *lang = sh->lang ? sh->lang : mp_gtext("unknown");
|
||||
|
166
configure
vendored
166
configure
vendored
@ -349,13 +349,7 @@ Codecs:
|
||||
--disable-qtx disable QuickTime codecs support [enabled]
|
||||
--disable-xanim disable XAnim codecs support [enabled]
|
||||
--disable-real disable RealPlayer codecs support [enabled]
|
||||
--disable-xvid disable Xvid [autodetect]
|
||||
--disable-libnut disable libnut [autodetect]
|
||||
--enable-libav skip Libav autodetection [autodetect]
|
||||
--disable-libvorbis disable libvorbis support [autodetect]
|
||||
--disable-tremor disable Tremor [autodetect if no libvorbis]
|
||||
--disable-speex disable Speex support [autodetect]
|
||||
--enable-theora enable OggTheora libraries [autodetect]
|
||||
--enable-faad enable FAAD2 (AAC) [autodetect]
|
||||
--disable-ladspa disable LADSPA plugin support [autodetect]
|
||||
--disable-libbs2b disable libbs2b audio filter support [autodetect]
|
||||
@ -364,8 +358,6 @@ Codecs:
|
||||
--disable-mad disable libmad (MPEG audio) support [autodetect]
|
||||
--enable-libdca enable libdca support [autodetect]
|
||||
--disable-liba52 disable liba52 [autodetect]
|
||||
--enable-musepack enable libmpcdec support (deprecated, libavcodec
|
||||
Musepack decoder is preferred) [disabled]
|
||||
|
||||
Video output:
|
||||
--enable-gl enable OpenGL video output [autodetect]
|
||||
@ -492,10 +484,6 @@ _jack=auto
|
||||
_openal=no
|
||||
_libcdio=auto
|
||||
_mad=auto
|
||||
_tremor=auto
|
||||
_libvorbis=auto
|
||||
_speex=auto
|
||||
_theora=auto
|
||||
_mpg123=auto
|
||||
_liba52=auto
|
||||
_libdca=auto
|
||||
@ -538,8 +526,6 @@ _winsock2_h=auto
|
||||
_smb=auto
|
||||
_libquvi=auto
|
||||
_joystick=no
|
||||
_xvid=auto
|
||||
_libnut=auto
|
||||
_lirc=auto
|
||||
_lircc=auto
|
||||
_apple_remote=auto
|
||||
@ -568,7 +554,6 @@ _enca=auto
|
||||
_inet6=auto
|
||||
_gethostbyname2=auto
|
||||
_ftp=auto
|
||||
_musepack=no
|
||||
_vstream=auto
|
||||
_pthreads=auto
|
||||
_w32threads=auto
|
||||
@ -751,22 +736,12 @@ for ac_option do
|
||||
--disable-mad) _mad=no ;;
|
||||
--enable-libcdio) _libcdio=yes ;;
|
||||
--disable-libcdio) _libcdio=no ;;
|
||||
--enable-libvorbis) _libvorbis=yes ;;
|
||||
--disable-libvorbis) _libvorbis=no ;;
|
||||
--enable-speex) _speex=yes ;;
|
||||
--disable-speex) _speex=no ;;
|
||||
--enable-tremor) _tremor=yes ;;
|
||||
--disable-tremor) _tremor=no ;;
|
||||
--enable-theora) _theora=yes ;;
|
||||
--disable-theora) _theora=no ;;
|
||||
--enable-mpg123) _mpg123=yes ;;
|
||||
--disable-mpg123) _mpg123=no ;;
|
||||
--enable-liba52) _liba52=yes ;;
|
||||
--disable-liba52) _liba52=no ;;
|
||||
--enable-libdca) _libdca=yes ;;
|
||||
--disable-libdca) _libdca=no ;;
|
||||
--enable-musepack) _musepack=yes ;;
|
||||
--disable-musepack) _musepack=no ;;
|
||||
--enable-faad) _faad=yes ;;
|
||||
--disable-faad) _faad=no ;;
|
||||
--enable-ladspa) _ladspa=yes ;;
|
||||
@ -835,10 +810,6 @@ for ac_option do
|
||||
--disable-libquvi) _libquvi=no ;;
|
||||
--enable-joystick) _joystick=yes ;;
|
||||
--disable-joystick) _joystick=no ;;
|
||||
--enable-xvid) _xvid=yes ;;
|
||||
--disable-xvid) _xvid=no ;;
|
||||
--enable-libnut) _libnut=yes ;;
|
||||
--disable-libnut) _libnut=no ;;
|
||||
--enable-libav) ffmpeg=yes ;;
|
||||
--ffmpeg-source-dir=*)
|
||||
_ffmpeg_source=$(echo $ac_option | cut -d '=' -f 2 ) ;;
|
||||
@ -3396,71 +3367,6 @@ else
|
||||
fi
|
||||
echores "$_mad"
|
||||
|
||||
echocheck "OggVorbis support"
|
||||
if test "$_libvorbis" = auto; then
|
||||
_libvorbis=no
|
||||
statement_check vorbis/codec.h 'vorbis_packet_blocksize(0, 0)' -lvorbis -logg $_ld_lm && _libvorbis=yes && _tremor=no
|
||||
elif test "$_libvorbis" = yes ; then
|
||||
_tremor=no
|
||||
fi
|
||||
if test "$_tremor" = auto; then
|
||||
_tremor=no
|
||||
statement_check tremor/ivorbiscodec.h 'vorbis_packet_blocksize(0, 0)' -logg -lvorbisidec $_ld_lm && _tremor=yes
|
||||
fi
|
||||
if test "$_tremor" = yes ; then
|
||||
_vorbis=yes
|
||||
def_vorbis='#define CONFIG_OGGVORBIS 1'
|
||||
def_tremor='#define CONFIG_TREMOR 1'
|
||||
codecmodules="tremor(external) $codecmodules"
|
||||
res_comment="external Tremor"
|
||||
extra_ldflags="$extra_ldflags -logg -lvorbisidec"
|
||||
elif test "$_libvorbis" = yes ; then
|
||||
_vorbis=yes
|
||||
def_vorbis='#define CONFIG_OGGVORBIS 1'
|
||||
codecmodules="libvorbis $codecmodules"
|
||||
res_comment="libvorbis"
|
||||
extra_ldflags="$extra_ldflags -lvorbis -logg"
|
||||
else
|
||||
_vorbis=no
|
||||
nocodecmodules="libvorbis $nocodecmodules"
|
||||
fi
|
||||
echores "$_vorbis"
|
||||
|
||||
echocheck "libspeex (version >= 1.1 required)"
|
||||
if test "$_speex" = auto ; then
|
||||
_speex=no
|
||||
cat > $TMPC << EOF
|
||||
#include <stddef.h>
|
||||
#include <speex/speex.h>
|
||||
int main(void) { SpeexBits bits; void *dec = NULL; speex_decode_int(dec, &bits, dec); return 0; }
|
||||
EOF
|
||||
cc_check -lspeex $_ld_lm && _speex=yes
|
||||
fi
|
||||
if test "$_speex" = yes ; then
|
||||
def_speex='#define CONFIG_SPEEX 1'
|
||||
extra_ldflags="$extra_ldflags -lspeex"
|
||||
codecmodules="speex $codecmodules"
|
||||
else
|
||||
def_speex='#undef CONFIG_SPEEX'
|
||||
nocodecmodules="speex $nocodecmodules"
|
||||
fi
|
||||
echores "$_speex"
|
||||
|
||||
echocheck "OggTheora support"
|
||||
if test "$_theora" = auto ; then
|
||||
_theora=no
|
||||
if pkg_config_add theora ; then
|
||||
_theora=yes
|
||||
fi
|
||||
fi
|
||||
if test "$_theora" = yes ; then
|
||||
def_theora='#define CONFIG_OGGTHEORA 1'
|
||||
codecmodules="libtheora $codecmodules"
|
||||
else
|
||||
def_theora='#undef CONFIG_OGGTHEORA'
|
||||
nocodecmodules="libtheora $nocodecmodules"
|
||||
fi
|
||||
echores "$_theora"
|
||||
|
||||
# Any version of libmpg123 that knows MPG123_RESYNC_LIMIT shall be fine.
|
||||
# That is, 1.2.0 onwards. Recommened is 1.14 onwards, though.
|
||||
@ -3514,32 +3420,6 @@ else
|
||||
fi
|
||||
echores "$_libdca"
|
||||
|
||||
echocheck "libmpcdec (musepack, version >= 1.2.1 required)"
|
||||
if test "$_musepack" = yes ; then
|
||||
_musepack=no
|
||||
cat > $TMPC << EOF
|
||||
#include <stddef.h>
|
||||
#include <mpcdec/mpcdec.h>
|
||||
int main(void) {
|
||||
mpc_streaminfo info;
|
||||
mpc_decoder decoder;
|
||||
mpc_decoder_set_streaminfo(&decoder, &info);
|
||||
mpc_decoder_decode_frame(&decoder, NULL, 0, NULL);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
cc_check -lmpcdec $_ld_lm && _musepack=yes
|
||||
fi
|
||||
if test "$_musepack" = yes ; then
|
||||
def_musepack='#define CONFIG_MUSEPACK 1'
|
||||
extra_ldflags="$extra_ldflags -lmpcdec"
|
||||
codecmodules="musepack $codecmodules"
|
||||
else
|
||||
def_musepack='#undef CONFIG_MUSEPACK'
|
||||
nocodecmodules="musepack $nocodecmodules"
|
||||
fi
|
||||
echores "$_musepack"
|
||||
|
||||
|
||||
echocheck "FAAD2 support"
|
||||
if test "$_faad" = auto ; then
|
||||
@ -3819,40 +3699,6 @@ fi
|
||||
echores "$_libdv"
|
||||
|
||||
|
||||
echocheck "Xvid"
|
||||
if test "$_xvid" = auto ; then
|
||||
_xvid=no
|
||||
for _ld_tmp in "-lxvidcore $_ld_lm" "-lxvidcore $_ld_lm $_ld_pthread" ; do
|
||||
statement_check xvid.h 'xvid_global(0, 0, 0, 0)' $_ld_tmp &&
|
||||
extra_ldflags="$extra_ldflags $_ld_tmp" && _xvid=yes && break
|
||||
done
|
||||
fi
|
||||
|
||||
if test "$_xvid" = yes ; then
|
||||
def_xvid='#define CONFIG_XVID4 1'
|
||||
codecmodules="xvid $codecmodules"
|
||||
else
|
||||
def_xvid='#undef CONFIG_XVID4'
|
||||
nocodecmodules="xvid $nocodecmodules"
|
||||
fi
|
||||
echores "$_xvid"
|
||||
|
||||
|
||||
echocheck "libnut"
|
||||
if test "$_libnut" = auto ; then
|
||||
_libnut=no
|
||||
statement_check libnut.h 'nut_context_tt * nut; nut_error(0)' -lnut && _libnut=yes
|
||||
fi
|
||||
|
||||
if test "$_libnut" = yes ; then
|
||||
def_libnut='#define CONFIG_LIBNUT 1'
|
||||
extra_ldflags="$extra_ldflags -lnut"
|
||||
else
|
||||
def_libnut='#undef CONFIG_LIBNUT'
|
||||
fi
|
||||
echores "$_libnut"
|
||||
|
||||
|
||||
echocheck "TV interface"
|
||||
if test "$_tv" = yes ; then
|
||||
def_tv='#define CONFIG_TV 1'
|
||||
@ -4391,7 +4237,6 @@ LIBDVDCSS_INTERNAL = $_libdvdcss_internal
|
||||
LIBMAD = $_mad
|
||||
LIBNEMESI = $_nemesi
|
||||
LCMS2 = $_lcms2
|
||||
LIBNUT = $_libnut
|
||||
LIBPOSTPROC = $libpostproc
|
||||
LIBSMBCLIENT = $_smb
|
||||
LIBQUVI = $_libquvi
|
||||
@ -4402,7 +4247,6 @@ MACOSX_FINDER = $_macosx_finder
|
||||
MD5SUM = $_md5sum
|
||||
MNG = $_mng
|
||||
MPG123 = $_mpg123
|
||||
MUSEPACK = $_musepack
|
||||
NATIVE_RTSP = $_native_rtsp
|
||||
NETWORKING = $networking
|
||||
OPENAL = $_openal
|
||||
@ -4421,7 +4265,6 @@ RADIO=$_radio
|
||||
RADIO_CAPTURE=$_radio_capture
|
||||
REAL_CODECS = $_real
|
||||
RSOUND = $_rsound
|
||||
SPEEX = $_speex
|
||||
STREAM_CACHE = $_stream_cache
|
||||
TGA = $_tga
|
||||
TV = $_tv
|
||||
@ -4433,14 +4276,12 @@ TV_V4L2 = $_tv_v4l2
|
||||
V4L2 = $_v4l2
|
||||
VCD = $_vcd
|
||||
VDPAU = $_vdpau
|
||||
VORBIS = $_vorbis
|
||||
VSTREAM = $_vstream
|
||||
WIN32DLL = $_win32dll
|
||||
WIN32_EMULATION = $_win32_emulation
|
||||
X11 = $_x11
|
||||
XANIM_CODECS = $_xanim
|
||||
XV = $_xv
|
||||
XVID4 = $_xvid
|
||||
YUV4MPEG = $_yuv4mpeg
|
||||
|
||||
# FFmpeg
|
||||
@ -4624,16 +4465,9 @@ $def_libdca
|
||||
$def_libdv
|
||||
$def_mad
|
||||
$def_mpg123
|
||||
$def_musepack
|
||||
$def_speex
|
||||
$def_theora
|
||||
$def_tremor
|
||||
$def_vorbis
|
||||
$def_xvid
|
||||
$def_zlib
|
||||
|
||||
$def_libpostproc
|
||||
$def_libnut
|
||||
|
||||
|
||||
/* binary codecs */
|
||||
|
111
etc/codecs.conf
111
etc/codecs.conf
@ -445,13 +445,6 @@ videocodec ffsgi
|
||||
driver ffmpeg
|
||||
dll sgi
|
||||
|
||||
videocodec sgi
|
||||
info "SGI image"
|
||||
status working
|
||||
fourcc SGI1 ; SGI1 is an internal MPlayer FOURCC
|
||||
driver sgi
|
||||
out BGR24
|
||||
|
||||
videocodec ffsunras
|
||||
info "FFmpeg SUN Rasterfile"
|
||||
status working
|
||||
@ -562,14 +555,6 @@ videocodec lzo
|
||||
out YV12,I420
|
||||
out BGR24 flip
|
||||
|
||||
videocodec theora
|
||||
info "Theora (free, reworked VP3)"
|
||||
status working
|
||||
fourcc theo,Thra
|
||||
driver theora
|
||||
dll libtheora
|
||||
out YV12,422P,444P
|
||||
|
||||
; prefer native codecs over win32?
|
||||
; the win32 codecs probably are (better) optimized and support direct
|
||||
; rendering, so this may be not the best idea...
|
||||
@ -1099,41 +1084,6 @@ videocodec fflibdirac
|
||||
driver ffmpeg
|
||||
dll libdirac
|
||||
|
||||
videocodec xvid
|
||||
info "Xvid (MPEG-4)"
|
||||
status working
|
||||
fourcc FMP4,fmp4
|
||||
fourcc DIVX,divx
|
||||
fourcc xvid,XVID,XviD,XVIX
|
||||
fourcc DIV1,div1 divx
|
||||
fourcc MP4S,mp4s ; ISO MPEG-4 Video V1
|
||||
fourcc M4S2,m4s2
|
||||
fourcc DX50,dx50,BLZ0 DX50
|
||||
fourcc mp4v,MP4V
|
||||
format 0x4
|
||||
fourcc UMP4
|
||||
fourcc RMP4
|
||||
fourcc 3IV2,3iv2 ; 3ivx Delta 4
|
||||
fourcc DXGM
|
||||
fourcc SEDG ; diskless camcorder Samsung Miniket VP-M110
|
||||
fourcc SMP4,smp4 ; Samsung SMP4 video codec
|
||||
fourcc VIDM ; vidm 4.01 codec
|
||||
fourcc FFDS
|
||||
fourcc DCOD,MVXM,EM4A,PM4V
|
||||
fourcc M4T3,DMK2,DIGI,INMC
|
||||
fourcc EPHV,SN40,WAWV
|
||||
fourcc uldx,ULDX,VSPX
|
||||
format 0x10000004 ; mpeg 4 es
|
||||
fourcc SIPP ; Samsung SHR-6040
|
||||
driver xvid
|
||||
out YV12
|
||||
out I420
|
||||
out YUY2
|
||||
out UYVY
|
||||
out YVYU
|
||||
out BGR32,BGR24,BGR16,BGR15
|
||||
dll "libxvidcore.a"
|
||||
|
||||
; is divx4vfw stable enough, working everywhere and faster than divxds?
|
||||
|
||||
videocodec divx4vfw
|
||||
@ -3860,13 +3810,6 @@ audiocodec ffadpcmimadk3
|
||||
driver ffmpeg
|
||||
dll adpcm_ima_dk3
|
||||
|
||||
audiocodec dk3adpcm
|
||||
info "Duck DK3 ADPCM (rogue format number)"
|
||||
status working
|
||||
format 0x62 ; This format number was used by Duck Corp. but not officially
|
||||
; registered with Microsoft
|
||||
driver dk3adpcm
|
||||
|
||||
audiocodec ffroqaudio
|
||||
info "Id RoQ File Audio"
|
||||
status working
|
||||
@ -4501,13 +4444,6 @@ audiocodec ffmusepack8
|
||||
driver ffmpeg
|
||||
dll "mpc8"
|
||||
|
||||
audiocodec musepack
|
||||
info "Musepack audio codec"
|
||||
status working
|
||||
fourcc "MPC "
|
||||
format 0x2b4d
|
||||
driver mpcdec
|
||||
|
||||
audiocodec ffamrnb
|
||||
info "AMR Narrowband"
|
||||
status working
|
||||
@ -4630,46 +4566,6 @@ audiocodec ffvorbis
|
||||
driver ffmpeg
|
||||
dll "vorbis"
|
||||
|
||||
audiocodec vorbis
|
||||
info "OggVorbis Audio"
|
||||
status working
|
||||
comment "OggVorbis driver using libvorbis"
|
||||
fourcc vrbs
|
||||
format 0x566F
|
||||
driver libvorbis
|
||||
dll "libvorbis"
|
||||
|
||||
audiocodec tremor
|
||||
info "OggVorbis audio"
|
||||
status working
|
||||
comment "fixed-point decoder useful for systems without floating-point unit"
|
||||
fourcc vrbs
|
||||
format 0x566F
|
||||
driver tremor
|
||||
dll "tremor"
|
||||
|
||||
audiocodec vorbisacm
|
||||
info "OggVorbis ACM"
|
||||
status working
|
||||
comment "OggVorbis driver using vorbis.acm"
|
||||
format 0x674F ; mode1
|
||||
format 0x6750 ; mode2
|
||||
; format 0x6751 ; mode3
|
||||
format 0x676F ; mode1+
|
||||
format 0x6770 ; mode2+
|
||||
format 0x6771 ; mode3+
|
||||
driver acm
|
||||
dll "vorbis.acm"
|
||||
|
||||
audiocodec speex
|
||||
info "Speex audio"
|
||||
status working
|
||||
comment "Speex driver using libspeex"
|
||||
fourcc 'spx '
|
||||
format 0xA109
|
||||
driver speex
|
||||
dll "speex"
|
||||
|
||||
audiocodec vivoaudio
|
||||
info "Vivo G.723/Siren Audio Codec"
|
||||
status working
|
||||
@ -4797,13 +4693,6 @@ audiocodec fftwinvq
|
||||
driver ffmpeg
|
||||
dll twinvq
|
||||
|
||||
audiocodec TwinVQ
|
||||
info "VQF codec by NTTLabs"
|
||||
status working
|
||||
fourcc TWIN
|
||||
driver vqf
|
||||
dll "tvqdec.dll"
|
||||
|
||||
audiocodec hwmpa
|
||||
info "MPEG audio pass-through for hardware MPEG decoders"
|
||||
status working
|
||||
|
@ -41,20 +41,14 @@ extern const ad_functions_t mpcodecs_ad_dvdpcm;
|
||||
extern const ad_functions_t mpcodecs_ad_alaw;
|
||||
extern const ad_functions_t mpcodecs_ad_imaadpcm;
|
||||
extern const ad_functions_t mpcodecs_ad_msadpcm;
|
||||
extern const ad_functions_t mpcodecs_ad_dk3adpcm;
|
||||
extern const ad_functions_t mpcodecs_ad_dk4adpcm;
|
||||
extern const ad_functions_t mpcodecs_ad_dshow;
|
||||
extern const ad_functions_t mpcodecs_ad_dmo;
|
||||
extern const ad_functions_t mpcodecs_ad_acm;
|
||||
extern const ad_functions_t mpcodecs_ad_faad;
|
||||
extern const ad_functions_t mpcodecs_ad_libvorbis;
|
||||
extern const ad_functions_t mpcodecs_ad_speex;
|
||||
extern const ad_functions_t mpcodecs_ad_libmad;
|
||||
extern const ad_functions_t mpcodecs_ad_realaud;
|
||||
extern const ad_functions_t mpcodecs_ad_libdv;
|
||||
extern const ad_functions_t mpcodecs_ad_qtaudio;
|
||||
extern const ad_functions_t mpcodecs_ad_twin;
|
||||
extern const ad_functions_t mpcodecs_ad_libmusepack;
|
||||
extern const ad_functions_t mpcodecs_ad_libdca;
|
||||
|
||||
const ad_functions_t * const mpcodecs_ad_drivers[] =
|
||||
@ -73,7 +67,6 @@ const ad_functions_t * const mpcodecs_ad_drivers[] =
|
||||
&mpcodecs_ad_alaw,
|
||||
&mpcodecs_ad_imaadpcm,
|
||||
&mpcodecs_ad_msadpcm,
|
||||
&mpcodecs_ad_dk3adpcm,
|
||||
#ifdef CONFIG_WIN32DLL
|
||||
&mpcodecs_ad_dshow,
|
||||
&mpcodecs_ad_dmo,
|
||||
@ -86,12 +79,6 @@ const ad_functions_t * const mpcodecs_ad_drivers[] =
|
||||
#ifdef CONFIG_FAAD
|
||||
&mpcodecs_ad_faad,
|
||||
#endif
|
||||
#ifdef CONFIG_OGGVORBIS
|
||||
&mpcodecs_ad_libvorbis,
|
||||
#endif
|
||||
#ifdef CONFIG_SPEEX
|
||||
&mpcodecs_ad_speex,
|
||||
#endif
|
||||
#ifdef CONFIG_LIBMAD
|
||||
&mpcodecs_ad_libmad,
|
||||
#endif
|
||||
@ -101,9 +88,6 @@ const ad_functions_t * const mpcodecs_ad_drivers[] =
|
||||
#ifdef CONFIG_LIBDV095
|
||||
&mpcodecs_ad_libdv,
|
||||
#endif
|
||||
#ifdef CONFIG_MUSEPACK
|
||||
&mpcodecs_ad_libmusepack,
|
||||
#endif
|
||||
#ifdef CONFIG_LIBDCA
|
||||
&mpcodecs_ad_libdca,
|
||||
#endif
|
||||
|
@ -1,262 +0,0 @@
|
||||
/*
|
||||
* DK3 ADPCM decoder
|
||||
*
|
||||
* "This format number was used by Duck Corp. but not officially
|
||||
* registered with Microsoft"
|
||||
*
|
||||
* This file is responsible for decoding audio data encoded with
|
||||
* Duck Corp's DK3 ADPCM algorithm. Details about the data format
|
||||
* can be found here:
|
||||
* http://www.pcisys.net/~melanson/codecs/
|
||||
*
|
||||
* Copyright (c) 2002 Mike Melanson
|
||||
*
|
||||
* 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 <libavutil/intreadwrite.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "ad_internal.h"
|
||||
|
||||
static const ad_info_t info =
|
||||
{
|
||||
"Duck Corp. DK3 ADPCM decoder",
|
||||
"dk3adpcm",
|
||||
"Nick Kurshev",
|
||||
"Mike Melanson",
|
||||
""
|
||||
};
|
||||
|
||||
LIBAD_EXTERN(dk3adpcm)
|
||||
|
||||
#define DK3_ADPCM_PREAMBLE_SIZE 16
|
||||
|
||||
// useful macros
|
||||
// clamp a number between 0 and 88
|
||||
#define CLAMP_0_TO_88(x) if (x < 0) x = 0; else if (x > 88) x = 88;
|
||||
// clamp a number within a signed 16-bit range
|
||||
#define CLAMP_S16(x) if (x < -32768) x = -32768; \
|
||||
else if (x > 32767) x = 32767;
|
||||
// clamp a number above 16
|
||||
#define CLAMP_ABOVE_16(x) if (x < 16) x = 16;
|
||||
// sign extend a 16-bit value
|
||||
#define SE_16BIT(x) if (x & 0x8000) x -= 0x10000;
|
||||
// sign extend a 4-bit value
|
||||
#define SE_4BIT(x) if (x & 0x8) x -= 0x10;
|
||||
|
||||
// pertinent tables
|
||||
static int adpcm_step[89] =
|
||||
{
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
|
||||
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
|
||||
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
|
||||
130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
|
||||
337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
|
||||
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
|
||||
2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
|
||||
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
|
||||
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
|
||||
};
|
||||
|
||||
static int adpcm_index[16] =
|
||||
{
|
||||
-1, -1, -1, -1, 2, 4, 6, 8,
|
||||
-1, -1, -1, -1, 2, 4, 6, 8
|
||||
};
|
||||
|
||||
static int preinit(sh_audio_t *sh_audio)
|
||||
{
|
||||
sh_audio->audio_out_minsize = sh_audio->wf->nBlockAlign * 6;
|
||||
sh_audio->ds->ss_div =
|
||||
(sh_audio->wf->nBlockAlign - DK3_ADPCM_PREAMBLE_SIZE) * 8 / 3;
|
||||
sh_audio->audio_in_minsize=
|
||||
sh_audio->ds->ss_mul = sh_audio->wf->nBlockAlign;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int init(sh_audio_t *sh_audio)
|
||||
{
|
||||
sh_audio->channels = sh_audio->wf->nChannels;
|
||||
sh_audio->samplerate = sh_audio->wf->nSamplesPerSec;
|
||||
sh_audio->i_bps =
|
||||
(sh_audio->ds->ss_mul * sh_audio->samplerate) / sh_audio->ds->ss_div;
|
||||
sh_audio->samplesize=2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void uninit(sh_audio_t *sh_audio)
|
||||
{
|
||||
}
|
||||
|
||||
static int control(sh_audio_t *sh_audio,int cmd,void* arg, ...)
|
||||
{
|
||||
if(cmd==ADCTRL_SKIP_FRAME){
|
||||
demux_read_data(sh_audio->ds, sh_audio->a_in_buffer,sh_audio->ds->ss_mul);
|
||||
return CONTROL_TRUE;
|
||||
}
|
||||
return CONTROL_UNKNOWN;
|
||||
}
|
||||
|
||||
#define DK3_GET_NEXT_NIBBLE() \
|
||||
if (decode_top_nibble_next) \
|
||||
{ \
|
||||
nibble = (last_byte >> 4) & 0x0F; \
|
||||
decode_top_nibble_next = 0; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
last_byte = input[in_ptr++]; \
|
||||
nibble = last_byte & 0x0F; \
|
||||
decode_top_nibble_next = 1; \
|
||||
}
|
||||
|
||||
// note: This decoder assumes the format 0x62 data always comes in
|
||||
// stereo flavor
|
||||
static int dk3_adpcm_decode_block(unsigned short *output, unsigned char *input,
|
||||
int block_size)
|
||||
{
|
||||
int sum_pred;
|
||||
int diff_pred;
|
||||
int sum_index;
|
||||
int diff_index;
|
||||
int diff_channel;
|
||||
int in_ptr = 0x10;
|
||||
int out_ptr = 0;
|
||||
|
||||
unsigned char last_byte = 0;
|
||||
unsigned char nibble;
|
||||
int decode_top_nibble_next = 0;
|
||||
|
||||
// ADPCM work variables
|
||||
int sign;
|
||||
int delta;
|
||||
int step;
|
||||
int diff;
|
||||
|
||||
sum_pred = AV_RL16(&input[10]);
|
||||
diff_pred = AV_RL16(&input[12]);
|
||||
SE_16BIT(sum_pred);
|
||||
SE_16BIT(diff_pred);
|
||||
diff_channel = diff_pred;
|
||||
sum_index = input[14];
|
||||
diff_index = input[15];
|
||||
|
||||
while (in_ptr < block_size - !decode_top_nibble_next)
|
||||
// while (in_ptr < 2048)
|
||||
{
|
||||
// process the first predictor of the sum channel
|
||||
DK3_GET_NEXT_NIBBLE();
|
||||
|
||||
step = adpcm_step[sum_index];
|
||||
|
||||
sign = nibble & 8;
|
||||
delta = nibble & 7;
|
||||
|
||||
diff = step >> 3;
|
||||
if (delta & 4) diff += step;
|
||||
if (delta & 2) diff += step >> 1;
|
||||
if (delta & 1) diff += step >> 2;
|
||||
|
||||
if (sign)
|
||||
sum_pred -= diff;
|
||||
else
|
||||
sum_pred += diff;
|
||||
|
||||
CLAMP_S16(sum_pred);
|
||||
|
||||
sum_index += adpcm_index[nibble];
|
||||
CLAMP_0_TO_88(sum_index);
|
||||
|
||||
// process the diff channel predictor
|
||||
DK3_GET_NEXT_NIBBLE();
|
||||
|
||||
step = adpcm_step[diff_index];
|
||||
|
||||
sign = nibble & 8;
|
||||
delta = nibble & 7;
|
||||
|
||||
diff = step >> 3;
|
||||
if (delta & 4) diff += step;
|
||||
if (delta & 2) diff += step >> 1;
|
||||
if (delta & 1) diff += step >> 2;
|
||||
|
||||
if (sign)
|
||||
diff_pred -= diff;
|
||||
else
|
||||
diff_pred += diff;
|
||||
|
||||
CLAMP_S16(diff_pred);
|
||||
|
||||
diff_index += adpcm_index[nibble];
|
||||
CLAMP_0_TO_88(diff_index);
|
||||
|
||||
// output the first pair of stereo PCM samples
|
||||
diff_channel = (diff_channel + diff_pred) / 2;
|
||||
output[out_ptr++] = sum_pred + diff_channel;
|
||||
output[out_ptr++] = sum_pred - diff_channel;
|
||||
|
||||
// process the second predictor of the sum channel
|
||||
DK3_GET_NEXT_NIBBLE();
|
||||
|
||||
step = adpcm_step[sum_index];
|
||||
|
||||
sign = nibble & 8;
|
||||
delta = nibble & 7;
|
||||
|
||||
diff = step >> 3;
|
||||
if (delta & 4) diff += step;
|
||||
if (delta & 2) diff += step >> 1;
|
||||
if (delta & 1) diff += step >> 2;
|
||||
|
||||
if (sign)
|
||||
sum_pred -= diff;
|
||||
else
|
||||
sum_pred += diff;
|
||||
|
||||
CLAMP_S16(sum_pred);
|
||||
|
||||
sum_index += adpcm_index[nibble];
|
||||
CLAMP_0_TO_88(sum_index);
|
||||
|
||||
// output the second pair of stereo PCM samples
|
||||
output[out_ptr++] = sum_pred + diff_channel;
|
||||
output[out_ptr++] = sum_pred - diff_channel;
|
||||
}
|
||||
|
||||
return out_ptr;
|
||||
}
|
||||
|
||||
static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen)
|
||||
{
|
||||
if (demux_read_data(sh_audio->ds, sh_audio->a_in_buffer,
|
||||
sh_audio->ds->ss_mul) !=
|
||||
sh_audio->ds->ss_mul)
|
||||
return -1; /* EOF */
|
||||
|
||||
if (maxlen < 2 * 4 * sh_audio->wf->nBlockAlign * 2 / 3) {
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_V, "dk3adpcm: maxlen too small in decode_audio\n");
|
||||
return -1;
|
||||
}
|
||||
return 2 * dk3_adpcm_decode_block(
|
||||
(unsigned short*)buf, sh_audio->a_in_buffer,
|
||||
sh_audio->ds->ss_mul);
|
||||
}
|
@ -1,350 +0,0 @@
|
||||
/*
|
||||
* 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 <stdarg.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "ad_internal.h"
|
||||
#include "libaf/reorder_ch.h"
|
||||
|
||||
static const ad_info_t info =
|
||||
{
|
||||
"Ogg/Vorbis audio decoder",
|
||||
#ifdef CONFIG_TREMOR
|
||||
"tremor",
|
||||
#else
|
||||
"libvorbis",
|
||||
#endif
|
||||
"Felix Buenemann, A'rpi",
|
||||
"libvorbis",
|
||||
""
|
||||
};
|
||||
|
||||
LIBAD_EXTERN(libvorbis)
|
||||
|
||||
#ifdef CONFIG_TREMOR
|
||||
#include <tremor/ivorbiscodec.h>
|
||||
#else
|
||||
#include <vorbis/codec.h>
|
||||
#endif
|
||||
|
||||
// This struct is also defined in demux_ogg.c => common header ?
|
||||
typedef struct ov_struct_st {
|
||||
vorbis_info vi; /* struct that stores all the static vorbis bitstream
|
||||
settings */
|
||||
vorbis_comment vc; /* struct that stores all the bitstream user comments */
|
||||
vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
|
||||
vorbis_block vb; /* local working space for packet->PCM decode */
|
||||
float rg_scale; /* replaygain scale */
|
||||
#ifdef CONFIG_TREMOR
|
||||
int rg_scale_int;
|
||||
#endif
|
||||
} ov_struct_t;
|
||||
|
||||
static int read_vorbis_comment( char* ptr, const char* comment, const char* format, ... ) {
|
||||
va_list va;
|
||||
int clen, ret;
|
||||
|
||||
va_start( va, format );
|
||||
clen = strlen( comment );
|
||||
ret = strncasecmp( ptr, comment, clen) == 0 ? vsscanf( ptr+clen, format, va ) : 0;
|
||||
va_end( va );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int preinit(sh_audio_t *sh)
|
||||
{
|
||||
sh->audio_out_minsize=1024*4; // 1024 samples/frame
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int init(sh_audio_t *sh)
|
||||
{
|
||||
unsigned int offset, i, length, hsizes[3];
|
||||
void *headers[3];
|
||||
unsigned char* extradata;
|
||||
ogg_packet op;
|
||||
vorbis_comment vc;
|
||||
struct ov_struct_st *ov;
|
||||
#define ERROR() { \
|
||||
vorbis_comment_clear(&vc); \
|
||||
vorbis_info_clear(&ov->vi); \
|
||||
free(ov); \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
/// Init the decoder with the 3 header packets
|
||||
ov = malloc(sizeof(struct ov_struct_st));
|
||||
vorbis_info_init(&ov->vi);
|
||||
vorbis_comment_init(&vc);
|
||||
|
||||
if(! sh->wf) {
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_ERR,"ad_vorbis, extradata seems to be absent! exit\n");
|
||||
ERROR();
|
||||
}
|
||||
|
||||
if(! sh->wf->cbSize) {
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_ERR,"ad_vorbis, extradata seems to be absent!, exit\n");
|
||||
ERROR();
|
||||
}
|
||||
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_V,"ad_vorbis, extradata seems is %d bytes long\n", sh->wf->cbSize);
|
||||
extradata = (char*) (sh->wf+1);
|
||||
if(!extradata) {
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_ERR,"ad_vorbis, extradata seems to be NULL!, exit\n");
|
||||
ERROR();
|
||||
}
|
||||
|
||||
if(*extradata != 2) {
|
||||
mp_msg (MSGT_DEMUX, MSGL_WARN, "ad_vorbis: Vorbis track does not contain valid headers.\n");
|
||||
ERROR();
|
||||
}
|
||||
|
||||
offset = 1;
|
||||
for (i=0; i < 2; i++) {
|
||||
length = 0;
|
||||
while ((extradata[offset] == (unsigned char) 0xFF) && length < sh->wf->cbSize) {
|
||||
length += 255;
|
||||
offset++;
|
||||
}
|
||||
if(offset >= (sh->wf->cbSize - 1)) {
|
||||
mp_msg (MSGT_DEMUX, MSGL_WARN, "ad_vorbis: Vorbis track does not contain valid headers.\n");
|
||||
ERROR();
|
||||
}
|
||||
length += extradata[offset];
|
||||
offset++;
|
||||
mp_msg (MSGT_DEMUX, MSGL_V, "ad_vorbis, offset: %u, length: %u\n", offset, length);
|
||||
hsizes[i] = length;
|
||||
}
|
||||
|
||||
headers[0] = &extradata[offset];
|
||||
headers[1] = &extradata[offset + hsizes[0]];
|
||||
headers[2] = &extradata[offset + hsizes[0] + hsizes[1]];
|
||||
hsizes[2] = sh->wf->cbSize - offset - hsizes[0] - hsizes[1];
|
||||
mp_msg (MSGT_DEMUX, MSGL_V, "ad_vorbis, header sizes: %d %d %d\n", hsizes[0], hsizes[1], hsizes[2]);
|
||||
|
||||
for(i=0; i<3; i++) {
|
||||
op.bytes = hsizes[i];
|
||||
op.packet = headers[i];
|
||||
op.b_o_s = (i == 0);
|
||||
if(vorbis_synthesis_headerin(&ov->vi,&vc,&op) <0) {
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_ERR,"OggVorbis: header n. %d broken! len=%ld\n", i, op.bytes);
|
||||
ERROR();
|
||||
}
|
||||
if(i == 2) {
|
||||
float rg_gain=0.f, rg_peak=0.f;
|
||||
char **ptr=vc.user_comments;
|
||||
while(*ptr){
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbisComment: %s\n",*ptr);
|
||||
/* replaygain */
|
||||
read_vorbis_comment( *ptr, "replaygain_album_gain=", "%f", &rg_gain );
|
||||
read_vorbis_comment( *ptr, "rg_audiophile=", "%f", &rg_gain );
|
||||
if( !rg_gain ) {
|
||||
read_vorbis_comment( *ptr, "replaygain_track_gain=", "%f", &rg_gain );
|
||||
read_vorbis_comment( *ptr, "rg_radio=", "%f", &rg_gain );
|
||||
}
|
||||
read_vorbis_comment( *ptr, "replaygain_album_peak=", "%f", &rg_peak );
|
||||
if( !rg_peak ) {
|
||||
read_vorbis_comment( *ptr, "replaygain_track_peak=", "%f", &rg_peak );
|
||||
read_vorbis_comment( *ptr, "rg_peak=", "%f", &rg_peak );
|
||||
}
|
||||
++ptr;
|
||||
}
|
||||
/* replaygain: scale */
|
||||
if(!rg_gain)
|
||||
ov->rg_scale = 1.f; /* just in case pow() isn't standard-conformant */
|
||||
else
|
||||
ov->rg_scale = pow(10.f, rg_gain/20);
|
||||
/* replaygain: anticlip */
|
||||
if(ov->rg_scale * rg_peak > 1.f)
|
||||
ov->rg_scale = 1.f / rg_peak;
|
||||
/* replaygain: security */
|
||||
if(ov->rg_scale > 15.)
|
||||
ov->rg_scale = 15.;
|
||||
#ifdef CONFIG_TREMOR
|
||||
ov->rg_scale_int = (int)(ov->rg_scale*64.f);
|
||||
#endif
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Bitstream is %d channel%s, %dHz, %dbit/s %cBR\n",(int)ov->vi.channels,ov->vi.channels>1?"s":"",(int)ov->vi.rate,(int)ov->vi.bitrate_nominal,
|
||||
(ov->vi.bitrate_lower!=ov->vi.bitrate_nominal)||(ov->vi.bitrate_upper!=ov->vi.bitrate_nominal)?'V':'C');
|
||||
if(rg_gain || rg_peak)
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Gain = %+.2f dB, Peak = %.4f, Scale = %.2f\n", rg_gain, rg_peak, ov->rg_scale);
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Encoded by: %s\n",vc.vendor);
|
||||
}
|
||||
}
|
||||
|
||||
vorbis_comment_clear(&vc);
|
||||
|
||||
// printf("lower=%d upper=%d \n",(int)ov->vi.bitrate_lower,(int)ov->vi.bitrate_upper);
|
||||
|
||||
// Setup the decoder
|
||||
sh->channels=ov->vi.channels;
|
||||
sh->samplerate=ov->vi.rate;
|
||||
sh->samplesize=2;
|
||||
// assume 128kbit if bitrate not specified in the header
|
||||
sh->i_bps=((ov->vi.bitrate_nominal>0) ? ov->vi.bitrate_nominal : 128000)/8;
|
||||
sh->context = ov;
|
||||
|
||||
/// Finish the decoder init
|
||||
vorbis_synthesis_init(&ov->vd,&ov->vi);
|
||||
vorbis_block_init(&ov->vd,&ov->vb);
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Init OK!\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void uninit(sh_audio_t *sh)
|
||||
{
|
||||
struct ov_struct_st *ov = sh->context;
|
||||
vorbis_dsp_clear(&ov->vd);
|
||||
vorbis_block_clear(&ov->vb);
|
||||
vorbis_info_clear(&ov->vi);
|
||||
free(ov);
|
||||
}
|
||||
|
||||
static int control(sh_audio_t *sh,int cmd,void* arg, ...)
|
||||
{
|
||||
switch(cmd)
|
||||
{
|
||||
#if 0
|
||||
case ADCTRL_RESYNC_STREAM:
|
||||
return CONTROL_TRUE;
|
||||
case ADCTRL_SKIP_FRAME:
|
||||
return CONTROL_TRUE;
|
||||
#endif
|
||||
}
|
||||
return CONTROL_UNKNOWN;
|
||||
}
|
||||
|
||||
static int decode_audio(sh_audio_t *sh,unsigned char *buf,int minlen,int maxlen)
|
||||
{
|
||||
int len = 0;
|
||||
int samples;
|
||||
#ifdef CONFIG_TREMOR
|
||||
ogg_int32_t **pcm;
|
||||
#else
|
||||
float scale;
|
||||
float **pcm;
|
||||
#endif
|
||||
struct ov_struct_st *ov = sh->context;
|
||||
while(len < minlen) {
|
||||
while((samples=vorbis_synthesis_pcmout(&ov->vd,&pcm))<=0){
|
||||
ogg_packet op;
|
||||
double pts;
|
||||
memset(&op,0,sizeof(op)); //op.b_o_s = op.e_o_s = 0;
|
||||
op.bytes = ds_get_packet_pts(sh->ds,&op.packet, &pts);
|
||||
if(op.bytes<=0) break;
|
||||
if (pts != MP_NOPTS_VALUE) {
|
||||
sh->pts = pts;
|
||||
sh->pts_bytes = 0;
|
||||
}
|
||||
if(vorbis_synthesis(&ov->vb,&op)==0) /* test for success! */
|
||||
vorbis_synthesis_blockin(&ov->vd,&ov->vb);
|
||||
}
|
||||
if(samples<=0) break; // error/EOF
|
||||
while(samples>0){
|
||||
int i,j;
|
||||
int clipflag=0;
|
||||
int convsize=(maxlen-len)/(2*ov->vi.channels); // max size!
|
||||
int bout=((samples<convsize)?samples:convsize);
|
||||
|
||||
if(bout<=0) break; // no buffer space
|
||||
|
||||
/* convert floats to 16 bit signed ints (host order) and
|
||||
interleave */
|
||||
#ifdef CONFIG_TREMOR
|
||||
if (ov->rg_scale_int == 64) {
|
||||
for(i=0;i<ov->vi.channels;i++){
|
||||
ogg_int16_t *convbuffer=(ogg_int16_t *)(&buf[len]);
|
||||
ogg_int16_t *ptr=convbuffer+i;
|
||||
ogg_int32_t *mono=pcm[i];
|
||||
for(j=0;j<bout;j++){
|
||||
int val=mono[j]>>9;
|
||||
/* might as well guard against clipping */
|
||||
if(val>32767){
|
||||
val=32767;
|
||||
clipflag=1;
|
||||
}
|
||||
if(val<-32768){
|
||||
val=-32768;
|
||||
clipflag=1;
|
||||
}
|
||||
*ptr=val;
|
||||
ptr+=ov->vi.channels;
|
||||
}
|
||||
}
|
||||
} else
|
||||
#endif /* CONFIG_TREMOR */
|
||||
{
|
||||
#ifndef CONFIG_TREMOR
|
||||
scale = 32767.f * ov->rg_scale;
|
||||
#endif
|
||||
for(i=0;i<ov->vi.channels;i++){
|
||||
ogg_int16_t *convbuffer=(ogg_int16_t *)(&buf[len]);
|
||||
ogg_int16_t *ptr=convbuffer+i;
|
||||
#ifdef CONFIG_TREMOR
|
||||
ogg_int32_t *mono=pcm[i];
|
||||
for(j=0;j<bout;j++){
|
||||
int val=(mono[j]*ov->rg_scale_int)>>(9+6);
|
||||
#else
|
||||
float *mono=pcm[i];
|
||||
for(j=0;j<bout;j++){
|
||||
int val=mono[j]*scale;
|
||||
/* might as well guard against clipping */
|
||||
if(val>32767){
|
||||
val=32767;
|
||||
clipflag=1;
|
||||
}
|
||||
if(val<-32768){
|
||||
val=-32768;
|
||||
clipflag=1;
|
||||
}
|
||||
#endif /* CONFIG_TREMOR */
|
||||
*ptr=val;
|
||||
ptr+=ov->vi.channels;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(clipflag)
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"Clipping in frame %ld\n",(long)(ov->vd.sequence));
|
||||
len+=2*ov->vi.channels*bout;
|
||||
sh->pts_bytes += 2*ov->vi.channels*bout;
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"\n[decoded: %d / %d ]\n",bout,samples);
|
||||
samples-=bout;
|
||||
vorbis_synthesis_read(&ov->vd,bout); /* tell libvorbis how
|
||||
many samples we
|
||||
actually consumed */
|
||||
} //while(samples>0)
|
||||
// if (!samples) break; // why? how?
|
||||
}
|
||||
|
||||
if (len > 0 && ov->vi.channels >= 5) {
|
||||
reorder_channel_nch(buf, AF_CHANNEL_LAYOUT_VORBIS_DEFAULT,
|
||||
AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT,
|
||||
ov->vi.channels, len / sh->samplesize,
|
||||
sh->samplesize);
|
||||
}
|
||||
|
||||
|
||||
return len;
|
||||
}
|
@ -1,231 +0,0 @@
|
||||
/*
|
||||
* Musepack audio files decoder for MPlayer
|
||||
* by Reza Jelveh <reza.jelveh@tuhh.de> and
|
||||
* Reimar Döffinger <Reimar.Doeffinger@stud.uni-karlsruhe.de>
|
||||
*
|
||||
* This code may be be relicensed under the terms of the GNU LGPL when it
|
||||
* becomes part of the FFmpeg project (ffmpeg.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 "ad_internal.h"
|
||||
#include "libaf/af_format.h"
|
||||
#include "libvo/fastmemcpy.h"
|
||||
|
||||
static const ad_info_t info =
|
||||
{
|
||||
"Musepack audio decoder",
|
||||
"mpcdec",
|
||||
"Reza Jelveh and Reimar Döffinger",
|
||||
"",
|
||||
""
|
||||
};
|
||||
|
||||
LIBAD_EXTERN(libmusepack)
|
||||
|
||||
#include <mpcdec/mpcdec.h>
|
||||
|
||||
// BUFFER_LENGTH is in MPC_SAMPLE_FORMAT units
|
||||
#define MAX_FRAMESIZE (4 * MPC_DECODER_BUFFER_LENGTH)
|
||||
//! this many frames should decode good after seeking
|
||||
#define MIN_SEEK_GOOD 5
|
||||
//! how many frames to discard at most after seeking
|
||||
#define MAX_SEEK_DISCARD 50
|
||||
|
||||
typedef struct context_s {
|
||||
char *header;
|
||||
int header_len;
|
||||
sh_audio_t *sh;
|
||||
uint32_t pos;
|
||||
mpc_decoder decoder;
|
||||
} context_t;
|
||||
|
||||
/**
|
||||
* \brief mpc_reader callback function for reading the header
|
||||
*/
|
||||
static mpc_int32_t cb_read(void *data, void *buf, mpc_int32_t size) {
|
||||
context_t *d = (context_t *)data;
|
||||
char *p = (char *)buf;
|
||||
int s = size;
|
||||
if (d->pos < d->header_len) {
|
||||
if (s > d->header_len - d->pos)
|
||||
s = d->header_len - d->pos;
|
||||
fast_memcpy(p, &d->header[d->pos], s);
|
||||
} else
|
||||
s = 0;
|
||||
memset(&p[s], 0, size - s);
|
||||
d->pos += size;
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief dummy mpc_reader callback function for seeking
|
||||
*/
|
||||
static mpc_bool_t cb_seek(void *data, mpc_int32_t offset ) {
|
||||
context_t *d = (context_t *)data;
|
||||
d->pos = offset;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief dummy mpc_reader callback function for getting stream position
|
||||
*/
|
||||
static mpc_int32_t cb_tell(void *data) {
|
||||
context_t *d = (context_t *)data;
|
||||
return d->pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief dummy mpc_reader callback function for getting stream length
|
||||
*/
|
||||
static mpc_int32_t cb_get_size(void *data) {
|
||||
return 1 << 30;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief mpc_reader callback function, we cannot seek.
|
||||
*/
|
||||
static mpc_bool_t cb_canseek(void *data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
mpc_reader header_reader = {
|
||||
.read = cb_read, .seek = cb_seek, .tell = cb_tell,
|
||||
.get_size = cb_get_size, .canseek = cb_canseek
|
||||
};
|
||||
|
||||
static int preinit(sh_audio_t *sh) {
|
||||
sh->audio_out_minsize = MAX_FRAMESIZE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void uninit(sh_audio_t *sh) {
|
||||
free(sh->context);
|
||||
sh->context = NULL;
|
||||
}
|
||||
|
||||
static int init(sh_audio_t *sh) {
|
||||
mpc_streaminfo info;
|
||||
context_t *cd = malloc(sizeof(context_t));
|
||||
|
||||
if (!sh->wf || (sh->wf->cbSize < 6 * 4)) {
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_FATAL, "Missing extradata!\n");
|
||||
return 0;
|
||||
}
|
||||
cd->header = (char *)(sh->wf + 1);
|
||||
cd->header_len = sh->wf->cbSize;
|
||||
cd->sh = sh;
|
||||
cd->pos = 0;
|
||||
sh->context = (char *)cd;
|
||||
|
||||
/* read file's streaminfo data */
|
||||
mpc_streaminfo_init(&info);
|
||||
header_reader.data = cd;
|
||||
if (mpc_streaminfo_read(&info, &header_reader) != ERROR_CODE_OK) {
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_FATAL, "Not a valid musepack file.\n");
|
||||
return 0;
|
||||
}
|
||||
// this value is nonsense, since it relies on the get_size function.
|
||||
// use the value from the demuxer instead.
|
||||
// sh->i_bps = info.average_bitrate / 8;
|
||||
sh->channels = info.channels;
|
||||
sh->samplerate = info.sample_freq;
|
||||
sh->samplesize = 4;
|
||||
sh->sample_format =
|
||||
#if MPC_SAMPLE_FORMAT == float
|
||||
AF_FORMAT_FLOAT_NE;
|
||||
#elif MPC_SAMPLE_FORMAT == mpc_int32_t
|
||||
AF_FORMAT_S32_NE;
|
||||
#else
|
||||
#error musepack lib must use either float or mpc_int32_t sample format
|
||||
#endif
|
||||
|
||||
mpc_decoder_setup(&cd->decoder, NULL);
|
||||
mpc_decoder_set_streaminfo(&cd->decoder, &info);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// FIXME: minlen is currently ignored
|
||||
static int decode_audio(sh_audio_t *sh, unsigned char *buf,
|
||||
int minlen, int maxlen) {
|
||||
int status, len;
|
||||
MPC_SAMPLE_FORMAT *sample_buffer = (MPC_SAMPLE_FORMAT *)buf;
|
||||
mpc_uint32_t *packet = NULL;
|
||||
|
||||
context_t *cd = (context_t *) sh->context;
|
||||
if (maxlen < MAX_FRAMESIZE) {
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_V, "maxlen too small in decode_audio\n");
|
||||
return -1;
|
||||
}
|
||||
len = ds_get_packet(sh->ds, (unsigned char **)&packet);
|
||||
if (len <= 0) return -1;
|
||||
status = mpc_decoder_decode_frame(&cd->decoder, packet, len, sample_buffer);
|
||||
if (status == -1) // decode error
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_FATAL, "Error decoding file.\n");
|
||||
if (status <= 0) // error or EOF
|
||||
return -1;
|
||||
|
||||
status = MPC_FRAME_LENGTH * sh->channels; // one sample per channel
|
||||
#if MPC_SAMPLE_FORMAT == float || MPC_SAMPLE_FORMAT == mpc_int32_t
|
||||
status *= 4;
|
||||
#else
|
||||
// should not happen
|
||||
status *= 2;
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief check if the decoded values are in a sane range
|
||||
* \param buf decoded buffer
|
||||
* \param len length of buffer in bytes
|
||||
* \return 1 if all values are in (-1.01, 1.01) range, 0 otherwise
|
||||
*/
|
||||
static int check_clip(void *buf, int len) {
|
||||
#if MPC_SAMPLE_FORMAT == float
|
||||
float *p = buf;
|
||||
if (len < 4) return 1;
|
||||
len = -len / 4;
|
||||
p = &p[-len];
|
||||
do {
|
||||
if (p[len] < -1 || p[len] > 1) return 0;
|
||||
} while (++len);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int control(sh_audio_t *sh, int cmd, void* arg, ...) {
|
||||
if (cmd == ADCTRL_RESYNC_STREAM) {
|
||||
unsigned char *buf = malloc(MAX_FRAMESIZE);
|
||||
int i;
|
||||
int nr_ok = 0;
|
||||
for (i = 0; i < MAX_SEEK_DISCARD; i++) {
|
||||
int len = decode_audio(sh, buf, 0, MAX_FRAMESIZE);
|
||||
if (check_clip(buf, len)) nr_ok++; else nr_ok = 0;
|
||||
if (nr_ok > MIN_SEEK_GOOD) break;
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
return CONTROL_UNKNOWN;
|
||||
}
|
@ -1,179 +0,0 @@
|
||||
/*
|
||||
* Speex decoder by Reimar Döffinger <Reimar.Doeffinger@stud.uni-karlsruhe.de>
|
||||
*
|
||||
* This code may be be relicensed under the terms of the GNU LGPL when it
|
||||
* becomes part of the FFmpeg project (ffmpeg.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 "config.h"
|
||||
#include <stdlib.h>
|
||||
#include <speex/speex.h>
|
||||
#include <speex/speex_stereo.h>
|
||||
#include <speex/speex_header.h>
|
||||
#include "ad_internal.h"
|
||||
|
||||
static const ad_info_t info = {
|
||||
"Speex audio decoder",
|
||||
"speex",
|
||||
"Reimar Döffinger",
|
||||
"",
|
||||
""
|
||||
};
|
||||
|
||||
LIBAD_EXTERN(speex)
|
||||
|
||||
typedef struct {
|
||||
SpeexBits bits;
|
||||
void *dec_context;
|
||||
SpeexStereoState stereo;
|
||||
SpeexHeader *hdr;
|
||||
} context_t;
|
||||
|
||||
#define MAX_FRAMES_PER_PACKET 100
|
||||
|
||||
static int preinit(sh_audio_t *sh) {
|
||||
sh->audio_out_minsize = 2 * 320 * MAX_FRAMES_PER_PACKET * 2 * sizeof(short);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int read_le32(const uint8_t **src) {
|
||||
const uint8_t *p = *src;
|
||||
*src += 4;
|
||||
return p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
|
||||
}
|
||||
|
||||
static int init(sh_audio_t *sh) {
|
||||
context_t *ctx = calloc(1, sizeof(context_t));
|
||||
const uint8_t *hdr = (const uint8_t *)(sh->wf + 1);
|
||||
const SpeexMode *spx_mode;
|
||||
const SpeexStereoState st_st = SPEEX_STEREO_STATE_INIT; // hack
|
||||
if (sh->wf && sh->wf->cbSize >= 80)
|
||||
ctx->hdr = speex_packet_to_header((char *)&sh->wf[1], sh->wf->cbSize);
|
||||
if (!ctx->hdr && sh->wf->cbSize == 0x72 && hdr[0] == 1 && hdr[1] == 0) {
|
||||
// speex.acm format: raw SpeexHeader dump
|
||||
ctx->hdr = calloc(1, sizeof(*ctx->hdr));
|
||||
hdr += 2;
|
||||
hdr += 8; // identifier string
|
||||
hdr += 20; // version string
|
||||
ctx->hdr->speex_version_id = read_le32(&hdr);
|
||||
ctx->hdr->header_size = read_le32(&hdr);
|
||||
ctx->hdr->rate = read_le32(&hdr);
|
||||
ctx->hdr->mode = read_le32(&hdr);
|
||||
ctx->hdr->mode_bitstream_version = read_le32(&hdr);
|
||||
ctx->hdr->nb_channels = read_le32(&hdr);
|
||||
ctx->hdr->bitrate = read_le32(&hdr);
|
||||
ctx->hdr->frame_size = read_le32(&hdr);
|
||||
ctx->hdr->vbr = read_le32(&hdr);
|
||||
ctx->hdr->frames_per_packet = read_le32(&hdr);
|
||||
}
|
||||
if (!ctx->hdr) {
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_ERR, "Invalid or missing extradata! Assuming defaults.\n");
|
||||
ctx->hdr = calloc(1, sizeof(*ctx->hdr));
|
||||
ctx->hdr->frames_per_packet = 1;
|
||||
ctx->hdr->mode = 0;
|
||||
if (sh->wf) {
|
||||
ctx->hdr->nb_channels = sh->wf->nChannels;
|
||||
ctx->hdr->rate = sh->wf->nSamplesPerSec;
|
||||
if (ctx->hdr->rate > 16000)
|
||||
ctx->hdr->mode = 2;
|
||||
else if (ctx->hdr->rate > 8000)
|
||||
ctx->hdr->mode = 1;
|
||||
}
|
||||
}
|
||||
if (ctx->hdr->nb_channels != 1 && ctx->hdr->nb_channels != 2) {
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_WARN, "Invalid number of channels (%i), "
|
||||
"assuming mono\n", ctx->hdr->nb_channels);
|
||||
ctx->hdr->nb_channels = 1;
|
||||
}
|
||||
if (ctx->hdr->frames_per_packet > MAX_FRAMES_PER_PACKET) {
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_WARN, "Invalid number of frames per packet (%i), "
|
||||
"assuming 1\n", ctx->hdr->frames_per_packet);
|
||||
ctx->hdr->frames_per_packet = 1;
|
||||
}
|
||||
switch (ctx->hdr->mode) {
|
||||
case 0:
|
||||
spx_mode = &speex_nb_mode; break;
|
||||
case 1:
|
||||
spx_mode = &speex_wb_mode; break;
|
||||
case 2:
|
||||
spx_mode = &speex_uwb_mode; break;
|
||||
default:
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_WARN, "Unknown speex mode (%i)\n", ctx->hdr->mode);
|
||||
spx_mode = &speex_nb_mode;
|
||||
}
|
||||
ctx->dec_context = speex_decoder_init(spx_mode);
|
||||
speex_bits_init(&ctx->bits);
|
||||
memcpy(&ctx->stereo, &st_st, sizeof(ctx->stereo)); // hack part 2
|
||||
sh->channels = ctx->hdr->nb_channels;
|
||||
sh->samplerate = ctx->hdr->rate;
|
||||
sh->samplesize = 2;
|
||||
sh->sample_format = AF_FORMAT_S16_NE;
|
||||
sh->context = ctx;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void uninit(sh_audio_t *sh) {
|
||||
context_t *ctx = sh->context;
|
||||
if (ctx) {
|
||||
speex_bits_destroy(&ctx->bits);
|
||||
speex_decoder_destroy(ctx->dec_context);
|
||||
free(ctx->hdr);
|
||||
free(ctx);
|
||||
}
|
||||
ctx = NULL;
|
||||
}
|
||||
|
||||
static int decode_audio(sh_audio_t *sh, unsigned char *buf,
|
||||
int minlen, int maxlen) {
|
||||
double pts;
|
||||
context_t *ctx = sh->context;
|
||||
int len, framelen, framesamples;
|
||||
char *packet;
|
||||
int i, err;
|
||||
speex_decoder_ctl(ctx->dec_context, SPEEX_GET_FRAME_SIZE, &framesamples);
|
||||
framelen = framesamples * ctx->hdr->nb_channels * sizeof(short);
|
||||
if (maxlen < ctx->hdr->frames_per_packet * framelen) {
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_V, "maxlen too small in decode_audio\n");
|
||||
return -1;
|
||||
}
|
||||
len = ds_get_packet_pts(sh->ds, (unsigned char **)&packet, &pts);
|
||||
if (len <= 0) return -1;
|
||||
if (sh->pts == MP_NOPTS_VALUE)
|
||||
sh->pts = 0;
|
||||
if (pts != MP_NOPTS_VALUE) {
|
||||
sh->pts = pts;
|
||||
sh->pts_bytes = 0;
|
||||
}
|
||||
speex_bits_read_from(&ctx->bits, packet, len);
|
||||
i = ctx->hdr->frames_per_packet;
|
||||
do {
|
||||
err = speex_decode_int(ctx->dec_context, &ctx->bits, (short *)buf);
|
||||
if (err == -2)
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_ERR, "Error decoding file.\n");
|
||||
if (ctx->hdr->nb_channels == 2)
|
||||
speex_decode_stereo_int((short *)buf, framesamples, &ctx->stereo);
|
||||
buf = &buf[framelen];
|
||||
} while (--i > 0);
|
||||
sh->pts_bytes += ctx->hdr->frames_per_packet * framelen;
|
||||
return ctx->hdr->frames_per_packet * framelen;
|
||||
}
|
||||
|
||||
static int control(sh_audio_t *sh, int cmd, void *arg, ...) {
|
||||
return CONTROL_UNKNOWN;
|
||||
}
|
@ -1,523 +0,0 @@
|
||||
/*
|
||||
* 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 "ad_internal.h"
|
||||
#include "vqf.h"
|
||||
#include "libmpdemux/aviprint.h"
|
||||
#include "loader/ldt_keeper.h"
|
||||
#include "loader/wine/windef.h"
|
||||
#include "libaf/af_format.h"
|
||||
|
||||
|
||||
static const ad_info_t info =
|
||||
{
|
||||
"TWinVQ decoder",
|
||||
"vqf",
|
||||
"Roberto Togni",
|
||||
"Nick Kurshev",
|
||||
"Ported from MPlayerXP"
|
||||
};
|
||||
|
||||
LIBAD_EXTERN(twin)
|
||||
|
||||
void* WINAPI LoadLibraryA(char* name);
|
||||
void* WINAPI GetProcAddress(void* handle, char* func);
|
||||
int WINAPI FreeLibrary(void* handle);
|
||||
|
||||
static int (*TvqInitialize)( headerInfo *setupInfo, INDEX *index, int dispErrorMessageBox );
|
||||
static void (*TvqTerminate)( INDEX *index );
|
||||
static void (*TvqGetVectorInfo)(int *bits0[], int *bits1[]);
|
||||
|
||||
static void (*TvqDecodeFrame)(INDEX *indexp, float out[]);
|
||||
static int (*TvqWtypeToBtype)( int w_type, int *btype );
|
||||
static void (*TvqUpdateVectorInfo)(int varbits, int *ndiv, int bits0[], int bits1[]);
|
||||
|
||||
static int (*TvqCheckVersion)(char *versionID);
|
||||
static void (*TvqGetConfInfo)(tvqConfInfo *cf);
|
||||
static int (*TvqGetFrameSize)(void);
|
||||
static int (*TvqGetNumFixedBitsPerFrame)(void);
|
||||
|
||||
#define BYTE_BIT 8
|
||||
#define BBUFSIZ 1024 /* Bit buffer size (bytes) */
|
||||
#define BBUFLEN (BBUFSIZ*BYTE_BIT) /* Bit buffer length (bits) */
|
||||
typedef struct vqf_priv_s
|
||||
{
|
||||
float pts;
|
||||
WAVEFORMATEX o_wf; // out format
|
||||
INDEX index;
|
||||
tvqConfInfo cf;
|
||||
headerInfo hi;
|
||||
int *bits_0[N_INTR_TYPE], *bits_1[N_INTR_TYPE];
|
||||
unsigned framesize;
|
||||
/* stream related */
|
||||
int readable;
|
||||
int ptr; /* current point in the bit buffer */
|
||||
int nbuf; /* bit buffer size */
|
||||
char buf[BBUFSIZ]; /* the bit buffer */
|
||||
int skip_cnt;
|
||||
}vqf_priv_t;
|
||||
|
||||
static void* vqf_dll;
|
||||
|
||||
static int load_dll( char *libname )
|
||||
{
|
||||
#ifdef WIN32_LOADER
|
||||
Setup_LDT_Keeper();
|
||||
#endif
|
||||
vqf_dll = LoadLibraryA(libname);
|
||||
if( vqf_dll == NULL )
|
||||
{
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_ERR, "failed loading dll\n" );
|
||||
return 0;
|
||||
}
|
||||
TvqInitialize = GetProcAddress(vqf_dll,"TvqInitialize");
|
||||
TvqTerminate = GetProcAddress(vqf_dll,"TvqTerminate");
|
||||
TvqGetVectorInfo = GetProcAddress(vqf_dll,"TvqGetVectorInfo");
|
||||
TvqDecodeFrame = GetProcAddress(vqf_dll,"TvqDecodeFrame");
|
||||
TvqWtypeToBtype = GetProcAddress(vqf_dll,"TvqWtypeToBtype");
|
||||
TvqUpdateVectorInfo = GetProcAddress(vqf_dll,"TvqUpdateVectorInfo");
|
||||
TvqCheckVersion = GetProcAddress(vqf_dll,"TvqCheckVersion");
|
||||
TvqGetConfInfo = GetProcAddress(vqf_dll,"TvqGetConfInfo");
|
||||
TvqGetFrameSize = GetProcAddress(vqf_dll,"TvqGetFrameSize");
|
||||
TvqGetNumFixedBitsPerFrame = GetProcAddress(vqf_dll,"TvqGetNumFixedBitsPerFrame");
|
||||
return TvqInitialize && TvqTerminate && TvqGetVectorInfo &&
|
||||
TvqDecodeFrame && TvqWtypeToBtype && TvqUpdateVectorInfo &&
|
||||
TvqCheckVersion && TvqGetConfInfo && TvqGetFrameSize &&
|
||||
TvqGetNumFixedBitsPerFrame;
|
||||
}
|
||||
|
||||
static int init_vqf_audio_codec(sh_audio_t *sh_audio){
|
||||
WAVEFORMATEX *in_fmt=sh_audio->wf;
|
||||
vqf_priv_t*priv=sh_audio->context;
|
||||
int ver;
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_INFO, "======= Win32 (TWinVQ) AUDIO Codec init =======\n");
|
||||
|
||||
sh_audio->channels=in_fmt->nChannels;
|
||||
sh_audio->samplerate=in_fmt->nSamplesPerSec;
|
||||
sh_audio->sample_format=AF_FORMAT_S16_NE;
|
||||
// sh_audio->sample_format=AF_FORMAT_FLOAT_NE;
|
||||
sh_audio->samplesize=af_fmt2bits(sh_audio->sample_format)/8;
|
||||
priv->o_wf.nChannels=in_fmt->nChannels;
|
||||
priv->o_wf.nSamplesPerSec=in_fmt->nSamplesPerSec;
|
||||
priv->o_wf.nBlockAlign=sh_audio->samplesize*in_fmt->nChannels;
|
||||
priv->o_wf.nAvgBytesPerSec=in_fmt->nBlockAlign*in_fmt->nChannels;
|
||||
priv->o_wf.wFormatTag=0x01;
|
||||
priv->o_wf.wBitsPerSample=in_fmt->wBitsPerSample;
|
||||
priv->o_wf.cbSize=0;
|
||||
|
||||
if( mp_msg_test(MSGT_DECAUDIO,MSGL_V) )
|
||||
{
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_V, "Input format:\n");
|
||||
print_wave_header(in_fmt, MSGL_V);
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_V, "Output fmt:\n");
|
||||
print_wave_header(&priv->o_wf, MSGL_V);
|
||||
}
|
||||
memcpy(&priv->hi,&in_fmt[1],sizeof(headerInfo));
|
||||
if((ver=TvqInitialize(&priv->hi,&priv->index,0))){
|
||||
const char *tvqe[]={
|
||||
"No errors",
|
||||
"General error",
|
||||
"Wrong version",
|
||||
"Channel setting error",
|
||||
"Wrong coding mode",
|
||||
"Inner parameter setting error",
|
||||
"Wrong number of VQ pre-selection candidates, used only in encoder" };
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_ERR, "Tvq initialization error: %s\n",ver>=0&&ver<7?tvqe[ver]:"Unknown");
|
||||
return 0;
|
||||
}
|
||||
ver=TvqCheckVersion(priv->hi.ID);
|
||||
if(ver==TVQ_UNKNOWN_VERSION){
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_ERR, "Tvq unknown version of stream\n" );
|
||||
return 0;
|
||||
}
|
||||
TvqGetConfInfo(&priv->cf);
|
||||
TvqGetVectorInfo(priv->bits_0,priv->bits_1);
|
||||
priv->framesize=TvqGetFrameSize();
|
||||
sh_audio->audio_in_minsize=priv->framesize*in_fmt->nChannels;
|
||||
sh_audio->a_in_buffer_size=4*sh_audio->audio_in_minsize;
|
||||
sh_audio->a_in_buffer=av_malloc(sh_audio->a_in_buffer_size);
|
||||
sh_audio->a_in_buffer_len=0;
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int close_vqf_audio_codec(sh_audio_t *sh_audio)
|
||||
{
|
||||
vqf_priv_t*priv=sh_audio->context;
|
||||
TvqTerminate(&priv->index);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int init(sh_audio_t *sh_audio)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int preinit(sh_audio_t *sh_audio)
|
||||
{
|
||||
/* Win32 VQF audio codec: */
|
||||
vqf_priv_t *priv;
|
||||
if(!(sh_audio->context=malloc(sizeof(vqf_priv_t)))) return 0;
|
||||
priv=sh_audio->context;
|
||||
if(!load_dll(sh_audio->codec->dll))
|
||||
{
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_ERR, "win32.dll looks broken :(\n");
|
||||
return 0;
|
||||
}
|
||||
if(!init_vqf_audio_codec(sh_audio)){
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_ERR, "TWinVQ initialization fail\n");
|
||||
return 0;
|
||||
}
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_INFO, "INFO: TWinVQ (%s) audio codec init OK!\n",sh_audio->codec->dll);
|
||||
priv->skip_cnt = 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void uninit(sh_audio_t *sh)
|
||||
{
|
||||
close_vqf_audio_codec(sh);
|
||||
free(sh->context);
|
||||
FreeLibrary(vqf_dll);
|
||||
}
|
||||
|
||||
static int control(sh_audio_t *sh_audio,int cmd,void* arg, ...)
|
||||
{
|
||||
switch(cmd) {
|
||||
case ADCTRL_QUERY_FORMAT:
|
||||
return CONTROL_TRUE;
|
||||
default:
|
||||
return CONTROL_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static int bread(char *data, /* Output: Output data array */
|
||||
int size, /* Input: Length of each data */
|
||||
int nbits, /* Input: Number of bits to write */
|
||||
sh_audio_t *sh) /* Input: File pointer */
|
||||
{
|
||||
/*--- Variables ---*/
|
||||
int ibits, iptr, idata, ibufadr, ibufbit, icl;
|
||||
unsigned char mask, tmpdat;
|
||||
int retval;
|
||||
vqf_priv_t *priv=sh->context;
|
||||
|
||||
/*--- Main operation ---*/
|
||||
retval = 0;
|
||||
mask = 0x1;
|
||||
for ( ibits=0; ibits<nbits; ibits++ ){
|
||||
if ( priv->readable == 0 ){ /* when the file data buffer is empty */
|
||||
priv->nbuf = demux_read_data(sh->ds, priv->buf, BBUFSIZ);
|
||||
priv->nbuf *= 8;
|
||||
priv->readable = 1;
|
||||
}
|
||||
iptr = priv->ptr; /* current file data buffer pointer */
|
||||
if ( iptr >= priv->nbuf ) /* If data file is empty then return */
|
||||
return retval;
|
||||
ibufadr = iptr/BYTE_BIT; /* current file data buffer address */
|
||||
ibufbit = iptr%BYTE_BIT; /* current file data buffer bit */
|
||||
/* tmpdat = stream->buf[ibufadr] >> (BYTE_BIT-ibufbit-1); */
|
||||
tmpdat = (unsigned char)priv->buf[ibufadr];
|
||||
tmpdat >>= (BYTE_BIT-ibufbit-1);
|
||||
/* current data bit */
|
||||
|
||||
idata = ibits*size; /* output data address */
|
||||
data[idata] = (char)(tmpdat & mask); /* set output data */
|
||||
for (icl=1; icl<size; icl++)
|
||||
data[idata+icl] = 0; /* clear the rest output data buffer */
|
||||
priv->ptr += 1; /* update data buffer pointer */
|
||||
if (priv->ptr == BBUFLEN){
|
||||
priv->ptr = 0;
|
||||
priv->readable = 0;
|
||||
}
|
||||
++retval;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
#define BITS_INT (sizeof(int)*8)
|
||||
|
||||
static int get_bstm(int *data, /* Input: input data */
|
||||
unsigned nbits, /* Input: number of bits */
|
||||
sh_audio_t *sh) /* Input: bit file pointer */
|
||||
{
|
||||
unsigned ibit;
|
||||
unsigned mask;
|
||||
unsigned work;
|
||||
char tmpbit[BITS_INT];
|
||||
int retval;
|
||||
|
||||
if ( nbits > BITS_INT ){
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_ERR, "get_bstm(): %d: %d Error.\n",
|
||||
nbits, BITS_INT);
|
||||
exit(1);
|
||||
}
|
||||
retval = bread(tmpbit, sizeof(*tmpbit), nbits, sh);
|
||||
for (ibit=retval; ibit<nbits; ibit++){
|
||||
tmpbit[ibit] = 0;
|
||||
}
|
||||
mask = 0x1<<(nbits-1);
|
||||
work=0;
|
||||
for ( ibit=0; ibit<nbits; ibit++ ){
|
||||
work += mask*tmpbit[ibit];
|
||||
mask >>= 1;
|
||||
}
|
||||
*data = work;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int GetVqInfo( tvqConfInfoSubBlock *cfg,
|
||||
int bits0[],
|
||||
int bits1[],
|
||||
int variableBits,
|
||||
INDEX *index,
|
||||
sh_audio_t *sh)
|
||||
{
|
||||
int idiv;
|
||||
int bitcount = 0;
|
||||
|
||||
if ( index->btype == BLK_LONG ){
|
||||
TvqUpdateVectorInfo( variableBits, &cfg->ndiv, bits0, bits1 ); // re-calculate VQ bits
|
||||
}
|
||||
for ( idiv=0; idiv<cfg->ndiv; idiv++ ){
|
||||
bitcount += get_bstm(&index->wvq[idiv],bits0[idiv],sh); /* CB 0 */
|
||||
bitcount += get_bstm(&index->wvq[idiv+cfg->ndiv],bits1[idiv],sh); /* CB 1 */
|
||||
}
|
||||
return bitcount;
|
||||
}
|
||||
|
||||
static int GetBseInfo( tvqConfInfo *cf, tvqConfInfoSubBlock *cfg, INDEX *index, sh_audio_t *sh)
|
||||
{
|
||||
int i_sup, isf, itmp, idiv;
|
||||
int bitcount = 0;
|
||||
|
||||
for ( i_sup=0; i_sup<cf->N_CH; i_sup++ ){
|
||||
for ( isf=0; isf<cfg->nsf; isf++ ){
|
||||
for ( idiv=0; idiv<cfg->fw_ndiv; idiv++ ){
|
||||
itmp = idiv + ( isf + i_sup * cfg->nsf ) * cfg->fw_ndiv;
|
||||
bitcount += get_bstm(&index->fw[itmp],cfg->fw_nbit,sh);
|
||||
}
|
||||
}
|
||||
}
|
||||
for ( i_sup=0; i_sup<cf->N_CH; i_sup++ ){
|
||||
for ( isf=0; isf<cfg->nsf; isf++ ){
|
||||
bitcount += get_bstm(&index->fw_alf[i_sup * cfg->nsf + isf],cf->FW_ARSW_BITS,sh);
|
||||
}
|
||||
}
|
||||
return bitcount;
|
||||
}
|
||||
|
||||
static int GetGainInfo(tvqConfInfo *cf, tvqConfInfoSubBlock *cfg, INDEX *index, sh_audio_t *sh )
|
||||
{
|
||||
int i_sup, iptop, isf;
|
||||
int bitcount = 0;
|
||||
|
||||
for ( i_sup=0; i_sup<cf->N_CH; i_sup++ ){
|
||||
iptop = ( cfg->nsubg + 1 ) * i_sup;
|
||||
bitcount += get_bstm(&index->pow[iptop], cf->GAIN_BITS,sh);
|
||||
for ( isf=0; isf<cfg->nsubg; isf++ ){
|
||||
bitcount += get_bstm(&index->pow[iptop+isf+1], cf->SUB_GAIN_BITS,sh);
|
||||
}
|
||||
}
|
||||
return bitcount;
|
||||
}
|
||||
|
||||
static int GetLspInfo( tvqConfInfo *cf, INDEX *index, sh_audio_t *sh )
|
||||
{
|
||||
int i_sup, itmp;
|
||||
int bitcount = 0;
|
||||
|
||||
for ( i_sup=0; i_sup<cf->N_CH; i_sup++ ){
|
||||
bitcount += get_bstm(&index->lsp[i_sup][0], cf->LSP_BIT0,sh); /* pred. switch */
|
||||
bitcount += get_bstm(&index->lsp[i_sup][1], cf->LSP_BIT1,sh); /* first stage */
|
||||
for ( itmp=0; itmp<cf->LSP_SPLIT; itmp++ ){ /* second stage */
|
||||
bitcount += get_bstm(&index->lsp[i_sup][itmp+2], cf->LSP_BIT2,sh);
|
||||
}
|
||||
}
|
||||
|
||||
return bitcount;
|
||||
}
|
||||
|
||||
static int GetPpcInfo( tvqConfInfo *cf, INDEX *index, sh_audio_t *sh)
|
||||
{
|
||||
int idiv, i_sup;
|
||||
int bitcount = 0;
|
||||
vqf_priv_t*priv=sh->context;
|
||||
|
||||
for ( idiv=0; idiv<cf->N_DIV_P; idiv++ ){
|
||||
bitcount += get_bstm(&(index->pls[idiv]), priv->bits_0[BLK_PPC][idiv],sh); /*CB0*/
|
||||
bitcount += get_bstm(&(index->pls[idiv+cf->N_DIV_P]), priv->bits_1[BLK_PPC][idiv],sh);/*CB1*/
|
||||
}
|
||||
for (i_sup=0; i_sup<cf->N_CH; i_sup++){
|
||||
bitcount += get_bstm(&(index->pit[i_sup]), cf->BASF_BIT,sh);
|
||||
bitcount += get_bstm(&(index->pgain[i_sup]), cf->PGAIN_BIT,sh);
|
||||
}
|
||||
|
||||
return bitcount;
|
||||
}
|
||||
|
||||
static int GetEbcInfo( tvqConfInfo *cf, tvqConfInfoSubBlock *cfg, INDEX *index, sh_audio_t *sh)
|
||||
{
|
||||
int i_sup, isf, itmp;
|
||||
int bitcount = 0;
|
||||
|
||||
for ( i_sup=0; i_sup<cf->N_CH; i_sup++ ){
|
||||
for ( isf=0; isf<cfg->nsf; isf++){
|
||||
int indexSfOffset = isf * ( cfg->ncrb - cfg->ebc_crb_base ) - cfg->ebc_crb_base;
|
||||
for ( itmp=cfg->ebc_crb_base; itmp<cfg->ncrb; itmp++ ){
|
||||
bitcount += get_bstm(&index->bc[i_sup][itmp+indexSfOffset], cfg->ebc_bits,sh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bitcount;
|
||||
}
|
||||
|
||||
static int vqf_read_frame(sh_audio_t *sh,INDEX *index)
|
||||
{
|
||||
/*--- Variables ---*/
|
||||
tvqConfInfoSubBlock *cfg;
|
||||
int variableBits;
|
||||
int bitcount;
|
||||
int numFixedBitsPerFrame = TvqGetNumFixedBitsPerFrame();
|
||||
int btype;
|
||||
vqf_priv_t *priv=sh->context;
|
||||
|
||||
/*--- Initialization ---*/
|
||||
variableBits = 0;
|
||||
bitcount = 0;
|
||||
|
||||
/*--- read block independent factors ---*/
|
||||
/* Window type */
|
||||
bitcount += get_bstm( &index->w_type, priv->cf.BITS_WTYPE, sh );
|
||||
if ( TvqWtypeToBtype( index->w_type, &index->btype ) ) {
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_ERR, "Error: unknown window type: %d\n", index->w_type);
|
||||
return 0;
|
||||
}
|
||||
btype = index->btype;
|
||||
|
||||
/*--- read block dependent factors ---*/
|
||||
cfg = &priv->cf.cfg[btype]; // set the block dependent paremeters table
|
||||
|
||||
bitcount += variableBits;
|
||||
|
||||
/* Interleaved vector quantization */
|
||||
bitcount += GetVqInfo( cfg, priv->bits_0[btype], priv->bits_1[btype], variableBits, index, sh );
|
||||
|
||||
/* Bark-scale envelope */
|
||||
bitcount += GetBseInfo( &priv->cf, cfg, index, sh );
|
||||
/* Gain */
|
||||
bitcount += GetGainInfo( &priv->cf, cfg, index, sh );
|
||||
/* LSP */
|
||||
bitcount += GetLspInfo( &priv->cf, index, sh );
|
||||
/* PPC */
|
||||
if ( cfg->ppc_enable ){
|
||||
bitcount += GetPpcInfo( &priv->cf, index, sh );
|
||||
}
|
||||
/* Energy Balance Calibration */
|
||||
if ( cfg->ebc_enable ){
|
||||
bitcount += GetEbcInfo( &priv->cf, cfg, index, sh );
|
||||
}
|
||||
|
||||
return bitcount == numFixedBitsPerFrame ? bitcount/8 : 0;
|
||||
}
|
||||
|
||||
static void frtobuf_s16(float out[], /* Input --- input data frame */
|
||||
short bufout[], /* Output --- output data buffer array */
|
||||
unsigned frameSize, /* Input --- frame size */
|
||||
unsigned numChannels) /* Input --- number of channels */
|
||||
{
|
||||
/*--- Variables ---*/
|
||||
unsigned ismp, ich;
|
||||
float *ptr;
|
||||
float dtmp;
|
||||
|
||||
for ( ich=0; ich<numChannels; ich++ ){
|
||||
ptr = out+ich*frameSize;
|
||||
for ( ismp=0; ismp<frameSize; ismp++ ){
|
||||
dtmp = ptr[ismp];
|
||||
if ( dtmp >= 0. ) {
|
||||
if ( dtmp > 32700. )
|
||||
dtmp = 32700.;
|
||||
bufout[ismp*numChannels+ich] = (short)(dtmp+0.5);
|
||||
} else {
|
||||
if ( dtmp < -32700. )
|
||||
dtmp = -32700.;
|
||||
bufout[ismp*numChannels+ich] = (short)(dtmp-0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void frtobuf_float(float out[], /* Input --- input data frame */
|
||||
float bufout[], /* Output --- output data buffer array */
|
||||
unsigned frameSize, /* Input --- frame size */
|
||||
unsigned numChannels) /* Input --- number of channels */
|
||||
{
|
||||
/*--- Variables ---*/
|
||||
unsigned ismp, ich;
|
||||
float *ptr;
|
||||
float dtmp;
|
||||
|
||||
for ( ich=0; ich<numChannels; ich++ ){
|
||||
ptr = out+ich*frameSize;
|
||||
for ( ismp=0; ismp<frameSize; ismp++ ){
|
||||
dtmp = ptr[ismp];
|
||||
if ( dtmp >= 0. ) {
|
||||
if ( dtmp > 32700. )
|
||||
dtmp = 32700.;
|
||||
bufout[ismp*numChannels+ich] = dtmp/32767.;
|
||||
} else {
|
||||
if ( dtmp < -32700. )
|
||||
dtmp = -32700.;
|
||||
bufout[ismp*numChannels+ich] = dtmp/32767.;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen)
|
||||
{
|
||||
int l, len=0;
|
||||
vqf_priv_t *priv=sh_audio->context;
|
||||
while(len<minlen)
|
||||
{
|
||||
float out[priv->framesize*sh_audio->channels];
|
||||
l=vqf_read_frame(sh_audio,&priv->index);
|
||||
if(!l) break;
|
||||
TvqDecodeFrame(&priv->index, out);
|
||||
if (priv->skip_cnt) {
|
||||
// Ingnore first two frames, replace them with silence
|
||||
priv->skip_cnt--;
|
||||
memset(buf, 0, priv->framesize*sh_audio->channels*sh_audio->samplesize);
|
||||
} else {
|
||||
if (sh_audio->sample_format == AF_FORMAT_S16_NE)
|
||||
frtobuf_s16(out, (short *)buf, priv->framesize, sh_audio->channels);
|
||||
else
|
||||
frtobuf_float(out, (float *)buf, priv->framesize, sh_audio->channels);
|
||||
}
|
||||
len += priv->framesize*sh_audio->channels*sh_audio->samplesize;
|
||||
buf += priv->framesize*sh_audio->channels*sh_audio->samplesize;
|
||||
}
|
||||
return len;
|
||||
}
|
@ -31,7 +31,6 @@
|
||||
|
||||
#include "stream/stream.h"
|
||||
#include "libmpdemux/demuxer.h"
|
||||
#include "libmpdemux/parse_es.h"
|
||||
|
||||
#include "codec-cfg.h"
|
||||
|
||||
|
@ -39,7 +39,6 @@
|
||||
|
||||
extern const vd_functions_t mpcodecs_vd_null;
|
||||
extern const vd_functions_t mpcodecs_vd_ffmpeg;
|
||||
extern const vd_functions_t mpcodecs_vd_theora;
|
||||
extern const vd_functions_t mpcodecs_vd_dshow;
|
||||
extern const vd_functions_t mpcodecs_vd_dmo;
|
||||
extern const vd_functions_t mpcodecs_vd_vfw;
|
||||
@ -50,10 +49,7 @@ extern const vd_functions_t mpcodecs_vd_xanim;
|
||||
extern const vd_functions_t mpcodecs_vd_mpng;
|
||||
extern const vd_functions_t mpcodecs_vd_ijpg;
|
||||
extern const vd_functions_t mpcodecs_vd_mtga;
|
||||
extern const vd_functions_t mpcodecs_vd_sgi;
|
||||
extern const vd_functions_t mpcodecs_vd_mpegpes;
|
||||
extern const vd_functions_t mpcodecs_vd_realvid;
|
||||
extern const vd_functions_t mpcodecs_vd_xvid;
|
||||
extern const vd_functions_t mpcodecs_vd_libdv;
|
||||
extern const vd_functions_t mpcodecs_vd_lzo;
|
||||
extern const vd_functions_t mpcodecs_vd_qtvideo;
|
||||
@ -65,9 +61,6 @@ extern const vd_functions_t mpcodecs_vd_qtvideo;
|
||||
const vd_functions_t * const mpcodecs_vd_drivers[] = {
|
||||
&mpcodecs_vd_null,
|
||||
&mpcodecs_vd_ffmpeg,
|
||||
#ifdef CONFIG_OGGTHEORA
|
||||
&mpcodecs_vd_theora,
|
||||
#endif
|
||||
#ifdef CONFIG_WIN32DLL
|
||||
&mpcodecs_vd_dshow,
|
||||
&mpcodecs_vd_dmo,
|
||||
@ -87,14 +80,9 @@ const vd_functions_t * const mpcodecs_vd_drivers[] = {
|
||||
&mpcodecs_vd_ijpg,
|
||||
#endif
|
||||
&mpcodecs_vd_mtga,
|
||||
&mpcodecs_vd_sgi,
|
||||
&mpcodecs_vd_mpegpes,
|
||||
#ifdef CONFIG_REALCODECS
|
||||
&mpcodecs_vd_realvid,
|
||||
#endif
|
||||
#ifdef CONFIG_XVID4
|
||||
&mpcodecs_vd_xvid,
|
||||
#endif
|
||||
#ifdef CONFIG_LIBDV095
|
||||
&mpcodecs_vd_libdv,
|
||||
#endif
|
||||
|
@ -1,84 +0,0 @@
|
||||
/*
|
||||
* 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 "config.h"
|
||||
#include "mp_msg.h"
|
||||
#include "libmpdemux/mpeg_hdr.h"
|
||||
|
||||
#include "vd_internal.h"
|
||||
|
||||
static const vd_info_t info =
|
||||
{
|
||||
"MPEG 1/2 Video passthrough",
|
||||
"mpegpes",
|
||||
"A'rpi",
|
||||
"A'rpi",
|
||||
"for hw decoders"
|
||||
};
|
||||
|
||||
LIBVD_EXTERN(mpegpes)
|
||||
|
||||
//#include "libmpdemux/parse_es.h"
|
||||
|
||||
#include "libvo/video_out.h"
|
||||
|
||||
// to set/get/query special features/parameters
|
||||
static int control(sh_video_t *sh,int cmd,void* arg,...){
|
||||
return CONTROL_UNKNOWN;
|
||||
}
|
||||
|
||||
// init driver
|
||||
static int init(sh_video_t *sh){
|
||||
return mpcodecs_config_vo(sh,sh->disp_w,sh->disp_h,IMGFMT_MPEGPES);
|
||||
}
|
||||
|
||||
// uninit driver
|
||||
static void uninit(sh_video_t *sh){
|
||||
}
|
||||
|
||||
// decode a frame
|
||||
static mp_image_t* decode(sh_video_t *sh,void* data,int len,int flags){
|
||||
mp_image_t* mpi;
|
||||
static vo_mpegpes_t packet;
|
||||
mp_mpeg_header_t picture;
|
||||
const unsigned char *d = data;
|
||||
|
||||
if(len>10 && !d[0] && !d[1] && d[2]==1 && d[3]==0xB3) {
|
||||
float old_aspect = sh->aspect;
|
||||
int oldw = sh->disp_w, oldh = sh->disp_h;
|
||||
mp_header_process_sequence_header(&picture, &d[4]);
|
||||
sh->aspect = mpeg12_aspect_info(&picture);
|
||||
sh->disp_w = picture.display_picture_width;
|
||||
sh->disp_h = picture.display_picture_height;
|
||||
if(sh->aspect != old_aspect || sh->disp_w != oldw || sh->disp_h != oldh) {
|
||||
if(!mpcodecs_config_vo(sh, sh->disp_w,sh->disp_h,IMGFMT_MPEGPES))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
mpi=mpcodecs_get_image(sh, MP_IMGTYPE_EXPORT, 0, sh->disp_w, sh->disp_h);
|
||||
packet.data=data;
|
||||
packet.size=len;
|
||||
packet.timestamp=sh->timer*90000.0;
|
||||
packet.id=0x1E0; //+sh_video->ds->id;
|
||||
mpi->planes[0]=(uint8_t*)(&packet);
|
||||
return mpi;
|
||||
}
|
@ -1,343 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2003 Todd Kirby <slapcat@pacbell.net>
|
||||
*
|
||||
* 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 <libavutil/intreadwrite.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "mp_msg.h"
|
||||
#include "mpbswap.h"
|
||||
#include "vd_internal.h"
|
||||
|
||||
#define SGI_HEADER_LEN 512
|
||||
#define SGI_MAGIC 474
|
||||
|
||||
#define SGI_GRAYSCALE_IMAGE 1
|
||||
#define SGI_RGB_IMAGE 3
|
||||
#define SGI_RGBA_IMAGE 4
|
||||
|
||||
#define OUT_PIXEL_STRIDE 3 /* RGB */
|
||||
|
||||
|
||||
static const vd_info_t info =
|
||||
{
|
||||
"SGI Image decoder",
|
||||
"sgi",
|
||||
"Todd Kirby",
|
||||
"Todd Kirby",
|
||||
""
|
||||
};
|
||||
|
||||
LIBVD_EXTERN(sgi)
|
||||
|
||||
typedef struct {
|
||||
short magic;
|
||||
char rle;
|
||||
char bytes_per_channel;
|
||||
unsigned short dimension;
|
||||
unsigned short xsize;
|
||||
unsigned short ysize;
|
||||
unsigned short zsize;
|
||||
} SGIInfo;
|
||||
|
||||
static unsigned int outfmt = IMGFMT_BGR24;
|
||||
|
||||
static unsigned short last_x = -1;
|
||||
static unsigned short last_y = -1;
|
||||
|
||||
|
||||
/* to set/get/query special features/parameters */
|
||||
static int
|
||||
control(sh_video_t* sh, int cmd, void *arg, ...)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case VDCTRL_QUERY_FORMAT:
|
||||
if (*((unsigned int *) arg) == outfmt) {
|
||||
return CONTROL_TRUE;
|
||||
}
|
||||
return CONTROL_FALSE;
|
||||
}
|
||||
return CONTROL_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
/* init driver */
|
||||
static int
|
||||
init(sh_video_t *sh)
|
||||
{
|
||||
sh->context = calloc(1, sizeof(SGIInfo));
|
||||
last_x = -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* uninit driver */
|
||||
static void
|
||||
uninit(sh_video_t *sh)
|
||||
{
|
||||
SGIInfo *info = sh->context;
|
||||
free(info);
|
||||
}
|
||||
|
||||
|
||||
/* expand an rle row into a channel */
|
||||
static void
|
||||
expandrow(unsigned char *optr, unsigned char *iptr, int chan_offset)
|
||||
{
|
||||
unsigned char pixel, count;
|
||||
optr += chan_offset;
|
||||
|
||||
while (1) {
|
||||
pixel = *iptr++;
|
||||
|
||||
if (!(count = (pixel & 0x7f))) {
|
||||
return;
|
||||
}
|
||||
if(pixel & 0x80) {
|
||||
while (count--) {
|
||||
*optr = *iptr;
|
||||
optr += OUT_PIXEL_STRIDE;
|
||||
iptr++;
|
||||
}
|
||||
} else {
|
||||
pixel = *iptr++;
|
||||
|
||||
while (count--) {
|
||||
*optr = pixel;
|
||||
optr += OUT_PIXEL_STRIDE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* expand an rle row into all 3 channels.
|
||||
a separate function for grayscale so we don't slow down the
|
||||
more common case rgb function with a bunch of ifs. */
|
||||
static void
|
||||
expandrow_gs(unsigned char *optr, unsigned char *iptr)
|
||||
{
|
||||
unsigned char pixel, count;
|
||||
|
||||
while (1) {
|
||||
pixel = *iptr++;
|
||||
|
||||
if (!(count = (pixel & 0x7f))) {
|
||||
return;
|
||||
}
|
||||
if(pixel & 0x80) {
|
||||
while (count--) {
|
||||
optr[0] = *iptr;
|
||||
optr[1] = *iptr;
|
||||
optr[2] = *iptr;
|
||||
optr += OUT_PIXEL_STRIDE;
|
||||
iptr++;
|
||||
}
|
||||
} else {
|
||||
pixel = *iptr++;
|
||||
|
||||
while (count--) {
|
||||
optr[0] = pixel;
|
||||
optr[1] = pixel;
|
||||
optr[2] = pixel;
|
||||
optr += OUT_PIXEL_STRIDE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* decode a run length encoded sgi image */
|
||||
static void
|
||||
decode_rle_sgi(SGIInfo *info, unsigned char *data, mp_image_t *mpi)
|
||||
{
|
||||
unsigned char *rle_data, *dest_row;
|
||||
uint32_t *starttab;
|
||||
int y, z, ysize, zsize, chan_offset;
|
||||
long start_offset;
|
||||
|
||||
ysize = info->ysize;
|
||||
zsize = info->zsize;
|
||||
|
||||
/* rle offset table is right after the header */
|
||||
starttab = (uint32_t*)(data + SGI_HEADER_LEN);
|
||||
|
||||
for (z = 0; z < zsize; z++) {
|
||||
|
||||
/* set chan_offset so RGB ends up BGR */
|
||||
chan_offset = (zsize - 1) - z;
|
||||
|
||||
/* The origin for SGI images is the lower-left corner
|
||||
so read scan lines from bottom to top */
|
||||
for (y = ysize - 1; y >= 0; y--) {
|
||||
dest_row = mpi->planes[0] + mpi->stride[0] * (ysize - 1 - y);
|
||||
|
||||
/* set start of next run (offsets are from start of header) */
|
||||
start_offset = AV_RB32(&starttab[y + z * ysize]);
|
||||
|
||||
rle_data = &data[start_offset];
|
||||
|
||||
if(info->zsize == SGI_GRAYSCALE_IMAGE) {
|
||||
expandrow_gs(dest_row, rle_data);
|
||||
} else {
|
||||
expandrow(dest_row, rle_data, chan_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* decode an sgi image */
|
||||
static void
|
||||
decode_uncompressed_sgi(SGIInfo *info, unsigned char *data, mp_image_t *mpi)
|
||||
{
|
||||
unsigned char *src_row, *dest_row;
|
||||
int x, y, z, xsize, ysize, zsize, chan_offset;
|
||||
|
||||
xsize = info->xsize;
|
||||
ysize = info->ysize;
|
||||
zsize = info->zsize;
|
||||
|
||||
/* skip header */
|
||||
data += SGI_HEADER_LEN;
|
||||
|
||||
for (z = 0; z < zsize; z++) {
|
||||
|
||||
/* set row ptr to start of current plane */
|
||||
src_row = data + (xsize * ysize * z);
|
||||
|
||||
/* set chan_offset for RGB -> BGR */
|
||||
chan_offset = (zsize - 1) - z;
|
||||
|
||||
/* the origin for SGI images is the lower-left corner
|
||||
so read scan lines from bottom to top. */
|
||||
for (y = ysize - 1; y >= 0; y--) {
|
||||
dest_row = mpi->planes[0] + mpi->stride[0] * y;
|
||||
for (x = 0; x < xsize; x++) {
|
||||
|
||||
/* we only do 24 bit output so promote 8 bit pixels to 24 */
|
||||
if (zsize == SGI_GRAYSCALE_IMAGE) {
|
||||
/* write greyscale value into all channels */
|
||||
dest_row[0] = src_row[x];
|
||||
dest_row[1] = src_row[x];
|
||||
dest_row[2] = src_row[x];
|
||||
} else {
|
||||
dest_row[chan_offset] = src_row[x];
|
||||
}
|
||||
|
||||
dest_row += OUT_PIXEL_STRIDE;
|
||||
}
|
||||
|
||||
/* move to next row of the current source plane */
|
||||
src_row += xsize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* read sgi header fields */
|
||||
static void
|
||||
read_sgi_header(unsigned char *buf, SGIInfo *info)
|
||||
{
|
||||
/* sgi data is always stored in big endian byte order */
|
||||
info->magic = AV_RB16(&buf[0]);
|
||||
info->rle = buf[2];
|
||||
info->bytes_per_channel = buf[3];
|
||||
info->dimension = AV_RB16(&buf[4]);
|
||||
info->xsize = AV_RB16(&buf[6]);
|
||||
info->ysize = AV_RB16(&buf[8]);
|
||||
info->zsize = AV_RB16(&buf[10]);
|
||||
}
|
||||
|
||||
|
||||
/* decode a frame */
|
||||
static
|
||||
mp_image_t *decode(sh_video_t *sh, void *raw, int len, int flags)
|
||||
{
|
||||
SGIInfo *info = sh->context;
|
||||
unsigned char *data = raw;
|
||||
mp_image_t *mpi;
|
||||
|
||||
if (len <= 0) {
|
||||
return NULL; /* skip frame */
|
||||
}
|
||||
|
||||
read_sgi_header(data, info);
|
||||
|
||||
/* make sure this is an SGI image file */
|
||||
if (info->magic != SGI_MAGIC) {
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Bad magic number in image.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* check image depth */
|
||||
if (info->bytes_per_channel != 1) {
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_INFO,
|
||||
"Unsupported bytes per channel value %i.\n", info->bytes_per_channel);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* check image dimension */
|
||||
if (info->dimension != 2 && info->dimension != 3) {
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Unsupported image dimension %i.\n",
|
||||
info->dimension);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* change rgba images to rgb so alpha channel will be ignored */
|
||||
if (info->zsize == SGI_RGBA_IMAGE) {
|
||||
info->zsize = SGI_RGB_IMAGE;
|
||||
}
|
||||
|
||||
/* check image depth */
|
||||
if (info->zsize != SGI_RGB_IMAGE && info->zsize != SGI_GRAYSCALE_IMAGE) {
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Unsupported image depth.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* (re)init libvo if image size is changed */
|
||||
if (last_x != info->xsize || last_y != info->ysize)
|
||||
{
|
||||
last_x = info->xsize;
|
||||
last_y = info->ysize;
|
||||
|
||||
if (!mpcodecs_config_vo(sh, info->xsize, info->ysize, outfmt)) {
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Config vo failed:\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(mpi = mpcodecs_get_image(sh, MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE,
|
||||
info->xsize, info->ysize))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (info->rle) {
|
||||
decode_rle_sgi(info, data, mpi);
|
||||
} else {
|
||||
decode_uncompressed_sgi(info, data, mpi);
|
||||
}
|
||||
|
||||
return mpi;
|
||||
}
|
@ -1,207 +0,0 @@
|
||||
/*
|
||||
* 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 <stdarg.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <libavutil/intreadwrite.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "mp_msg.h"
|
||||
|
||||
#include "vd_internal.h"
|
||||
|
||||
|
||||
static const vd_info_t info = {
|
||||
"Theora/VP3",
|
||||
"theora",
|
||||
"David Kuehling",
|
||||
"www.theora.org",
|
||||
"Theora project's VP3 codec"
|
||||
};
|
||||
|
||||
LIBVD_EXTERN(theora)
|
||||
|
||||
#include <theora/theora.h>
|
||||
|
||||
#define THEORA_NUM_HEADER_PACKETS 3
|
||||
|
||||
typedef struct theora_struct_st {
|
||||
theora_state st;
|
||||
theora_comment cc;
|
||||
theora_info inf;
|
||||
} theora_struct_t;
|
||||
|
||||
/** Convert Theora pixelformat to the corresponding IMGFMT_ */
|
||||
static uint32_t theora_pixelformat2imgfmt(theora_pixelformat fmt){
|
||||
switch(fmt) {
|
||||
case OC_PF_420: return IMGFMT_YV12;
|
||||
case OC_PF_422: return IMGFMT_422P;
|
||||
case OC_PF_444: return IMGFMT_444P;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// to set/get/query special features/parameters
|
||||
static int control(sh_video_t *sh,int cmd,void* arg,...){
|
||||
theora_struct_t *context = sh->context;
|
||||
switch(cmd) {
|
||||
case VDCTRL_QUERY_FORMAT:
|
||||
if (*(int*)arg == theora_pixelformat2imgfmt(context->inf.pixelformat))
|
||||
return CONTROL_TRUE;
|
||||
return CONTROL_FALSE;
|
||||
}
|
||||
|
||||
return CONTROL_UNKNOWN;
|
||||
}
|
||||
|
||||
/*
|
||||
* init driver
|
||||
*/
|
||||
static int init(sh_video_t *sh){
|
||||
theora_struct_t *context = NULL;
|
||||
uint8_t *extradata = (uint8_t *)(sh->bih + 1);
|
||||
int extradata_size = sh->bih->biSize - sizeof(*sh->bih);
|
||||
int errorCode = 0;
|
||||
ogg_packet op;
|
||||
int i;
|
||||
|
||||
context = calloc (sizeof (theora_struct_t), 1);
|
||||
sh->context = context;
|
||||
if (!context)
|
||||
goto err_out;
|
||||
|
||||
theora_info_init(&context->inf);
|
||||
theora_comment_init(&context->cc);
|
||||
|
||||
/* Read all header packets, pass them to theora_decode_header. */
|
||||
for (i = 0; i < THEORA_NUM_HEADER_PACKETS; i++)
|
||||
{
|
||||
if (extradata_size > 2) {
|
||||
op.bytes = AV_RB16(extradata);
|
||||
op.packet = extradata + 2;
|
||||
op.b_o_s = 1;
|
||||
if (extradata_size < op.bytes + 2) {
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Theora header too small\n");
|
||||
goto err_out;
|
||||
}
|
||||
extradata += op.bytes + 2;
|
||||
extradata_size -= op.bytes + 2;
|
||||
} else {
|
||||
op.bytes = ds_get_packet (sh->ds, &op.packet);
|
||||
op.b_o_s = 1;
|
||||
}
|
||||
|
||||
if ( (errorCode = theora_decode_header (&context->inf, &context->cc, &op)) )
|
||||
{
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Broken Theora header; errorCode=%i!\n", errorCode);
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
/* now init codec */
|
||||
errorCode = theora_decode_init (&context->st, &context->inf);
|
||||
if (errorCode)
|
||||
{
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Theora decode init failed: %i \n", errorCode);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if(sh->aspect==0.0 && context->inf.aspect_denominator!=0)
|
||||
{
|
||||
sh->aspect = ((double)context->inf.aspect_numerator * context->inf.width)/
|
||||
((double)context->inf.aspect_denominator * context->inf.height);
|
||||
}
|
||||
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V,"INFO: Theora video init ok!\n");
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_INFO,"Frame: %dx%d, Picture %dx%d, Offset [%d,%d]\n", context->inf.width, context->inf.height, context->inf.frame_width, context->inf.frame_height, context->inf.offset_x, context->inf.offset_y);
|
||||
|
||||
return mpcodecs_config_vo (sh,context->inf.width,context->inf.height,theora_pixelformat2imgfmt(context->inf.pixelformat));
|
||||
|
||||
err_out:
|
||||
free(context);
|
||||
sh->context = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* uninit driver
|
||||
*/
|
||||
static void uninit(sh_video_t *sh)
|
||||
{
|
||||
theora_struct_t *context = sh->context;
|
||||
|
||||
if (context)
|
||||
{
|
||||
theora_info_clear(&context->inf);
|
||||
theora_comment_clear(&context->cc);
|
||||
theora_clear (&context->st);
|
||||
free (context);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* decode frame
|
||||
*/
|
||||
static mp_image_t* decode(sh_video_t *sh,void* data,int len,int flags)
|
||||
{
|
||||
theora_struct_t *context = sh->context;
|
||||
int errorCode = 0;
|
||||
ogg_packet op;
|
||||
yuv_buffer yuv;
|
||||
mp_image_t* mpi;
|
||||
|
||||
// no delayed frames
|
||||
if (!data || !len)
|
||||
return NULL;
|
||||
|
||||
memset (&op, 0, sizeof (op));
|
||||
op.bytes = len;
|
||||
op.packet = data;
|
||||
op.granulepos = -1;
|
||||
|
||||
errorCode = theora_decode_packetin (&context->st, &op);
|
||||
if (errorCode)
|
||||
{
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Theora decode packetin failed: %i \n",
|
||||
errorCode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
errorCode = theora_decode_YUVout (&context->st, &yuv);
|
||||
if (errorCode)
|
||||
{
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Theora decode YUVout failed: %i \n",
|
||||
errorCode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mpi = mpcodecs_get_image(sh, MP_IMGTYPE_EXPORT, 0, yuv.y_width, yuv.y_height);
|
||||
if(!mpi) return NULL;
|
||||
|
||||
mpi->planes[0]=yuv.y;
|
||||
mpi->stride[0]=yuv.y_stride;
|
||||
mpi->planes[1]=yuv.u;
|
||||
mpi->stride[1]=yuv.uv_stride;
|
||||
mpi->planes[2]=yuv.v;
|
||||
mpi->stride[2]=yuv.uv_stride;
|
||||
|
||||
return mpi;
|
||||
}
|
@ -1,393 +0,0 @@
|
||||
/*
|
||||
* - XviD 1.x decoder module for mplayer -
|
||||
*
|
||||
* Copyright(C) 2003 Marco Belli <elcabesa@inwind.it>
|
||||
* 2003-2004 Edouard Gomez <ed.gomez@free.fr>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
* Includes
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "mp_msg.h"
|
||||
|
||||
#include "vd_internal.h"
|
||||
#include "m_option.h"
|
||||
|
||||
#include <xvid.h>
|
||||
|
||||
/*****************************************************************************
|
||||
* Configuration options
|
||||
****************************************************************************/
|
||||
|
||||
static int do_dr2 = 1;
|
||||
static int filmeffect = 0;
|
||||
static int lumadeblock = 0;
|
||||
static int chromadeblock = 0;
|
||||
static int lumadering = 0;
|
||||
static int chromadering = 0;
|
||||
|
||||
const m_option_t xvid_dec_opts[] = {
|
||||
{ "dr2", &do_dr2, CONF_TYPE_FLAG, 0, 0, 1, NULL},
|
||||
{ "nodr2", &do_dr2, CONF_TYPE_FLAG, 0, 1, 0, NULL},
|
||||
{ "filmeffect", &filmeffect, CONF_TYPE_FLAG, 0, 0, 1, NULL},
|
||||
{ "deblock-luma", &lumadeblock, CONF_TYPE_FLAG, 0, 0, 1, NULL},
|
||||
{ "deblock-chroma", &chromadeblock, CONF_TYPE_FLAG, 0, 0, 1, NULL},
|
||||
{ "dering-luma", &lumadering, CONF_TYPE_FLAG, 0, 0, 1, NULL},
|
||||
{ "dering-chroma", &chromadering, CONF_TYPE_FLAG, 0, 0, 1, NULL},
|
||||
{NULL, NULL, 0, 0, 0, 0, NULL}
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* Module private data
|
||||
****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
int cs;
|
||||
unsigned char img_type;
|
||||
void* hdl;
|
||||
mp_image_t* mpi;
|
||||
int vo_initialized;
|
||||
} priv_t;
|
||||
|
||||
/*****************************************************************************
|
||||
* Module function helpers
|
||||
****************************************************************************/
|
||||
|
||||
static float stats2aspect(xvid_dec_stats_t *stats);
|
||||
|
||||
/*****************************************************************************
|
||||
* Video decoder API function definitions
|
||||
****************************************************************************/
|
||||
|
||||
/*============================================================================
|
||||
* control - to set/get/query special features/parameters
|
||||
*==========================================================================*/
|
||||
|
||||
static int control(sh_video_t *sh,int cmd,void* arg,...)
|
||||
{
|
||||
return CONTROL_UNKNOWN;
|
||||
}
|
||||
|
||||
/*============================================================================
|
||||
* init - initialize the codec
|
||||
*==========================================================================*/
|
||||
|
||||
static int init(sh_video_t *sh)
|
||||
{
|
||||
xvid_gbl_info_t xvid_gbl_info;
|
||||
xvid_gbl_init_t xvid_ini;
|
||||
xvid_dec_create_t dec_p;
|
||||
priv_t* p;
|
||||
int cs;
|
||||
|
||||
memset(&xvid_gbl_info, 0, sizeof(xvid_gbl_info_t));
|
||||
xvid_gbl_info.version = XVID_VERSION;
|
||||
|
||||
memset(&xvid_ini, 0, sizeof(xvid_gbl_init_t));
|
||||
xvid_ini.version = XVID_VERSION;
|
||||
|
||||
memset(&dec_p, 0, sizeof(xvid_dec_create_t));
|
||||
dec_p.version = XVID_VERSION;
|
||||
|
||||
|
||||
switch(sh->codec->outfmt[sh->outfmtidx]){
|
||||
case IMGFMT_YV12:
|
||||
/* We will use our own buffers, this speeds decoding avoiding
|
||||
* frame memcpy's overhead */
|
||||
cs = (do_dr2)?XVID_CSP_INTERNAL:XVID_CSP_USER;
|
||||
break;
|
||||
case IMGFMT_YUY2:
|
||||
cs = XVID_CSP_YUY2;
|
||||
break;
|
||||
case IMGFMT_UYVY:
|
||||
cs = XVID_CSP_UYVY;
|
||||
break;
|
||||
case IMGFMT_I420:
|
||||
case IMGFMT_IYUV:
|
||||
/* We will use our own buffers, this speeds decoding avoiding
|
||||
* frame memcpy's overhead */
|
||||
cs = (do_dr2)?XVID_CSP_INTERNAL:XVID_CSP_USER;
|
||||
break;
|
||||
case IMGFMT_BGR15:
|
||||
cs = XVID_CSP_RGB555;
|
||||
break;
|
||||
case IMGFMT_BGR16:
|
||||
cs = XVID_CSP_RGB565;
|
||||
break;
|
||||
case IMGFMT_BGR32:
|
||||
cs = XVID_CSP_BGRA;
|
||||
break;
|
||||
case IMGFMT_YVYU:
|
||||
cs = XVID_CSP_YVYU;
|
||||
break;
|
||||
default:
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Unsupported out_fmt: 0x%X\n",
|
||||
sh->codec->outfmt[sh->outfmtidx]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Gather some information about the host library */
|
||||
if(xvid_global(NULL, XVID_GBL_INFO, &xvid_gbl_info, NULL) < 0) {
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_INFO, "xvid: could not get information about the library\n");
|
||||
} else {
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_INFO, "xvid: using library version %d.%d.%d (build %s)\n",
|
||||
XVID_VERSION_MAJOR(xvid_gbl_info.actual_version),
|
||||
XVID_VERSION_MINOR(xvid_gbl_info.actual_version),
|
||||
XVID_VERSION_PATCH(xvid_gbl_info.actual_version),
|
||||
xvid_gbl_info.build);
|
||||
}
|
||||
|
||||
/* Initialize the xvidcore library */
|
||||
if(xvid_global(NULL, XVID_GBL_INIT, &xvid_ini, NULL))
|
||||
return 0;
|
||||
|
||||
/* We use 0 width and height so xvidcore will resize its buffers
|
||||
* if required. That allows this vd plugin to do resize on first
|
||||
* VOL encountered (don't trust containers' width and height) */
|
||||
dec_p.width = 0;
|
||||
dec_p.height = 0;
|
||||
|
||||
/* Get a decoder instance */
|
||||
if(xvid_decore(0, XVID_DEC_CREATE, &dec_p, NULL)<0) {
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_ERR, "XviD init failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = malloc(sizeof(priv_t));
|
||||
p->cs = cs;
|
||||
p->hdl = dec_p.handle;
|
||||
p->vo_initialized = 0;
|
||||
sh->context = p;
|
||||
|
||||
switch(cs) {
|
||||
case XVID_CSP_INTERNAL:
|
||||
p->img_type = MP_IMGTYPE_EXPORT;
|
||||
break;
|
||||
case XVID_CSP_USER:
|
||||
p->img_type = MP_IMGTYPE_STATIC;
|
||||
break;
|
||||
default:
|
||||
p->img_type = MP_IMGTYPE_TEMP;
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*============================================================================
|
||||
* uninit - close the codec
|
||||
*==========================================================================*/
|
||||
|
||||
static void uninit(sh_video_t *sh){
|
||||
priv_t* p = sh->context;
|
||||
if(!p)
|
||||
return;
|
||||
xvid_decore(p->hdl,XVID_DEC_DESTROY, NULL, NULL);
|
||||
free(p);
|
||||
}
|
||||
|
||||
/*============================================================================
|
||||
* decode - decode a frame from stream
|
||||
*==========================================================================*/
|
||||
|
||||
static mp_image_t* decode(sh_video_t *sh, void* data, int len, int flags)
|
||||
{
|
||||
xvid_dec_frame_t dec;
|
||||
xvid_dec_stats_t stats;
|
||||
mp_image_t* mpi = NULL;
|
||||
|
||||
priv_t* p = sh->context;
|
||||
|
||||
|
||||
if(!data || len <= 0)
|
||||
return NULL;
|
||||
|
||||
memset(&dec,0,sizeof(xvid_dec_frame_t));
|
||||
memset(&stats, 0, sizeof(xvid_dec_stats_t));
|
||||
dec.version = XVID_VERSION;
|
||||
stats.version = XVID_VERSION;
|
||||
|
||||
dec.bitstream = data;
|
||||
dec.length = len;
|
||||
|
||||
dec.general |= XVID_LOWDELAY
|
||||
/* XXX: if lowdelay is unset, and xvidcore internal buffers are
|
||||
* used => crash. MUST FIX */
|
||||
| (filmeffect ? XVID_FILMEFFECT : 0 )
|
||||
| (lumadeblock ? XVID_DEBLOCKY : 0 )
|
||||
| (chromadeblock ? XVID_DEBLOCKUV : 0 );
|
||||
#if XVID_API >= XVID_MAKE_API(4,1)
|
||||
dec.general |= (lumadering ? XVID_DEBLOCKY|XVID_DERINGY : 0 );
|
||||
dec.general |= (chromadering ? XVID_DEBLOCKUV|XVID_DERINGUV : 0 );
|
||||
#endif
|
||||
dec.output.csp = p->cs;
|
||||
|
||||
/* Decoding loop because xvidcore may return VOL information for
|
||||
* on the fly buffer resizing. In that case we must decode VOL,
|
||||
* init VO, then decode the frame */
|
||||
do {
|
||||
int consumed;
|
||||
|
||||
/* If we don't know frame size yet, don't even try to request
|
||||
* a buffer, we must loop until we find a VOL, so VO plugin
|
||||
* is initialized and we can obviously output something */
|
||||
if (p->vo_initialized) {
|
||||
mpi = mpcodecs_get_image(sh, p->img_type,
|
||||
MP_IMGFLAG_ACCEPT_STRIDE,
|
||||
sh->disp_w, sh->disp_h);
|
||||
|
||||
if(p->cs != XVID_CSP_INTERNAL) {
|
||||
dec.output.plane[0] = mpi->planes[0];
|
||||
dec.output.plane[1] = mpi->planes[1];
|
||||
dec.output.plane[2] = mpi->planes[2];
|
||||
|
||||
dec.output.stride[0] = mpi->stride[0];
|
||||
dec.output.stride[1] = mpi->stride[1];
|
||||
dec.output.stride[2] = mpi->stride[2];
|
||||
}
|
||||
}
|
||||
|
||||
/* Decode data */
|
||||
consumed = xvid_decore(p->hdl, XVID_DEC_DECODE, &dec, &stats);
|
||||
if (consumed < 0) {
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Decoding error\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Found a VOL information stats, if VO plugin is not initialized
|
||||
* yet then do it now */
|
||||
if (stats.type == XVID_TYPE_VOL && !p->vo_initialized) {
|
||||
sh->aspect = stats2aspect(&stats);
|
||||
if(!mpcodecs_config_vo(sh, stats.data.vol.width, stats.data.vol.height, IMGFMT_YV12))
|
||||
return NULL;
|
||||
|
||||
/* Don't take this path twice */
|
||||
p->vo_initialized = !p->vo_initialized;
|
||||
}
|
||||
|
||||
/* Don't forget to update buffer position and buffer length */
|
||||
dec.bitstream = (char *)dec.bitstream + consumed;
|
||||
dec.length -= consumed;
|
||||
} while ((stats.type == XVID_TYPE_VOL || stats.type == XVID_TYPE_NOTHING) && dec.length > 0);
|
||||
|
||||
/* There are two ways to get out of the decoding loop:
|
||||
* - a frame has been returned
|
||||
* - no more data in buffer and no frames returned */
|
||||
|
||||
/* If mpi is NULL, it proves nothing has been returned by the decoder
|
||||
* so don't try to display internal buffers. */
|
||||
if (mpi != NULL && p->cs == XVID_CSP_INTERNAL) {
|
||||
mpi->planes[0] = dec.output.plane[0];
|
||||
mpi->planes[1] = dec.output.plane[1];
|
||||
mpi->planes[2] = dec.output.plane[2];
|
||||
|
||||
mpi->stride[0] = dec.output.stride[0];
|
||||
mpi->stride[1] = dec.output.stride[1];
|
||||
mpi->stride[2] = dec.output.stride[2];
|
||||
}
|
||||
|
||||
/* If we got out the decoding loop because the buffer was empty and there was nothing
|
||||
* to output yet, then just return NULL */
|
||||
return (stats.type == XVID_TYPE_NOTHING) ? NULL : mpi;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Helper functions
|
||||
****************************************************************************/
|
||||
|
||||
/* Returns DAR value according to VOL's informations contained in stats
|
||||
* param */
|
||||
static float stats2aspect(xvid_dec_stats_t *stats)
|
||||
{
|
||||
if (stats->type == XVID_TYPE_VOL) {
|
||||
float wpar;
|
||||
float hpar;
|
||||
float dar;
|
||||
|
||||
/* MPEG4 strem stores PAR (Pixel Aspect Ratio), mplayer uses
|
||||
* DAR (Display Aspect Ratio)
|
||||
*
|
||||
* Both are related thanks to the equation:
|
||||
* width
|
||||
* DAR = ----- x PAR
|
||||
* height
|
||||
*
|
||||
* As MPEG4 is so well designed (*cough*), VOL header carries
|
||||
* both informations together -- lucky eh ? */
|
||||
|
||||
switch (stats->data.vol.par) {
|
||||
case XVID_PAR_11_VGA: /* 1:1 vga (square), default if supplied PAR is not a valid value */
|
||||
wpar = hpar = 1.0f;
|
||||
break;
|
||||
case XVID_PAR_43_PAL: /* 4:3 pal (12:11 625-line) */
|
||||
wpar = 12;
|
||||
hpar = 11;
|
||||
break;
|
||||
case XVID_PAR_43_NTSC: /* 4:3 ntsc (10:11 525-line) */
|
||||
wpar = 10;
|
||||
hpar = 11;
|
||||
break;
|
||||
case XVID_PAR_169_PAL: /* 16:9 pal (16:11 625-line) */
|
||||
wpar = 16;
|
||||
hpar = 11;
|
||||
break;
|
||||
case XVID_PAR_169_NTSC: /* 16:9 ntsc (40:33 525-line) */
|
||||
wpar = 40;
|
||||
hpar = 33;
|
||||
break;
|
||||
case XVID_PAR_EXT: /* extended par; use par_width, par_height */
|
||||
wpar = stats->data.vol.par_width;
|
||||
hpar = stats->data.vol.par_height;
|
||||
break;
|
||||
default:
|
||||
wpar = hpar = 1.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
dar = ((float)stats->data.vol.width*wpar);
|
||||
dar /= ((float)stats->data.vol.height*hpar);
|
||||
|
||||
return dar;
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Module structure definition
|
||||
****************************************************************************/
|
||||
|
||||
static const vd_info_t info =
|
||||
{
|
||||
"XviD 1.0 decoder",
|
||||
"xvid",
|
||||
"Marco Belli <elcabesa@inwind.it>, Edouard Gomez <ed.gomez@free.fr>",
|
||||
"Marco Belli <elcabesa@inwind.it>, Edouard Gomez <ed.gomez@free.fr>",
|
||||
"No Comment"
|
||||
};
|
||||
|
||||
LIBVD_EXTERN(xvid)
|
||||
|
||||
/* Please do not change that tag comment.
|
||||
* arch-tag: b7d654a5-76ea-4768-9713-2c791567fe7d mplayer xvid decoder module */
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Nico Sabbi
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#include "aac_hdr.h"
|
||||
#include "libavutil/attributes.h"
|
||||
|
||||
/// \param srate (out) sample rate
|
||||
/// \param num (out) number of audio frames in this ADTS frame
|
||||
/// \return size of the ADTS frame in bytes
|
||||
/// aac_parse_frames needs a buffer at least 8 bytes long
|
||||
int aac_parse_frame(uint8_t *buf, int *srate, int *num)
|
||||
{
|
||||
int i = 0, sr, fl = 0, id av_unused;
|
||||
static int srates[] = {96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 0, 0, 0};
|
||||
|
||||
if((buf[i] != 0xFF) || ((buf[i+1] & 0xF6) != 0xF0))
|
||||
return 0;
|
||||
|
||||
id = (buf[i+1] >> 3) & 0x01; //id=1 mpeg2, 0: mpeg4
|
||||
sr = (buf[i+2] >> 2) & 0x0F;
|
||||
if(sr > 11)
|
||||
return 0;
|
||||
*srate = srates[sr];
|
||||
|
||||
fl = ((buf[i+3] & 0x03) << 11) | (buf[i+4] << 3) | ((buf[i+5] >> 5) & 0x07);
|
||||
*num = (buf[i+6] & 0x02) + 1;
|
||||
|
||||
return fl;
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MPLAYER_AAC_HDR_H
|
||||
#define MPLAYER_AAC_HDR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
int aac_parse_frame(uint8_t *buf, int *srate, int *num);
|
||||
|
||||
#endif /* MPLAYER_AAC_HDR_H */
|
@ -1,260 +0,0 @@
|
||||
/*
|
||||
* 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 <string.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "mp_msg.h"
|
||||
|
||||
#include "stream/stream.h"
|
||||
#include "demuxer.h"
|
||||
#include "parse_es.h"
|
||||
#include "stheader.h"
|
||||
#include "aac_hdr.h"
|
||||
#include "ms_hdr.h"
|
||||
|
||||
typedef struct {
|
||||
uint8_t *buf;
|
||||
uint64_t size; /// amount of time of data packets pushed to demuxer->audio (in bytes)
|
||||
float time; /// amount of time elapsed based upon samples_per_frame/sample_rate (in milliseconds)
|
||||
float last_pts; /// last pts seen
|
||||
int bitrate; /// bitrate computed as size/time
|
||||
} aac_priv_t;
|
||||
|
||||
static int demux_aac_init(demuxer_t *demuxer)
|
||||
{
|
||||
aac_priv_t *priv;
|
||||
|
||||
priv = calloc(1, sizeof(aac_priv_t));
|
||||
if(!priv)
|
||||
return 0;
|
||||
|
||||
priv->buf = malloc(8);
|
||||
if(!priv->buf)
|
||||
{
|
||||
free(priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
demuxer->priv = priv;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void demux_close_aac(demuxer_t *demuxer)
|
||||
{
|
||||
aac_priv_t *priv = (aac_priv_t *) demuxer->priv;
|
||||
|
||||
if(!priv)
|
||||
return;
|
||||
|
||||
free(priv->buf);
|
||||
|
||||
free(demuxer->priv);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/// returns DEMUXER_TYPE_AAC if it finds 8 ADTS frames in 32768 bytes, 0 otherwise
|
||||
static int demux_aac_probe(demuxer_t *demuxer)
|
||||
{
|
||||
int cnt = 0, c, len, srate, num;
|
||||
off_t init, probed;
|
||||
aac_priv_t *priv;
|
||||
|
||||
if(! demux_aac_init(demuxer))
|
||||
{
|
||||
mp_msg(MSGT_DEMUX, MSGL_ERR, "COULDN'T INIT aac_demux, exit\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
priv = (aac_priv_t *) demuxer->priv;
|
||||
|
||||
init = probed = stream_tell(demuxer->stream);
|
||||
while(probed-init <= 32768 && cnt < 8)
|
||||
{
|
||||
c = 0;
|
||||
while(c != 0xFF)
|
||||
{
|
||||
c = stream_read_char(demuxer->stream);
|
||||
if(c < 0)
|
||||
goto fail;
|
||||
}
|
||||
priv->buf[0] = 0xFF;
|
||||
if(stream_read(demuxer->stream, &(priv->buf[1]), 7) < 7)
|
||||
goto fail;
|
||||
|
||||
len = aac_parse_frame(priv->buf, &srate, &num);
|
||||
if(len > 0)
|
||||
{
|
||||
cnt++;
|
||||
stream_skip(demuxer->stream, len - 8);
|
||||
}
|
||||
probed = stream_tell(demuxer->stream);
|
||||
}
|
||||
|
||||
stream_seek(demuxer->stream, init);
|
||||
if(cnt < 8)
|
||||
goto fail;
|
||||
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "demux_aac_probe, INIT: %"PRIu64", PROBED: %"PRIu64", cnt: %d\n", init, probed, cnt);
|
||||
return DEMUXER_TYPE_AAC;
|
||||
|
||||
fail:
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "demux_aac_probe, failed to detect an AAC stream\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static demuxer_t* demux_aac_open(demuxer_t *demuxer)
|
||||
{
|
||||
sh_audio_t *sh;
|
||||
|
||||
sh = new_sh_audio(demuxer, 0);
|
||||
sh->ds = demuxer->audio;
|
||||
sh->format = mmioFOURCC('M', 'P', '4', 'A');
|
||||
demuxer->audio->id = 0;
|
||||
demuxer->audio->sh = sh;
|
||||
|
||||
demuxer->filepos = stream_tell(demuxer->stream);
|
||||
|
||||
return demuxer;
|
||||
}
|
||||
|
||||
static int demux_aac_fill_buffer(demuxer_t *demuxer, demux_stream_t *ds)
|
||||
{
|
||||
aac_priv_t *priv = (aac_priv_t *) demuxer->priv;
|
||||
demux_packet_t *dp;
|
||||
int c1, c2, len, srate, num;
|
||||
float tm = 0;
|
||||
|
||||
if(demuxer->stream->eof || (demuxer->movi_end && stream_tell(demuxer->stream) >= demuxer->movi_end))
|
||||
return 0;
|
||||
|
||||
while(! demuxer->stream->eof)
|
||||
{
|
||||
c1 = c2 = 0;
|
||||
while(c1 != 0xFF)
|
||||
{
|
||||
c1 = stream_read_char(demuxer->stream);
|
||||
if(c1 < 0)
|
||||
return 0;
|
||||
}
|
||||
c2 = stream_read_char(demuxer->stream);
|
||||
if(c2 < 0)
|
||||
return 0;
|
||||
if((c2 & 0xF6) != 0xF0)
|
||||
continue;
|
||||
|
||||
priv->buf[0] = (unsigned char) c1;
|
||||
priv->buf[1] = (unsigned char) c2;
|
||||
if(stream_read(demuxer->stream, &(priv->buf[2]), 6) < 6)
|
||||
return 0;
|
||||
|
||||
len = aac_parse_frame(priv->buf, &srate, &num);
|
||||
if(len > 0)
|
||||
{
|
||||
dp = new_demux_packet(len);
|
||||
if(! dp)
|
||||
{
|
||||
mp_msg(MSGT_DEMUX, MSGL_ERR, "fill_buffer, NEW_ADD_PACKET(%d)FAILED\n", len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
memcpy(dp->buffer, priv->buf, 8);
|
||||
stream_read(demuxer->stream, &(dp->buffer[8]), len-8);
|
||||
if(srate)
|
||||
tm = (float) (num * 1024.0/srate);
|
||||
priv->last_pts += tm;
|
||||
dp->pts = priv->last_pts;
|
||||
//fprintf(stderr, "\nPTS: %.3f\n", dp->pts);
|
||||
ds_add_packet(demuxer->audio, dp);
|
||||
priv->size += len;
|
||||
priv->time += tm;
|
||||
|
||||
priv->bitrate = (int) (priv->size / priv->time);
|
||||
demuxer->filepos = stream_tell(demuxer->stream);
|
||||
|
||||
return len;
|
||||
}
|
||||
else
|
||||
stream_skip(demuxer->stream, -6);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//This is an almost verbatim copy of high_res_mp3_seek(), from demux_audio.c
|
||||
static void demux_aac_seek(demuxer_t *demuxer, float rel_seek_secs, float audio_delay, int flags)
|
||||
{
|
||||
aac_priv_t *priv = (aac_priv_t *) demuxer->priv;
|
||||
demux_stream_t *d_audio=demuxer->audio;
|
||||
sh_audio_t *sh_audio=d_audio->sh;
|
||||
float time;
|
||||
|
||||
ds_free_packs(d_audio);
|
||||
|
||||
time = (flags & SEEK_ABSOLUTE) ? rel_seek_secs - priv->last_pts : rel_seek_secs;
|
||||
if(time < 0)
|
||||
{
|
||||
stream_seek(demuxer->stream, demuxer->movi_start);
|
||||
time = priv->last_pts + time;
|
||||
priv->last_pts = 0;
|
||||
}
|
||||
|
||||
if(time > 0)
|
||||
{
|
||||
int len, nf, srate, num;
|
||||
|
||||
nf = time * sh_audio->samplerate/1024;
|
||||
|
||||
while(nf > 0)
|
||||
{
|
||||
if(stream_read(demuxer->stream,priv->buf, 8) < 8)
|
||||
break;
|
||||
len = aac_parse_frame(priv->buf, &srate, &num);
|
||||
if(len <= 0)
|
||||
{
|
||||
stream_skip(demuxer->stream, -7);
|
||||
continue;
|
||||
}
|
||||
stream_skip(demuxer->stream, len - 8);
|
||||
priv->last_pts += (float) (num*1024.0/srate);
|
||||
nf -= num;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const demuxer_desc_t demuxer_desc_aac = {
|
||||
"AAC demuxer",
|
||||
"aac",
|
||||
"AAC",
|
||||
"Nico Sabbi",
|
||||
"Raw AAC files ",
|
||||
DEMUXER_TYPE_AAC,
|
||||
0, // unsafe autodetect
|
||||
demux_aac_probe,
|
||||
demux_aac_fill_buffer,
|
||||
demux_aac_open,
|
||||
demux_close_aac,
|
||||
demux_aac_seek,
|
||||
NULL
|
||||
};
|
@ -29,7 +29,6 @@
|
||||
#include "stream/stream.h"
|
||||
#include "demuxer.h"
|
||||
#include "stheader.h"
|
||||
#include "demux_ogg.h"
|
||||
#include "aviheader.h"
|
||||
|
||||
extern const demuxer_desc_t demuxer_desc_avi_ni;
|
||||
@ -862,38 +861,6 @@ static int avi_check_file(demuxer_t *demuxer)
|
||||
}
|
||||
|
||||
|
||||
static demuxer_t* demux_open_hack_avi(demuxer_t *demuxer)
|
||||
{
|
||||
struct MPOpts *opts = demuxer->opts;
|
||||
sh_audio_t* sh_a;
|
||||
|
||||
demuxer = demux_open_avi(demuxer);
|
||||
if(!demuxer) return NULL; // failed to open
|
||||
sh_a = demuxer->audio->sh;
|
||||
if(demuxer->audio->id != -2 && sh_a) {
|
||||
#ifdef CONFIG_OGGVORBIS
|
||||
// support for Ogg-in-AVI:
|
||||
if(sh_a->format == 0xFFFE)
|
||||
demuxer = init_avi_with_ogg(demuxer);
|
||||
else if(sh_a->format == 0x674F) {
|
||||
stream_t* s;
|
||||
demuxer_t *od;
|
||||
s = new_ds_stream(demuxer->audio);
|
||||
od = new_demuxer(opts, s,DEMUXER_TYPE_OGG,-1,-2,-2,NULL);
|
||||
if(!demux_ogg_open(od)) {
|
||||
mp_tmsg( MSGT_DEMUXER,MSGL_ERR,"Unable to open the Ogg demuxer.\n");
|
||||
free_stream(s);
|
||||
demuxer->audio->id = -2;
|
||||
} else
|
||||
demuxer = new_demuxers_demuxer(demuxer,od,demuxer);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return demuxer;
|
||||
}
|
||||
|
||||
|
||||
const demuxer_desc_t demuxer_desc_avi = {
|
||||
"AVI demuxer",
|
||||
"avi",
|
||||
@ -904,7 +871,7 @@ const demuxer_desc_t demuxer_desc_avi = {
|
||||
1, // safe autodetect
|
||||
avi_check_file,
|
||||
demux_avi_fill_buffer,
|
||||
demux_open_hack_avi,
|
||||
demux_open_avi,
|
||||
demux_close_avi,
|
||||
demux_seek_avi,
|
||||
demux_avi_control
|
||||
@ -920,7 +887,7 @@ const demuxer_desc_t demuxer_desc_avi_ni = {
|
||||
1, // safe autodetect
|
||||
avi_check_file,
|
||||
demux_avi_fill_buffer_ni,
|
||||
demux_open_hack_avi,
|
||||
demux_open_avi,
|
||||
demux_close_avi,
|
||||
demux_seek_avi,
|
||||
demux_avi_control
|
||||
@ -936,7 +903,7 @@ const demuxer_desc_t demuxer_desc_avi_nini = {
|
||||
1, // safe autodetect
|
||||
avi_check_file,
|
||||
demux_avi_fill_buffer_nini,
|
||||
demux_open_hack_avi,
|
||||
demux_open_avi,
|
||||
demux_close_avi,
|
||||
demux_seek_avi,
|
||||
demux_avi_control
|
||||
|
@ -1,490 +0,0 @@
|
||||
/*
|
||||
* FILM file parser
|
||||
* Copyright (C) 2002 Mike Melanson
|
||||
*
|
||||
* This demuxer handles FILM (a.k.a. CPK) files commonly found on Sega
|
||||
* Saturn CD-ROM games. FILM files have also been found on 3DO games.
|
||||
*
|
||||
* details of the FILM file format can be found at:
|
||||
* http://www.pcisys.net/~melanson/codecs/
|
||||
*
|
||||
* 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 "mp_msg.h"
|
||||
|
||||
#include "stream/stream.h"
|
||||
#include "demuxer.h"
|
||||
#include "stheader.h"
|
||||
|
||||
// chunk types found in a FILM file
|
||||
#define CHUNK_FILM mmioFOURCC('F', 'I', 'L', 'M')
|
||||
#define CHUNK_FDSC mmioFOURCC('F', 'D', 'S', 'C')
|
||||
#define CHUNK_STAB mmioFOURCC('S', 'T', 'A', 'B')
|
||||
|
||||
typedef struct film_chunk_t
|
||||
{
|
||||
off_t chunk_offset;
|
||||
int chunk_size;
|
||||
unsigned int syncinfo1;
|
||||
unsigned int syncinfo2;
|
||||
|
||||
float pts;
|
||||
} film_chunk_t;
|
||||
|
||||
typedef struct film_data_t
|
||||
{
|
||||
unsigned int total_chunks;
|
||||
unsigned int current_chunk;
|
||||
film_chunk_t *chunks;
|
||||
unsigned int chunks_per_second;
|
||||
unsigned int film_version;
|
||||
} film_data_t;
|
||||
|
||||
static void demux_seek_film(demuxer_t *demuxer, float rel_seek_secs, float audio_delay, int flags)
|
||||
{
|
||||
film_data_t *film_data = (film_data_t *)demuxer->priv;
|
||||
int new_current_chunk=(flags&SEEK_ABSOLUTE)?0:film_data->current_chunk;
|
||||
|
||||
if(flags&SEEK_FACTOR)
|
||||
new_current_chunk += rel_seek_secs * film_data->total_chunks; // 0..1
|
||||
else
|
||||
new_current_chunk += rel_seek_secs * film_data->chunks_per_second; // secs
|
||||
|
||||
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_INFO,"current, total chunks = %d, %d; seek %5.3f sec, new chunk guess = %d\n",
|
||||
film_data->current_chunk, film_data->total_chunks,
|
||||
rel_seek_secs, new_current_chunk);
|
||||
|
||||
// check if the new chunk number is valid
|
||||
if (new_current_chunk < 0)
|
||||
new_current_chunk = 0;
|
||||
if ((unsigned int)new_current_chunk > film_data->total_chunks)
|
||||
new_current_chunk = film_data->total_chunks - 1;
|
||||
|
||||
while (((film_data->chunks[new_current_chunk].syncinfo1 == 0xFFFFFFFF) ||
|
||||
(film_data->chunks[new_current_chunk].syncinfo1 & 0x80000000)) &&
|
||||
(new_current_chunk > 0))
|
||||
new_current_chunk--;
|
||||
|
||||
film_data->current_chunk = new_current_chunk;
|
||||
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_INFO," (flags = %X) actual new chunk = %d (syncinfo1 = %08X)\n",
|
||||
flags, film_data->current_chunk, film_data->chunks[film_data->current_chunk].syncinfo1);
|
||||
demuxer->video->pts=film_data->chunks[film_data->current_chunk].pts;
|
||||
|
||||
}
|
||||
|
||||
// return value:
|
||||
// 0 = EOF or no stream found
|
||||
// 1 = successfully read a packet
|
||||
static int demux_film_fill_buffer(demuxer_t *demuxer, demux_stream_t *ds)
|
||||
{
|
||||
int i;
|
||||
unsigned char byte_swap;
|
||||
int cvid_size;
|
||||
sh_video_t *sh_video = demuxer->video->sh;
|
||||
sh_audio_t *sh_audio = demuxer->audio->sh;
|
||||
film_data_t *film_data = (film_data_t *)demuxer->priv;
|
||||
film_chunk_t film_chunk;
|
||||
int length_fix_bytes;
|
||||
demux_packet_t* dp;
|
||||
|
||||
// see if the end has been reached
|
||||
if (film_data->current_chunk >= film_data->total_chunks)
|
||||
return 0;
|
||||
|
||||
film_chunk = film_data->chunks[film_data->current_chunk];
|
||||
|
||||
// position stream and fetch chunk
|
||||
stream_seek(demuxer->stream, film_chunk.chunk_offset);
|
||||
|
||||
// load the chunks manually (instead of using ds_read_packet()), since
|
||||
// they require some adjustment
|
||||
// (all ones in syncinfo1 indicates an audio chunk)
|
||||
if (film_chunk.syncinfo1 == 0xFFFFFFFF)
|
||||
{
|
||||
if(demuxer->audio->id>=-1){ // audio not disabled
|
||||
dp = new_demux_packet(film_chunk.chunk_size);
|
||||
if (stream_read(demuxer->stream, dp->buffer, film_chunk.chunk_size) !=
|
||||
film_chunk.chunk_size)
|
||||
return 0;
|
||||
dp->pts = film_chunk.pts;
|
||||
dp->pos = film_chunk.chunk_offset;
|
||||
|
||||
// adjust the data before queuing it:
|
||||
// 8-bit: signed -> unsigned
|
||||
// 16-bit: big-endian -> little-endian
|
||||
if (sh_audio->wf->wBitsPerSample == 8)
|
||||
for (i = 0; i < film_chunk.chunk_size; i++)
|
||||
dp->buffer[i] += 128;
|
||||
else
|
||||
for (i = 0; i < film_chunk.chunk_size; i += 2)
|
||||
{
|
||||
byte_swap = dp->buffer[i];
|
||||
dp->buffer[i] = dp->buffer[i + 1];
|
||||
dp->buffer[i + 1] = byte_swap;
|
||||
}
|
||||
|
||||
/* for SegaSaturn .cpk file, translate audio data if stereo */
|
||||
if (sh_audio->wf->nChannels == 2) {
|
||||
if (sh_audio->wf->wBitsPerSample == 8) {
|
||||
unsigned char* tmp = dp->buffer;
|
||||
unsigned char buf[film_chunk.chunk_size];
|
||||
for(i = 0; i < film_chunk.chunk_size/2; i++) {
|
||||
buf[i*2] = tmp[i];
|
||||
buf[i*2+1] = tmp[film_chunk.chunk_size/2+i];
|
||||
}
|
||||
memcpy( tmp, buf, film_chunk.chunk_size );
|
||||
}
|
||||
else {/* for 16bit */
|
||||
unsigned short *tmp = (unsigned short *)dp->buffer;
|
||||
unsigned short buf[film_chunk.chunk_size/2];
|
||||
for(i = 0; i < film_chunk.chunk_size/4; i++) {
|
||||
buf[i*2] = tmp[i];
|
||||
buf[i*2+1] = tmp[film_chunk.chunk_size/4+i];
|
||||
}
|
||||
memcpy( tmp, buf, film_chunk.chunk_size );
|
||||
}
|
||||
}
|
||||
|
||||
// append packet to DS stream
|
||||
ds_add_packet(demuxer->audio, dp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the demuxer is dealing with CVID data, deal with it a special way
|
||||
if (sh_video->format == mmioFOURCC('c', 'v', 'i', 'd'))
|
||||
{
|
||||
if (film_data->film_version)
|
||||
length_fix_bytes = 2;
|
||||
else
|
||||
length_fix_bytes = 6;
|
||||
|
||||
// account for the fix bytes when allocating the buffer
|
||||
dp = new_demux_packet(film_chunk.chunk_size - length_fix_bytes);
|
||||
|
||||
// these CVID data chunks have a few extra bytes; skip them
|
||||
if (stream_read(demuxer->stream, dp->buffer, 10) != 10)
|
||||
return 0;
|
||||
stream_skip(demuxer->stream, length_fix_bytes);
|
||||
|
||||
if (stream_read(demuxer->stream, dp->buffer + 10,
|
||||
film_chunk.chunk_size - (10 + length_fix_bytes)) !=
|
||||
(film_chunk.chunk_size - (10 + length_fix_bytes)))
|
||||
return 0;
|
||||
|
||||
dp->pts = film_chunk.pts;
|
||||
dp->pos = film_chunk.chunk_offset;
|
||||
dp->keyframe = film_chunk.syncinfo1 & 0x80000000;
|
||||
|
||||
// fix the CVID chunk size
|
||||
cvid_size = film_chunk.chunk_size - length_fix_bytes;
|
||||
dp->buffer[1] = (cvid_size >> 16) & 0xFF;
|
||||
dp->buffer[2] = (cvid_size >> 8) & 0xFF;
|
||||
dp->buffer[3] = (cvid_size >> 0) & 0xFF;
|
||||
|
||||
// append packet to DS stream
|
||||
ds_add_packet(demuxer->video, dp);
|
||||
}
|
||||
else
|
||||
{
|
||||
ds_read_packet(demuxer->video, demuxer->stream, film_chunk.chunk_size,
|
||||
film_chunk.pts,
|
||||
film_chunk.chunk_offset, (film_chunk.syncinfo1 & 0x80000000) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
film_data->current_chunk++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static demuxer_t* demux_open_film(demuxer_t* demuxer)
|
||||
{
|
||||
sh_video_t *sh_video = NULL;
|
||||
sh_audio_t *sh_audio = NULL;
|
||||
film_data_t *film_data;
|
||||
film_chunk_t film_chunk;
|
||||
int header_size;
|
||||
unsigned int chunk_type;
|
||||
unsigned int chunk_size;
|
||||
unsigned int i;
|
||||
unsigned int video_format;
|
||||
int audio_channels;
|
||||
int counting_chunks;
|
||||
unsigned int total_audio_bytes = 0;
|
||||
|
||||
film_data = malloc(sizeof(film_data_t));
|
||||
film_data->total_chunks = 0;
|
||||
film_data->current_chunk = 0;
|
||||
film_data->chunks = NULL;
|
||||
film_data->chunks_per_second = 0;
|
||||
|
||||
// go back to the beginning
|
||||
stream_reset(demuxer->stream);
|
||||
stream_seek(demuxer->stream, 0);
|
||||
|
||||
// read the master chunk type
|
||||
chunk_type = stream_read_fourcc(demuxer->stream);
|
||||
// validate the chunk type
|
||||
if (chunk_type != CHUNK_FILM)
|
||||
{
|
||||
mp_msg(MSGT_DEMUX, MSGL_ERR, "Not a FILM file\n");
|
||||
free(film_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// get the header size, which implicitly points past the header and
|
||||
// to the start of the data
|
||||
header_size = stream_read_dword(demuxer->stream);
|
||||
film_data->film_version = stream_read_fourcc(demuxer->stream);
|
||||
demuxer->movi_start = header_size;
|
||||
demuxer->movi_end = demuxer->stream->end_pos;
|
||||
header_size -= 16;
|
||||
|
||||
mp_msg(MSGT_DEMUX, MSGL_HINT, "FILM version %.4s\n",
|
||||
(char *)&film_data->film_version);
|
||||
|
||||
// skip to where the next chunk should be
|
||||
stream_skip(demuxer->stream, 4);
|
||||
|
||||
// traverse through the header
|
||||
while (header_size > 0)
|
||||
{
|
||||
// fetch the chunk type and size
|
||||
chunk_type = stream_read_fourcc(demuxer->stream);
|
||||
chunk_size = stream_read_dword(demuxer->stream);
|
||||
header_size -= chunk_size;
|
||||
|
||||
switch (chunk_type)
|
||||
{
|
||||
case CHUNK_FDSC:
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_V, "parsing FDSC chunk\n");
|
||||
|
||||
// fetch the video codec fourcc to see if there's any video
|
||||
video_format = stream_read_fourcc(demuxer->stream);
|
||||
if (video_format)
|
||||
{
|
||||
// create and initialize the video stream header
|
||||
sh_video = new_sh_video(demuxer, 0);
|
||||
demuxer->video->sh = sh_video;
|
||||
sh_video->ds = demuxer->video;
|
||||
|
||||
sh_video->format = video_format;
|
||||
sh_video->disp_h = stream_read_dword(demuxer->stream);
|
||||
sh_video->disp_w = stream_read_dword(demuxer->stream);
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_V,
|
||||
" FILM video: %d x %d\n", sh_video->disp_w,
|
||||
sh_video->disp_h);
|
||||
}
|
||||
else
|
||||
// skip height and width if no video
|
||||
stream_skip(demuxer->stream, 8);
|
||||
|
||||
if(demuxer->audio->id<-1){
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_INFO,"chunk size = 0x%X \n",chunk_size);
|
||||
stream_skip(demuxer->stream, chunk_size-12-8);
|
||||
break; // audio disabled (or no soundcard)
|
||||
}
|
||||
|
||||
// skip over unknown byte, but only if file had non-NULL version
|
||||
if (film_data->film_version)
|
||||
stream_skip(demuxer->stream, 1);
|
||||
|
||||
// fetch the audio channels to see if there's any audio
|
||||
// don't do this if the file is a quirky file with NULL version
|
||||
if (film_data->film_version)
|
||||
{
|
||||
audio_channels = stream_read_char(demuxer->stream);
|
||||
if (audio_channels > 0)
|
||||
{
|
||||
// create and initialize the audio stream header
|
||||
sh_audio = new_sh_audio(demuxer, 0);
|
||||
demuxer->audio->id = 0;
|
||||
demuxer->audio->sh = sh_audio;
|
||||
sh_audio->ds = demuxer->audio;
|
||||
|
||||
sh_audio->wf = malloc(sizeof(*sh_audio->wf));
|
||||
|
||||
// uncompressed PCM format
|
||||
sh_audio->wf->wFormatTag = 1;
|
||||
sh_audio->format = 1;
|
||||
sh_audio->wf->nChannels = audio_channels;
|
||||
sh_audio->wf->wBitsPerSample = stream_read_char(demuxer->stream);
|
||||
stream_skip(demuxer->stream, 1); // skip unknown byte
|
||||
sh_audio->wf->nSamplesPerSec = stream_read_word(demuxer->stream);
|
||||
sh_audio->wf->nAvgBytesPerSec =
|
||||
sh_audio->wf->nSamplesPerSec * sh_audio->wf->wBitsPerSample
|
||||
* sh_audio->wf->nChannels / 8;
|
||||
stream_skip(demuxer->stream, 6); // skip the rest of the unknown
|
||||
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_V,
|
||||
" FILM audio: %d channels, %d bits, %d Hz\n",
|
||||
sh_audio->wf->nChannels, 8 * sh_audio->wf->wBitsPerSample,
|
||||
sh_audio->wf->nSamplesPerSec);
|
||||
}
|
||||
else
|
||||
stream_skip(demuxer->stream, 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise, make some assumptions about the audio
|
||||
|
||||
// create and initialize the audio stream header
|
||||
sh_audio = new_sh_audio(demuxer, 0);
|
||||
demuxer->audio->sh = sh_audio;
|
||||
sh_audio->ds = demuxer->audio;
|
||||
|
||||
sh_audio->wf = malloc(sizeof(*sh_audio->wf));
|
||||
|
||||
// uncompressed PCM format
|
||||
sh_audio->wf->wFormatTag = 1;
|
||||
sh_audio->format = 1;
|
||||
sh_audio->wf->nChannels = 1;
|
||||
sh_audio->wf->wBitsPerSample = 8;
|
||||
sh_audio->wf->nSamplesPerSec = 22050;
|
||||
sh_audio->wf->nAvgBytesPerSec =
|
||||
sh_audio->wf->nSamplesPerSec * sh_audio->wf->wBitsPerSample
|
||||
* sh_audio->wf->nChannels / 8;
|
||||
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_V,
|
||||
" FILM audio: %d channels, %d bits, %d Hz\n",
|
||||
sh_audio->wf->nChannels, sh_audio->wf->wBitsPerSample,
|
||||
sh_audio->wf->nSamplesPerSec);
|
||||
}
|
||||
break;
|
||||
|
||||
case CHUNK_STAB:
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_V, "parsing STAB chunk\n");
|
||||
|
||||
if (sh_video)
|
||||
{
|
||||
sh_video->fps = stream_read_dword(demuxer->stream);
|
||||
sh_video->frametime = 1.0 / sh_video->fps;
|
||||
}
|
||||
|
||||
// fetch the number of chunks
|
||||
film_data->total_chunks = stream_read_dword(demuxer->stream);
|
||||
film_data->current_chunk = 0;
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_V,
|
||||
" STAB chunk contains %d chunks\n", film_data->total_chunks);
|
||||
|
||||
// allocate enough entries for the chunk
|
||||
film_data->chunks =
|
||||
calloc(film_data->total_chunks, sizeof(film_chunk_t));
|
||||
|
||||
// build the chunk index
|
||||
counting_chunks = 1;
|
||||
for (i = 0; i < film_data->total_chunks; i++)
|
||||
{
|
||||
film_chunk = film_data->chunks[i];
|
||||
film_chunk.chunk_offset =
|
||||
demuxer->movi_start + stream_read_dword(demuxer->stream);
|
||||
film_chunk.chunk_size = stream_read_dword(demuxer->stream);
|
||||
film_chunk.syncinfo1 = stream_read_dword(demuxer->stream);
|
||||
film_chunk.syncinfo2 = stream_read_dword(demuxer->stream);
|
||||
|
||||
// count chunks for the purposes of seeking
|
||||
if (counting_chunks)
|
||||
{
|
||||
// if we're counting chunks, always count an audio chunk
|
||||
if (film_chunk.syncinfo1 == 0xFFFFFFFF)
|
||||
film_data->chunks_per_second++;
|
||||
// if it's a video chunk, check if it's time to stop counting
|
||||
else if ((film_chunk.syncinfo1 & 0x7FFFFFFF) >= sh_video->fps)
|
||||
counting_chunks = 0;
|
||||
else
|
||||
film_data->chunks_per_second++;
|
||||
}
|
||||
|
||||
// precalculate PTS
|
||||
if (film_chunk.syncinfo1 == 0xFFFFFFFF)
|
||||
{
|
||||
if(demuxer->audio->id>=-1)
|
||||
film_chunk.pts =
|
||||
(float)total_audio_bytes / (float)sh_audio->wf->nAvgBytesPerSec;
|
||||
total_audio_bytes += film_chunk.chunk_size;
|
||||
}
|
||||
else
|
||||
film_chunk.pts =
|
||||
(film_chunk.syncinfo1 & 0x7FFFFFFF) / sh_video->fps;
|
||||
|
||||
film_data->chunks[i] = film_chunk;
|
||||
}
|
||||
|
||||
// in some FILM files (notably '1.09'), the length of the FDSC chunk
|
||||
// follows different rules
|
||||
if (chunk_size == (film_data->total_chunks * 16))
|
||||
header_size -= 16;
|
||||
break;
|
||||
|
||||
default:
|
||||
mp_msg(MSGT_DEMUX, MSGL_ERR, "Unrecognized FILM header chunk: %08X\n",
|
||||
chunk_type);
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
demuxer->priv = film_data;
|
||||
|
||||
return demuxer;
|
||||
}
|
||||
|
||||
static void demux_close_film(demuxer_t* demuxer) {
|
||||
film_data_t *film_data = demuxer->priv;
|
||||
|
||||
if(!film_data)
|
||||
return;
|
||||
free(film_data->chunks);
|
||||
free(film_data);
|
||||
|
||||
}
|
||||
|
||||
static int film_check_file(demuxer_t* demuxer)
|
||||
{
|
||||
int signature=stream_read_fourcc(demuxer->stream);
|
||||
|
||||
// check for the FILM file magic number
|
||||
if(signature==mmioFOURCC('F', 'I', 'L', 'M'))
|
||||
return DEMUXER_TYPE_FILM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const demuxer_desc_t demuxer_desc_film = {
|
||||
"FILM/CPK demuxer for Sega Saturn CD-ROM games",
|
||||
"film",
|
||||
"FILM",
|
||||
"Mike Melanson",
|
||||
"",
|
||||
DEMUXER_TYPE_FILM,
|
||||
0, // unsafe autodetect (short signature)
|
||||
film_check_file,
|
||||
demux_film_fill_buffer,
|
||||
demux_open_film,
|
||||
demux_close_film,
|
||||
demux_seek_film,
|
||||
NULL
|
||||
};
|
@ -1,228 +0,0 @@
|
||||
/*
|
||||
* FLI file parser
|
||||
* copyright (c) 2001 Mike Melanson
|
||||
*
|
||||
* 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 "mp_msg.h"
|
||||
|
||||
#include "stream/stream.h"
|
||||
#include "demuxer.h"
|
||||
#include "stheader.h"
|
||||
|
||||
typedef struct {
|
||||
int num_frames;
|
||||
int current_frame;
|
||||
off_t *filepos;
|
||||
unsigned int *frame_size;
|
||||
} fli_frames_t;
|
||||
|
||||
static void demux_seek_fli(demuxer_t *demuxer,float rel_seek_secs,float audio_delay,int flags){
|
||||
fli_frames_t *frames = (fli_frames_t *)demuxer->priv;
|
||||
sh_video_t *sh_video = demuxer->video->sh;
|
||||
int newpos=(flags&SEEK_ABSOLUTE)?0:frames->current_frame;
|
||||
if(flags&SEEK_FACTOR){
|
||||
// float 0..1
|
||||
newpos+=rel_seek_secs*frames->num_frames;
|
||||
} else {
|
||||
// secs
|
||||
newpos+=rel_seek_secs*sh_video->fps;
|
||||
}
|
||||
if(newpos<0) newpos=0; else
|
||||
if(newpos>frames->num_frames) newpos=frames->num_frames;
|
||||
frames->current_frame=newpos;
|
||||
}
|
||||
|
||||
// return value:
|
||||
// 0 = EOF or no stream found
|
||||
// 1 = successfully read a packet
|
||||
static int demux_fli_fill_buffer(demuxer_t *demuxer, demux_stream_t *ds){
|
||||
fli_frames_t *frames = (fli_frames_t *)demuxer->priv;
|
||||
sh_video_t *sh_video = demuxer->video->sh;
|
||||
|
||||
// see if the end has been reached
|
||||
if (frames->current_frame >= frames->num_frames)
|
||||
return 0;
|
||||
|
||||
// fetch the frame from the file
|
||||
// first, position the file properly since ds_read_packet() doesn't
|
||||
// seem to do it, even though it takes a file offset as a parameter
|
||||
stream_seek(demuxer->stream, frames->filepos[frames->current_frame]);
|
||||
ds_read_packet(demuxer->video,
|
||||
demuxer->stream,
|
||||
frames->frame_size[frames->current_frame],
|
||||
frames->current_frame/sh_video->fps,
|
||||
frames->filepos[frames->current_frame],
|
||||
0 /* what flags? -> demuxer.h (alex) */
|
||||
);
|
||||
|
||||
// get the next frame ready
|
||||
frames->current_frame++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static demuxer_t* demux_open_fli(demuxer_t* demuxer){
|
||||
sh_video_t *sh_video = NULL;
|
||||
fli_frames_t *frames = malloc(sizeof(fli_frames_t));
|
||||
int frame_number;
|
||||
int speed;
|
||||
unsigned int frame_size;
|
||||
int magic_number;
|
||||
unsigned char * header;
|
||||
|
||||
// go back to the beginning
|
||||
stream_reset(demuxer->stream);
|
||||
stream_seek(demuxer->stream, 0);
|
||||
|
||||
header = calloc(1, sizeof(BITMAPINFOHEADER) + 128);
|
||||
stream_read(demuxer->stream, header + sizeof(BITMAPINFOHEADER), 128);
|
||||
stream_seek(demuxer->stream, 0);
|
||||
|
||||
demuxer->movi_start = 128;
|
||||
demuxer->movi_end = stream_read_dword_le(demuxer->stream);
|
||||
|
||||
magic_number = stream_read_word_le(demuxer->stream);
|
||||
|
||||
if ((magic_number != 0xAF11) && (magic_number != 0xAF12))
|
||||
{
|
||||
mp_msg(MSGT_DEMUX, MSGL_ERR, "Bad/unknown magic number (%04x)\n",
|
||||
magic_number);
|
||||
free(header);
|
||||
free(frames);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// fetch the number of frames
|
||||
frames->num_frames = stream_read_word_le(demuxer->stream);
|
||||
frames->current_frame = 0;
|
||||
|
||||
// allocate enough entries for the indices
|
||||
// audit: num_frames is 16bit so it is safe against overflow
|
||||
frames->filepos = malloc(frames->num_frames * sizeof(off_t));
|
||||
frames->frame_size = malloc(frames->num_frames * sizeof(int));
|
||||
|
||||
// create a new video stream header
|
||||
sh_video = new_sh_video(demuxer, 0);
|
||||
|
||||
// make sure the demuxer knows about the new video stream header
|
||||
// (even though new_sh_video() ought to take care of it)
|
||||
demuxer->video->sh = sh_video;
|
||||
|
||||
// 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;
|
||||
|
||||
// custom fourcc for internal MPlayer use
|
||||
sh_video->format = mmioFOURCC('F', 'L', 'I', 'C');
|
||||
|
||||
sh_video->disp_w = stream_read_word_le(demuxer->stream);
|
||||
sh_video->disp_h = stream_read_word_le(demuxer->stream);
|
||||
|
||||
// pass extradata to codec
|
||||
sh_video->bih = (BITMAPINFOHEADER*)header;
|
||||
sh_video->bih->biSize = sizeof(BITMAPINFOHEADER) + 128;
|
||||
sh_video->bih->biWidth = sh_video->disp_w;
|
||||
sh_video->bih->biHeight = sh_video->disp_h;
|
||||
|
||||
// skip the video depth and flags
|
||||
stream_skip(demuxer->stream, 4);
|
||||
|
||||
// get the speed
|
||||
speed = stream_read_word_le(demuxer->stream);
|
||||
if (speed == 0)
|
||||
speed = 1;
|
||||
if (magic_number == 0xAF11)
|
||||
speed *= 1000/70;
|
||||
sh_video->fps = 1000 / speed;
|
||||
sh_video->frametime = 1/sh_video->fps;
|
||||
|
||||
// build the frame index
|
||||
stream_seek(demuxer->stream, demuxer->movi_start);
|
||||
frame_number = 0;
|
||||
while ((!stream_eof(demuxer->stream)) && (frame_number < frames->num_frames))
|
||||
{
|
||||
frames->filepos[frame_number] = stream_tell(demuxer->stream);
|
||||
frame_size = stream_read_dword_le(demuxer->stream);
|
||||
magic_number = stream_read_word_le(demuxer->stream);
|
||||
stream_skip(demuxer->stream, frame_size - 6);
|
||||
|
||||
// if this chunk has the right magic number, index it
|
||||
if ((magic_number == 0xF1FA) || (magic_number == 0xF5FA))
|
||||
{
|
||||
frames->frame_size[frame_number] = frame_size;
|
||||
frame_number++;
|
||||
}
|
||||
}
|
||||
|
||||
// save the actual number of frames indexed
|
||||
frames->num_frames = frame_number;
|
||||
|
||||
demuxer->priv = frames;
|
||||
|
||||
return demuxer;
|
||||
}
|
||||
|
||||
static void demux_close_fli(demuxer_t* demuxer) {
|
||||
fli_frames_t *frames = demuxer->priv;
|
||||
|
||||
if(!frames)
|
||||
return;
|
||||
|
||||
free(frames->filepos);
|
||||
free(frames->frame_size);
|
||||
free(frames);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int fli_check_file(demuxer_t* demuxer)
|
||||
{
|
||||
int id;
|
||||
|
||||
stream_seek(demuxer->stream, 4);
|
||||
id=stream_read_word_le(demuxer->stream);
|
||||
// check for the FLI file magic number
|
||||
if((id==0xAF11) || (id==0xAF12))
|
||||
return DEMUXER_TYPE_FLI;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const demuxer_desc_t demuxer_desc_fli = {
|
||||
"Autodesk FLIC demuxer",
|
||||
"fli",
|
||||
"FLI",
|
||||
"Mike Melanson",
|
||||
"Supports also some extensions",
|
||||
DEMUXER_TYPE_FLI,
|
||||
0, // unsafe autodetect (short signature)
|
||||
fli_check_file,
|
||||
demux_fli_fill_buffer,
|
||||
demux_open_fli,
|
||||
demux_close_fli,
|
||||
demux_seek_fli,
|
||||
NULL
|
||||
};
|
@ -1,385 +0,0 @@
|
||||
/*
|
||||
* LMLM4 MPEG4 Compression Card stream & file parser
|
||||
* Copyright (C) 2003 Maxim Yevtyushkin <max@linuxmedialabs.com>
|
||||
* based on SMJPEG file parser by Alex Beregszaszi
|
||||
*
|
||||
* 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 <string.h> /* strtok */
|
||||
|
||||
#include "config.h"
|
||||
#include "mp_msg.h"
|
||||
|
||||
#include "stream/stream.h"
|
||||
#include "demuxer.h"
|
||||
#include "stheader.h"
|
||||
|
||||
typedef struct FrameInfo
|
||||
{
|
||||
ssize_t frameSize;
|
||||
ssize_t paddingSize;
|
||||
int frameType;
|
||||
int channelNo;
|
||||
} FrameInfo;
|
||||
|
||||
#define FRAMETYPE_I 0
|
||||
#define FRAMETYPE_P 1
|
||||
#define FRAMETYPE_B 2
|
||||
#define FRAMETYPE_AUDIO_MPEG1L2 4
|
||||
#define FRAMETYPE_AUDIO_ULAW 5
|
||||
#define FRAMETYPE_AUDIO_ADPCM 6
|
||||
|
||||
#define PACKET_BLOCK_SIZE 0x00000200
|
||||
#define PACKET_BLOCK_LAST 0x000001FF
|
||||
#define PACKET_BLOCK_MASK 0xFFFFFE00
|
||||
|
||||
#define MAX_PACKET_SIZE 1048576 // 1 Mb
|
||||
|
||||
#define STREAM_START_CODE_SIZE 4
|
||||
|
||||
/*
|
||||
// codes in MSB first
|
||||
static unsigned int start_code [] =
|
||||
{
|
||||
0xB0010000, // VISUAL_OBJECT_SEQUENCE_START_CODE
|
||||
0xB6010000, // VOP_START_CODE
|
||||
0x04C4FDFF, // MPEG1LAYERII_START_CODE
|
||||
0x00000000 // end of start codes list
|
||||
};
|
||||
*/
|
||||
|
||||
static int imeHeaderValid(FrameInfo *frame)
|
||||
{
|
||||
if ( frame->channelNo > 7 ||
|
||||
frame->frameSize > MAX_PACKET_SIZE || frame->frameSize <= 0)
|
||||
{
|
||||
mp_msg(MSGT_DEMUX, MSGL_V,
|
||||
"Invalid packet in LMLM4 stream: ch=%d size=%zd\n",
|
||||
frame->channelNo, frame->frameSize);
|
||||
return 0;
|
||||
}
|
||||
switch (frame->frameType) {
|
||||
case FRAMETYPE_I:
|
||||
case FRAMETYPE_P:
|
||||
case FRAMETYPE_B:
|
||||
case FRAMETYPE_AUDIO_MPEG1L2:
|
||||
case FRAMETYPE_AUDIO_ULAW:
|
||||
case FRAMETYPE_AUDIO_ADPCM:
|
||||
break;
|
||||
default:
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "Invalid packet in LMLM4 stream (wrong packet type %d)\n", frame->frameType);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
int searchMPEG4Stream(demuxer_t* demuxer, IME6400Header *imeHeader)
|
||||
{
|
||||
void *data;
|
||||
ssize_t imeHeaderSize = sizeof(IME6400Header);
|
||||
ssize_t dataSize = sizeof(IME6400Header) * 3;
|
||||
ssize_t ptr = imeHeaderSize * 2;
|
||||
int errNo, startCodeNo;
|
||||
off_t pos;
|
||||
|
||||
data = malloc(dataSize);
|
||||
|
||||
imeHeaderSwap(imeHeader);
|
||||
memcpy(data + imeHeaderSize, imeHeader, imeHeaderSize);
|
||||
|
||||
// printHex(data + imeHeaderSize, imeHeaderSize);
|
||||
|
||||
while ((errNo = stream_read(demuxer->stream, data + imeHeaderSize * 2 , imeHeaderSize)) == imeHeaderSize)
|
||||
{
|
||||
// printHex(data + imeHeaderSize * 2, imeHeaderSize);
|
||||
|
||||
pos = stream_tell(demuxer->stream);
|
||||
while (dataSize - ptr >= STREAM_START_CODE_SIZE) {
|
||||
startCodeNo = 0;
|
||||
while (start_code[startCodeNo])
|
||||
{
|
||||
if (memcmp(&start_code[startCodeNo], data + ptr, STREAM_START_CODE_SIZE) == 0) // start code match
|
||||
{
|
||||
memcpy(imeHeader, data + ptr - imeHeaderSize, imeHeaderSize);
|
||||
imeHeaderSwap(imeHeader);
|
||||
if (imeHeaderValid(imeHeader))
|
||||
{
|
||||
stream_seek(demuxer->stream, pos - (dataSize - ptr));
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
startCodeNo++;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
memcpy(data,data + imeHeaderSize, imeHeaderSize * 2);
|
||||
ptr -= imeHeaderSize;
|
||||
}
|
||||
|
||||
free(data);
|
||||
return errNo;
|
||||
}
|
||||
*/
|
||||
|
||||
static int getFrame(demuxer_t *demuxer, FrameInfo *frameInfo)
|
||||
{
|
||||
unsigned int packetSize;
|
||||
|
||||
frameInfo->channelNo = stream_read_word(demuxer->stream);
|
||||
frameInfo->frameType = stream_read_word(demuxer->stream);
|
||||
packetSize=stream_read_dword(demuxer->stream);
|
||||
|
||||
if(stream_eof(demuxer->stream)){
|
||||
frameInfo->frameSize = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
frameInfo->frameSize = packetSize - 8; //sizeof(IME6400Header);
|
||||
frameInfo->paddingSize = (packetSize & PACKET_BLOCK_LAST) ? PACKET_BLOCK_SIZE - (packetSize & PACKET_BLOCK_LAST) : 0;
|
||||
|
||||
mp_msg(MSGT_DEMUX, MSGL_DBG2, "typ: %d chan: %d size: %zd pad: %zd\n",
|
||||
frameInfo->frameType,
|
||||
frameInfo->channelNo,
|
||||
frameInfo->frameSize,
|
||||
frameInfo->paddingSize);
|
||||
|
||||
if(!imeHeaderValid(frameInfo)){
|
||||
// skip this packet
|
||||
stream_skip(demuxer->stream,PACKET_BLOCK_SIZE-8);
|
||||
frameInfo->frameSize = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lmlm4_check_file(demuxer_t* demuxer)
|
||||
{
|
||||
FrameInfo frameInfo;
|
||||
unsigned int first;
|
||||
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "Checking for LMLM4 Stream Format\n");
|
||||
|
||||
if(getFrame(demuxer, &frameInfo)!=1){
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "LMLM4 Stream Format not found\n");
|
||||
return 0;
|
||||
}
|
||||
first=stream_read_dword(demuxer->stream);
|
||||
stream_skip(demuxer->stream,-12);
|
||||
|
||||
mp_msg(MSGT_DEMUXER,MSGL_V,"LMLM4: first=0x%08X\n",first);
|
||||
|
||||
switch(frameInfo.frameType){
|
||||
case FRAMETYPE_AUDIO_MPEG1L2:
|
||||
if( (first & 0xffe00000) != 0xffe00000 ){
|
||||
mp_msg(MSGT_DEMUXER,MSGL_V,"LMLM4: not mpeg audio\n");
|
||||
return 0;
|
||||
}
|
||||
if((4-((first>>17)&3))!=2){
|
||||
mp_msg(MSGT_DEMUXER,MSGL_V,"LMLM4: not layer-2\n");
|
||||
return 0;
|
||||
}
|
||||
if(((first>>10)&0x3)==3){
|
||||
mp_msg(MSGT_DEMUXER,MSGL_V,"LMLM4: invalid audio sampelrate\n");
|
||||
return 0;
|
||||
}
|
||||
mp_msg(MSGT_DEMUXER,MSGL_V,"LMLM4: first packet is audio, header checks OK!\n");
|
||||
break;
|
||||
// TODO: add checks for video header too, for case of disabled audio
|
||||
}
|
||||
|
||||
|
||||
// stream_reset(demuxer->stream);
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "LMLM4 Stream Format found\n");
|
||||
|
||||
return DEMUXER_TYPE_LMLM4;
|
||||
}
|
||||
|
||||
static int video = 0;
|
||||
static int frames= 0;
|
||||
|
||||
// return value:
|
||||
// 0 = EOF or no stream found
|
||||
// 1 = successfully read a packet
|
||||
static int demux_lmlm4_fill_buffer(demuxer_t *demux, demux_stream_t *ds)
|
||||
{
|
||||
FrameInfo frameInfo;
|
||||
double pts;
|
||||
int id=1;
|
||||
int ret;
|
||||
|
||||
//hdr:
|
||||
demux->filepos = stream_tell(demux->stream);
|
||||
mp_msg(MSGT_DEMUX, MSGL_DBG2, "fpos = %"PRId64"\n", (int64_t)demux->filepos);
|
||||
|
||||
ret=getFrame(demux, &frameInfo);
|
||||
if(ret<=0) return ret; // EOF/error
|
||||
|
||||
pts=demux->video->sh ? frames*((sh_video_t*)(demux->video->sh))->frametime : 0;
|
||||
|
||||
switch(frameInfo.frameType){
|
||||
case FRAMETYPE_AUDIO_MPEG1L2:
|
||||
mp_dbg(MSGT_DEMUX, MSGL_DBG2, "Audio Packet\n");
|
||||
if (!video)
|
||||
{
|
||||
stream_skip(demux->stream, frameInfo.frameSize + frameInfo.paddingSize);
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "Skip Audio Packet\n");
|
||||
return -1; //goto hdr;
|
||||
}
|
||||
if(demux->audio->id==-1){
|
||||
if(!demux->a_streams[id]) new_sh_audio(demux,id);
|
||||
demux->audio->id=id;
|
||||
demux->audio->sh=demux->a_streams[id];
|
||||
((sh_audio_t*)(demux->audio->sh))->format=0x50; // mpeg audio layer 1/2
|
||||
}
|
||||
if(demux->audio->id==id)
|
||||
ds_read_packet(demux->audio, demux->stream, frameInfo.frameSize,
|
||||
pts, demux->filepos, 0);
|
||||
else
|
||||
stream_skip(demux->stream,frameInfo.frameSize);
|
||||
break;
|
||||
case FRAMETYPE_I:
|
||||
if (!video) {
|
||||
video = 1;
|
||||
mp_dbg(MSGT_DEMUX, MSGL_DBG2, "First Video Packet\n");
|
||||
}
|
||||
case FRAMETYPE_P:
|
||||
frames=(frames+1)&(1024*1024-1); // wrap around at 4 hrs to avoid inaccurate float calculations
|
||||
if (!video)
|
||||
{
|
||||
stream_skip(demux->stream, frameInfo.frameSize + frameInfo.paddingSize);
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "Skip Video P Packet\n");
|
||||
return -1; //goto hdr;
|
||||
}
|
||||
mp_dbg(MSGT_DEMUX, MSGL_DBG2, "Video Packet\n");
|
||||
if(demux->video->id==-1){
|
||||
if(!demux->v_streams[id]) new_sh_video(demux,id);
|
||||
demux->video->id=id;
|
||||
demux->video->sh=demux->v_streams[id];
|
||||
((sh_video_t*)(demux->video->sh))->format=0x10000004; // mpeg4-ES
|
||||
}
|
||||
if(demux->video->id==id)
|
||||
ds_read_packet(demux->video, demux->stream, frameInfo.frameSize,
|
||||
pts, demux->filepos, 0);
|
||||
break;
|
||||
default:
|
||||
stream_skip(demux->stream,frameInfo.frameSize);
|
||||
}
|
||||
|
||||
stream_skip(demux->stream, frameInfo.paddingSize);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static demuxer_t* demux_open_lmlm4(demuxer_t* demuxer){
|
||||
sh_audio_t *sh_audio=NULL;
|
||||
sh_video_t *sh_video=NULL;
|
||||
|
||||
#if 0
|
||||
sh_video_t* sh_video;
|
||||
sh_audio_t* sh_audio;
|
||||
unsigned int htype = 0, hleng;
|
||||
int i = 0;
|
||||
|
||||
sh_video = new_sh_video(demuxer, 0);
|
||||
demuxer->video->sh = sh_video;
|
||||
sh_video->ds = demuxer->video;
|
||||
sh_video->disp_w = 640;
|
||||
sh_video->disp_h = 480;
|
||||
sh_video->format = mmioFOURCC('D','I','V','X');
|
||||
|
||||
sh_video->bih = calloc(1, sizeof(*sh_video->bih));
|
||||
|
||||
/* these are false values */
|
||||
sh_video->bih->biSize = 40;
|
||||
sh_video->bih->biWidth = sh_video->disp_w;
|
||||
sh_video->bih->biHeight = sh_video->disp_h;
|
||||
sh_video->bih->biPlanes = 3;
|
||||
sh_video->bih->biBitCount = 16;
|
||||
sh_video->bih->biCompression = sh_video->format;
|
||||
sh_video->bih->biSizeImage = sh_video->disp_w*sh_video->disp_h;
|
||||
|
||||
sh_audio = new_sh_audio(demuxer, 0);
|
||||
demuxer->audio->sh = sh_audio;
|
||||
sh_audio->ds = demuxer->audio;
|
||||
|
||||
sh_audio->wf = calloc(1, sizeof(*sh_audio->wf));
|
||||
|
||||
sh_audio->samplerate = 48000;
|
||||
sh_audio->wf->wBitsPerSample = 16;
|
||||
sh_audio->channels = 2;
|
||||
sh_audio->format = 0x50;
|
||||
sh_audio->wf->wFormatTag = sh_audio->format;
|
||||
sh_audio->wf->nChannels = sh_audio->channels;
|
||||
sh_audio->wf->nSamplesPerSec = sh_audio->samplerate;
|
||||
sh_audio->wf->nAvgBytesPerSec = sh_audio->wf->nChannels*
|
||||
sh_audio->wf->wBitsPerSample*sh_audio->wf->nSamplesPerSec/8;
|
||||
sh_audio->wf->nBlockAlign = sh_audio->channels *2;
|
||||
sh_audio->wf->cbSize = 0;
|
||||
|
||||
#endif
|
||||
|
||||
demuxer->seekable = 0;
|
||||
|
||||
if(!ds_fill_buffer(demuxer->video)){
|
||||
mp_msg(MSGT_DEMUXER, MSGL_INFO, "LMLM4: %s",
|
||||
mp_gtext("No video stream found.\n"));
|
||||
demuxer->video->sh=NULL;
|
||||
} else {
|
||||
sh_video=demuxer->video->sh;sh_video->ds=demuxer->video;
|
||||
}
|
||||
if(demuxer->audio->id!=-2) {
|
||||
if(!ds_fill_buffer(demuxer->audio)){
|
||||
mp_msg(MSGT_DEMUXER, MSGL_INFO, "LMLM4: %s",
|
||||
mp_gtext("No audio stream found -> no sound.\n"));
|
||||
demuxer->audio->sh=NULL;
|
||||
} else {
|
||||
sh_audio=demuxer->audio->sh;sh_audio->ds=demuxer->audio;
|
||||
}
|
||||
}
|
||||
|
||||
return demuxer;
|
||||
}
|
||||
|
||||
static void demux_close_lmlm4(demuxer_t *demuxer)
|
||||
{
|
||||
// printf("Close LMLM4 Stream\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const demuxer_desc_t demuxer_desc_lmlm4 = {
|
||||
"LMLM4 MPEG4 Compression Card stream demuxer",
|
||||
"lmlm4",
|
||||
"RAW LMLM4",
|
||||
"Maxim Yevtyushkin",
|
||||
"",
|
||||
DEMUXER_TYPE_LMLM4,
|
||||
0, // unsafe autodetect
|
||||
lmlm4_check_file,
|
||||
demux_lmlm4_fill_buffer,
|
||||
demux_open_lmlm4,
|
||||
demux_close_lmlm4,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -1,24 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MPLAYER_DEMUX_MOV_H
|
||||
#define MPLAYER_DEMUX_MOV_H
|
||||
|
||||
unsigned int store_ughvlc(unsigned char *s, unsigned int v);
|
||||
|
||||
#endif /* MPLAYER_DEMUX_MOV_H */
|
@ -1,235 +0,0 @@
|
||||
/*
|
||||
* demuxer for Musepack v7 bitstream
|
||||
* copyright (c) 2005 Reimar Doeffinger <Reimar.Doeffinger@stud.uni-karlsruhe.de>
|
||||
*
|
||||
* This code may be be relicensed under the terms of the GNU LGPL when it
|
||||
* becomes part of the FFmpeg project (ffmpeg.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 "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "mp_msg.h"
|
||||
#include "libavutil/common.h"
|
||||
#include "mpbswap.h"
|
||||
#include "stream/stream.h"
|
||||
#include "demuxer.h"
|
||||
#include "stheader.h"
|
||||
|
||||
|
||||
#define HDR_SIZE (6 * 4)
|
||||
|
||||
typedef struct da_priv {
|
||||
float last_pts;
|
||||
float pts_per_packet;
|
||||
uint32_t dword;
|
||||
int pos;
|
||||
float length;
|
||||
} da_priv_t;
|
||||
|
||||
static uint32_t get_bits(da_priv_t* priv, stream_t* s, int bits) {
|
||||
uint32_t out = priv->dword;
|
||||
uint32_t mask = (1 << bits) - 1;
|
||||
priv->pos += bits;
|
||||
if (priv->pos < 32) {
|
||||
out >>= (32 - priv->pos);
|
||||
}
|
||||
else {
|
||||
stream_read(s, (void *)&priv->dword, 4);
|
||||
priv->dword = le2me_32(priv->dword);
|
||||
priv->pos -= 32;
|
||||
if (priv->pos) {
|
||||
out <<= priv->pos;
|
||||
out |= priv->dword >> (32 - priv->pos);
|
||||
}
|
||||
}
|
||||
return out & mask;
|
||||
}
|
||||
|
||||
static int demux_mpc_check(demuxer_t* demuxer) {
|
||||
stream_t *s = demuxer->stream;
|
||||
uint8_t hdr[HDR_SIZE];
|
||||
int i;
|
||||
|
||||
if (stream_read(s, hdr, HDR_SIZE) != HDR_SIZE)
|
||||
return 0;
|
||||
for (i = 0; i < 30000 && !s->eof; i++) {
|
||||
if (hdr[0] == 'M' && hdr[1] == 'P' && hdr[2] == '+')
|
||||
break;
|
||||
memmove(hdr, &hdr[1], HDR_SIZE - 1);
|
||||
stream_read(s, &hdr[HDR_SIZE - 1], 1);
|
||||
}
|
||||
|
||||
if (hdr[0] != 'M' || hdr[1] != 'P' || hdr[2] != '+')
|
||||
return 0;
|
||||
demuxer->movi_start = stream_tell(s) - HDR_SIZE;
|
||||
demuxer->movi_end = s->end_pos;
|
||||
demuxer->priv = malloc(HDR_SIZE);
|
||||
memcpy(demuxer->priv, hdr, HDR_SIZE);
|
||||
return DEMUXER_TYPE_MPC;
|
||||
}
|
||||
|
||||
static demuxer_t *demux_mpc_open(demuxer_t* demuxer) {
|
||||
float seconds = 0;
|
||||
stream_t *s = demuxer->stream;
|
||||
sh_audio_t* sh_audio;
|
||||
da_priv_t* priv = demuxer->priv;
|
||||
|
||||
sh_audio = new_sh_audio(demuxer,0);
|
||||
|
||||
{
|
||||
char *wf = calloc(1, sizeof(WAVEFORMATEX) + HDR_SIZE);
|
||||
char *header = &wf[sizeof(WAVEFORMATEX)];
|
||||
const int freqs[4] = {44100, 48000, 37800, 32000};
|
||||
int frames;
|
||||
sh_audio->format = mmioFOURCC('M', 'P', 'C', ' ');
|
||||
memcpy(header, priv, HDR_SIZE);
|
||||
free(priv);
|
||||
frames = header[4] | header[5] << 8 | header[6] << 16 | header[7] << 24;
|
||||
sh_audio->wf = (WAVEFORMATEX *)wf;
|
||||
sh_audio->wf->wFormatTag = sh_audio->format;
|
||||
sh_audio->wf->nChannels = 2;
|
||||
sh_audio->wf->nSamplesPerSec = freqs[header[10] & 3];
|
||||
sh_audio->wf->nBlockAlign = 32 * 36;
|
||||
sh_audio->wf->wBitsPerSample = 16;
|
||||
seconds = 1152 * frames / (float)sh_audio->wf->nSamplesPerSec;
|
||||
if (demuxer->movi_end > demuxer->movi_start && seconds > 1)
|
||||
sh_audio->wf->nAvgBytesPerSec = (demuxer->movi_end - demuxer->movi_start) / seconds;
|
||||
else
|
||||
sh_audio->wf->nAvgBytesPerSec = 32 * 1024; // dummy to make mencoder not hang
|
||||
sh_audio->wf->cbSize = HDR_SIZE;
|
||||
demuxer->movi_start = stream_tell(s);
|
||||
demuxer->movi_end = s->end_pos;
|
||||
}
|
||||
|
||||
priv = malloc(sizeof(da_priv_t));
|
||||
priv->last_pts = -1;
|
||||
priv->pts_per_packet = (32 * 36) / (float)sh_audio->wf->nSamplesPerSec;
|
||||
priv->length = seconds;
|
||||
priv->dword = 0;
|
||||
priv->pos = 32; // empty bit buffer
|
||||
get_bits(priv, s, 8); // discard first 8 bits
|
||||
demuxer->priv = priv;
|
||||
demuxer->audio->id = 0;
|
||||
demuxer->audio->sh = sh_audio;
|
||||
sh_audio->ds = demuxer->audio;
|
||||
sh_audio->samplerate = sh_audio->wf->nSamplesPerSec;
|
||||
sh_audio->i_bps = sh_audio->wf->nAvgBytesPerSec;
|
||||
sh_audio->audio.dwSampleSize = 0;
|
||||
sh_audio->audio.dwScale = 32 * 36;
|
||||
sh_audio->audio.dwRate = sh_audio->samplerate;
|
||||
|
||||
return demuxer;
|
||||
}
|
||||
|
||||
static int demux_mpc_fill_buffer(demuxer_t *demux, demux_stream_t *ds) {
|
||||
int l;
|
||||
int bit_len;
|
||||
demux_packet_t* dp;
|
||||
sh_audio_t* sh_audio = ds->sh;
|
||||
da_priv_t* priv = demux->priv;
|
||||
stream_t* s = demux->stream;
|
||||
sh_audio = ds->sh;
|
||||
|
||||
if (s->eof)
|
||||
return 0;
|
||||
|
||||
bit_len = get_bits(priv, s, 20);
|
||||
dp = new_demux_packet((bit_len + 7) / 8);
|
||||
for (l = 0; l < (bit_len / 8); l++)
|
||||
dp->buffer[l] = get_bits(priv, s, 8);
|
||||
bit_len %= 8;
|
||||
if (bit_len)
|
||||
dp->buffer[l] = get_bits(priv, s, bit_len) << (8 - bit_len);
|
||||
if (priv->last_pts < 0)
|
||||
priv->last_pts = 0;
|
||||
else
|
||||
priv->last_pts += priv->pts_per_packet;
|
||||
dp->pts = priv->last_pts;
|
||||
ds_add_packet(ds, dp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void demux_mpc_seek(demuxer_t *demuxer,float rel_seek_secs,float audio_delay,int flags){
|
||||
sh_audio_t* sh_audio = demuxer->audio->sh;
|
||||
da_priv_t* priv = demuxer->priv;
|
||||
stream_t* s = demuxer->stream;
|
||||
float target = rel_seek_secs;
|
||||
if (flags & SEEK_FACTOR)
|
||||
target *= priv->length;
|
||||
if (!(flags & SEEK_ABSOLUTE))
|
||||
target += priv->last_pts;
|
||||
if (target < priv->last_pts) {
|
||||
stream_seek(s, demuxer->movi_start);
|
||||
priv->pos = 32; // empty bit buffer
|
||||
get_bits(priv, s, 8); // discard first 8 bits
|
||||
priv->last_pts = 0;
|
||||
}
|
||||
while (target > priv->last_pts) {
|
||||
int bit_len = get_bits(priv, s, 20);
|
||||
if (bit_len > 32) {
|
||||
stream_skip(s, bit_len / 32 * 4 - 4);
|
||||
get_bits(priv, s, 32); // make sure dword is reloaded
|
||||
}
|
||||
get_bits(priv, s, bit_len % 32);
|
||||
priv->last_pts += priv->pts_per_packet;
|
||||
if (s->eof) break;
|
||||
}
|
||||
if (!sh_audio) return;
|
||||
}
|
||||
|
||||
static void demux_close_mpc(demuxer_t* demuxer) {
|
||||
da_priv_t* priv = demuxer->priv;
|
||||
|
||||
free(priv);
|
||||
}
|
||||
|
||||
static int demux_mpc_control(demuxer_t *demuxer,int cmd, void *arg){
|
||||
da_priv_t* priv = demuxer->priv;
|
||||
switch (cmd) {
|
||||
case DEMUXER_CTRL_GET_TIME_LENGTH:
|
||||
if (priv->length < 1) return DEMUXER_CTRL_DONTKNOW;
|
||||
*((double *)arg) = priv->length;
|
||||
return DEMUXER_CTRL_OK;
|
||||
case DEMUXER_CTRL_GET_PERCENT_POS:
|
||||
if (priv->length < 1) return DEMUXER_CTRL_DONTKNOW;
|
||||
*((int *)arg) = priv->last_pts * 100 / priv->length;
|
||||
return DEMUXER_CTRL_OK;
|
||||
}
|
||||
return DEMUXER_CTRL_NOTIMPL;
|
||||
}
|
||||
|
||||
|
||||
const demuxer_desc_t demuxer_desc_mpc = {
|
||||
"Musepack demuxer",
|
||||
"mpc",
|
||||
"MPC",
|
||||
"Reza Jelveh, Reimar Doeffinger",
|
||||
"supports v7 bitstream only",
|
||||
DEMUXER_TYPE_MPC,
|
||||
0, // unsafe autodetect
|
||||
demux_mpc_check,
|
||||
demux_mpc_fill_buffer,
|
||||
demux_mpc_open,
|
||||
demux_close_mpc,
|
||||
demux_mpc_seek,
|
||||
demux_mpc_control
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -1,345 +0,0 @@
|
||||
/*
|
||||
* Nullsoft Streaming Video demuxer
|
||||
* copyright (c) 2004 by Reza Jelveh <reza.jelveh@tuhh.de>
|
||||
* Based on A'rpis G2 work
|
||||
*
|
||||
* seeking and PCM audio not yet supported
|
||||
* PCM needs extra audio chunk "miniheader" parsing
|
||||
*
|
||||
* 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 "mp_msg.h"
|
||||
#include "stream/stream.h"
|
||||
#include "demuxer.h"
|
||||
#include "stheader.h"
|
||||
|
||||
typedef struct {
|
||||
float v_pts;
|
||||
int video_pack_no;
|
||||
unsigned int a_format;
|
||||
unsigned int v_format;
|
||||
unsigned char fps;
|
||||
} nsv_priv_t;
|
||||
|
||||
#define HEADER_SEARCH_SIZE 256000
|
||||
|
||||
|
||||
/**
|
||||
* Seeking still to be implemented
|
||||
*/
|
||||
static void demux_seek_nsv ( demuxer_t *demuxer, float rel_seek_secs, float audio_delay, int flags )
|
||||
{
|
||||
// seeking is not yet implemented
|
||||
}
|
||||
|
||||
|
||||
static int demux_nsv_fill_buffer ( demuxer_t *demuxer, demux_stream_t *ds )
|
||||
{
|
||||
unsigned char hdr[17];
|
||||
// for the extra data
|
||||
unsigned char aux[6];
|
||||
int i_aux = 0;
|
||||
// videolen = audio chunk length, audiolen = video chunk length
|
||||
int videolen,audiolen;
|
||||
|
||||
sh_video_t *sh_video = demuxer->video->sh;
|
||||
sh_audio_t *sh_audio = demuxer->audio->sh;
|
||||
|
||||
nsv_priv_t * priv = demuxer->priv;
|
||||
|
||||
// if the audio/video chunk has no new header the first 2 bytes will be discarded 0xBEEF
|
||||
// or rather 0xEF 0xBE
|
||||
stream_read(demuxer->stream,hdr,7);
|
||||
if(stream_eof(demuxer->stream)) return 0;
|
||||
// sometimes instead of 0xBEEF as described for the next audio/video chunk we get
|
||||
// a whole new header
|
||||
|
||||
mp_dbg(MSGT_DEMUX, MSGL_DBG2, "demux_nsv: %08X %08X\n",
|
||||
hdr[0]<<8|hdr[1], (unsigned int)stream_tell(demuxer->stream));
|
||||
switch(hdr[0]<<8|hdr[1]) {
|
||||
case 0x4E53:
|
||||
if(hdr[2]==0x56 && hdr[3]==0x73){
|
||||
// NSVs
|
||||
// get the header since there is no more metaheader after the first one
|
||||
// there is no more need to skip that
|
||||
stream_read(demuxer->stream,hdr+7,17-7);
|
||||
stream_read(demuxer->stream,hdr,7);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xEFBE:
|
||||
break;
|
||||
|
||||
default:
|
||||
mp_dbg(MSGT_DEMUX,MSGL_WARN,"demux_nsv: sync lost\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (sh_video)
|
||||
priv->v_pts =demuxer->video->pts= priv->video_pack_no *
|
||||
(float)sh_video->frametime;
|
||||
else
|
||||
priv->v_pts = priv->video_pack_no;
|
||||
|
||||
demuxer->filepos=stream_tell(demuxer->stream);
|
||||
|
||||
|
||||
mp_dbg(MSGT_DEMUX,MSGL_DBG2,"demux_nsv: %08X: %02X %02X | %02X %02X %02X | %02X %02X \n",
|
||||
(int)demuxer->filepos, hdr[0],hdr[1],hdr[2],hdr[3],hdr[4],hdr[5],hdr[6]);
|
||||
|
||||
// read video:
|
||||
videolen=(hdr[2]>>4)|(hdr[3]<<4)|(hdr[4]<<0xC);
|
||||
//check if we got extra data like subtitles here
|
||||
if( (hdr[2]&0x0f) != 0x0 ) {
|
||||
stream_read( demuxer->stream, aux, 6);
|
||||
|
||||
i_aux = aux[0]|aux[1]<<8;
|
||||
// We skip this extra data
|
||||
stream_skip( demuxer->stream, i_aux );
|
||||
i_aux+=6;
|
||||
videolen -= i_aux;
|
||||
}
|
||||
|
||||
|
||||
// we need to return an empty packet when the
|
||||
// video frame is empty otherwise the stream will fasten up
|
||||
if(sh_video) {
|
||||
if( (hdr[2]&0x0f) != 0x0 )
|
||||
ds_read_packet(demuxer->video,demuxer->stream,videolen,priv->v_pts,demuxer->filepos-i_aux,0);
|
||||
else
|
||||
ds_read_packet(demuxer->video,demuxer->stream,videolen,priv->v_pts,demuxer->filepos,0);
|
||||
}
|
||||
else
|
||||
stream_skip(demuxer->stream,videolen);
|
||||
|
||||
// read audio:
|
||||
audiolen=(hdr[5])|(hdr[6]<<8);
|
||||
// we need to return an empty packet when the
|
||||
// audio frame is empty otherwise the stream will fasten up
|
||||
if(sh_audio) {
|
||||
ds_read_packet(demuxer->audio,demuxer->stream,audiolen,priv->v_pts,demuxer->filepos+videolen,0);
|
||||
}
|
||||
else
|
||||
stream_skip(demuxer->stream,audiolen);
|
||||
|
||||
++priv->video_pack_no;
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static demuxer_t* demux_open_nsv ( demuxer_t* demuxer )
|
||||
{
|
||||
// last 2 bytes 17 and 18 are unknown but right after that comes the length
|
||||
unsigned char hdr[17];
|
||||
int videolen,audiolen;
|
||||
unsigned char buf[10];
|
||||
sh_video_t *sh_video = NULL;
|
||||
sh_audio_t *sh_audio = NULL;
|
||||
|
||||
|
||||
nsv_priv_t * priv = malloc(sizeof(nsv_priv_t));
|
||||
demuxer->priv=priv;
|
||||
priv->video_pack_no=0;
|
||||
|
||||
/* disable seeking yet to be fixed*/
|
||||
demuxer->seekable = 0;
|
||||
|
||||
stream_read(demuxer->stream,hdr,4);
|
||||
if(stream_eof(demuxer->stream)) return 0;
|
||||
|
||||
if(hdr[0]==0x4E && hdr[1]==0x53 && hdr[2]==0x56){
|
||||
// NSV header!
|
||||
if(hdr[3]==0x73){
|
||||
// NSVs
|
||||
stream_read(demuxer->stream,hdr+4,17-4);
|
||||
}
|
||||
|
||||
if(hdr[3]==0x66){
|
||||
// NSVf
|
||||
int len=stream_read_dword_le(demuxer->stream);
|
||||
// TODO: parse out metadata!!!!
|
||||
stream_skip(demuxer->stream,len-8);
|
||||
|
||||
// NSVs
|
||||
stream_read(demuxer->stream,hdr,17);
|
||||
if (stream_eof(demuxer->stream) || strncmp(hdr, "NSVs", 4))
|
||||
return 0;
|
||||
}
|
||||
|
||||
// dummy debug message
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"demux_nsv: Header: %.12s\n",hdr);
|
||||
|
||||
// bytes 8-11 audio codec fourcc
|
||||
// PCM fourcc needs extra parsing for every audio chunk, yet to implement
|
||||
if((demuxer->audio->id != -2) && strncmp(hdr+8,"NONE", 4)){//&&strncmp(hdr+8,"VLB ", 4)){
|
||||
sh_audio = new_sh_audio ( demuxer, 0 );
|
||||
demuxer->audio->id = 0;
|
||||
demuxer->audio->sh = sh_audio;
|
||||
sh_audio->format=mmioFOURCC(hdr[8],hdr[9],hdr[10],hdr[11]);
|
||||
sh_audio->ds = demuxer->audio;
|
||||
priv->a_format=mmioFOURCC(hdr[8],hdr[9],hdr[10],hdr[11]);
|
||||
}
|
||||
|
||||
// store hdr fps
|
||||
priv->fps=hdr[16];
|
||||
|
||||
if ((demuxer->video->id != -2) && strncmp(hdr+4,"NONE", 4)) {
|
||||
/* Create a new video stream header */
|
||||
sh_video = new_sh_video ( demuxer, 0 );
|
||||
|
||||
/* Make sure the demuxer knows about the new video stream header
|
||||
* (even though new_sh_video() ought to take care of it)
|
||||
*/
|
||||
demuxer->video->sh = sh_video;
|
||||
|
||||
/* 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;
|
||||
|
||||
// bytes 4-7 video codec fourcc
|
||||
priv->v_format = sh_video->format=mmioFOURCC(hdr[4],hdr[5],hdr[6],hdr[7]);
|
||||
|
||||
// new video stream! parse header
|
||||
sh_video->disp_w=hdr[12]|(hdr[13]<<8);
|
||||
sh_video->disp_h=hdr[14]|(hdr[15]<<8);
|
||||
sh_video->bih=calloc(1,sizeof(*sh_video->bih));
|
||||
sh_video->bih->biSize=sizeof(*sh_video->bih);
|
||||
sh_video->bih->biPlanes=1;
|
||||
sh_video->bih->biBitCount=24;
|
||||
sh_video->bih->biWidth=hdr[12]|(hdr[13]<<8);
|
||||
sh_video->bih->biHeight=hdr[14]|(hdr[15]<<8);
|
||||
memcpy(&sh_video->bih->biCompression,hdr+4,4);
|
||||
sh_video->bih->biSizeImage=sh_video->bih->biWidth*sh_video->bih->biHeight*3;
|
||||
|
||||
// here we search for the correct keyframe
|
||||
// vp6 keyframe is when the 2nd byte of the vp6 header is
|
||||
// 0x36 for VP61 and 0x46 for VP62
|
||||
if((priv->v_format==mmioFOURCC('V','P','6','1')) ||
|
||||
(priv->v_format==mmioFOURCC('V','P','6','2')) ||
|
||||
(priv->v_format==mmioFOURCC('V','P','3','1'))) {
|
||||
stream_read(demuxer->stream,buf,10);
|
||||
if (((((priv->v_format>>16) & 0xff) == '6') && ((buf[8]&0x0e)!=0x06)) ||
|
||||
((((priv->v_format>>16) & 0xff) == '3') && (buf[8]!=0x00 || buf[9]!=0x08))) {
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"demux_nsv: searching %.4s keyframe...\n", (char*)&priv->v_format);
|
||||
while(((((priv->v_format>>16) & 0xff) == '6') && ((buf[8]&0x0e)!=0x06)) ||
|
||||
((((priv->v_format>>16) & 0xff) == '3') && (buf[8]!=0x00 || buf[9]!=0x08))){
|
||||
mp_msg(MSGT_DEMUX,MSGL_DBG2,"demux_nsv: %.4s block skip.\n", (char*)&priv->v_format);
|
||||
videolen=(buf[2]>>4)|(buf[3]<<4)|(buf[4]<<0xC);
|
||||
audiolen=(buf[5])|(buf[6]<<8);
|
||||
stream_skip(demuxer->stream, videolen+audiolen-3);
|
||||
stream_read(demuxer->stream,buf,10);
|
||||
if(stream_eof(demuxer->stream)) return 0;
|
||||
if(buf[0]==0x4E){
|
||||
mp_msg(MSGT_DEMUX,MSGL_DBG2,"demux_nsv: Got NSVs block.\n");
|
||||
stream_skip(demuxer->stream,7);
|
||||
stream_read(demuxer->stream,buf,10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// data starts 10 bytes before current pos but later
|
||||
// we seek 17 backwards
|
||||
stream_skip(demuxer->stream,7);
|
||||
}
|
||||
|
||||
switch(priv->fps){
|
||||
case 0x80:
|
||||
sh_video->fps=30;
|
||||
break;
|
||||
case 0x81:
|
||||
sh_video->fps=(float)30000.0/1001.0;
|
||||
break;
|
||||
case 0x82:
|
||||
sh_video->fps=25;
|
||||
break;
|
||||
case 0x83:
|
||||
sh_video->fps=(float)24000.0/1001.0;
|
||||
break;
|
||||
case 0x85:
|
||||
sh_video->fps=(float)15000.0/1001.0;
|
||||
break;
|
||||
case 0x89:
|
||||
sh_video->fps=(float)10000.0/1001.0;
|
||||
break;
|
||||
default:
|
||||
sh_video->fps = (float)priv->fps;
|
||||
}
|
||||
sh_video->frametime = (float)1.0 / (float)sh_video->fps;
|
||||
}
|
||||
}
|
||||
|
||||
// seek to start of NSV header
|
||||
stream_seek(demuxer->stream,stream_tell(demuxer->stream)-17);
|
||||
|
||||
return demuxer;
|
||||
}
|
||||
|
||||
static int nsv_check_file ( demuxer_t* demuxer )
|
||||
{
|
||||
uint32_t hdr = 0;
|
||||
int i;
|
||||
|
||||
mp_msg ( MSGT_DEMUX, MSGL_V, "Checking for Nullsoft Streaming Video\n" );
|
||||
|
||||
for (i = 0; i < HEADER_SEARCH_SIZE; i++) {
|
||||
uint8_t c = stream_read_char(demuxer->stream);
|
||||
if (stream_eof(demuxer->stream))
|
||||
return 0;
|
||||
if (hdr == mmioFOURCC('s', 'V', 'S', 'N') ||
|
||||
(hdr == mmioFOURCC('f', 'V', 'S', 'N') && !c)) {
|
||||
stream_seek(demuxer->stream,stream_tell(demuxer->stream)-5);
|
||||
return DEMUXER_TYPE_NSV;
|
||||
}
|
||||
hdr = (hdr << 8) | c;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void demux_close_nsv(demuxer_t* demuxer) {
|
||||
nsv_priv_t* priv = demuxer->priv;
|
||||
|
||||
free(priv);
|
||||
|
||||
}
|
||||
|
||||
|
||||
const demuxer_desc_t demuxer_desc_nsv = {
|
||||
"NullsoftVideo demuxer",
|
||||
"nsv",
|
||||
"Nullsoft Streaming Video",
|
||||
"Reza Jelveh",
|
||||
"nsv and nsa streaming files",
|
||||
DEMUXER_TYPE_NSV,
|
||||
0, // safe but expensive autodetect
|
||||
nsv_check_file,
|
||||
demux_nsv_fill_buffer,
|
||||
demux_open_nsv,
|
||||
demux_close_nsv,
|
||||
demux_seek_nsv,
|
||||
NULL
|
||||
};
|
@ -1,321 +0,0 @@
|
||||
/*
|
||||
* 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 "config.h"
|
||||
#include "mp_msg.h"
|
||||
|
||||
|
||||
#include "stream/stream.h"
|
||||
#include "demuxer.h"
|
||||
#include "stheader.h"
|
||||
|
||||
#include <libnut.h>
|
||||
|
||||
typedef struct {
|
||||
int last_pts; // FIXME
|
||||
nut_context_tt * nut;
|
||||
nut_stream_header_tt * s;
|
||||
} nut_priv_tt;
|
||||
|
||||
static size_t mp_read(void * h, size_t len, uint8_t * buf) {
|
||||
stream_t * stream = (stream_t*)h;
|
||||
|
||||
if(stream_eof(stream)) return 0;
|
||||
//len = MIN(len, 5);
|
||||
|
||||
return stream_read(stream, buf, len);
|
||||
}
|
||||
|
||||
static int mp_eof(void * h) {
|
||||
stream_t * stream = (stream_t*)h;
|
||||
if(stream_eof(stream)) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static off_t mp_seek(void * h, long long pos, int whence) {
|
||||
stream_t * stream = (stream_t*)h;
|
||||
|
||||
if (stream->end_pos < stream_tell(stream))
|
||||
stream->end_pos = stream_tell(stream);
|
||||
|
||||
if (whence == SEEK_CUR) pos += stream_tell(stream);
|
||||
else if (whence == SEEK_END) pos += stream->end_pos;
|
||||
else if (whence != SEEK_SET) return -1;
|
||||
|
||||
if (pos < stream->end_pos && stream->eof) stream_reset(stream);
|
||||
if (stream_seek(stream, pos) == 0) return -1;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
#define ID_STRING "nut/multimedia container"
|
||||
#define ID_LENGTH (strlen(ID_STRING) + 1)
|
||||
|
||||
static int nut_check_file(demuxer_t * demuxer) {
|
||||
uint8_t buf[ID_LENGTH];
|
||||
|
||||
if (stream_read(demuxer->stream, buf, ID_LENGTH) != ID_LENGTH) return 0;
|
||||
|
||||
if (memcmp(buf, ID_STRING, ID_LENGTH)) return 0;
|
||||
|
||||
stream_seek(demuxer->stream, 0);
|
||||
return DEMUXER_TYPE_NUT;
|
||||
}
|
||||
|
||||
static demuxer_t * demux_open_nut(demuxer_t * demuxer) {
|
||||
nut_demuxer_opts_tt dopts = {
|
||||
.input = {
|
||||
.priv = demuxer->stream,
|
||||
.seek = mp_seek,
|
||||
.read = mp_read,
|
||||
.eof = mp_eof,
|
||||
.file_pos = stream_tell(demuxer->stream),
|
||||
},
|
||||
.alloc = { .malloc = NULL },
|
||||
.read_index = index_mode,
|
||||
.cache_syncpoints = 1,
|
||||
};
|
||||
nut_priv_tt * priv = demuxer->priv = calloc(1, sizeof(nut_priv_tt));
|
||||
nut_context_tt * nut = priv->nut = nut_demuxer_init(&dopts);
|
||||
nut_stream_header_tt * s;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
while ((ret = nut_read_headers(nut, &s, NULL)) == NUT_ERR_EAGAIN);
|
||||
if (ret) {
|
||||
mp_msg(MSGT_HEADER, MSGL_ERR, "NUT error: %s\n", nut_error(ret));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
priv->s = s;
|
||||
|
||||
for (i = 0; s[i].type != -1 && i < 2; i++) switch(s[i].type) {
|
||||
case NUT_AUDIO_CLASS: {
|
||||
WAVEFORMATEX *wf =
|
||||
calloc(sizeof(*wf) +
|
||||
s[i].codec_specific_len, 1);
|
||||
sh_audio_t* sh_audio = new_sh_audio(demuxer, i);
|
||||
int j;
|
||||
mp_tmsg(MSGT_DEMUX, MSGL_INFO, "[%s] Audio stream found, -aid %d\n", "nut", i);
|
||||
|
||||
sh_audio->wf= wf; sh_audio->ds = demuxer->audio;
|
||||
sh_audio->audio.dwSampleSize = 0; // FIXME
|
||||
sh_audio->audio.dwScale = s[i].time_base.num;
|
||||
sh_audio->audio.dwRate = s[i].time_base.den;
|
||||
sh_audio->format = 0;
|
||||
for (j = 0; j < s[i].fourcc_len && j < 4; j++)
|
||||
sh_audio->format |= s[i].fourcc[j]<<(j*8);
|
||||
sh_audio->channels = s[i].channel_count;
|
||||
sh_audio->samplerate =
|
||||
s[i].samplerate_num / s[i].samplerate_denom;
|
||||
sh_audio->i_bps = 0; // FIXME
|
||||
|
||||
wf->wFormatTag = sh_audio->format;
|
||||
wf->nChannels = s[i].channel_count;
|
||||
wf->nSamplesPerSec =
|
||||
s[i].samplerate_num / s[i].samplerate_denom;
|
||||
wf->nAvgBytesPerSec = 0; // FIXME
|
||||
wf->nBlockAlign = 0; // FIXME
|
||||
wf->wBitsPerSample = 0; // FIXME
|
||||
wf->cbSize = s[i].codec_specific_len;
|
||||
if (s[i].codec_specific_len)
|
||||
memcpy(wf + 1, s[i].codec_specific,
|
||||
s[i].codec_specific_len);
|
||||
|
||||
demuxer->audio->id = i;
|
||||
demuxer->audio->sh= demuxer->a_streams[i];
|
||||
break;
|
||||
}
|
||||
case NUT_VIDEO_CLASS: {
|
||||
BITMAPINFOHEADER * bih =
|
||||
calloc(sizeof(*bih) +
|
||||
s[i].codec_specific_len, 1);
|
||||
sh_video_t * sh_video = new_sh_video(demuxer, i);
|
||||
int j;
|
||||
mp_tmsg(MSGT_DEMUX, MSGL_INFO, "[%s] Video stream found, -vid %d\n", "nut", i);
|
||||
|
||||
sh_video->bih = bih;
|
||||
sh_video->ds = demuxer->video;
|
||||
sh_video->disp_w = s[i].width;
|
||||
sh_video->disp_h = s[i].height;
|
||||
sh_video->video.dwScale = s[i].time_base.num;
|
||||
sh_video->video.dwRate = s[i].time_base.den;
|
||||
|
||||
sh_video->fps = sh_video->video.dwRate/
|
||||
(float)sh_video->video.dwScale;
|
||||
sh_video->frametime = 1./sh_video->fps;
|
||||
sh_video->format = 0;
|
||||
for (j = 0; j < s[i].fourcc_len && j < 4; j++)
|
||||
sh_video->format |= s[i].fourcc[j]<<(j*8);
|
||||
if (!s[i].sample_height) sh_video->aspect = 0;
|
||||
else sh_video->aspect =
|
||||
s[i].sample_width / (float)s[i].sample_height;
|
||||
sh_video->i_bps = 0; // FIXME
|
||||
|
||||
bih->biSize = sizeof(*bih) +
|
||||
s[i].codec_specific_len;
|
||||
bih->biWidth = s[i].width;
|
||||
bih->biHeight = s[i].height;
|
||||
bih->biBitCount = 0; // FIXME
|
||||
bih->biSizeImage = 0; // FIXME
|
||||
bih->biCompression = sh_video->format;
|
||||
|
||||
if (s[i].codec_specific_len)
|
||||
memcpy(bih + 1, s[i].codec_specific,
|
||||
s[i].codec_specific_len);
|
||||
|
||||
demuxer->video->id = i;
|
||||
demuxer->video->sh = demuxer->v_streams[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return demuxer;
|
||||
}
|
||||
|
||||
static int demux_nut_fill_buffer(demuxer_t * demuxer, demux_stream_t * dsds) {
|
||||
nut_priv_tt * priv = demuxer->priv;
|
||||
nut_context_tt * nut = priv->nut;
|
||||
demux_packet_t *dp;
|
||||
demux_stream_t *ds;
|
||||
nut_packet_tt pd;
|
||||
int ret;
|
||||
double pts;
|
||||
|
||||
demuxer->filepos = stream_tell(demuxer->stream);
|
||||
if (stream_eof(demuxer->stream)) return 0;
|
||||
|
||||
while ((ret = nut_read_next_packet(nut, &pd)) == NUT_ERR_EAGAIN);
|
||||
if (ret) {
|
||||
if (ret != NUT_ERR_EOF)
|
||||
mp_msg(MSGT_HEADER, MSGL_ERR, "NUT error: %s\n",
|
||||
nut_error(ret));
|
||||
return 0; // fatal error
|
||||
}
|
||||
|
||||
pts = (double)pd.pts * priv->s[pd.stream].time_base.num /
|
||||
priv->s[pd.stream].time_base.den;
|
||||
|
||||
if (pd.stream == demuxer->audio->id) {
|
||||
ds = demuxer->audio;
|
||||
}
|
||||
else if (pd.stream == demuxer->video->id) {
|
||||
ds = demuxer->video;
|
||||
}
|
||||
else {
|
||||
uint8_t buf[pd.len];
|
||||
while ((ret = nut_read_frame(nut, &pd.len, buf)) == NUT_ERR_EAGAIN);
|
||||
if (ret) {
|
||||
mp_msg(MSGT_HEADER, MSGL_ERR, "NUT error: %s\n",
|
||||
nut_error(ret));
|
||||
return 0; // fatal error
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (pd.stream == 0) priv->last_pts = pd.pts;
|
||||
|
||||
dp = new_demux_packet(pd.len);
|
||||
|
||||
dp->pts = pts;
|
||||
|
||||
dp->pos = demuxer->filepos;
|
||||
dp->keyframe = pd.flags & NUT_FLAG_KEY;
|
||||
|
||||
{int len = pd.len;
|
||||
while ((ret = nut_read_frame(nut, &len, dp->buffer + pd.len-len)) == NUT_ERR_EAGAIN);
|
||||
}
|
||||
if (ret) {
|
||||
mp_msg(MSGT_HEADER, MSGL_ERR, "NUT error: %s\n",
|
||||
nut_error(ret));
|
||||
return 0; // fatal error
|
||||
}
|
||||
|
||||
ds_add_packet(ds, dp); // append packet to DS stream
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void demux_seek_nut(demuxer_t * demuxer, float time_pos, float audio_delay, int flags) {
|
||||
nut_context_tt * nut = ((nut_priv_tt*)demuxer->priv)->nut;
|
||||
nut_priv_tt * priv = demuxer->priv;
|
||||
int nutflags = 0;
|
||||
int ret;
|
||||
const int tmp[] = { 0, -1 };
|
||||
|
||||
if (!(flags & SEEK_ABSOLUTE)) {
|
||||
nutflags |= 1; // relative
|
||||
if (time_pos > 0) nutflags |= 2; // forwards
|
||||
}
|
||||
|
||||
if (flags & SEEK_FACTOR)
|
||||
time_pos *= priv->s[0].max_pts *
|
||||
(double)priv->s[0].time_base.num /
|
||||
priv->s[0].time_base.den;
|
||||
|
||||
while ((ret = nut_seek(nut, time_pos, nutflags, tmp)) == NUT_ERR_EAGAIN);
|
||||
priv->last_pts = -1;
|
||||
if (ret) mp_msg(MSGT_HEADER, MSGL_ERR, "NUT error: %s\n", nut_error(ret));
|
||||
demuxer->filepos = stream_tell(demuxer->stream);
|
||||
}
|
||||
|
||||
static int demux_control_nut(demuxer_t * demuxer, int cmd, void * arg) {
|
||||
nut_priv_tt * priv = demuxer->priv;
|
||||
switch (cmd) {
|
||||
case DEMUXER_CTRL_GET_TIME_LENGTH:
|
||||
*((double *)arg) = priv->s[0].max_pts *
|
||||
(double)priv->s[0].time_base.num /
|
||||
priv->s[0].time_base.den;
|
||||
return DEMUXER_CTRL_OK;
|
||||
case DEMUXER_CTRL_GET_PERCENT_POS:
|
||||
if (priv->s[0].max_pts == 0 || priv->last_pts == -1)
|
||||
return DEMUXER_CTRL_DONTKNOW;
|
||||
*((int *)arg) = priv->last_pts * 100 /
|
||||
(double)priv->s[0].max_pts;
|
||||
return DEMUXER_CTRL_OK;
|
||||
default:
|
||||
return DEMUXER_CTRL_NOTIMPL;
|
||||
}
|
||||
}
|
||||
|
||||
static void demux_close_nut(demuxer_t *demuxer) {
|
||||
nut_priv_tt * priv = demuxer->priv;
|
||||
if (!priv) return;
|
||||
nut_demuxer_uninit(priv->nut);
|
||||
free(demuxer->priv);
|
||||
demuxer->priv = NULL;
|
||||
}
|
||||
|
||||
|
||||
const demuxer_desc_t demuxer_desc_nut = {
|
||||
"NUT demuxer",
|
||||
"nut",
|
||||
"libnut",
|
||||
"Oded Shimon (ods15)",
|
||||
"NUT demuxer, requires libnut",
|
||||
DEMUXER_TYPE_NUT,
|
||||
1, // safe check demuxer
|
||||
nut_check_file,
|
||||
demux_nut_fill_buffer,
|
||||
demux_open_nut,
|
||||
demux_close_nut,
|
||||
demux_seek_nut,
|
||||
demux_control_nut
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -1,27 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MPLAYER_DEMUX_OGG_H
|
||||
#define MPLAYER_DEMUX_OGG_H
|
||||
|
||||
#include "demuxer.h"
|
||||
|
||||
int demux_ogg_open(demuxer_t *demuxer);
|
||||
demuxer_t *init_avi_with_ogg(demuxer_t *demuxer);
|
||||
|
||||
#endif /* MPLAYER_DEMUX_OGG_H */
|
@ -1,536 +0,0 @@
|
||||
/*
|
||||
* demuxer for PVA files, such as the ones produced by software to manage
|
||||
* DVB boards like the Hauppauge WinTV DVBs
|
||||
* copyright (c) 2002 Matteo Giani
|
||||
*
|
||||
* Uses info from the PVA file specifications found at
|
||||
* http://www.technotrend.de/download/av_format_v1.pdf
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* WARNING: Quite a hack was required in order to get files by MultiDec
|
||||
* played back correctly. If it breaks anything else, just comment out
|
||||
* the #define below and it will not be compiled in. */
|
||||
#define DEMUX_PVA_MULTIDEC_HACK
|
||||
#define PVA_NEW_PREBYTES_CODE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "mp_msg.h"
|
||||
|
||||
#include "stream/stream.h"
|
||||
#include "demuxer.h"
|
||||
#include "stheader.h"
|
||||
|
||||
/*
|
||||
* #defines below taken from PVA spec (see URL above)
|
||||
*/
|
||||
|
||||
#define PVA_MAX_VIDEO_PACK_LEN 6*1024
|
||||
|
||||
#define VIDEOSTREAM 0x01
|
||||
#define MAINAUDIOSTREAM 0x02
|
||||
|
||||
typedef struct {
|
||||
off_t offset;
|
||||
long size;
|
||||
uint8_t type;
|
||||
uint8_t is_packet_start;
|
||||
float pts;
|
||||
} pva_payload_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
float last_audio_pts;
|
||||
float last_video_pts;
|
||||
#ifdef PVA_NEW_PREBYTES_CODE
|
||||
float video_pts_after_prebytes;
|
||||
long video_size_after_prebytes;
|
||||
uint8_t prebytes_delivered;
|
||||
#endif
|
||||
uint8_t just_synced;
|
||||
uint8_t synced_stream_id;
|
||||
} pva_priv_t;
|
||||
|
||||
|
||||
|
||||
static int pva_sync(demuxer_t * demuxer)
|
||||
{
|
||||
uint8_t buffer[5]={0,0,0,0,0};
|
||||
int count;
|
||||
pva_priv_t * priv = (pva_priv_t *) demuxer->priv;
|
||||
|
||||
|
||||
/* This function is used to find the next nearest PVA packet start after a seek, since a PVA file
|
||||
* is not indexed.
|
||||
* The just_synced field is in the priv structure so that pva_get_payload knows pva_sync
|
||||
* has already read (part of) the PVA header. This way we can avoid to seek back and (hopefully)
|
||||
* be able to read from pipes and such.
|
||||
*/
|
||||
|
||||
|
||||
for(count=0 ; count<PVA_MAX_VIDEO_PACK_LEN && !demuxer->stream->eof && !priv->just_synced ; count++)
|
||||
{
|
||||
buffer[0]=buffer[1];
|
||||
buffer[1]=buffer[2];
|
||||
buffer[2]=buffer[3];
|
||||
buffer[3]=buffer[4];
|
||||
buffer[4]=stream_read_char(demuxer->stream);
|
||||
/*
|
||||
* Check for a PVA packet beginning sequence: we check both the "AV" word at the
|
||||
* very beginning and the "0x55" reserved byte (which is unused and set to 0x55 by spec)
|
||||
*/
|
||||
if(buffer[0]=='A' && buffer[1] == 'V' && buffer[4] == 0x55) priv->just_synced=1;
|
||||
//printf("demux_pva: pva_sync(): current offset= %ld\n",stream_tell(demuxer->stream));
|
||||
}
|
||||
if(priv->just_synced)
|
||||
{
|
||||
priv->synced_stream_id=buffer[2];
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int pva_check_file(demuxer_t * demuxer)
|
||||
{
|
||||
uint8_t buffer[5]={0,0,0,0,0};
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "Checking for PVA\n");
|
||||
stream_read(demuxer->stream,buffer,5);
|
||||
if(buffer[0]=='A' && buffer[1] == 'V' && buffer[4] == 0x55)
|
||||
{
|
||||
mp_msg(MSGT_DEMUX,MSGL_DBG2, "Success: PVA\n");
|
||||
return DEMUXER_TYPE_PVA;
|
||||
}
|
||||
else
|
||||
{
|
||||
mp_msg(MSGT_DEMUX,MSGL_DBG2, "Failed: PVA\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static demuxer_t * demux_open_pva (demuxer_t * demuxer)
|
||||
{
|
||||
sh_video_t *sh_video = new_sh_video(demuxer,0);
|
||||
sh_audio_t *sh_audio = new_sh_audio(demuxer,0);
|
||||
|
||||
|
||||
pva_priv_t * priv;
|
||||
|
||||
stream_reset(demuxer->stream);
|
||||
stream_seek(demuxer->stream,0);
|
||||
|
||||
|
||||
|
||||
priv=malloc(sizeof(pva_priv_t));
|
||||
|
||||
if(demuxer->stream->type!=STREAMTYPE_FILE) demuxer->seekable=0;
|
||||
else demuxer->seekable=1;
|
||||
|
||||
demuxer->priv=priv;
|
||||
memset(demuxer->priv,0,sizeof(pva_priv_t));
|
||||
|
||||
if(!pva_sync(demuxer))
|
||||
{
|
||||
mp_msg(MSGT_DEMUX,MSGL_ERR,"Not a PVA file.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//printf("priv->just_synced %s after initial sync!\n",priv->just_synced?"set":"UNSET");
|
||||
|
||||
demuxer->video->sh=sh_video;
|
||||
|
||||
//printf("demuxer->stream->end_pos= %d\n",demuxer->stream->end_pos);
|
||||
|
||||
|
||||
mp_msg(MSGT_DEMUXER,MSGL_INFO,"Opened PVA demuxer...\n");
|
||||
|
||||
/*
|
||||
* Audio and Video codecs:
|
||||
* the PVA spec only allows MPEG2 video and MPEG layer II audio. No need to check the formats then.
|
||||
* Moreover, there would be no way to do that since the PVA stream format has no fields to describe
|
||||
* the used codecs.
|
||||
*/
|
||||
|
||||
sh_video->format=0x10000002;
|
||||
sh_video->ds=demuxer->video;
|
||||
|
||||
/*
|
||||
printf("demuxer->video->id==%d\n",demuxer->video->id);
|
||||
printf("demuxer->audio->id==%d\n",demuxer->audio->id);
|
||||
*/
|
||||
|
||||
demuxer->audio->id = 0;
|
||||
demuxer->audio->sh=sh_audio;
|
||||
sh_audio->format=0x50;
|
||||
sh_audio->ds=demuxer->audio;
|
||||
|
||||
demuxer->movi_start=0;
|
||||
demuxer->movi_end=demuxer->stream->end_pos;
|
||||
|
||||
priv->last_video_pts=-1;
|
||||
priv->last_audio_pts=-1;
|
||||
|
||||
return demuxer;
|
||||
}
|
||||
|
||||
static int pva_get_payload(demuxer_t *d, pva_payload_t *payload)
|
||||
{
|
||||
uint8_t flags,pes_head_len;
|
||||
uint16_t pack_size;
|
||||
off_t pva_payload_start;
|
||||
unsigned char buffer[256];
|
||||
#ifndef PVA_NEW_PREBYTES_CODE
|
||||
demux_packet_t * dp; //hack to deliver the preBytes (see PVA doc)
|
||||
#endif
|
||||
pva_priv_t * priv;
|
||||
|
||||
|
||||
if(d==NULL)
|
||||
{
|
||||
mp_msg(MSGT_DEMUX,MSGL_ERR,"demux_pva: pva_get_payload got passed a NULL pointer!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
priv = (pva_priv_t *)d->priv;
|
||||
d->filepos=stream_tell(d->stream);
|
||||
|
||||
|
||||
|
||||
|
||||
if(d->stream->eof)
|
||||
{
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"demux_pva: pva_get_payload() detected stream->eof!!!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
//printf("priv->just_synced %s\n",priv->just_synced?"SET":"UNSET");
|
||||
|
||||
#ifdef PVA_NEW_PREBYTES_CODE
|
||||
if(priv->prebytes_delivered)
|
||||
/* The previous call to this fn has delivered the preBytes. Then we are already inside
|
||||
* the payload. Let's just deliver the video along with its right PTS, the one we stored
|
||||
* in the priv structure and was in the PVA header before the PreBytes.
|
||||
*/
|
||||
{
|
||||
//printf("prebytes_delivered=1. Resetting.\n");
|
||||
payload->size = priv->video_size_after_prebytes;
|
||||
payload->pts = priv->video_pts_after_prebytes;
|
||||
payload->is_packet_start = 1;
|
||||
payload->offset = stream_tell(d->stream);
|
||||
payload->type = VIDEOSTREAM;
|
||||
priv->prebytes_delivered = 0;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
if(!priv->just_synced)
|
||||
{
|
||||
if(stream_read_word(d->stream) != (('A'<<8)|'V'))
|
||||
{
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"demux_pva: pva_get_payload() missed a SyncWord at %"PRId64"!! Trying to sync...\n",(int64_t)stream_tell(d->stream));
|
||||
if(!pva_sync(d))
|
||||
{
|
||||
if (!d->stream->eof)
|
||||
{
|
||||
mp_msg(MSGT_DEMUX,MSGL_ERR,"demux_pva: couldn't sync! (broken file?)");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(priv->just_synced)
|
||||
{
|
||||
payload->type=priv->synced_stream_id;
|
||||
priv->just_synced=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
payload->type=stream_read_char(d->stream);
|
||||
stream_skip(d->stream,2); //counter and reserved
|
||||
}
|
||||
flags=stream_read_char(d->stream);
|
||||
payload->is_packet_start=flags & 0x10;
|
||||
pack_size=stream_read_word(d->stream);
|
||||
mp_msg(MSGT_DEMUX,MSGL_DBG2,"demux_pva::pva_get_payload(): pack_size=%u field read at offset %"PRIu64"\n",pack_size,(int64_t)stream_tell(d->stream)-2);
|
||||
pva_payload_start=stream_tell(d->stream);
|
||||
|
||||
|
||||
/*
|
||||
* The code in the #ifdef directive below is a hack needed to get badly formatted PVA files
|
||||
* such as the ones written by MultiDec played back correctly.
|
||||
* Basically, it works like this: if the PVA packet does not signal a PES header, but the
|
||||
* payload looks like one, let's assume it IS one. It has worked for me up to now.
|
||||
* It can be disabled since it's quite an ugly hack and could potentially break things up
|
||||
* if the PVA audio payload happens to start with 0x000001 even without being a non signalled
|
||||
* PES header start.
|
||||
* Though it's quite unlikely, it potentially could (AFAIK).
|
||||
*/
|
||||
#ifdef DEMUX_PVA_MULTIDEC_HACK
|
||||
if(payload->type==MAINAUDIOSTREAM)
|
||||
{
|
||||
stream_read(d->stream,buffer,3);
|
||||
if(buffer[0]==0x00 && buffer[1]==0x00 && buffer[2]==0x01 && !payload->is_packet_start)
|
||||
{
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"demux_pva: suspecting non signaled audio PES packet start. Maybe file by MultiDec?\n");
|
||||
payload->is_packet_start=1;
|
||||
}
|
||||
stream_seek(d->stream,stream_tell(d->stream)-3);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if(!payload->is_packet_start)
|
||||
{
|
||||
payload->offset=stream_tell(d->stream);
|
||||
payload->size=pack_size;
|
||||
}
|
||||
else
|
||||
{ //here comes the good part...
|
||||
switch(payload->type)
|
||||
{
|
||||
case VIDEOSTREAM:
|
||||
payload->pts=(float)(stream_read_dword(d->stream))/90000;
|
||||
//printf("Video PTS: %f\n",payload->pts);
|
||||
if((flags&0x03)
|
||||
#ifdef PVA_NEW_PREBYTES_CODE
|
||||
&& !priv->prebytes_delivered
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#ifndef PVA_NEW_PREBYTES_CODE
|
||||
dp=new_demux_packet(flags&0x03);
|
||||
stream_read(d->stream,dp->buffer,flags & 0x03); //read PreBytes
|
||||
ds_add_packet(d->video,dp);
|
||||
#else
|
||||
//printf("Delivering prebytes. Setting prebytes_delivered.");
|
||||
payload->offset=stream_tell(d->stream);
|
||||
payload->size = flags & 0x03;
|
||||
priv->video_pts_after_prebytes = payload->pts;
|
||||
priv->video_size_after_prebytes = pack_size - 4 - (flags & 0x03);
|
||||
payload->pts=priv->last_video_pts;
|
||||
payload->is_packet_start=0;
|
||||
priv->prebytes_delivered=1;
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//now we are at real beginning of payload.
|
||||
payload->offset=stream_tell(d->stream);
|
||||
//size is pack_size minus PTS size minus PreBytes size.
|
||||
payload->size=pack_size - 4 - (flags & 0x03);
|
||||
break;
|
||||
case MAINAUDIOSTREAM:
|
||||
stream_skip(d->stream,3); //FIXME properly parse PES header.
|
||||
//printf("StreamID in audio PES header: 0x%2X\n",stream_read_char(d->stream));
|
||||
stream_skip(d->stream,4);
|
||||
|
||||
buffer[255]=stream_read_char(d->stream);
|
||||
pes_head_len=stream_read_char(d->stream);
|
||||
stream_read(d->stream,buffer,pes_head_len);
|
||||
if(!(buffer[255]&0x80)) //PES header does not contain PTS.
|
||||
{
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"Audio PES packet does not contain PTS. (pes_head_len=%d)\n",pes_head_len);
|
||||
payload->pts=priv->last_audio_pts;
|
||||
break;
|
||||
}
|
||||
else //PES header DOES contain PTS
|
||||
{
|
||||
if((buffer[0] & 0xf0)!=0x20) // PTS badly formatted
|
||||
{
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"demux_pva: expected audio PTS but badly formatted... (read 0x%02X). Falling back to previous PTS (hack).\n",buffer[0]);
|
||||
payload->pts=priv->last_audio_pts;
|
||||
// return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64_t temp_pts;
|
||||
|
||||
temp_pts=0LL;
|
||||
temp_pts|=((uint64_t)(buffer[0] & 0x0e) << 29);
|
||||
temp_pts|=buffer[1]<<22;
|
||||
temp_pts|=(buffer[2] & 0xfe) << 14;
|
||||
temp_pts|=buffer[3]<<7;
|
||||
temp_pts|=(buffer[4] & 0xfe) >> 1;
|
||||
/*
|
||||
* PTS parsing is hopefully finished.
|
||||
*/
|
||||
payload->pts=(float)temp_pts/90000;
|
||||
}
|
||||
}
|
||||
payload->offset=stream_tell(d->stream);
|
||||
payload->size=pack_size-stream_tell(d->stream)+pva_payload_start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 0 = EOF or no stream found
|
||||
// 1 = successfully read a packet
|
||||
static int demux_pva_fill_buffer (demuxer_t * demux, demux_stream_t *ds)
|
||||
{
|
||||
uint8_t done=0;
|
||||
demux_packet_t * dp;
|
||||
pva_priv_t * priv=demux->priv;
|
||||
pva_payload_t current_payload;
|
||||
|
||||
while(!done)
|
||||
{
|
||||
if(!pva_get_payload(demux,¤t_payload)) return 0;
|
||||
switch(current_payload.type)
|
||||
{
|
||||
case VIDEOSTREAM:
|
||||
if(demux->video->id==-1) demux->video->id=0;
|
||||
if(!current_payload.is_packet_start && priv->last_video_pts==-1)
|
||||
{
|
||||
/* We should only be here at the beginning of a stream, when we have
|
||||
* not yet encountered a valid Video PTS, or after a seek.
|
||||
* So, skip these starting packets in order not to deliver the
|
||||
* player a bogus PTS.
|
||||
*/
|
||||
done=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* In every other condition, we are delivering the payload. Set this
|
||||
* so that the following code knows whether to skip it or read it.
|
||||
*/
|
||||
done=1;
|
||||
}
|
||||
if(demux->video->id!=0) done=0;
|
||||
if(current_payload.is_packet_start)
|
||||
{
|
||||
priv->last_video_pts=current_payload.pts;
|
||||
//mp_msg(MSGT_DEMUXER,MSGL_DBG2,"demux_pva: Video PTS=%llu , delivered %f\n",current_payload.pts,priv->last_video_pts);
|
||||
}
|
||||
if(done)
|
||||
{
|
||||
dp=new_demux_packet(current_payload.size);
|
||||
dp->pts=priv->last_video_pts;
|
||||
stream_read(demux->stream,dp->buffer,current_payload.size);
|
||||
ds_add_packet(demux->video,dp);
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("Skipping %u video bytes\n",current_payload.size);
|
||||
stream_skip(demux->stream,current_payload.size);
|
||||
}
|
||||
break;
|
||||
case MAINAUDIOSTREAM:
|
||||
if(demux->audio->id==-1) demux->audio->id=0;
|
||||
if(!current_payload.is_packet_start && priv->last_audio_pts==-1)
|
||||
{
|
||||
/* Same as above for invalid video PTS, just for audio. */
|
||||
done=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
done=1;
|
||||
}
|
||||
if(current_payload.is_packet_start)
|
||||
{
|
||||
priv->last_audio_pts=current_payload.pts;
|
||||
}
|
||||
if(demux->audio->id!=0) done=0;
|
||||
if(done)
|
||||
{
|
||||
dp=new_demux_packet(current_payload.size);
|
||||
dp->pts=priv->last_audio_pts;
|
||||
if(current_payload.offset != stream_tell(demux->stream))
|
||||
stream_seek(demux->stream,current_payload.offset);
|
||||
stream_read(demux->stream,dp->buffer,current_payload.size);
|
||||
ds_add_packet(demux->audio,dp);
|
||||
}
|
||||
else
|
||||
{
|
||||
stream_skip(demux->stream,current_payload.size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void demux_seek_pva(demuxer_t * demuxer,float rel_seek_secs,float audio_delay,int flags)
|
||||
{
|
||||
int total_bitrate=0;
|
||||
off_t dest_offset;
|
||||
pva_priv_t * priv=demuxer->priv;
|
||||
|
||||
total_bitrate=((sh_audio_t *)demuxer->audio->sh)->i_bps + ((sh_video_t *)demuxer->video->sh)->i_bps;
|
||||
|
||||
/*
|
||||
* Compute absolute offset inside the stream. Approximate total bitrate with sum of bitrates
|
||||
* reported by the audio and video codecs. The seek is not accurate because, just like
|
||||
* with MPEG streams, the bitrate is not constant. Moreover, we do not take into account
|
||||
* the overhead caused by PVA and PES headers.
|
||||
* If the calculated absolute offset is negative, seek to the beginning of the file.
|
||||
*/
|
||||
|
||||
dest_offset=stream_tell(demuxer->stream)+rel_seek_secs*total_bitrate;
|
||||
if(dest_offset<0) dest_offset=0;
|
||||
|
||||
stream_seek(demuxer->stream,dest_offset);
|
||||
|
||||
if(!pva_sync(demuxer))
|
||||
{
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"demux_pva: Couldn't seek!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the PTS info inside the pva_priv_t structure. This way we don't deliver
|
||||
* data with the wrong PTSs (the ones we had before seeking).
|
||||
*
|
||||
*/
|
||||
|
||||
priv->last_video_pts=-1;
|
||||
priv->last_audio_pts=-1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void demux_close_pva(demuxer_t * demuxer)
|
||||
{
|
||||
free(demuxer->priv);
|
||||
demuxer->priv = NULL;
|
||||
}
|
||||
|
||||
|
||||
const demuxer_desc_t demuxer_desc_pva = {
|
||||
"PVA demuxer",
|
||||
"pva",
|
||||
"PVA",
|
||||
"Matteo Giani",
|
||||
"streams from DVB cards",
|
||||
DEMUXER_TYPE_PVA,
|
||||
0, // unsafe autodetect
|
||||
pva_check_file,
|
||||
demux_pva_fill_buffer,
|
||||
demux_open_pva,
|
||||
demux_close_pva,
|
||||
demux_seek_pva,
|
||||
NULL
|
||||
};
|
@ -1,281 +0,0 @@
|
||||
/*
|
||||
* RoQ file demuxer
|
||||
* copyright (c) 2002 Mike Melanson
|
||||
* based on Dr. Tim Ferguson's RoQ document found at:
|
||||
* http://www.csse.monash.edu.au/~timf/videocodec.html
|
||||
*
|
||||
* 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 "mp_msg.h"
|
||||
|
||||
#include "stream/stream.h"
|
||||
#include "demuxer.h"
|
||||
#include "stheader.h"
|
||||
#include "libavutil/attributes.h"
|
||||
|
||||
#define RoQ_INFO 0x1001
|
||||
#define RoQ_QUAD_CODEBOOK 0x1002
|
||||
#define RoQ_QUAD_VQ 0x1011
|
||||
#define RoQ_SOUND_MONO 0x1020
|
||||
#define RoQ_SOUND_STEREO 0x1021
|
||||
|
||||
#define CHUNK_TYPE_AUDIO 0
|
||||
#define CHUNK_TYPE_VIDEO 1
|
||||
|
||||
typedef struct roq_chunk_t
|
||||
{
|
||||
int chunk_type;
|
||||
off_t chunk_offset;
|
||||
int chunk_size;
|
||||
|
||||
float video_chunk_number; // in the case of a video chunk
|
||||
int running_audio_sample_count; // for an audio chunk
|
||||
} roq_chunk_t;
|
||||
|
||||
typedef struct roq_data_t
|
||||
{
|
||||
int total_chunks;
|
||||
int current_chunk;
|
||||
int total_video_chunks;
|
||||
int total_audio_sample_count;
|
||||
roq_chunk_t *chunks;
|
||||
} roq_data_t;
|
||||
|
||||
// Check if a stream qualifies as a RoQ file based on the magic numbers
|
||||
// at the start of the file:
|
||||
// 84 10 FF FF FF FF xx xx
|
||||
static int roq_check_file(demuxer_t *demuxer)
|
||||
{
|
||||
if ((stream_read_dword(demuxer->stream) == 0x8410FFFF) &&
|
||||
((stream_read_dword(demuxer->stream) & 0xFFFF0000) == 0xFFFF0000))
|
||||
return DEMUXER_TYPE_ROQ;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return value:
|
||||
// 0 = EOF or no stream found
|
||||
// 1 = successfully read a packet
|
||||
static int demux_roq_fill_buffer(demuxer_t *demuxer, demux_stream_t *ds)
|
||||
{
|
||||
sh_video_t *sh_video = demuxer->video->sh;
|
||||
roq_data_t *roq_data = (roq_data_t *)demuxer->priv;
|
||||
roq_chunk_t roq_chunk;
|
||||
|
||||
if (roq_data->current_chunk >= roq_data->total_chunks)
|
||||
return 0;
|
||||
|
||||
roq_chunk = roq_data->chunks[roq_data->current_chunk];
|
||||
|
||||
// make sure we're at the right place in the stream and fetch the chunk
|
||||
stream_seek(demuxer->stream, roq_chunk.chunk_offset);
|
||||
|
||||
if (roq_chunk.chunk_type == CHUNK_TYPE_AUDIO)
|
||||
ds_read_packet(demuxer->audio, demuxer->stream, roq_chunk.chunk_size,
|
||||
0,
|
||||
roq_chunk.chunk_offset, 0);
|
||||
else
|
||||
ds_read_packet(demuxer->video, demuxer->stream, roq_chunk.chunk_size,
|
||||
roq_chunk.video_chunk_number / sh_video->fps,
|
||||
roq_chunk.chunk_offset, 0);
|
||||
|
||||
roq_data->current_chunk++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static demuxer_t* demux_open_roq(demuxer_t* demuxer)
|
||||
{
|
||||
sh_video_t *sh_video = NULL;
|
||||
sh_audio_t *sh_audio = NULL;
|
||||
|
||||
roq_data_t *roq_data = malloc(sizeof(roq_data_t));
|
||||
int chunk_id;
|
||||
int chunk_size;
|
||||
int chunk_arg av_unused;
|
||||
int last_chunk_id = 0;
|
||||
int largest_audio_chunk = 0;
|
||||
int fps;
|
||||
|
||||
roq_data->total_chunks = 0;
|
||||
roq_data->current_chunk = 0;
|
||||
roq_data->total_video_chunks = 0;
|
||||
roq_data->chunks = NULL;
|
||||
|
||||
// position the stream and start traversing
|
||||
stream_seek(demuxer->stream, 6);
|
||||
fps = stream_read_word_le(demuxer->stream);
|
||||
while (!stream_eof(demuxer->stream))
|
||||
{
|
||||
chunk_id = stream_read_word_le(demuxer->stream);
|
||||
chunk_size = stream_read_dword_le(demuxer->stream);
|
||||
chunk_arg = stream_read_word_le(demuxer->stream);
|
||||
|
||||
// this is the only useful header info in the file
|
||||
if (chunk_id == RoQ_INFO)
|
||||
{
|
||||
// there should only be one RoQ_INFO chunk per file
|
||||
if (sh_video)
|
||||
{
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_WARN, "Found more than one RoQ_INFO chunk\n");
|
||||
stream_skip(demuxer->stream, 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is a good opportunity to create a video stream header
|
||||
sh_video = new_sh_video(demuxer, 0);
|
||||
// make sure the demuxer knows about the new stream header
|
||||
demuxer->video->sh = sh_video;
|
||||
// make sure that the video demuxer stream header knows about its
|
||||
// parent video demuxer stream
|
||||
sh_video->ds = demuxer->video;
|
||||
|
||||
sh_video->disp_w = stream_read_word_le(demuxer->stream);
|
||||
sh_video->disp_h = stream_read_word_le(demuxer->stream);
|
||||
stream_skip(demuxer->stream, 4);
|
||||
|
||||
// custom fourcc for internal MPlayer use
|
||||
sh_video->format = mmioFOURCC('R', 'o', 'Q', 'V');
|
||||
|
||||
// constant frame rate
|
||||
sh_video->fps = fps;
|
||||
sh_video->frametime = 1 / sh_video->fps;
|
||||
}
|
||||
}
|
||||
else if ((chunk_id == RoQ_SOUND_MONO) ||
|
||||
(chunk_id == RoQ_SOUND_STEREO))
|
||||
{
|
||||
// create the audio stream header if it hasn't been created it
|
||||
if (sh_audio == NULL)
|
||||
{
|
||||
// make the header first
|
||||
sh_audio = new_sh_audio(demuxer, 0);
|
||||
// make sure the demuxer knows about the new stream header
|
||||
demuxer->audio->id = 0;
|
||||
demuxer->audio->sh = sh_audio;
|
||||
// make sure that the audio demuxer stream header knows about its
|
||||
// parent audio demuxer stream
|
||||
sh_audio->ds = demuxer->audio;
|
||||
|
||||
// go through the bother of making a WAVEFORMATEX structure
|
||||
sh_audio->wf = malloc(sizeof(*sh_audio->wf));
|
||||
|
||||
// custom fourcc for internal MPlayer use
|
||||
sh_audio->format = mmioFOURCC('R', 'o', 'Q', 'A');
|
||||
if (chunk_id == RoQ_SOUND_STEREO)
|
||||
sh_audio->wf->nChannels = 2;
|
||||
else
|
||||
sh_audio->wf->nChannels = 1;
|
||||
// always 22KHz, 16-bit
|
||||
sh_audio->wf->nSamplesPerSec = 22050;
|
||||
sh_audio->wf->wBitsPerSample = 16;
|
||||
}
|
||||
|
||||
// index the chunk
|
||||
roq_data->chunks = realloc(roq_data->chunks,
|
||||
(roq_data->total_chunks + 1) * sizeof (roq_chunk_t));
|
||||
roq_data->chunks[roq_data->total_chunks].chunk_type = CHUNK_TYPE_AUDIO;
|
||||
roq_data->chunks[roq_data->total_chunks].chunk_offset =
|
||||
stream_tell(demuxer->stream) - 8;
|
||||
roq_data->chunks[roq_data->total_chunks].chunk_size = chunk_size + 8;
|
||||
roq_data->chunks[roq_data->total_chunks].running_audio_sample_count =
|
||||
roq_data->total_audio_sample_count;
|
||||
|
||||
// audio housekeeping
|
||||
if (chunk_size > largest_audio_chunk)
|
||||
largest_audio_chunk = chunk_size;
|
||||
roq_data->total_audio_sample_count +=
|
||||
(chunk_size / sh_audio->wf->nChannels);
|
||||
|
||||
stream_skip(demuxer->stream, chunk_size);
|
||||
roq_data->total_chunks++;
|
||||
}
|
||||
else if ((chunk_id == RoQ_QUAD_CODEBOOK) ||
|
||||
((chunk_id == RoQ_QUAD_VQ) && (last_chunk_id != RoQ_QUAD_CODEBOOK)))
|
||||
{
|
||||
// index a new chunk if it's a codebook or quad VQ not following a
|
||||
// codebook
|
||||
roq_data->chunks = realloc(roq_data->chunks,
|
||||
(roq_data->total_chunks + 1) * sizeof (roq_chunk_t));
|
||||
roq_data->chunks[roq_data->total_chunks].chunk_type = CHUNK_TYPE_VIDEO;
|
||||
roq_data->chunks[roq_data->total_chunks].chunk_offset =
|
||||
stream_tell(demuxer->stream) - 8;
|
||||
roq_data->chunks[roq_data->total_chunks].chunk_size = chunk_size + 8;
|
||||
roq_data->chunks[roq_data->total_chunks].video_chunk_number =
|
||||
roq_data->total_video_chunks++;
|
||||
|
||||
stream_skip(demuxer->stream, chunk_size);
|
||||
roq_data->total_chunks++;
|
||||
}
|
||||
else if ((chunk_id == RoQ_QUAD_VQ) && (last_chunk_id == RoQ_QUAD_CODEBOOK))
|
||||
{
|
||||
// if it's a quad VQ chunk following a codebook chunk, extend the last
|
||||
// chunk
|
||||
roq_data->chunks[roq_data->total_chunks - 1].chunk_size += (chunk_size + 8);
|
||||
stream_skip(demuxer->stream, chunk_size);
|
||||
}
|
||||
else if (!stream_eof(demuxer->stream))
|
||||
{
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_WARN, "Unknown RoQ chunk ID: %04X\n", chunk_id);
|
||||
}
|
||||
|
||||
last_chunk_id = chunk_id;
|
||||
}
|
||||
|
||||
// minimum output buffer size = largest audio chunk * 2, since each byte
|
||||
// in the DPCM encoding effectively represents 1 16-bit sample
|
||||
// (store it in wf->nBlockAlign for the time being since init_audio() will
|
||||
// step on it anyway)
|
||||
if (sh_audio)
|
||||
sh_audio->wf->nBlockAlign = largest_audio_chunk * 2;
|
||||
|
||||
roq_data->current_chunk = 0;
|
||||
|
||||
demuxer->priv = roq_data;
|
||||
|
||||
stream_reset(demuxer->stream);
|
||||
|
||||
return demuxer;
|
||||
}
|
||||
|
||||
static void demux_close_roq(demuxer_t* demuxer) {
|
||||
roq_data_t *roq_data = demuxer->priv;
|
||||
|
||||
free(roq_data);
|
||||
}
|
||||
|
||||
|
||||
const demuxer_desc_t demuxer_desc_roq = {
|
||||
"RoQ demuxer",
|
||||
"roq",
|
||||
"ROQ",
|
||||
"Mike Melanson",
|
||||
"",
|
||||
DEMUXER_TYPE_ROQ,
|
||||
0, // unsafe autodetect
|
||||
roq_check_file,
|
||||
demux_roq_fill_buffer,
|
||||
demux_open_roq,
|
||||
demux_close_roq,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
@ -1,200 +0,0 @@
|
||||
/*
|
||||
* SMJPEG file parser
|
||||
* copyright (c) 2002 Alex Beregszaszi
|
||||
* based on text by Arpi (SMJPEG-format.txt) and later on
|
||||
* http://www.lokigames.com/development/download/smjpeg/SMJPEG.txt
|
||||
*
|
||||
* 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 <string.h> /* strtok */
|
||||
|
||||
#include "config.h"
|
||||
#include "mp_msg.h"
|
||||
#include "libavutil/attributes.h"
|
||||
#include "stream/stream.h"
|
||||
#include "demuxer.h"
|
||||
#include "stheader.h"
|
||||
|
||||
static int smjpeg_check_file(demuxer_t* demuxer){
|
||||
int orig_pos = stream_tell(demuxer->stream);
|
||||
char buf[8];
|
||||
int version;
|
||||
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "Checking for SMJPEG\n");
|
||||
|
||||
if (stream_read_word(demuxer->stream) == 0xA)
|
||||
{
|
||||
stream_read(demuxer->stream, buf, 6);
|
||||
buf[7] = 0;
|
||||
|
||||
if (strncmp("SMJPEG", buf, 6)) {
|
||||
mp_msg(MSGT_DEMUX, MSGL_DBG2, "Failed: SMJPEG\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
||||
version = stream_read_dword(demuxer->stream);
|
||||
if (version != 0)
|
||||
{
|
||||
mp_msg(MSGT_DEMUX, MSGL_ERR, "Unknown version (%d) of SMJPEG. Please report!\n",
|
||||
version);
|
||||
return 0;
|
||||
}
|
||||
|
||||
stream_seek(demuxer->stream, orig_pos);
|
||||
|
||||
return DEMUXER_TYPE_SMJPEG;
|
||||
}
|
||||
|
||||
|
||||
// return value:
|
||||
// 0 = EOF or no stream found
|
||||
// 1 = successfully read a packet
|
||||
static int demux_smjpeg_fill_buffer(demuxer_t *demux, demux_stream_t *ds)
|
||||
{
|
||||
int dtype, dsize, dpts;
|
||||
|
||||
demux->filepos = stream_tell(demux->stream);
|
||||
|
||||
dtype = stream_read_dword_le(demux->stream);
|
||||
dpts = stream_read_dword(demux->stream);
|
||||
dsize = stream_read_dword(demux->stream);
|
||||
|
||||
switch(dtype)
|
||||
{
|
||||
case mmioFOURCC('s','n','d','D'):
|
||||
/* fixme, but no decoder implemented yet */
|
||||
ds_read_packet(demux->audio, demux->stream, dsize,
|
||||
(float)dpts/1000.0, demux->filepos, 0);
|
||||
break;
|
||||
case mmioFOURCC('v','i','d','D'):
|
||||
ds_read_packet(demux->video, demux->stream, dsize,
|
||||
(float)dpts/1000.0, demux->filepos, 0);
|
||||
break;
|
||||
case mmioFOURCC('D','O','N','E'):
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static demuxer_t* demux_open_smjpeg(demuxer_t* demuxer){
|
||||
sh_video_t* sh_video;
|
||||
sh_audio_t* sh_audio;
|
||||
unsigned int htype = 0, hleng av_unused;
|
||||
int i = 0;
|
||||
|
||||
/* file header */
|
||||
stream_skip(demuxer->stream, 8); /* \x00\x0aSMJPEG */
|
||||
stream_skip(demuxer->stream, 4);
|
||||
|
||||
mp_msg(MSGT_DEMUX, MSGL_INFO, "This clip is %d seconds\n",
|
||||
stream_read_dword(demuxer->stream));
|
||||
|
||||
/* stream header */
|
||||
while (i < 3)
|
||||
{
|
||||
i++;
|
||||
htype = stream_read_dword_le(demuxer->stream);
|
||||
if (htype == mmioFOURCC('H','E','N','D'))
|
||||
break;
|
||||
hleng = (stream_read_word(demuxer->stream)<<16)|stream_read_word(demuxer->stream);
|
||||
switch(htype)
|
||||
{
|
||||
case mmioFOURCC('_','V','I','D'):
|
||||
sh_video = new_sh_video(demuxer, 0);
|
||||
demuxer->video->sh = sh_video;
|
||||
sh_video->ds = demuxer->video;
|
||||
|
||||
sh_video->bih = calloc(1, sizeof(*sh_video->bih));
|
||||
|
||||
stream_skip(demuxer->stream, 4); /* number of frames */
|
||||
// sh_video->fps = 24;
|
||||
// sh_video->frametime = 1.0f/sh_video->fps;
|
||||
sh_video->disp_w = stream_read_word(demuxer->stream);
|
||||
sh_video->disp_h = stream_read_word(demuxer->stream);
|
||||
sh_video->format = stream_read_dword_le(demuxer->stream);
|
||||
|
||||
/* these are false values */
|
||||
sh_video->bih->biSize = 40;
|
||||
sh_video->bih->biWidth = sh_video->disp_w;
|
||||
sh_video->bih->biHeight = sh_video->disp_h;
|
||||
sh_video->bih->biPlanes = 3;
|
||||
sh_video->bih->biBitCount = 12;
|
||||
sh_video->bih->biCompression = sh_video->format;
|
||||
sh_video->bih->biSizeImage = sh_video->disp_w*sh_video->disp_h;
|
||||
break;
|
||||
case mmioFOURCC('_','S','N','D'):
|
||||
sh_audio = new_sh_audio(demuxer, 0);
|
||||
demuxer->audio->id = 0;
|
||||
demuxer->audio->sh = sh_audio;
|
||||
sh_audio->ds = demuxer->audio;
|
||||
|
||||
sh_audio->wf = calloc(1, sizeof(*sh_audio->wf));
|
||||
|
||||
sh_audio->samplerate = stream_read_word(demuxer->stream);
|
||||
sh_audio->wf->wBitsPerSample = stream_read_char(demuxer->stream);
|
||||
sh_audio->channels = stream_read_char(demuxer->stream);
|
||||
sh_audio->format = stream_read_dword_le(demuxer->stream);
|
||||
sh_audio->wf->wFormatTag = sh_audio->format;
|
||||
sh_audio->wf->nChannels = sh_audio->channels;
|
||||
sh_audio->wf->nSamplesPerSec = sh_audio->samplerate;
|
||||
sh_audio->wf->nAvgBytesPerSec = sh_audio->wf->nChannels*
|
||||
sh_audio->wf->wBitsPerSample*sh_audio->wf->nSamplesPerSec/8;
|
||||
sh_audio->wf->nBlockAlign = sh_audio->channels *2;
|
||||
sh_audio->wf->cbSize = 0;
|
||||
break;
|
||||
case mmioFOURCC('_','T','X','T'):
|
||||
stream_skip(demuxer->stream, stream_read_dword(demuxer->stream));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
demuxer->seekable = 0;
|
||||
|
||||
return demuxer;
|
||||
}
|
||||
|
||||
static void demux_close_smjpeg(demuxer_t *demuxer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const demuxer_desc_t demuxer_desc_smjpeg = {
|
||||
"smjpeg demuxer",
|
||||
"smjpeg",
|
||||
"SMJPEG",
|
||||
"Alex Beregszasi",
|
||||
"",
|
||||
DEMUXER_TYPE_SMJPEG,
|
||||
1, // safe autodetect
|
||||
smjpeg_check_file,
|
||||
demux_smjpeg_fill_buffer,
|
||||
demux_open_smjpeg,
|
||||
demux_close_smjpeg,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -1,24 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MPLAYER_DEMUX_TS_H
|
||||
#define MPLAYER_DEMUX_TS_H
|
||||
|
||||
#define TS_MAX_PROBE_SIZE 2000000
|
||||
|
||||
#endif /* MPLAYER_DEMUX_TS_H */
|
@ -1,899 +0,0 @@
|
||||
/*
|
||||
* tivo@wingert.org, February 2003
|
||||
*
|
||||
* Copyright (C) 2003 Christopher R. Wingert
|
||||
*
|
||||
* The license covers the portions of this file regarding TiVo additions.
|
||||
*
|
||||
* Olaf Beck and Tridge (indirectly) were essential at providing
|
||||
* information regarding the format of the TiVo streams.
|
||||
*
|
||||
* However, no code in the following subsection is directly copied from
|
||||
* either author.
|
||||
*
|
||||
* 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 <time.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <libavutil/avstring.h>
|
||||
#include <libavutil/intreadwrite.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "mp_msg.h"
|
||||
|
||||
#include "libmpcodecs/dec_audio.h"
|
||||
#include "stream/stream.h"
|
||||
#include "demuxer.h"
|
||||
#ifdef DEMUX_TY_OSD
|
||||
#include "demux_ty_osd.h"
|
||||
#endif
|
||||
#include "parse_es.h"
|
||||
#include "stheader.h"
|
||||
#include "sub/sub_cc.h"
|
||||
#include "sub/sub.h"
|
||||
|
||||
// 2/c0: audio data
|
||||
// 3/c0: audio packet header (PES header)
|
||||
// 4/c0: audio data (S/A only?)
|
||||
// 9/c0: audio packet header, AC-3 audio
|
||||
// 2/e0: video data
|
||||
// 6/e0: video packet header (PES header)
|
||||
// 7/e0: video sequence header start
|
||||
// 8/e0: video I-frame header start
|
||||
// a/e0: video P-frame header start
|
||||
// b/e0: video B-frame header start
|
||||
// c/e0: video GOP header start
|
||||
// e/01: closed-caption data
|
||||
// e/02: Extended data services data
|
||||
|
||||
|
||||
#define TIVO_PES_FILEID 0xf5467abd
|
||||
#define TIVO_PART_LENGTH 0x20000000
|
||||
|
||||
#define CHUNKSIZE ( 128 * 1024 )
|
||||
#define MAX_AUDIO_BUFFER ( 16 * 1024 )
|
||||
|
||||
#define TY_V 1
|
||||
#define TY_A 2
|
||||
|
||||
typedef struct
|
||||
{
|
||||
off_t startOffset;
|
||||
off_t fileSize;
|
||||
int chunks;
|
||||
} tmf_fileParts;
|
||||
|
||||
#define MAX_TMF_PARTS 16
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int whichChunk;
|
||||
unsigned char chunk[ CHUNKSIZE ];
|
||||
|
||||
unsigned char lastAudio[ MAX_AUDIO_BUFFER ];
|
||||
int lastAudioEnd;
|
||||
|
||||
int tivoType; // 1 = SA, 2 = DTiVo
|
||||
|
||||
int64_t lastAudioPTS;
|
||||
int64_t lastVideoPTS;
|
||||
|
||||
off_t size;
|
||||
int readHeader;
|
||||
|
||||
int tmf;
|
||||
tmf_fileParts tmfparts[ MAX_TMF_PARTS ];
|
||||
int tmf_totalparts;
|
||||
} TiVoInfo;
|
||||
|
||||
// ===========================================================================
|
||||
#define TMF_SIG "showing.xml"
|
||||
|
||||
// ===========================================================================
|
||||
static int ty_tmf_filetoparts( demuxer_t *demux, TiVoInfo *tivo )
|
||||
{
|
||||
int parts = 0;
|
||||
|
||||
stream_seek(demux->stream, 0);
|
||||
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "Dumping tar contents\n" );
|
||||
while (!demux->stream->eof)
|
||||
{
|
||||
char header[ 512 ];
|
||||
char *name;
|
||||
char *extension;
|
||||
char *sizestr;
|
||||
int size;
|
||||
off_t skip;
|
||||
if (stream_read(demux->stream, header, 512) < 512)
|
||||
{
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "Read bad\n" );
|
||||
break;
|
||||
}
|
||||
name = header;
|
||||
name[99] = 0;
|
||||
sizestr = &header[124];
|
||||
sizestr[11] = 0;
|
||||
size = strtol(sizestr, NULL, 8);
|
||||
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "name %-20.20s size %-12.12s %d\n",
|
||||
name, sizestr, size );
|
||||
|
||||
extension = strrchr(name, '.');
|
||||
if (extension && strcmp(extension, ".ty") == 0)
|
||||
{
|
||||
if ( parts >= MAX_TMF_PARTS ) {
|
||||
mp_msg( MSGT_DEMUX, MSGL_ERR, "ty:tmf too big\n" );
|
||||
break;
|
||||
}
|
||||
tivo->tmfparts[ parts ].fileSize = size;
|
||||
tivo->tmfparts[ parts ].startOffset = stream_tell(demux->stream);
|
||||
tivo->tmfparts[ parts ].chunks = size / CHUNKSIZE;
|
||||
mp_msg(MSGT_DEMUX, MSGL_DBG3,
|
||||
"tmf_filetoparts(): index %d, chunks %d\n"
|
||||
"tmf_filetoparts(): size %"PRId64"\n"
|
||||
"tmf_filetoparts(): startOffset %"PRId64"\n",
|
||||
parts, tivo->tmfparts[ parts ].chunks,
|
||||
tivo->tmfparts[ parts ].fileSize, tivo->tmfparts[ parts ].startOffset
|
||||
);
|
||||
parts++;
|
||||
}
|
||||
|
||||
// size rounded up to blocks
|
||||
skip = (size + 511) & ~511;
|
||||
stream_skip(demux->stream, skip);
|
||||
}
|
||||
stream_reset(demux->stream);
|
||||
tivo->tmf_totalparts = parts;
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3,
|
||||
"tmf_filetoparts(): No More Part Files %d\n", parts );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// ===========================================================================
|
||||
static off_t tmf_filetooffset(TiVoInfo *tivo, int chunk)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < tivo->tmf_totalparts; i++) {
|
||||
if (chunk < tivo->tmfparts[i].chunks)
|
||||
return tivo->tmfparts[i].startOffset + chunk * CHUNKSIZE;
|
||||
chunk -= tivo->tmfparts[i].chunks;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// ===========================================================================
|
||||
static int tmf_load_chunk( demuxer_t *demux, TiVoInfo *tivo,
|
||||
unsigned char *buff, int readChunk )
|
||||
{
|
||||
off_t fileoffset;
|
||||
int count;
|
||||
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "\ntmf_load_chunk() begin %d\n",
|
||||
readChunk );
|
||||
|
||||
fileoffset = tmf_filetooffset(tivo, readChunk);
|
||||
|
||||
if (fileoffset == -1 || !stream_seek(demux->stream, fileoffset)) {
|
||||
mp_msg( MSGT_DEMUX, MSGL_ERR, "Read past EOF()\n" );
|
||||
return 0;
|
||||
}
|
||||
count = stream_read( demux->stream, buff, CHUNKSIZE );
|
||||
demux->filepos = stream_tell( demux->stream );
|
||||
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "tmf_load_chunk() count %x\n",
|
||||
count );
|
||||
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3,
|
||||
"tmf_load_chunk() bytes %x %x %x %x %x %x %x %x\n",
|
||||
buff[ 0 ], buff[ 1 ], buff[ 2 ], buff[ 3 ],
|
||||
buff[ 4 ], buff[ 5 ], buff[ 6 ], buff[ 7 ] );
|
||||
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "tmf_load_chunk() end\n" );
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
|
||||
// DTiVo MPEG 336, 480, 576, 768
|
||||
// SA TiVo 864
|
||||
// DTiVo AC-3 1550
|
||||
//
|
||||
#define SERIES1_PTS_LENGTH 11
|
||||
#define SERIES1_PTS_OFFSET 6
|
||||
#define SERIES2_PTS_LENGTH 16
|
||||
#define SERIES2_PTS_OFFSET 9
|
||||
#define AC3_PTS_LENGTH 16
|
||||
#define AC3_PTS_OFFSET 9
|
||||
|
||||
static int IsValidAudioPacket( int size, int *ptsOffset, int *ptsLen )
|
||||
{
|
||||
// AC-3
|
||||
if ( size == 1550 || size == 1552 )
|
||||
{
|
||||
*ptsOffset = AC3_PTS_OFFSET;
|
||||
*ptsLen = AC3_PTS_LENGTH;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// MPEG
|
||||
if ( (size & 15) == (SERIES1_PTS_LENGTH & 15) )
|
||||
{
|
||||
*ptsOffset = SERIES1_PTS_OFFSET;
|
||||
*ptsLen = SERIES1_PTS_LENGTH;
|
||||
return 1;
|
||||
}
|
||||
if ( (size & 15) == (SERIES2_PTS_LENGTH & 15) )
|
||||
{
|
||||
*ptsOffset = SERIES2_PTS_OFFSET;
|
||||
*ptsLen = SERIES2_PTS_LENGTH;
|
||||
return 1;
|
||||
}
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "ty:Tossing Audio Packet Size %d\n",
|
||||
size );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int64_t get_ty_pts( unsigned char *buf )
|
||||
{
|
||||
int a = buf[0] & 0xe;
|
||||
int b = AV_RB16(buf + 1);
|
||||
int c = AV_RB16(buf + 3);
|
||||
|
||||
if (!(1 & a & b & c)) // invalid MPEG timestamp
|
||||
return MP_NOPTS_VALUE;
|
||||
a >>= 1; b >>= 1; c >>= 1;
|
||||
return (((uint64_t)a) << 30) | (b << 15) | c;
|
||||
}
|
||||
|
||||
static void demux_ty_AddToAudioBuffer( TiVoInfo *tivo, unsigned char *buffer,
|
||||
int size )
|
||||
{
|
||||
if ( tivo->lastAudioEnd + size < MAX_AUDIO_BUFFER )
|
||||
{
|
||||
memcpy( &tivo->lastAudio[ tivo->lastAudioEnd ],
|
||||
buffer, size );
|
||||
tivo->lastAudioEnd += size;
|
||||
}
|
||||
else
|
||||
mp_msg( MSGT_DEMUX, MSGL_ERR,
|
||||
"ty:WARNING - Would have blown my audio buffer\n" );
|
||||
}
|
||||
|
||||
static void demux_ty_CopyToDemuxPacket( demux_stream_t *ds,
|
||||
unsigned char *buffer, int size, off_t pos, int64_t pts )
|
||||
{
|
||||
demux_packet_t *dp = new_demux_packet( size );
|
||||
memcpy( dp->buffer, buffer, size );
|
||||
if (pts != MP_NOPTS_VALUE)
|
||||
dp->pts = pts / 90000.0;
|
||||
dp->pos = pos;
|
||||
ds_add_packet( ds, dp );
|
||||
}
|
||||
|
||||
static int demux_ty_FindESHeader( uint8_t nal,
|
||||
unsigned char *buffer, int bufferSize )
|
||||
{
|
||||
uint32_t search = 0x00000100 | nal;
|
||||
uint32_t found = -1;
|
||||
uint8_t *p = buffer;
|
||||
uint8_t *end = p + bufferSize;
|
||||
while (p < end) {
|
||||
found <<= 8;
|
||||
found |= *p++;
|
||||
if (found == search)
|
||||
return p - buffer - 4;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void demux_ty_FindESPacket( uint8_t nal,
|
||||
unsigned char *buffer, int bufferSize, int *esOffset1, int *esOffset2 )
|
||||
{
|
||||
*esOffset1 = demux_ty_FindESHeader(nal, buffer, bufferSize);
|
||||
if (*esOffset1 == -1) {
|
||||
*esOffset2 = -1;
|
||||
return;
|
||||
}
|
||||
buffer += *esOffset1 + 1;
|
||||
bufferSize -= *esOffset1 + 1;
|
||||
*esOffset2 = demux_ty_FindESHeader(nal, buffer, bufferSize);
|
||||
if (*esOffset2 != -1)
|
||||
*esOffset2 += *esOffset1 + 1;
|
||||
}
|
||||
|
||||
#define VIDEO_NAL 0xe0
|
||||
#define AUDIO_NAL 0xc0
|
||||
#define AC3_NAL 0xbd
|
||||
|
||||
static int demux_ty_fill_buffer( demuxer_t *demux, demux_stream_t *dsds )
|
||||
{
|
||||
int invalidType = 0;
|
||||
int errorHeader = 0;
|
||||
int recordsDecoded = 0;
|
||||
|
||||
int readSize;
|
||||
|
||||
int numberRecs;
|
||||
unsigned char *recPtr;
|
||||
int offset;
|
||||
|
||||
int counter;
|
||||
|
||||
int aid;
|
||||
|
||||
TiVoInfo *tivo = demux->priv;
|
||||
unsigned char *chunk = tivo->chunk;
|
||||
|
||||
if ( demux->stream->type == STREAMTYPE_DVD )
|
||||
return 0;
|
||||
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "ty:ty processing\n" );
|
||||
|
||||
if( demux->stream->eof ) return 0;
|
||||
|
||||
// ======================================================================
|
||||
// If we haven't figured out the size of the stream, let's do so
|
||||
// ======================================================================
|
||||
if ( demux->stream->type == STREAMTYPE_VSTREAM )
|
||||
{
|
||||
// The vstream code figures out the exact size of the stream
|
||||
demux->movi_start = 0;
|
||||
demux->movi_end = demux->stream->end_pos;
|
||||
tivo->size = demux->stream->end_pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If its a local file, try to find the Part Headers, so we can
|
||||
// calculate the ACTUAL stream size
|
||||
// If we can't find it, go off with the file size and hope the
|
||||
// extract program did the "right thing"
|
||||
if ( tivo->readHeader == 0 )
|
||||
{
|
||||
off_t filePos;
|
||||
tivo->readHeader = 1;
|
||||
|
||||
filePos = demux->filepos;
|
||||
stream_seek( demux->stream, 0 );
|
||||
|
||||
readSize = stream_read( demux->stream, chunk, CHUNKSIZE );
|
||||
|
||||
if ( memcmp( chunk, TMF_SIG, sizeof( TMF_SIG ) ) == 0 )
|
||||
{
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "ty:Detected a tmf\n" );
|
||||
tivo->tmf = 1;
|
||||
ty_tmf_filetoparts( demux, tivo );
|
||||
readSize = tmf_load_chunk( demux, tivo, chunk, 0 );
|
||||
}
|
||||
|
||||
if ( readSize == CHUNKSIZE && AV_RB32(chunk) == TIVO_PES_FILEID )
|
||||
{
|
||||
off_t numberParts;
|
||||
|
||||
readSize = 0;
|
||||
|
||||
if ( tivo->tmf != 1 )
|
||||
{
|
||||
off_t offset;
|
||||
|
||||
numberParts = demux->stream->end_pos / TIVO_PART_LENGTH;
|
||||
offset = numberParts * TIVO_PART_LENGTH;
|
||||
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "ty:ty/ty+Number Parts %"PRId64"\n",
|
||||
(int64_t)numberParts );
|
||||
|
||||
if ( offset + CHUNKSIZE < demux->stream->end_pos )
|
||||
{
|
||||
stream_seek( demux->stream, offset );
|
||||
readSize = stream_read( demux->stream, chunk, CHUNKSIZE );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
numberParts = tivo->tmf_totalparts;
|
||||
offset = numberParts * TIVO_PART_LENGTH;
|
||||
readSize = tmf_load_chunk( demux, tivo, chunk,
|
||||
numberParts * ( TIVO_PART_LENGTH - CHUNKSIZE ) /
|
||||
CHUNKSIZE );
|
||||
}
|
||||
|
||||
if ( readSize == CHUNKSIZE && AV_RB32(chunk) == TIVO_PES_FILEID )
|
||||
{
|
||||
int size = AV_RB24(chunk + 12);
|
||||
size -= 4;
|
||||
size *= CHUNKSIZE;
|
||||
tivo->size = numberParts * TIVO_PART_LENGTH;
|
||||
tivo->size += size;
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3,
|
||||
"ty:Header Calc Stream Size %"PRId64"\n", tivo->size );
|
||||
}
|
||||
}
|
||||
|
||||
if ( demux->stream->start_pos > 0 )
|
||||
filePos = demux->stream->start_pos;
|
||||
stream_seek( demux->stream, filePos );
|
||||
demux->filepos = stream_tell( demux->stream );
|
||||
tivo->whichChunk = filePos / CHUNKSIZE;
|
||||
}
|
||||
demux->movi_start = 0;
|
||||
demux->movi_end = tivo->size;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// Give a clue as to where we are in the stream
|
||||
// ======================================================================
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3,
|
||||
"ty:ty header size %"PRIx64"\n", (int64_t)tivo->size );
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3,
|
||||
"ty:ty which Chunk %d\n", tivo->whichChunk );
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3,
|
||||
"ty:file end_pos %"PRIx64"\n", (int64_t)demux->stream->end_pos );
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3,
|
||||
"\nty:wanted current offset %"PRIx64"\n", (int64_t)stream_tell( demux->stream ) );
|
||||
|
||||
if ( tivo->size > 0 && stream_tell( demux->stream ) > tivo->size )
|
||||
{
|
||||
demux->stream->eof = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
if ( tivo->tmf != 1 )
|
||||
{
|
||||
// Make sure we are on a 128k boundary
|
||||
if ( demux->filepos % CHUNKSIZE != 0 )
|
||||
{
|
||||
int whichChunk = demux->filepos / CHUNKSIZE;
|
||||
if ( demux->filepos % CHUNKSIZE > CHUNKSIZE / 2 )
|
||||
whichChunk++;
|
||||
stream_seek( demux->stream, whichChunk * CHUNKSIZE );
|
||||
}
|
||||
|
||||
demux->filepos = stream_tell( demux->stream );
|
||||
tivo->whichChunk = demux->filepos / CHUNKSIZE;
|
||||
readSize = stream_read( demux->stream, chunk, CHUNKSIZE );
|
||||
if ( readSize != CHUNKSIZE )
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
readSize = tmf_load_chunk( demux, tivo, chunk, tivo->whichChunk );
|
||||
if ( readSize != CHUNKSIZE )
|
||||
return 0;
|
||||
tivo->whichChunk++;
|
||||
}
|
||||
if (AV_RB32(chunk) == TIVO_PES_FILEID)
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "ty:Skipping PART Header\n" );
|
||||
} while (AV_RB32(chunk) == TIVO_PES_FILEID);
|
||||
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3,
|
||||
"\nty:actual current offset %"PRIx64"\n", stream_tell( demux->stream ) -
|
||||
CHUNKSIZE );
|
||||
|
||||
|
||||
// Let's make a Video Demux Stream for MPlayer
|
||||
aid = 0x0;
|
||||
if( !demux->v_streams[ aid ] ) new_sh_video( demux, aid );
|
||||
if( demux->video->id == -1 ) demux->video->id = aid;
|
||||
if( demux->video->id == aid )
|
||||
{
|
||||
demux_stream_t *ds = demux->video;
|
||||
if( !ds->sh ) ds->sh = demux->v_streams[ aid ];
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// Finally, we get to actually parse the chunk
|
||||
// ======================================================================
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "ty:ty parsing a chunk\n" );
|
||||
numberRecs = chunk[ 0 ];
|
||||
recPtr = &chunk[ 4 ];
|
||||
offset = numberRecs * 16 + 4;
|
||||
for ( counter = 0 ; counter < numberRecs ; counter++ )
|
||||
{
|
||||
int size = AV_RB24(recPtr) >> 4;
|
||||
int type = recPtr[ 3 ];
|
||||
int nybbleType = recPtr[ 2 ] & 0x0f;
|
||||
recordsDecoded++;
|
||||
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3,
|
||||
"ty:Record Type %x/%x %d\n", nybbleType, type, size );
|
||||
|
||||
// ================================================================
|
||||
// Video Parsing
|
||||
// ================================================================
|
||||
if ( type == 0xe0 )
|
||||
{
|
||||
if ( size > 0 && size + offset <= CHUNKSIZE )
|
||||
{
|
||||
int esOffset1 = demux_ty_FindESHeader( VIDEO_NAL, &chunk[ offset ],
|
||||
size);
|
||||
if ( esOffset1 != -1 )
|
||||
tivo->lastVideoPTS = get_ty_pts(
|
||||
&chunk[ offset + esOffset1 + 9 ] );
|
||||
|
||||
// Do NOT Pass the PES Header onto the MPEG2 Decode
|
||||
if( nybbleType != 0x06 )
|
||||
demux_ty_CopyToDemuxPacket( demux->video,
|
||||
&chunk[ offset ], size, demux->filepos + offset,
|
||||
tivo->lastVideoPTS );
|
||||
offset += size;
|
||||
}
|
||||
else
|
||||
errorHeader++;
|
||||
}
|
||||
// ================================================================
|
||||
// Audio Parsing
|
||||
// ================================================================
|
||||
else if ( type == 0xc0 )
|
||||
{
|
||||
if ( size > 0 && size + offset <= CHUNKSIZE )
|
||||
{
|
||||
if( demux->audio->id == -1 )
|
||||
{
|
||||
if ( nybbleType == 0x02 )
|
||||
continue; // DTiVo inconclusive, wait for more
|
||||
else if ( nybbleType == 0x09 )
|
||||
{
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "ty:Setting AC-3 Audio\n" );
|
||||
aid = 0x80; // AC-3
|
||||
}
|
||||
else
|
||||
{
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "ty:Setting MPEG Audio\n" );
|
||||
aid = 0x0; // MPEG Audio
|
||||
}
|
||||
|
||||
demux->audio->id = aid;
|
||||
if( !demux->a_streams[ aid ] ) new_sh_audio( demux, aid );
|
||||
if( demux->audio->id == aid )
|
||||
{
|
||||
demux_stream_t *ds = demux->audio;
|
||||
if( !ds->sh ) {
|
||||
sh_audio_t* sh_a;
|
||||
ds->sh = demux->a_streams[ aid ];
|
||||
sh_a = (sh_audio_t*)ds->sh;
|
||||
switch(aid & 0xE0){ // 1110 0000 b (high 3 bit: type low 5: id)
|
||||
case 0x00: sh_a->format=0x50;break; // mpeg
|
||||
case 0xA0: sh_a->format=0x10001;break; // dvd pcm
|
||||
case 0x80: if((aid & 0xF8) == 0x88) sh_a->format=0x2001;//dts
|
||||
else sh_a->format=0x2000;break; // ac3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aid = demux->audio->id;
|
||||
|
||||
|
||||
// SA DTiVo Audio Data, no PES
|
||||
// ================================================
|
||||
if ( nybbleType == 0x02 || nybbleType == 0x04 )
|
||||
{
|
||||
if ( nybbleType == 0x02 && tivo->tivoType == 2 )
|
||||
demux_ty_AddToAudioBuffer( tivo, &chunk[ offset ], size );
|
||||
else
|
||||
{
|
||||
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3,
|
||||
"ty:Adding Audio Packet Size %d\n", size );
|
||||
demux_ty_CopyToDemuxPacket( demux->audio,
|
||||
&chunk[ offset ], size, ( demux->filepos + offset ),
|
||||
tivo->lastAudioPTS );
|
||||
}
|
||||
}
|
||||
|
||||
// 3 - MPEG Audio with PES Header, either SA or DTiVo
|
||||
// 9 - DTiVo AC3 Audio Data with PES Header
|
||||
// ================================================
|
||||
if ( nybbleType == 0x03 || nybbleType == 0x09 )
|
||||
{
|
||||
int esOffset1, esOffset2;
|
||||
if ( nybbleType == 0x03 )
|
||||
esOffset1 = demux_ty_FindESHeader( AUDIO_NAL, &chunk[ offset ],
|
||||
size);
|
||||
|
||||
// SA PES Header, No Audio Data
|
||||
// ================================================
|
||||
if ( nybbleType == 0x03 && esOffset1 == 0 && size == 16 )
|
||||
{
|
||||
tivo->tivoType = 1;
|
||||
tivo->lastAudioPTS = get_ty_pts( &chunk[ offset +
|
||||
SERIES2_PTS_OFFSET ] );
|
||||
}
|
||||
else
|
||||
// DTiVo Audio with PES Header
|
||||
// ================================================
|
||||
{
|
||||
tivo->tivoType = 2;
|
||||
|
||||
demux_ty_AddToAudioBuffer( tivo, &chunk[ offset ], size );
|
||||
demux_ty_FindESPacket( nybbleType == 9 ? AC3_NAL : AUDIO_NAL,
|
||||
tivo->lastAudio, tivo->lastAudioEnd, &esOffset1,
|
||||
&esOffset2 );
|
||||
|
||||
if ( esOffset1 != -1 && esOffset2 != -1 )
|
||||
{
|
||||
int packetSize = esOffset2 - esOffset1;
|
||||
int headerSize;
|
||||
int ptsOffset;
|
||||
|
||||
if ( IsValidAudioPacket( packetSize, &ptsOffset,
|
||||
&headerSize ) )
|
||||
{
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3,
|
||||
"ty:Adding DTiVo Audio Packet Size %d\n",
|
||||
packetSize );
|
||||
|
||||
tivo->lastAudioPTS = get_ty_pts(
|
||||
&tivo->lastAudio[ esOffset1 + ptsOffset ] );
|
||||
|
||||
if (nybbleType == 9) headerSize = 0;
|
||||
demux_ty_CopyToDemuxPacket
|
||||
(
|
||||
demux->audio,
|
||||
&tivo->lastAudio[ esOffset1 + headerSize ],
|
||||
packetSize - headerSize,
|
||||
demux->filepos + offset,
|
||||
tivo->lastAudioPTS
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// Collapse the Audio Buffer
|
||||
tivo->lastAudioEnd -= esOffset2;
|
||||
memmove( &tivo->lastAudio[ 0 ],
|
||||
&tivo->lastAudio[ esOffset2 ],
|
||||
tivo->lastAudioEnd );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
offset += size;
|
||||
}
|
||||
else
|
||||
errorHeader++;
|
||||
}
|
||||
// ================================================================
|
||||
// 1 = Closed Caption
|
||||
// 2 = Extended Data Services
|
||||
// ================================================================
|
||||
else if ( type == 0x01 || type == 0x02 )
|
||||
{
|
||||
unsigned char lastXDS[ 16 ];
|
||||
int b = AV_RB24(recPtr) >> 4;
|
||||
b &= 0x7f7f;
|
||||
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "ty:%s %04x\n", type == 1 ? "CC" : "XDS", b);
|
||||
|
||||
lastXDS[ 0x00 ] = 0x00;
|
||||
lastXDS[ 0x01 ] = 0x00;
|
||||
lastXDS[ 0x02 ] = 0x01;
|
||||
lastXDS[ 0x03 ] = 0xb2;
|
||||
lastXDS[ 0x04 ] = 'T';
|
||||
lastXDS[ 0x05 ] = 'Y';
|
||||
lastXDS[ 0x06 ] = type;
|
||||
lastXDS[ 0x07 ] = b >> 8;
|
||||
lastXDS[ 0x08 ] = b;
|
||||
if ( subcc_enabled )
|
||||
demux_ty_CopyToDemuxPacket( demux->video, lastXDS, 0x09,
|
||||
demux->filepos + offset, tivo->lastVideoPTS );
|
||||
}
|
||||
// ================================================================
|
||||
// Unknown
|
||||
// ================================================================
|
||||
else
|
||||
{
|
||||
if ( size > 0 && size + offset <= CHUNKSIZE )
|
||||
offset += size;
|
||||
if (type != 3 && type != 5 && (type != 0 || size > 0)) {
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "ty:Invalid Type %x\n", type );
|
||||
invalidType++;
|
||||
}
|
||||
}
|
||||
recPtr += 16;
|
||||
}
|
||||
|
||||
if ( errorHeader > 0 || invalidType > 0 )
|
||||
{
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3,
|
||||
"ty:Error Check - Records %d, Parsed %d, Errors %d + %d\n",
|
||||
numberRecs, recordsDecoded, errorHeader, invalidType );
|
||||
|
||||
// Invalid MPEG ES Size Check
|
||||
if ( errorHeader > numberRecs / 2 )
|
||||
return 0;
|
||||
|
||||
// Invalid MPEG Stream Type Check
|
||||
if ( invalidType > numberRecs / 2 )
|
||||
return 0;
|
||||
}
|
||||
|
||||
demux->filepos = stream_tell( demux->stream );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void demux_seek_ty( demuxer_t *demuxer, float rel_seek_secs, float audio_delay, int flags )
|
||||
{
|
||||
demux_stream_t *d_audio = demuxer->audio;
|
||||
demux_stream_t *d_video = demuxer->video;
|
||||
sh_audio_t *sh_audio = d_audio->sh;
|
||||
sh_video_t *sh_video = d_video->sh;
|
||||
off_t newpos;
|
||||
off_t res;
|
||||
TiVoInfo *tivo = demuxer->priv;
|
||||
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "ty:Seeking to %7.1f\n", rel_seek_secs );
|
||||
|
||||
tivo->lastAudioEnd = 0;
|
||||
tivo->lastAudioPTS = MP_NOPTS_VALUE;
|
||||
tivo->lastVideoPTS = MP_NOPTS_VALUE;
|
||||
//
|
||||
//================= seek in MPEG ==========================
|
||||
demuxer->filepos = stream_tell( demuxer->stream );
|
||||
|
||||
newpos = ( flags & SEEK_ABSOLUTE ) ? demuxer->movi_start : demuxer->filepos;
|
||||
|
||||
if( flags & SEEK_FACTOR )
|
||||
// float seek 0..1
|
||||
newpos += ( demuxer->movi_end - demuxer->movi_start ) * rel_seek_secs;
|
||||
else
|
||||
{
|
||||
// time seek (secs)
|
||||
if( ! sh_video->i_bps ) // unspecified or VBR
|
||||
newpos += 2324 * 75 * rel_seek_secs; // 174.3 kbyte/sec
|
||||
else
|
||||
newpos += sh_video->i_bps * rel_seek_secs;
|
||||
}
|
||||
|
||||
if ( newpos < demuxer->movi_start )
|
||||
{
|
||||
if( demuxer->stream->type != STREAMTYPE_VCD ) demuxer->movi_start = 0;
|
||||
if( newpos < demuxer->movi_start ) newpos = demuxer->movi_start;
|
||||
}
|
||||
|
||||
res = newpos / CHUNKSIZE;
|
||||
if ( rel_seek_secs >= 0 )
|
||||
newpos = ( res + 1 ) * CHUNKSIZE;
|
||||
else
|
||||
newpos = res * CHUNKSIZE;
|
||||
|
||||
if ( newpos < 0 )
|
||||
newpos = 0;
|
||||
|
||||
tivo->whichChunk = newpos / CHUNKSIZE;
|
||||
|
||||
stream_seek( demuxer->stream, newpos );
|
||||
|
||||
// re-sync video:
|
||||
videobuf_code_len = 0; // reset ES stream buffer
|
||||
|
||||
ds_fill_buffer( d_video );
|
||||
if( sh_audio )
|
||||
ds_fill_buffer( d_audio );
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
int i;
|
||||
if( sh_audio && !d_audio->eof && d_video->pts && d_audio->pts )
|
||||
{
|
||||
float a_pts = d_audio->pts;
|
||||
a_pts += ( ds_tell_pts( d_audio ) - sh_audio->a_in_buffer_len ) /
|
||||
(float)sh_audio->i_bps;
|
||||
if( d_video->pts > a_pts )
|
||||
{
|
||||
skip_audio_frame( sh_audio ); // sync audio
|
||||
continue;
|
||||
}
|
||||
}
|
||||
i = sync_video_packet( d_video );
|
||||
if( i == 0x1B3 || i == 0x1B8 ) break; // found it!
|
||||
if( !i || !skip_video_packet( d_video ) ) break; // EOF?
|
||||
}
|
||||
#ifdef DEMUX_TY_OSD
|
||||
if ( subcc_enabled )
|
||||
ty_ClearOSD( 0 );
|
||||
#endif
|
||||
}
|
||||
|
||||
static int demux_ty_control( demuxer_t *demuxer,int cmd, void *arg )
|
||||
{
|
||||
demux_stream_t *d_video = demuxer->video;
|
||||
sh_video_t *sh_video = d_video->sh;
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
case DEMUXER_CTRL_GET_TIME_LENGTH:
|
||||
if(!sh_video->i_bps) // unspecified or VBR
|
||||
return DEMUXER_CTRL_DONTKNOW;
|
||||
*(double *)arg=
|
||||
(double)demuxer->movi_end-demuxer->movi_start/sh_video->i_bps;
|
||||
return DEMUXER_CTRL_GUESS;
|
||||
|
||||
case DEMUXER_CTRL_GET_PERCENT_POS:
|
||||
return DEMUXER_CTRL_DONTKNOW;
|
||||
default:
|
||||
return DEMUXER_CTRL_NOTIMPL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void demux_close_ty( demuxer_t *demux )
|
||||
{
|
||||
TiVoInfo *tivo = demux->priv;
|
||||
|
||||
free( tivo );
|
||||
sub_justify = 0;
|
||||
}
|
||||
|
||||
|
||||
static int ty_check_file(demuxer_t* demuxer)
|
||||
{
|
||||
demuxer->filepos = 0;
|
||||
TiVoInfo *tivo = calloc(1, sizeof(TiVoInfo));
|
||||
demuxer->priv = tivo;
|
||||
return ds_fill_buffer(demuxer->video) ? DEMUXER_TYPE_MPEG_TY : 0;
|
||||
}
|
||||
|
||||
|
||||
static demuxer_t* demux_open_ty(demuxer_t* demuxer)
|
||||
{
|
||||
sh_audio_t *sh_audio=NULL;
|
||||
sh_video_t *sh_video=NULL;
|
||||
|
||||
sh_video=demuxer->video->sh;sh_video->ds=demuxer->video;
|
||||
|
||||
if(demuxer->audio->id!=-2) {
|
||||
if(!ds_fill_buffer(demuxer->audio)){
|
||||
mp_msg(MSGT_DEMUXER, MSGL_INFO, "MPEG: %s",
|
||||
mp_gtext("No audio stream found -> no sound.\n"));
|
||||
demuxer->audio->sh=NULL;
|
||||
} else {
|
||||
sh_audio=demuxer->audio->sh;sh_audio->ds=demuxer->audio;
|
||||
}
|
||||
}
|
||||
|
||||
return demuxer;
|
||||
}
|
||||
|
||||
|
||||
const demuxer_desc_t demuxer_desc_mpeg_ty = {
|
||||
"TiVo demuxer",
|
||||
"tivo",
|
||||
"TiVo",
|
||||
"Christopher R. Wingert",
|
||||
"Demux streams from TiVo",
|
||||
DEMUXER_TYPE_MPEG_TY,
|
||||
0, // unsafe autodetect
|
||||
ty_check_file,
|
||||
demux_ty_fill_buffer,
|
||||
demux_open_ty,
|
||||
demux_close_ty,
|
||||
demux_seek_ty,
|
||||
demux_ty_control
|
||||
};
|
@ -1,911 +0,0 @@
|
||||
// Most of this was written by Mike Baker <mbm@linux.com>
|
||||
// and released under the GPL v2+ license.
|
||||
//
|
||||
// Modifications and SEVERE cleanup of the code was done by
|
||||
// Christopher Wingert
|
||||
// Copyright 2003
|
||||
//
|
||||
// Released under GPL2 License.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "mp_msg.h"
|
||||
|
||||
//#include "stream/stream.h"
|
||||
//#include "demuxer.h"
|
||||
//#include "parse_es.h"
|
||||
//#include "stheader.h"
|
||||
//#include "mp3_hdr.h"
|
||||
//#include "subreader.h"
|
||||
#include "sub/sub_cc.h"
|
||||
#include "sub/sub.h"
|
||||
#include "demux_ty_osd.h"
|
||||
|
||||
//#include "dvdauth.h"
|
||||
|
||||
extern int sub_justify;
|
||||
|
||||
#define TY_TEXT_MODE ( 1 << 0 )
|
||||
#define TY_OSD_MODE ( 1 << 1 )
|
||||
|
||||
static int TY_OSD_flags = TY_TEXT_MODE | TY_OSD_MODE;
|
||||
static int TY_OSD_debug = 0;
|
||||
|
||||
// ===========================================================================
|
||||
// Closed Caption Decoding and OSD Presentation
|
||||
// ===========================================================================
|
||||
#define TY_CCNONE ( -3 )
|
||||
#define TY_CCTEXTMODE ( -2 )
|
||||
#define TY_CCPOPUPNB ( -1 )
|
||||
#define TY_CCPOPUP ( 0 )
|
||||
#define TY_CCPAINTON ( 1 )
|
||||
|
||||
#define TY_CC_MAX_X ( 45 )
|
||||
|
||||
static int TY_CC_CUR_X;
|
||||
static int TY_CC_CUR_Y;
|
||||
static int TY_CC_stat = TY_CCNONE;
|
||||
static char TY_CC_buf[ 255 ];
|
||||
static char *TY_CC_ptr = TY_CC_buf;
|
||||
static unsigned TY_CC_lastcap = 0;
|
||||
static int TY_CC_TextItalic;
|
||||
static int TY_CC_Y_Offset;
|
||||
|
||||
static subtitle ty_OSD1;
|
||||
static subtitle ty_OSD2;
|
||||
static subtitle *ty_pOSD1;
|
||||
static subtitle *ty_pOSD2;
|
||||
static int tyOSDInitialized = 0;
|
||||
static int tyOSDUpdate = 0;
|
||||
|
||||
static void ty_DrawOSD(void)
|
||||
{
|
||||
// printf( "Calling ty_DrawOSD()\n" );
|
||||
tyOSDUpdate = 1;
|
||||
}
|
||||
|
||||
void ty_ClearOSD( int start )
|
||||
{
|
||||
int index;
|
||||
// printf( "Calling ty_ClearOSD()\n" );
|
||||
for ( index = start ; index < SUB_MAX_TEXT ; index++ )
|
||||
{
|
||||
memset( ty_OSD1.text[ index ], ' ', TY_CC_MAX_X - 1 );
|
||||
ty_OSD1.text[ index ][ TY_CC_MAX_X - 1 ] = 0;
|
||||
memset( ty_OSD2.text[ index ], ' ', TY_CC_MAX_X - 1 );
|
||||
ty_OSD2.text[ index ][ TY_CC_MAX_X - 1 ] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ty_DrawChar( int *x, int *y, char disChar, int fgColor, int bgColor )
|
||||
{
|
||||
int cx;
|
||||
int cy;
|
||||
|
||||
cx = *x;
|
||||
cy = *y;
|
||||
|
||||
if ( *x >= ( TY_CC_MAX_X - 1 ) )
|
||||
{
|
||||
cx = 0;
|
||||
}
|
||||
if ( ( *y + TY_CC_Y_Offset ) > SUB_MAX_TEXT )
|
||||
{
|
||||
cy = SUB_MAX_TEXT - TY_CC_Y_Offset - 1;
|
||||
}
|
||||
|
||||
// printf( "Calling ty_DrawChar() x:%d y:%d %c fg:%d bg:%d\n",
|
||||
// cx, cy, disChar, fgColor, bgColor );
|
||||
|
||||
ty_OSD1.text[ TY_CC_Y_Offset + cy ][ cx ] = disChar;
|
||||
memset( &( ty_OSD1.text[ TY_CC_Y_Offset + cy ][ cx + 1 ] ), ' ',
|
||||
TY_CC_MAX_X - cx - 2 );
|
||||
( *x )++;
|
||||
}
|
||||
|
||||
static void ty_RollupBuf( int dest, int source, int numLines )
|
||||
{
|
||||
int index;
|
||||
|
||||
// printf( "Calling ty_RollupBuf() dest:%d source %d, numLines %d\n",
|
||||
// dest, source, numLines );
|
||||
//
|
||||
if ( ( source + TY_CC_Y_Offset + numLines ) > SUB_MAX_TEXT )
|
||||
{
|
||||
ty_ClearOSD( 1 );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ( source + TY_CC_Y_Offset + numLines ) < 0 )
|
||||
{
|
||||
ty_ClearOSD( 1 );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( numLines > SUB_MAX_TEXT )
|
||||
{
|
||||
ty_ClearOSD( 1 );
|
||||
return;
|
||||
}
|
||||
|
||||
for ( index = 0 ; index < numLines ; index++ )
|
||||
{
|
||||
strcpy( ty_OSD1.text[ TY_CC_Y_Offset + dest ],
|
||||
ty_OSD1.text[ TY_CC_Y_Offset + source ] );
|
||||
dest++;
|
||||
source++;
|
||||
}
|
||||
memset( ty_OSD1.text[ TY_CC_Y_Offset + source - 1 ], ' ', TY_CC_MAX_X - 1 );
|
||||
ty_OSD1.text[ TY_CC_Y_Offset + source - 1 ][ TY_CC_MAX_X - 1 ] = 0;
|
||||
}
|
||||
|
||||
static void ty_drawchar( char c )
|
||||
{
|
||||
if ( c < 2 ) return;
|
||||
|
||||
if ( TY_OSD_flags & TY_OSD_MODE && TY_CC_stat != TY_CCNONE &&
|
||||
TY_CC_CUR_Y != -1 )
|
||||
ty_DrawChar( &TY_CC_CUR_X, &TY_CC_CUR_Y, c, 4, 13 );
|
||||
|
||||
if ( TY_CC_ptr - TY_CC_buf > sizeof( TY_CC_buf ) - 1 )
|
||||
{ // buffer overflow
|
||||
TY_CC_ptr = TY_CC_buf;
|
||||
memset( TY_CC_buf, 0, sizeof( TY_CC_buf ) );
|
||||
}
|
||||
*( TY_CC_ptr++ ) = ( c == 14 ) ? '/' : c; // swap a '/' for musical note
|
||||
}
|
||||
|
||||
static void ty_draw(void)
|
||||
{
|
||||
if ( TY_CC_ptr != TY_CC_buf && TY_OSD_flags & TY_TEXT_MODE )
|
||||
{
|
||||
if ( *( TY_CC_ptr - 1 ) == '\n' ) *( TY_CC_ptr - 1 ) = 0;
|
||||
|
||||
mp_msg( MSGT_DEMUX, MSGL_V, "CC: %s\n", TY_CC_buf );
|
||||
}
|
||||
TY_CC_lastcap = time( NULL );
|
||||
|
||||
TY_CC_ptr = TY_CC_buf;
|
||||
memset( TY_CC_buf, 0, sizeof( TY_CC_buf) );
|
||||
|
||||
if ( TY_OSD_flags & TY_OSD_MODE ) ty_DrawOSD();
|
||||
if ( TY_CC_TextItalic ) TY_CC_TextItalic = 0;
|
||||
}
|
||||
|
||||
|
||||
static int CC_last = 0;
|
||||
static char CC_mode = 0;
|
||||
static int CC_row[] =
|
||||
{
|
||||
11, -1, 1, 2, 3, 4, 12, 13, 14, 15, 5, 6, 7, 8, 9, 10
|
||||
};
|
||||
|
||||
// char specialchar[] = { '®', '°', '½', '¿', '*', '¢', '£', 14, 'à', ' ', 'è', 'â', 'ê', 'î', 'ô', 'û' };
|
||||
|
||||
static int ty_CCdecode( char b1, char b2 )
|
||||
{
|
||||
int x;
|
||||
int data = ( b2 << 8 ) + b1;
|
||||
|
||||
if ( b1 & 0x60 ) // text
|
||||
{
|
||||
if ( !TY_OSD_debug && TY_CC_stat == TY_CCNONE ) return 0;
|
||||
if ( TY_OSD_debug > 3 )
|
||||
{
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "%c %c", b1, b2 );
|
||||
}
|
||||
ty_drawchar( b1 );
|
||||
ty_drawchar( b2 );
|
||||
|
||||
if ( TY_CC_stat > 0 && TY_OSD_flags & TY_OSD_MODE ) ty_DrawOSD();
|
||||
}
|
||||
else if ( ( b1 & 0x10 ) && ( b2 > 0x1F ) && ( data != CC_last ) )
|
||||
{
|
||||
#define CURRENT ( ( b1 & 0x08 ) >> 3 )
|
||||
|
||||
if ( CC_mode != CURRENT && TY_CC_stat != TY_CCNONE )
|
||||
{
|
||||
if ( TY_OSD_debug && TY_CC_ptr != TY_CC_buf ) ty_draw();
|
||||
TY_CC_stat = TY_CCNONE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( TY_CC_stat == TY_CCNONE || TY_CC_CUR_Y == -1 )
|
||||
{
|
||||
if ( TY_CC_ptr != TY_CC_buf )
|
||||
{
|
||||
if ( TY_OSD_debug )
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "(TY_OSD_debug) %s\n",
|
||||
TY_CC_buf );
|
||||
TY_CC_ptr = TY_CC_buf;
|
||||
memset(TY_CC_buf, 0, sizeof(TY_CC_buf));
|
||||
}
|
||||
|
||||
if ( CC_mode != CURRENT ) return 0;
|
||||
}
|
||||
|
||||
// preamble address code (row & indent)
|
||||
if ( b2 & 0x40 )
|
||||
{
|
||||
TY_CC_CUR_Y = CC_row[ ( ( b1 << 1 ) & 14 ) | ( ( b2 >> 5 ) & 1 ) ];
|
||||
|
||||
// Offset into MPlayer's Buffer
|
||||
if ( ( TY_CC_CUR_Y >= 1 ) && ( TY_CC_CUR_Y <= 4 ) )
|
||||
{
|
||||
TY_CC_Y_Offset = SUB_MAX_TEXT - 5 - 1;
|
||||
}
|
||||
if ( ( TY_CC_CUR_Y >= 5 ) && ( TY_CC_CUR_Y <= 10 ) )
|
||||
{
|
||||
TY_CC_Y_Offset = SUB_MAX_TEXT - 5 - 5;
|
||||
}
|
||||
if ( ( TY_CC_CUR_Y >= 12 ) && ( TY_CC_CUR_Y <= 15 ) )
|
||||
{
|
||||
TY_CC_Y_Offset = SUB_MAX_TEXT - 5 - 12;
|
||||
}
|
||||
|
||||
if ( TY_OSD_debug > 3 )
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "<< preamble %d >>\n", TY_CC_CUR_Y );
|
||||
|
||||
// we still have something in the text buffer
|
||||
if (TY_CC_ptr != TY_CC_buf)
|
||||
{
|
||||
*(TY_CC_ptr++) = '\n';
|
||||
if ( TY_CC_TextItalic )
|
||||
{
|
||||
TY_CC_TextItalic = 0;
|
||||
}
|
||||
}
|
||||
|
||||
TY_CC_CUR_X = 1;
|
||||
// row contains indent flag
|
||||
if ( b2 & 0x10 )
|
||||
{
|
||||
for ( x = 0 ; x < ( ( b2 & 0x0F ) << 1 ) ; x++ )
|
||||
{
|
||||
TY_CC_CUR_X++;
|
||||
*(TY_CC_ptr++) = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
// !(b2 & 0x40)
|
||||
{
|
||||
if ( TY_OSD_debug > 3 )
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "<< %02x >>\n", b1 & 0x7 );
|
||||
switch (b1 & 0x07)
|
||||
{
|
||||
case 0x00: // attribute
|
||||
{
|
||||
if ( TY_OSD_debug > 1 )
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "<<A: %d>>\n", b2 );
|
||||
break;
|
||||
}
|
||||
case 0x01: // midrow or char
|
||||
{
|
||||
switch (b2 & 0x70)
|
||||
{
|
||||
case 0x20: // midrow attribute change
|
||||
{
|
||||
switch (b2 & 0x0e)
|
||||
{
|
||||
case 0x00: // italics off
|
||||
{
|
||||
TY_CC_TextItalic = 0;
|
||||
*(TY_CC_ptr++) = ' ';
|
||||
break;
|
||||
}
|
||||
case 0x0e: // italics on
|
||||
{
|
||||
ty_drawchar(' ');
|
||||
TY_CC_TextItalic = 1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if ( TY_OSD_debug > 1 )
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "<<D: %d>>\n",
|
||||
b2 & 0x0e );
|
||||
}
|
||||
}
|
||||
if ( b2 & 0x01 )
|
||||
{
|
||||
// TextUnderline = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TextUnderline = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x30: // special character..
|
||||
{
|
||||
// transparent space
|
||||
if ( ( b2 & 0x0f ) == 9 )
|
||||
{
|
||||
TY_CC_CUR_X++;
|
||||
*(TY_CC_ptr++) = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
// ty_drawchar(specialchar[ b2 & 0x0f ] );
|
||||
ty_drawchar( ' ' );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x04: // misc
|
||||
case 0x05: // misc + F
|
||||
{
|
||||
if ( TY_OSD_debug > 3 )
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "<< misc %02x >>\n", b2 );
|
||||
switch ( b2 )
|
||||
{
|
||||
case 0x20: // resume caption (new caption)
|
||||
{
|
||||
if ( TY_OSD_flags & TY_OSD_MODE &&
|
||||
TY_CC_stat != TY_CCPOPUP )
|
||||
ty_ClearOSD( 1 );
|
||||
TY_CC_stat = TY_CCPOPUP;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x21: // backspace
|
||||
{
|
||||
TY_CC_CUR_X--;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x25: // 2-4 row captions
|
||||
case 0x26:
|
||||
case 0x27:
|
||||
{
|
||||
if ( TY_CC_stat == TY_CCPOPUP ) ty_ClearOSD( 1 );
|
||||
TY_CC_stat = b2 - 0x23;
|
||||
if ( TY_CC_CUR_Y < TY_CC_stat ) TY_CC_CUR_Y = TY_CC_stat;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x29: // resume direct caption
|
||||
{
|
||||
TY_CC_stat = TY_CCPAINTON;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x2A: // text restart
|
||||
{
|
||||
ty_draw();
|
||||
/* FALL */
|
||||
}
|
||||
|
||||
case 0x2B: // resume text display
|
||||
{
|
||||
TY_CC_stat = TY_CCTEXTMODE;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x2C: // erase displayed memory
|
||||
{
|
||||
TY_CC_lastcap = 0;
|
||||
if ( TY_OSD_flags & TY_OSD_MODE )
|
||||
{
|
||||
if ( TY_CC_stat > TY_CCPOPUP || TY_CC_ptr == TY_CC_buf )
|
||||
{
|
||||
ty_ClearOSD( 1 );
|
||||
ty_draw();
|
||||
}
|
||||
else
|
||||
{
|
||||
ty_ClearOSD( 1 );
|
||||
|
||||
// CRW -
|
||||
// new buffer
|
||||
// Used to be a buffer swap here, dunno why
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x2D: // carriage return
|
||||
{
|
||||
ty_draw();
|
||||
TY_CC_CUR_X = 1;
|
||||
if ( TY_OSD_flags & TY_OSD_MODE )
|
||||
{
|
||||
if ( TY_CC_stat > TY_CCPAINTON )
|
||||
ty_RollupBuf
|
||||
(
|
||||
TY_CC_CUR_Y - TY_CC_stat + 1 ,
|
||||
TY_CC_CUR_Y - TY_CC_stat + 2,
|
||||
TY_CC_stat - 1
|
||||
);
|
||||
else
|
||||
TY_CC_CUR_Y++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x2F: // end caption + swap memory
|
||||
{
|
||||
ty_draw();
|
||||
/* FALL THROUGH TO 0x2E */
|
||||
}
|
||||
|
||||
case 0x2E: // erase non-displayed memory
|
||||
{
|
||||
if ( TY_OSD_debug && TY_CC_ptr != TY_CC_buf )
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "(TY_OSD_debug) %s\n",
|
||||
TY_CC_buf );
|
||||
if ( TY_OSD_flags & TY_OSD_MODE ) ty_ClearOSD( 1 );
|
||||
|
||||
TY_CC_CUR_X = 1;
|
||||
TY_CC_CUR_Y = -1;
|
||||
|
||||
TY_CC_ptr = TY_CC_buf;
|
||||
memset( TY_CC_buf, 0, sizeof( TY_CC_buf ) );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x07: // misc (TAB)
|
||||
{
|
||||
for ( x = 0 ; x < ( b2 - 0x20 ) ; x++ )
|
||||
TY_CC_CUR_X++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CC_last = data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Extended Data Service Decoding and OSD Presentation
|
||||
// ===========================================================================
|
||||
#define XDS_BUFFER_LENGTH ( 16 )
|
||||
#define XDS_DISPLAY_FRAMES ( 120 )
|
||||
static char *ty_XDS_Display[ XDS_BUFFER_LENGTH ];
|
||||
static int ty_XDSAddLine = -1;
|
||||
static int ty_XDSDisplayCount = -1;
|
||||
|
||||
|
||||
static void ty_AddXDSToDisplay( const char *format, ... )
|
||||
{
|
||||
char line[ 80 ];
|
||||
int index;
|
||||
va_list ap;
|
||||
|
||||
if ( ty_XDSAddLine == -1 )
|
||||
{
|
||||
for( index = 0 ; index < XDS_BUFFER_LENGTH ; index++ )
|
||||
{
|
||||
ty_XDS_Display[ index ] = 0;
|
||||
}
|
||||
ty_XDSAddLine = 0;
|
||||
}
|
||||
|
||||
va_start( ap, format );
|
||||
vsnprintf( line, 80, format, ap );
|
||||
va_end( ap );
|
||||
mp_msg( MSGT_DEMUX, MSGL_V, "XDS: %s\n", line );
|
||||
|
||||
if ( ty_XDSAddLine == XDS_BUFFER_LENGTH )
|
||||
{
|
||||
mp_msg( MSGT_DEMUX, MSGL_ERR, "XDS Buffer would have been blown\n" );
|
||||
}
|
||||
|
||||
if ( ty_XDS_Display[ ty_XDSAddLine ] != 0 )
|
||||
{
|
||||
free( ty_XDS_Display[ ty_XDSAddLine ] );
|
||||
ty_XDS_Display[ ty_XDSAddLine ] = 0;
|
||||
}
|
||||
|
||||
ty_XDS_Display[ ty_XDSAddLine ] = malloc( strlen( line ) + 1 );
|
||||
strcpy( ty_XDS_Display[ ty_XDSAddLine ], line );
|
||||
ty_XDSAddLine++;
|
||||
}
|
||||
|
||||
|
||||
static void ty_DisplayXDSInfo(void)
|
||||
{
|
||||
int index;
|
||||
int size;
|
||||
|
||||
if ( ty_XDSDisplayCount == -1 )
|
||||
{
|
||||
for( index = 0 ; index < XDS_BUFFER_LENGTH ; index++ )
|
||||
{
|
||||
if ( ty_XDS_Display[ index ] != 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( index != XDS_BUFFER_LENGTH )
|
||||
{
|
||||
size = strlen( ty_XDS_Display[ index ] );
|
||||
|
||||
// Right Justify the XDS Stuff
|
||||
memcpy( &( ty_OSD1.text[ 0 ][ TY_CC_MAX_X - size - 1 ] ),
|
||||
ty_XDS_Display[ index ], size );
|
||||
free( ty_XDS_Display[ index ] );
|
||||
ty_XDS_Display[ index ] = 0;
|
||||
ty_XDSDisplayCount = 0;
|
||||
tyOSDUpdate = 1;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// We cleaned out all the XDS stuff to be displayed
|
||||
ty_XDSAddLine = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We displayed that piece of XDS information long enough
|
||||
// Let's move on
|
||||
ty_XDSDisplayCount++;
|
||||
if ( ty_XDSDisplayCount >= XDS_DISPLAY_FRAMES )
|
||||
{
|
||||
memset( ty_OSD1.text[ 0 ], ' ', TY_CC_MAX_X - 1 );
|
||||
ty_OSD1.text[ 0 ][ TY_CC_MAX_X - 1 ] = 0;
|
||||
ty_XDSDisplayCount = -1;
|
||||
tyOSDUpdate = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int TY_XDS_mode = 0;
|
||||
static int TY_XDS_type = 0;
|
||||
static int TY_XDS_length = 0;
|
||||
static char TY_XDS_checksum = 0;
|
||||
|
||||
// Array of [ Mode ][ Type ][ Length ]
|
||||
static char TY_XDS [ 8 ][ 25 ][ 34 ];
|
||||
static char TY_XDS_new[ 8 ][ 25 ][ 34 ];
|
||||
|
||||
// Array of [ MPAARating|TVRating ][ NumberRatings ]
|
||||
static const char * const TY_XDS_CHIP[ 2 ][ 8 ] =
|
||||
{
|
||||
{ "(NOT APPLICABLE)", "G", "PG", "PG-13", "R", "NC-17", "X", "(NOT RATED)" },
|
||||
{ "(NOT RATED)", "TV-Y", "TV-Y7", "TV-G", "TV-PG", "TV-14", "TV-MA",
|
||||
"(NOT RATED)" }
|
||||
};
|
||||
|
||||
static const char * const TY_XDS_modes[] =
|
||||
{
|
||||
"CURRENT", // 01h-02h current program
|
||||
"FUTURE ", // 03h-04h future program
|
||||
"CHANNEL", // 05h-06h channel
|
||||
"MISC. ", // 07h-08h miscellaneous
|
||||
"PUBLIC ", // 09h-0Ah public service
|
||||
"RESERV.", // 0Bh-0Ch reserved
|
||||
"UNDEF. ",
|
||||
"INVALID",
|
||||
"INVALID",
|
||||
"INVALID"
|
||||
};
|
||||
|
||||
static int ty_XDSdecode( char b1, char b2 )
|
||||
{
|
||||
char line[ 80 ];
|
||||
|
||||
if ( b1 < 0x0F )
|
||||
{ // start packet
|
||||
TY_XDS_length = 0;
|
||||
TY_XDS_mode = b1 >> 1; // every other mode is a resume
|
||||
TY_XDS_type = b2;
|
||||
TY_XDS_checksum = b1 + b2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
TY_XDS_checksum += b1 + b2;
|
||||
|
||||
// eof (next byte is checksum)
|
||||
if ( b1 == 0x0F )
|
||||
{
|
||||
// validity check
|
||||
if ( !TY_XDS_length || TY_XDS_checksum & 0x7F )
|
||||
{
|
||||
if ( TY_OSD_debug > 3 && !TY_XDS_length )
|
||||
{
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3,
|
||||
"%% TY_XDS CHECKSUM ERROR (ignoring)\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
TY_XDS_mode = 0;
|
||||
TY_XDS_type = 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// check to see if the data has changed.
|
||||
if ( strncmp( TY_XDS[ TY_XDS_mode ][ TY_XDS_type ],
|
||||
TY_XDS_new[ TY_XDS_mode ][ TY_XDS_type ], TY_XDS_length - 1 ) )
|
||||
{
|
||||
char *TY_XDS_ptr = TY_XDS[ TY_XDS_mode ][ TY_XDS_type ];
|
||||
|
||||
TY_XDS_ptr[ TY_XDS_length ] = 0;
|
||||
memcpy( TY_XDS[ TY_XDS_mode ][ TY_XDS_type ],
|
||||
TY_XDS_new[ TY_XDS_mode ][ TY_XDS_type ], TY_XDS_length );
|
||||
|
||||
// nasty hack: only print time codes if seconds are 0
|
||||
if ( TY_XDS_mode == 3 && TY_XDS_type == 1 &&
|
||||
!( TY_XDS_new[ 3 ][ 1 ][ 3 ] & 0x20 ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if ( TY_XDS_mode == 0 && TY_XDS_type == 2 &&
|
||||
( TY_XDS_new[ 0 ][ 2 ][ 4 ] & 0x3f ) > 1 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "%% %s ", TY_XDS_modes[ TY_XDS_mode ] );
|
||||
|
||||
line[ 0 ] = 0;
|
||||
// printf( "XDS Code %x\n",
|
||||
// ( TY_XDS_mode << 9 ) + TY_XDS_type + 0x100 );
|
||||
switch ( ( TY_XDS_mode << 9 ) + TY_XDS_type + 0x100 )
|
||||
{
|
||||
// cases are specified in 2 bytes hex representing mode, type.
|
||||
// TY_XDS_ptr will point to the current class buffer
|
||||
case 0x0101: // current
|
||||
case 0x0301: // future
|
||||
{
|
||||
char *mon[] =
|
||||
{
|
||||
"0", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
|
||||
"Aug", "Sep", "Oct", "Nov", "Dec", "13", "14", "15"
|
||||
};
|
||||
ty_AddXDSToDisplay( "AIR DATE: %s %2d %d:%02d:00",
|
||||
mon[ TY_XDS_ptr[ 3 ] & 0x0f ],
|
||||
TY_XDS_ptr[ 2 ] & 0x1f,
|
||||
TY_XDS_ptr[ 1 ] & 0x1f,
|
||||
TY_XDS_ptr[ 0 ] & 0x3f
|
||||
);
|
||||
|
||||
// Program is tape delayed
|
||||
if ( TY_XDS_ptr[ 3 ] & 0x10 ) ty_AddXDSToDisplay( " TAPE" );
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0102: // current program length
|
||||
case 0x0302: // future
|
||||
{
|
||||
ty_AddXDSToDisplay(
|
||||
"DURATION: %d:%02d:%02d of %d:%02d:%02d",
|
||||
TY_XDS_ptr[ 3 ] & 0x3f,
|
||||
TY_XDS_ptr[ 2 ] & 0x3f,
|
||||
TY_XDS_ptr[ 4 ] & 0x3f,
|
||||
TY_XDS_ptr[ 1 ] & 0x3f,
|
||||
TY_XDS_ptr[ 0 ] & 0x3f, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0103: // current program name
|
||||
case 0x0303: // future
|
||||
{
|
||||
ty_AddXDSToDisplay( "TITLE: %s", TY_XDS_ptr );
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0104: // current program type
|
||||
case 0x0304: // future
|
||||
{
|
||||
// for now just print out the raw data
|
||||
// requires a 127 string array to parse
|
||||
// properly and isn't worth it.
|
||||
sprintf ( line, "%sGENRE:", line );
|
||||
{
|
||||
int x;
|
||||
for ( x = 0 ; x < TY_XDS_length ; x++ )
|
||||
sprintf( line, "%s %02x", line, TY_XDS_ptr[ x ] );
|
||||
}
|
||||
ty_AddXDSToDisplay( line );
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0105: // current program rating
|
||||
case 0x0305: // future
|
||||
{
|
||||
sprintf( line, "%sRATING: %s", line,
|
||||
TY_XDS_CHIP[ ( TY_XDS_ptr[ 0 ] & 0x08 ) >> 3 ]
|
||||
[ TY_XDS_ptr[ 1 ] & 0x07 ] );
|
||||
if ( TY_XDS_ptr[ 0 ] & 0x20 )
|
||||
sprintf( line, "%s DIALOGUE", line );
|
||||
if ( TY_XDS_ptr[ 1 ] & 0x08 )
|
||||
sprintf( line, "%s LANGUAGE", line );
|
||||
if ( TY_XDS_ptr[ 1 ] & 0x10 )
|
||||
sprintf( line, "%s SEXUAL", line );
|
||||
if ( TY_XDS_ptr[ 1 ] & 0x20 )
|
||||
sprintf( line, "%s VIOLENCE", line );
|
||||
ty_AddXDSToDisplay( line );
|
||||
|
||||
// raw output for verification.
|
||||
if ( TY_OSD_debug > 1 )
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, " (%02x %02x)",
|
||||
TY_XDS_ptr[ 0 ], TY_XDS_ptr[ 1 ] );
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0106: // current program audio services
|
||||
case 0x0306: // future
|
||||
{
|
||||
// requires table, never actually seen it used either
|
||||
ty_AddXDSToDisplay( "AUDIO: %02x %02x", TY_XDS_ptr[ 0 ],
|
||||
TY_XDS_ptr[ 1 ] );
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0109: // current program aspect ratio
|
||||
case 0x0309: // future
|
||||
{
|
||||
// requires table, rare
|
||||
ty_AddXDSToDisplay( "ASPECT: %02x %02x",
|
||||
TY_XDS_ptr[ 0 ], TY_XDS_ptr[ 1 ] );
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0110: // program description
|
||||
case 0x0111:
|
||||
case 0x0112:
|
||||
case 0x0113:
|
||||
case 0x0114:
|
||||
case 0x0115:
|
||||
case 0x0116:
|
||||
case 0x0117:
|
||||
{
|
||||
ty_AddXDSToDisplay( "DESCRIP: %s", TY_XDS_ptr );
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0501: // channel network name
|
||||
{
|
||||
ty_AddXDSToDisplay( "NETWORK: %s", TY_XDS_ptr );
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0502: // channel network call letters
|
||||
{
|
||||
ty_AddXDSToDisplay( "CALLSIGN: %s", TY_XDS_ptr );
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0701: // misc. time of day
|
||||
{
|
||||
#define TIMEZONE ( TY_XDS[ 3 ][ 4 ][ 0 ] & 0x1f )
|
||||
#define DST ( ( TY_XDS[ 3 ][ 4 ][ 0 ] & 0x20 ) >> 5 )
|
||||
struct tm tm =
|
||||
{
|
||||
.tm_sec = 0, // sec
|
||||
.tm_min = ( TY_XDS_ptr[ 0 ] & 0x3F ), // min
|
||||
.tm_hour = ( TY_XDS_ptr[ 1 ] & 0x1F ), // hour
|
||||
.tm_mday = ( TY_XDS_ptr[ 2 ] & 0x1F ), // day
|
||||
.tm_mon = ( TY_XDS_ptr[ 3 ] & 0x1f ) - 1, // month
|
||||
.tm_year = ( TY_XDS_ptr[ 5 ] & 0x3f ) + 90, // year
|
||||
.tm_wday = 0, // day of week
|
||||
.tm_yday = 0, // day of year
|
||||
.tm_isdst = 0, // DST
|
||||
};
|
||||
|
||||
time_t time_t = mktime( &tm );
|
||||
char *timestr;
|
||||
|
||||
time_t -= ( ( TIMEZONE - DST ) * 60 * 60 );
|
||||
timestr = ctime( &time_t );
|
||||
timestr[ strlen( timestr ) - 1 ] = 0;
|
||||
|
||||
sprintf( line, "%sCUR.TIME: %s ", line, timestr );
|
||||
if ( TY_XDS[ 3 ][ 4 ][ 0 ] )
|
||||
{
|
||||
sprintf( line, "%sUTC-%d", line, TIMEZONE );
|
||||
if (DST) sprintf( line, "%s DST", line );
|
||||
}
|
||||
else
|
||||
sprintf( line, "%sUTC", line );
|
||||
|
||||
ty_AddXDSToDisplay( line );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0704: //misc. local time zone
|
||||
{
|
||||
sprintf( line, "%sTIMEZONE: UTC-%d",
|
||||
line, TY_XDS_ptr[ 0 ] & 0x1f );
|
||||
if ( TY_XDS_ptr[ 0 ] & 0x20 ) sprintf( line, "%s DST", line );
|
||||
ty_AddXDSToDisplay( line );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "UNKNOWN CLASS %d TYPE %d",
|
||||
( TY_XDS_mode << 1 ) + 1, TY_XDS_type );
|
||||
if ( TY_OSD_debug > 1 )
|
||||
{
|
||||
int x;
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "\nDUMP:\n" );
|
||||
for ( x = 0 ; x < TY_XDS_length ; x++ )
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, " %02x %c",
|
||||
TY_XDS_ptr[ x ], TY_XDS_ptr[ x ] );
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, "\n" );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( TY_OSD_debug > 1 )
|
||||
mp_msg( MSGT_DEMUX, MSGL_DBG3, " (%d)", TY_XDS_length );
|
||||
}
|
||||
TY_XDS_mode = 0;
|
||||
TY_XDS_type = 0;
|
||||
}
|
||||
else if ( TY_XDS_length < 34 )
|
||||
{
|
||||
TY_XDS_new[ TY_XDS_mode ][ TY_XDS_type ][ TY_XDS_length++ ] = b1;
|
||||
TY_XDS_new[ TY_XDS_mode ][ TY_XDS_type ][ TY_XDS_length++ ] = b2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ===========================================================================
|
||||
// Callback from Video Display Processing to put up the OSD
|
||||
// ===========================================================================
|
||||
void ty_processuserdata( const unsigned char* buf, int len )
|
||||
{
|
||||
int index;
|
||||
|
||||
sub_justify = 1;
|
||||
|
||||
if ( subcc_enabled )
|
||||
{
|
||||
if ( tyOSDInitialized == 0 )
|
||||
{
|
||||
for ( index = 0; index < SUB_MAX_TEXT ; index++ )
|
||||
{
|
||||
ty_OSD1.text[ index ] = malloc( TY_CC_MAX_X );
|
||||
ty_OSD2.text[ index ] = malloc( TY_CC_MAX_X );
|
||||
}
|
||||
ty_ClearOSD( 0 );
|
||||
ty_OSD1.lines = SUB_MAX_TEXT;
|
||||
ty_OSD2.lines = SUB_MAX_TEXT;
|
||||
ty_pOSD1 = &ty_OSD1;
|
||||
ty_pOSD2 = &ty_OSD2;
|
||||
tyOSDUpdate = 0;
|
||||
tyOSDInitialized = 1;
|
||||
}
|
||||
|
||||
if ( buf[ 0 ] == 0x01 )
|
||||
{
|
||||
ty_CCdecode( buf[ 1 ], buf[ 2 ] );
|
||||
}
|
||||
if ( buf[ 0 ] == 0x02 )
|
||||
{
|
||||
ty_XDSdecode( buf[ 1 ], buf[ 2 ] );
|
||||
}
|
||||
|
||||
ty_DisplayXDSInfo();
|
||||
|
||||
if ( tyOSDUpdate )
|
||||
{
|
||||
// for ( index = 0; index < SUB_MAX_TEXT ; index++ )
|
||||
// {
|
||||
// printf( "OSD:%d:%s\n", index, ty_OSD1.text[ index ] );
|
||||
// }
|
||||
vo_sub = &ty_OSD1;
|
||||
vo_osd_changed( OSDTYPE_SUBTITLE );
|
||||
tyOSDUpdate = 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MPLAYER_DEMUX_TY_OSD_H
|
||||
#define MPLAYER_DEMUX_TY_OSD_H
|
||||
|
||||
void ty_ClearOSD(int start);
|
||||
void ty_processuserdata(const unsigned char *buf, int len);
|
||||
|
||||
#endif /* MPLAYER_DEMUX_TY_OSD_H */
|
@ -1,240 +0,0 @@
|
||||
/*
|
||||
* 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 "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <libavutil/common.h>
|
||||
#include <libavutil/intreadwrite.h>
|
||||
|
||||
#include "stream/stream.h"
|
||||
#include "demuxer.h"
|
||||
#include "stheader.h"
|
||||
#include "libmpcodecs/vqf.h"
|
||||
|
||||
static int demux_probe_vqf(demuxer_t* demuxer)
|
||||
{
|
||||
char buf[KEYWORD_BYTES];
|
||||
stream_t *s;
|
||||
s = demuxer->stream;
|
||||
if(stream_read(s,buf,KEYWORD_BYTES)!=KEYWORD_BYTES)
|
||||
return 0;
|
||||
if(memcmp(buf,"TWIN",KEYWORD_BYTES)==0) return DEMUXER_TYPE_VQF; /*version: 97012000*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static demuxer_t* demux_open_vqf(demuxer_t* demuxer) {
|
||||
sh_audio_t* sh_audio;
|
||||
WAVEFORMATEX* w;
|
||||
stream_t *s;
|
||||
headerInfo *hi;
|
||||
|
||||
s = demuxer->stream;
|
||||
|
||||
sh_audio = new_sh_audio(demuxer,0);
|
||||
sh_audio->wf = w = calloc(1, sizeof(*sh_audio->wf)+sizeof(headerInfo));
|
||||
hi = (headerInfo *)&w[1];
|
||||
w->wFormatTag = 0x1;
|
||||
sh_audio->format = mmioFOURCC('T','W','I','N'); /* TWinVQ */
|
||||
w->nChannels = sh_audio->channels = 2;
|
||||
w->nSamplesPerSec = sh_audio->samplerate = 44100;
|
||||
w->nAvgBytesPerSec = w->nSamplesPerSec*sh_audio->channels*2;
|
||||
w->nBlockAlign = 0;
|
||||
sh_audio->samplesize = 2;
|
||||
w->wBitsPerSample = 8*sh_audio->samplesize;
|
||||
w->cbSize = 0;
|
||||
strcpy(hi->ID,"TWIN");
|
||||
stream_read(s,hi->ID+KEYWORD_BYTES,VERSION_BYTES); /* fourcc+version_id */
|
||||
while(1)
|
||||
{
|
||||
char chunk_id[4];
|
||||
unsigned chunk_size;
|
||||
hi->size=chunk_size=stream_read_dword(s); /* include itself */
|
||||
stream_read(s,chunk_id,4);
|
||||
if (chunk_size < 8) return NULL;
|
||||
chunk_size -= 8;
|
||||
if(AV_RL32(chunk_id)==mmioFOURCC('C','O','M','M'))
|
||||
{
|
||||
char buf[BUFSIZ];
|
||||
unsigned i,subchunk_size;
|
||||
if (chunk_size > sizeof(buf) || chunk_size < 20) return NULL;
|
||||
if(stream_read(s,buf,chunk_size)!=chunk_size) return NULL;
|
||||
i=0;
|
||||
subchunk_size = AV_RB32(buf);
|
||||
hi->channelMode = AV_RB32(buf + 4);
|
||||
w->nChannels=sh_audio->channels=hi->channelMode+1; /*0-mono;1-stereo*/
|
||||
hi->bitRate = AV_RB32(buf + 8);
|
||||
sh_audio->i_bps=hi->bitRate*1000/8; /* bitrate kbit/s */
|
||||
w->nAvgBytesPerSec = sh_audio->i_bps;
|
||||
hi->samplingRate = AV_RB32(buf + 12);
|
||||
switch(hi->samplingRate){
|
||||
case 44:
|
||||
w->nSamplesPerSec=44100;
|
||||
break;
|
||||
case 22:
|
||||
w->nSamplesPerSec=22050;
|
||||
break;
|
||||
case 11:
|
||||
w->nSamplesPerSec=11025;
|
||||
break;
|
||||
default:
|
||||
w->nSamplesPerSec=hi->samplingRate*1000;
|
||||
break;
|
||||
}
|
||||
sh_audio->samplerate=w->nSamplesPerSec;
|
||||
hi->securityLevel = AV_RB32(buf + 16);
|
||||
w->nBlockAlign = 0;
|
||||
sh_audio->samplesize = 4;
|
||||
w->wBitsPerSample = 8*sh_audio->samplesize;
|
||||
w->cbSize = 0;
|
||||
if (subchunk_size > chunk_size - 4) continue;
|
||||
i+=subchunk_size+4;
|
||||
while(i + 8 < chunk_size)
|
||||
{
|
||||
unsigned slen,sid;
|
||||
char sdata[BUFSIZ];
|
||||
sid = AV_RL32(buf + i); i+=4;
|
||||
slen = AV_RB32(buf + i); i+=4;
|
||||
if (slen > sizeof(sdata) - 1 || slen > chunk_size - i) break;
|
||||
if(sid==mmioFOURCC('D','S','I','Z'))
|
||||
{
|
||||
hi->Dsiz=AV_RB32(buf + i);
|
||||
continue; /* describes the same info as size of DATA chunk */
|
||||
}
|
||||
memcpy(sdata,&buf[i],slen); sdata[slen]=0; i+=slen;
|
||||
if(sid==mmioFOURCC('N','A','M','E'))
|
||||
{
|
||||
memcpy(hi->Name,sdata,FFMIN(BUFSIZ,slen));
|
||||
demux_info_add(demuxer,"Title",sdata);
|
||||
}
|
||||
else
|
||||
if(sid==mmioFOURCC('A','U','T','H'))
|
||||
{
|
||||
memcpy(hi->Auth,sdata,FFMIN(BUFSIZ,slen));
|
||||
demux_info_add(demuxer,"Author",sdata);
|
||||
}
|
||||
else
|
||||
if(sid==mmioFOURCC('C','O','M','T'))
|
||||
{
|
||||
memcpy(hi->Comt,sdata,FFMIN(BUFSIZ,slen));
|
||||
demux_info_add(demuxer,"Comment",sdata);
|
||||
}
|
||||
else
|
||||
if(sid==mmioFOURCC('(','c',')',' '))
|
||||
{
|
||||
memcpy(hi->Cpyr,sdata,FFMIN(BUFSIZ,slen));
|
||||
demux_info_add(demuxer,"Copyright",sdata);
|
||||
}
|
||||
else
|
||||
if(sid==mmioFOURCC('F','I','L','E'))
|
||||
{
|
||||
memcpy(hi->File,sdata,FFMIN(BUFSIZ,slen));
|
||||
}
|
||||
else
|
||||
if(sid==mmioFOURCC('A','L','B','M')) demux_info_add(demuxer,"Album",sdata);
|
||||
else
|
||||
if(sid==mmioFOURCC('Y','E','A','R')) demux_info_add(demuxer,"Date",sdata);
|
||||
else
|
||||
if(sid==mmioFOURCC('T','R','A','C')) demux_info_add(demuxer,"Track",sdata);
|
||||
else
|
||||
if(sid==mmioFOURCC('E','N','C','D')) demux_info_add(demuxer,"Encoder",sdata);
|
||||
else
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "Unhandled subchunk '%c%c%c%c'='%s'\n",((char *)&sid)[0],((char *)&sid)[1],((char *)&sid)[2],((char *)&sid)[3],sdata);
|
||||
/* rest not recognized due to untranslatable Japanese expressions */
|
||||
}
|
||||
}
|
||||
else
|
||||
if(AV_RL32(chunk_id)==mmioFOURCC('D','A','T','A'))
|
||||
{
|
||||
demuxer->movi_start=stream_tell(s);
|
||||
demuxer->movi_end=demuxer->movi_start+chunk_size;
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "Found data at %"PRIX64" size %"PRIu64"\n",demuxer->movi_start,demuxer->movi_end);
|
||||
/* Done! play it */
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "Unhandled chunk '%c%c%c%c' %u bytes\n",chunk_id[0],chunk_id[1],chunk_id[2],chunk_id[3],chunk_size);
|
||||
stream_skip(s,chunk_size); /*unknown chunk type */
|
||||
}
|
||||
}
|
||||
|
||||
demuxer->audio->id = 0;
|
||||
demuxer->audio->sh = sh_audio;
|
||||
sh_audio->ds = demuxer->audio;
|
||||
stream_seek(s,demuxer->movi_start);
|
||||
demuxer->seekable=0;
|
||||
return demuxer;
|
||||
}
|
||||
|
||||
static int demux_vqf_fill_buffer(demuxer_t* demuxer, demux_stream_t *ds) {
|
||||
sh_audio_t* sh_audio = demuxer->audio->sh;
|
||||
int l = sh_audio->wf->nAvgBytesPerSec;
|
||||
off_t spos = stream_tell(demuxer->stream);
|
||||
demux_packet_t* dp;
|
||||
|
||||
if(stream_eof(demuxer->stream))
|
||||
return 0;
|
||||
|
||||
dp = new_demux_packet(l);
|
||||
ds->pts = spos / (float)(sh_audio->wf->nAvgBytesPerSec);
|
||||
ds->pos = spos;
|
||||
|
||||
l=stream_read(demuxer->stream,dp->buffer,l);
|
||||
resize_demux_packet(dp,l);
|
||||
ds_add_packet(ds,dp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void demux_seek_vqf(demuxer_t *demuxer,float rel_seek_secs,float audio_delay,int flags){
|
||||
#if 0
|
||||
stream_t* s = demuxer->stream;
|
||||
sh_audio_t* sh_audio = demuxer->audio->sh;
|
||||
off_t base,pos;
|
||||
|
||||
base = (flags & SEEK_ABSOLUTE) ? demuxer->movi_start : stream_tell(s);
|
||||
if(flags & SEEK_FACTOR)
|
||||
pos = base + ((demuxer->movi_end - demuxer->movi_start)*rel_seek_secs);
|
||||
else
|
||||
pos = base + (rel_seek_secs*sh_audio->i_bps);
|
||||
|
||||
pos -= (pos % (sh_audio->channels * sh_audio->samplesize) );
|
||||
stream_seek(s,pos);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void demux_close_vqf(demuxer_t* demuxer) {}
|
||||
|
||||
|
||||
const demuxer_desc_t demuxer_desc_vqf = {
|
||||
"TwinVQ demuxer",
|
||||
"vqf",
|
||||
"VQF",
|
||||
"Nick Kurshev",
|
||||
"ported from MPlayerXP",
|
||||
DEMUXER_TYPE_VQF,
|
||||
1, // safe autodetect
|
||||
demux_probe_vqf,
|
||||
demux_vqf_fill_buffer,
|
||||
demux_open_vqf,
|
||||
demux_close_vqf,
|
||||
demux_seek_vqf,
|
||||
NULL
|
||||
};
|
@ -1,325 +0,0 @@
|
||||
/*
|
||||
* Y4M file parser
|
||||
* copyright (c) 2001 Rik Snel
|
||||
* (using yuv4mpeg*.[ch] from mjpeg.sourceforge.net)
|
||||
* (derived from demux_viv.c)
|
||||
* older YUV4MPEG (used by xawtv) support by Alex Beregszaszi
|
||||
*
|
||||
* 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 <string.h> /* strtok */
|
||||
|
||||
#include "config.h"
|
||||
#include "mp_msg.h"
|
||||
#include "yuv4mpeg.h"
|
||||
|
||||
#include "stream/stream.h"
|
||||
#include "demuxer.h"
|
||||
#include "stheader.h"
|
||||
|
||||
typedef struct {
|
||||
int framenum;
|
||||
y4m_stream_info_t* si;
|
||||
int is_older;
|
||||
} y4m_priv_t;
|
||||
|
||||
static int y4m_check_file(demuxer_t* demuxer){
|
||||
int orig_pos = stream_tell(demuxer->stream);
|
||||
char buf[10];
|
||||
y4m_priv_t* priv;
|
||||
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "Checking for YUV4MPEG2\n");
|
||||
|
||||
if(stream_read(demuxer->stream, buf, 9)!=9)
|
||||
return 0;
|
||||
|
||||
buf[9] = 0;
|
||||
|
||||
if (strncmp("YUV4MPEG2", buf, 9) && strncmp("YUV4MPEG ", buf, 9)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
demuxer->priv = malloc(sizeof(y4m_priv_t));
|
||||
priv = demuxer->priv;
|
||||
|
||||
priv->is_older = 0;
|
||||
|
||||
if (!strncmp("YUV4MPEG ", buf, 9))
|
||||
{
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "Found older YUV4MPEG format (used by xawtv)\n");
|
||||
priv->is_older = 1;
|
||||
}
|
||||
|
||||
mp_msg(MSGT_DEMUX,MSGL_DBG2,"Success: YUV4MPEG2\n");
|
||||
|
||||
stream_seek(demuxer->stream, orig_pos);
|
||||
|
||||
return DEMUXER_TYPE_Y4M;
|
||||
}
|
||||
|
||||
static void read_streaminfo(demuxer_t *demuxer);
|
||||
|
||||
// return value:
|
||||
// 0 = EOF or no stream found
|
||||
// 1 = successfully read a packet
|
||||
static int demux_y4m_fill_buffer(demuxer_t *demux, demux_stream_t *dsds) {
|
||||
demux_stream_t *ds=demux->video;
|
||||
demux_packet_t *dp;
|
||||
y4m_priv_t *priv=demux->priv;
|
||||
y4m_frame_info_t fi;
|
||||
unsigned char *buf[3];
|
||||
int err, size;
|
||||
int nextc;
|
||||
|
||||
// Concatenated stream check; only done if seekable so skip(-1) works
|
||||
if (demux->stream->flags & MP_STREAM_SEEK_BW) {
|
||||
nextc = stream_read_char(demux->stream);
|
||||
stream_skip(demux->stream, -1);
|
||||
if (nextc == 'Y') {
|
||||
read_streaminfo(demux);
|
||||
demux->seekable = 0;
|
||||
}
|
||||
}
|
||||
|
||||
y4m_init_frame_info(&fi);
|
||||
|
||||
demux->filepos=stream_tell(demux->stream);
|
||||
|
||||
size = ((sh_video_t*)ds->sh)->disp_w*((sh_video_t*)ds->sh)->disp_h;
|
||||
|
||||
dp = new_demux_packet(3*size/2);
|
||||
|
||||
/* swap U and V components */
|
||||
buf[0] = dp->buffer;
|
||||
buf[1] = dp->buffer + 5*size/4;
|
||||
buf[2] = dp->buffer + size;
|
||||
|
||||
if (priv->is_older)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = stream_read_char(demux->stream); /* F */
|
||||
if (c == -256)
|
||||
return 0; /* EOF */
|
||||
if (c != 'F')
|
||||
{
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "Bad frame at %d\n", (int)stream_tell(demux->stream)-1);
|
||||
return 0;
|
||||
}
|
||||
stream_skip(demux->stream, 5); /* RAME\n */
|
||||
stream_read(demux->stream, buf[0], size);
|
||||
stream_read(demux->stream, buf[1], size/4);
|
||||
stream_read(demux->stream, buf[2], size/4);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((err=y4m_read_frame(demux->stream, priv->si, &fi, buf)) != Y4M_OK) {
|
||||
mp_msg(MSGT_DEMUX, MSGL_ERR, "error reading frame %s\n", y4m_strerr(err));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* This seems to be the right way to calculate the presentation time stamp */
|
||||
dp->pts=(float)priv->framenum/((sh_video_t*)ds->sh)->fps;
|
||||
priv->framenum++;
|
||||
dp->pos=demux->filepos;
|
||||
ds_add_packet(ds, dp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void read_streaminfo(demuxer_t *demuxer)
|
||||
{
|
||||
y4m_priv_t *priv = demuxer->priv;
|
||||
sh_video_t *sh = demuxer->video->sh;
|
||||
y4m_ratio_t ratio;
|
||||
int err;
|
||||
|
||||
if (priv->is_older)
|
||||
{
|
||||
char buf[4];
|
||||
int frame_rate_code;
|
||||
|
||||
stream_skip(demuxer->stream, 8); /* YUV4MPEG */
|
||||
stream_skip(demuxer->stream, 1); /* space */
|
||||
stream_read(demuxer->stream, (char *)&buf[0], 3);
|
||||
buf[3] = 0;
|
||||
sh->disp_w = atoi(buf);
|
||||
stream_skip(demuxer->stream, 1); /* space */
|
||||
stream_read(demuxer->stream, (char *)&buf[0], 3);
|
||||
buf[3] = 0;
|
||||
sh->disp_h = atoi(buf);
|
||||
stream_skip(demuxer->stream, 1); /* space */
|
||||
stream_read(demuxer->stream, (char *)&buf[0], 1);
|
||||
buf[1] = 0;
|
||||
frame_rate_code = atoi(buf);
|
||||
stream_skip(demuxer->stream, 1); /* new-line */
|
||||
|
||||
if (!sh->fps)
|
||||
{
|
||||
/* values from xawtv */
|
||||
switch(frame_rate_code)
|
||||
{
|
||||
case 1:
|
||||
sh->fps = 23.976f;
|
||||
break;
|
||||
case 2:
|
||||
sh->fps = 24.0f;
|
||||
break;
|
||||
case 3:
|
||||
sh->fps = 25.0f;
|
||||
break;
|
||||
case 4:
|
||||
sh->fps = 29.97f;
|
||||
break;
|
||||
case 5:
|
||||
sh->fps = 30.0f;
|
||||
break;
|
||||
case 6:
|
||||
sh->fps = 50.0f;
|
||||
break;
|
||||
case 7:
|
||||
sh->fps = 59.94f;
|
||||
break;
|
||||
case 8:
|
||||
sh->fps = 60.0f;
|
||||
break;
|
||||
default:
|
||||
sh->fps = 25.0f;
|
||||
}
|
||||
}
|
||||
sh->frametime = 1.0f/sh->fps;
|
||||
}
|
||||
else
|
||||
{
|
||||
y4m_init_stream_info(priv->si);
|
||||
if ((err=y4m_read_stream_header(demuxer->stream, priv->si)) != Y4M_OK)
|
||||
mp_msg(MSGT_DEMUXER, MSGL_FATAL, "error parsing YUV4MPEG header: %s\n", y4m_strerr(err));
|
||||
|
||||
if(!sh->fps) {
|
||||
ratio = y4m_si_get_framerate(priv->si);
|
||||
if (ratio.d != 0)
|
||||
sh->fps=(float)ratio.n/(float)ratio.d;
|
||||
else
|
||||
sh->fps=15.0f;
|
||||
}
|
||||
sh->frametime=1.0f/sh->fps;
|
||||
|
||||
ratio = y4m_si_get_sampleaspect(priv->si);
|
||||
|
||||
sh->disp_w = y4m_si_get_width(priv->si);
|
||||
sh->disp_h = y4m_si_get_height(priv->si);
|
||||
|
||||
if (ratio.d != 0 && ratio.n != 0)
|
||||
sh->aspect = (float)(sh->disp_w*ratio.n)/(float)(sh->disp_h*ratio.d);
|
||||
|
||||
demuxer->seekable = 0;
|
||||
}
|
||||
|
||||
sh->format = mmioFOURCC('Y', 'V', '1', '2');
|
||||
|
||||
sh->bih->biSize=40;
|
||||
sh->bih->biWidth = sh->disp_w;
|
||||
sh->bih->biHeight = sh->disp_h;
|
||||
sh->bih->biPlanes=3;
|
||||
sh->bih->biBitCount=12;
|
||||
sh->bih->biCompression=sh->format;
|
||||
sh->bih->biSizeImage=sh->bih->biWidth*sh->bih->biHeight*3/2; /* YV12 */
|
||||
|
||||
mp_msg(MSGT_DEMUX, MSGL_INFO, "YUV4MPEG2 Video stream %d size: display: %dx%d, codec: %ux%u\n",
|
||||
demuxer->video->id, sh->disp_w, sh->disp_h, sh->bih->biWidth,
|
||||
sh->bih->biHeight);
|
||||
}
|
||||
|
||||
static demuxer_t* demux_open_y4m(demuxer_t* demuxer){
|
||||
y4m_priv_t* priv = demuxer->priv;
|
||||
sh_video_t* sh=new_sh_video(demuxer,0);
|
||||
|
||||
priv->framenum = 0;
|
||||
priv->si = malloc(sizeof(y4m_stream_info_t));
|
||||
|
||||
sh->bih=calloc(1, sizeof(*sh->bih));
|
||||
|
||||
demuxer->video->sh=sh;
|
||||
sh->ds=demuxer->video;
|
||||
demuxer->video->id=0;
|
||||
|
||||
read_streaminfo(demuxer);
|
||||
|
||||
return demuxer;
|
||||
}
|
||||
|
||||
static void demux_seek_y4m(demuxer_t *demuxer, float rel_seek_secs, float audio_delay, int flags) {
|
||||
sh_video_t* sh = demuxer->video->sh;
|
||||
y4m_priv_t* priv = demuxer->priv;
|
||||
int rel_seek_frames = sh->fps*rel_seek_secs;
|
||||
int size = 3*sh->disp_w*sh->disp_h/2;
|
||||
off_t curr_pos = stream_tell(demuxer->stream);
|
||||
|
||||
if (priv->framenum + rel_seek_frames < 0) rel_seek_frames = -priv->framenum;
|
||||
|
||||
//printf("seektoframe=%d rel_seek_secs=%f seektooffset=%ld\n", priv->framenum + rel_seek_frames, rel_seek_secs, curr_pos + rel_seek_frames*(size+6));
|
||||
//printf("framenum=%d, curr_pos=%ld, currpos/(size+6)=%f\n", priv->framenum, curr_pos, (float)curr_pos/(float)(size+6));
|
||||
priv->framenum += rel_seek_frames;
|
||||
|
||||
if (priv->is_older) {
|
||||
/* Well this is easy: every frame takes up size+6 bytes
|
||||
* in the stream and we may assume that the stream pointer
|
||||
* is always at the beginning of a frame.
|
||||
* framenum is the number of the frame that is about to be
|
||||
* demuxed (counting from ONE (see demux_open_y4m)) */
|
||||
stream_seek(demuxer->stream, curr_pos + rel_seek_frames*(size+6));
|
||||
} else {
|
||||
/* should never come here, because seeking for YUV4MPEG2
|
||||
* is disabled. */
|
||||
mp_msg(MSGT_DEMUX, MSGL_WARN, "Seeking for YUV4MPEG2 not yet implemented!\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void demux_close_y4m(demuxer_t *demuxer)
|
||||
{
|
||||
y4m_priv_t* priv = demuxer->priv;
|
||||
|
||||
if(!priv)
|
||||
return;
|
||||
if (!priv->is_older)
|
||||
y4m_fini_stream_info(((y4m_priv_t*)demuxer->priv)->si);
|
||||
free(((y4m_priv_t*)demuxer->priv)->si);
|
||||
free(demuxer->priv);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const demuxer_desc_t demuxer_desc_y4m = {
|
||||
"YUV4MPEG2 demuxer",
|
||||
"y4m",
|
||||
"YUV4MPEG2",
|
||||
"Rik snel",
|
||||
"",
|
||||
DEMUXER_TYPE_Y4M,
|
||||
1, // safe autodetect
|
||||
y4m_check_file,
|
||||
demux_y4m_fill_buffer,
|
||||
demux_open_y4m,
|
||||
demux_close_y4m,
|
||||
demux_seek_y4m,
|
||||
NULL
|
||||
};
|
@ -58,41 +58,19 @@ extern const demuxer_desc_t demuxer_desc_rawvideo;
|
||||
extern const demuxer_desc_t demuxer_desc_tv;
|
||||
extern const demuxer_desc_t demuxer_desc_mf;
|
||||
extern const demuxer_desc_t demuxer_desc_avi;
|
||||
extern const demuxer_desc_t demuxer_desc_y4m;
|
||||
extern const demuxer_desc_t demuxer_desc_asf;
|
||||
extern const demuxer_desc_t demuxer_desc_real;
|
||||
extern const demuxer_desc_t demuxer_desc_smjpeg;
|
||||
extern const demuxer_desc_t demuxer_desc_matroska;
|
||||
extern const demuxer_desc_t demuxer_desc_realaudio;
|
||||
extern const demuxer_desc_t demuxer_desc_vqf;
|
||||
extern const demuxer_desc_t demuxer_desc_mov;
|
||||
extern const demuxer_desc_t demuxer_desc_vivo;
|
||||
extern const demuxer_desc_t demuxer_desc_fli;
|
||||
extern const demuxer_desc_t demuxer_desc_film;
|
||||
extern const demuxer_desc_t demuxer_desc_roq;
|
||||
extern const demuxer_desc_t demuxer_desc_gif;
|
||||
extern const demuxer_desc_t demuxer_desc_ogg;
|
||||
extern const demuxer_desc_t demuxer_desc_avs;
|
||||
extern const demuxer_desc_t demuxer_desc_pva;
|
||||
extern const demuxer_desc_t demuxer_desc_nsv;
|
||||
extern const demuxer_desc_t demuxer_desc_mpeg_ts;
|
||||
extern const demuxer_desc_t demuxer_desc_lmlm4;
|
||||
extern const demuxer_desc_t demuxer_desc_mpeg_ps;
|
||||
extern const demuxer_desc_t demuxer_desc_mpeg_pes;
|
||||
extern const demuxer_desc_t demuxer_desc_mpeg_es;
|
||||
extern const demuxer_desc_t demuxer_desc_mpeg_gxf;
|
||||
extern const demuxer_desc_t demuxer_desc_mpeg4_es;
|
||||
extern const demuxer_desc_t demuxer_desc_h264_es;
|
||||
extern const demuxer_desc_t demuxer_desc_rawdv;
|
||||
extern const demuxer_desc_t demuxer_desc_mpc;
|
||||
extern const demuxer_desc_t demuxer_desc_audio;
|
||||
extern const demuxer_desc_t demuxer_desc_mpeg_ty;
|
||||
extern const demuxer_desc_t demuxer_desc_rtp;
|
||||
extern const demuxer_desc_t demuxer_desc_rtp_nemesi;
|
||||
extern const demuxer_desc_t demuxer_desc_lavf;
|
||||
extern const demuxer_desc_t demuxer_desc_lavf_preferred;
|
||||
extern const demuxer_desc_t demuxer_desc_aac;
|
||||
extern const demuxer_desc_t demuxer_desc_nut;
|
||||
extern const demuxer_desc_t demuxer_desc_mng;
|
||||
|
||||
/* Please do not add any new demuxers here. If you want to implement a new
|
||||
@ -110,39 +88,16 @@ const demuxer_desc_t *const demuxer_list[] = {
|
||||
&demuxer_desc_mf,
|
||||
&demuxer_desc_lavf_preferred,
|
||||
&demuxer_desc_avi,
|
||||
&demuxer_desc_y4m,
|
||||
&demuxer_desc_asf,
|
||||
&demuxer_desc_nsv,
|
||||
&demuxer_desc_real,
|
||||
&demuxer_desc_smjpeg,
|
||||
&demuxer_desc_matroska,
|
||||
&demuxer_desc_realaudio,
|
||||
&demuxer_desc_vqf,
|
||||
&demuxer_desc_mov,
|
||||
&demuxer_desc_vivo,
|
||||
&demuxer_desc_fli,
|
||||
&demuxer_desc_film,
|
||||
&demuxer_desc_roq,
|
||||
#ifdef CONFIG_GIF
|
||||
&demuxer_desc_gif,
|
||||
#endif
|
||||
#ifdef CONFIG_OGGVORBIS
|
||||
&demuxer_desc_ogg,
|
||||
#endif
|
||||
#ifdef CONFIG_WIN32DLL
|
||||
&demuxer_desc_avs,
|
||||
#endif
|
||||
&demuxer_desc_pva,
|
||||
&demuxer_desc_mpeg_ts,
|
||||
&demuxer_desc_lmlm4,
|
||||
&demuxer_desc_mpeg_ps,
|
||||
&demuxer_desc_mpeg_pes,
|
||||
&demuxer_desc_mpeg_es,
|
||||
&demuxer_desc_mpeg_gxf,
|
||||
&demuxer_desc_mpeg4_es,
|
||||
&demuxer_desc_h264_es,
|
||||
&demuxer_desc_audio,
|
||||
&demuxer_desc_mpeg_ty,
|
||||
#ifdef CONFIG_LIVE555
|
||||
&demuxer_desc_rtp,
|
||||
#endif
|
||||
@ -150,15 +105,8 @@ const demuxer_desc_t *const demuxer_list[] = {
|
||||
&demuxer_desc_rtp_nemesi,
|
||||
#endif
|
||||
&demuxer_desc_lavf,
|
||||
#ifdef CONFIG_MUSEPACK
|
||||
&demuxer_desc_mpc,
|
||||
#endif
|
||||
#ifdef CONFIG_LIBDV095
|
||||
&demuxer_desc_rawdv,
|
||||
#endif
|
||||
&demuxer_desc_aac,
|
||||
#ifdef CONFIG_LIBNUT
|
||||
&demuxer_desc_nut,
|
||||
#endif
|
||||
#ifdef CONFIG_MNG
|
||||
&demuxer_desc_mng,
|
||||
@ -1002,6 +950,22 @@ static struct demuxer *demux_open_stream(struct MPOpts *opts,
|
||||
struct demuxer *demuxer = NULL;
|
||||
const struct demuxer_desc *desc;
|
||||
|
||||
// Some code (e.g. dvd stuff, network code, or extension.c) explicitly
|
||||
// request certain file formats. The list of formats are always handled by
|
||||
// libavformat.
|
||||
// Maybe attempts should be made to convert the mplayer format to the libav
|
||||
// format, instead of reyling on libav to auto-detect the stream's format
|
||||
// correctly.
|
||||
switch (file_format) {
|
||||
case DEMUXER_TYPE_MPEG_PS:
|
||||
case DEMUXER_TYPE_MPEG_TS:
|
||||
case DEMUXER_TYPE_Y4M:
|
||||
case DEMUXER_TYPE_NSV:
|
||||
case DEMUXER_TYPE_AAC:
|
||||
case DEMUXER_TYPE_MPC:
|
||||
file_format = DEMUXER_TYPE_LAVF;
|
||||
}
|
||||
|
||||
// If somebody requested a demuxer check it
|
||||
if (file_format) {
|
||||
desc = get_demuxer_desc_from_type(file_format);
|
||||
|
@ -44,47 +44,30 @@ struct MPOpts;
|
||||
|
||||
enum demuxer_type {
|
||||
DEMUXER_TYPE_UNKNOWN = 0,
|
||||
DEMUXER_TYPE_MPEG_ES,
|
||||
DEMUXER_TYPE_MPEG_PS,
|
||||
DEMUXER_TYPE_AVI,
|
||||
DEMUXER_TYPE_AVI_NI,
|
||||
DEMUXER_TYPE_AVI_NINI,
|
||||
DEMUXER_TYPE_ASF,
|
||||
DEMUXER_TYPE_MOV,
|
||||
DEMUXER_TYPE_VIVO,
|
||||
DEMUXER_TYPE_TV,
|
||||
DEMUXER_TYPE_FLI,
|
||||
DEMUXER_TYPE_REAL,
|
||||
DEMUXER_TYPE_Y4M,
|
||||
DEMUXER_TYPE_FILM,
|
||||
DEMUXER_TYPE_ROQ,
|
||||
DEMUXER_TYPE_MF,
|
||||
DEMUXER_TYPE_AUDIO,
|
||||
DEMUXER_TYPE_OGG,
|
||||
DEMUXER_TYPE_RAWAUDIO,
|
||||
DEMUXER_TYPE_RTP,
|
||||
DEMUXER_TYPE_RAWDV,
|
||||
DEMUXER_TYPE_PVA,
|
||||
DEMUXER_TYPE_SMJPEG,
|
||||
DEMUXER_TYPE_XMMS,
|
||||
DEMUXER_TYPE_RAWVIDEO,
|
||||
DEMUXER_TYPE_MPEG4_ES,
|
||||
DEMUXER_TYPE_GIF,
|
||||
DEMUXER_TYPE_MPEG_TS,
|
||||
DEMUXER_TYPE_H264_ES,
|
||||
DEMUXER_TYPE_MATROSKA,
|
||||
DEMUXER_TYPE_REALAUDIO,
|
||||
DEMUXER_TYPE_MPEG_TY,
|
||||
DEMUXER_TYPE_LMLM4,
|
||||
DEMUXER_TYPE_LAVF,
|
||||
DEMUXER_TYPE_NSV,
|
||||
DEMUXER_TYPE_VQF,
|
||||
DEMUXER_TYPE_AVS,
|
||||
DEMUXER_TYPE_AAC,
|
||||
DEMUXER_TYPE_MPC,
|
||||
DEMUXER_TYPE_MPEG_PES,
|
||||
DEMUXER_TYPE_MPEG_GXF,
|
||||
DEMUXER_TYPE_NUT,
|
||||
DEMUXER_TYPE_LAVF_PREFERRED,
|
||||
DEMUXER_TYPE_RTP_NEMESI,
|
||||
DEMUXER_TYPE_MNG,
|
||||
|
@ -38,9 +38,6 @@ static struct {
|
||||
const char *extension;
|
||||
int demuxer_type;
|
||||
} extensions_table[] = {
|
||||
// { "mpeg", DEMUXER_TYPE_MPEG_PS },
|
||||
// { "mpg", DEMUXER_TYPE_MPEG_PS },
|
||||
// { "mpe", DEMUXER_TYPE_MPEG_PS },
|
||||
{ "vob", DEMUXER_TYPE_MPEG_PS },
|
||||
{ "m2v", DEMUXER_TYPE_MPEG_PS },
|
||||
{ "avi", DEMUXER_TYPE_AVI },
|
||||
@ -58,16 +55,16 @@ static struct {
|
||||
{ "wav", DEMUXER_TYPE_AUDIO },
|
||||
{ "flac", DEMUXER_TYPE_AUDIO },
|
||||
{ "fla", DEMUXER_TYPE_AUDIO },
|
||||
{ "ogg", DEMUXER_TYPE_OGG },
|
||||
{ "ogm", DEMUXER_TYPE_OGG },
|
||||
{ "ogg", DEMUXER_TYPE_LAVF },
|
||||
{ "ogm", DEMUXER_TYPE_LAVF },
|
||||
// { "pls", DEMUXER_TYPE_PLAYLIST },
|
||||
// { "m3u", DEMUXER_TYPE_PLAYLIST },
|
||||
{ "xm", DEMUXER_TYPE_XMMS },
|
||||
{ "mod", DEMUXER_TYPE_XMMS },
|
||||
{ "s3m", DEMUXER_TYPE_XMMS },
|
||||
{ "it", DEMUXER_TYPE_XMMS },
|
||||
{ "mid", DEMUXER_TYPE_XMMS },
|
||||
{ "midi", DEMUXER_TYPE_XMMS },
|
||||
{ "xm", DEMUXER_TYPE_LAVF },
|
||||
{ "mod", DEMUXER_TYPE_LAVF },
|
||||
{ "s3m", DEMUXER_TYPE_LAVF },
|
||||
{ "it", DEMUXER_TYPE_LAVF },
|
||||
{ "mid", DEMUXER_TYPE_LAVF },
|
||||
{ "midi", DEMUXER_TYPE_LAVF },
|
||||
{ "nsv", DEMUXER_TYPE_NSV },
|
||||
{ "nsa", DEMUXER_TYPE_NSV },
|
||||
{ "mpc", DEMUXER_TYPE_MPC },
|
||||
@ -75,8 +72,8 @@ static struct {
|
||||
{ "avs", DEMUXER_TYPE_AVS },
|
||||
#endif
|
||||
{ "302", DEMUXER_TYPE_LAVF },
|
||||
{ "264", DEMUXER_TYPE_H264_ES },
|
||||
{ "26l", DEMUXER_TYPE_H264_ES },
|
||||
{ "264", DEMUXER_TYPE_LAVF },
|
||||
{ "26l", DEMUXER_TYPE_LAVF },
|
||||
{ "ac3", DEMUXER_TYPE_LAVF },
|
||||
{ "ape", DEMUXER_TYPE_LAVF },
|
||||
{ "apl", DEMUXER_TYPE_LAVF },
|
||||
|
@ -1,539 +0,0 @@
|
||||
/*
|
||||
* based on libmpeg2/header.c by Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
|
||||
*
|
||||
* 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 <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "mpeg_hdr.h"
|
||||
#include "libavutil/attributes.h"
|
||||
#include "mp_msg.h"
|
||||
|
||||
static float frameratecode2framerate[16] = {
|
||||
0,
|
||||
// Official mpeg1/2 framerates: (1-8)
|
||||
24000.0/1001, 24,25,
|
||||
30000.0/1001, 30,50,
|
||||
60000.0/1001, 60,
|
||||
// Xing's 15fps: (9)
|
||||
15,
|
||||
// libmpeg3's "Unofficial economy rates": (10-13)
|
||||
5,10,12,15,
|
||||
// some invalid ones: (14-15)
|
||||
0,0
|
||||
};
|
||||
|
||||
|
||||
int mp_header_process_sequence_header (mp_mpeg_header_t * picture, const unsigned char * buffer)
|
||||
{
|
||||
int height;
|
||||
|
||||
if ((buffer[6] & 0x20) != 0x20){
|
||||
fprintf(stderr, "missing marker bit!\n");
|
||||
return 1; /* missing marker_bit */
|
||||
}
|
||||
|
||||
height = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2];
|
||||
|
||||
picture->display_picture_width = height >> 12;
|
||||
picture->display_picture_height = height & 0xfff;
|
||||
|
||||
picture->aspect_ratio_information = buffer[3] >> 4;
|
||||
picture->frame_rate_code = buffer[3] & 15;
|
||||
picture->fps=frameratecode2framerate[picture->frame_rate_code];
|
||||
picture->bitrate = (buffer[4]<<10)|(buffer[5]<<2)|(buffer[6]>>6);
|
||||
picture->mpeg1 = 1;
|
||||
picture->picture_structure = 3; //FRAME_PICTURE;
|
||||
picture->display_time=100;
|
||||
picture->frame_rate_extension_n = 1;
|
||||
picture->frame_rate_extension_d = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int header_process_sequence_extension (mp_mpeg_header_t * picture,
|
||||
unsigned char * buffer)
|
||||
{
|
||||
/* check chroma format, size extensions, marker bit */
|
||||
|
||||
if ( ((buffer[1] & 0x06) == 0x00) ||
|
||||
((buffer[1] & 0x01) != 0x00) || (buffer[2] & 0xe0) ||
|
||||
((buffer[3] & 0x01) != 0x01) )
|
||||
return 1;
|
||||
|
||||
picture->progressive_sequence = (buffer[1] >> 3) & 1;
|
||||
picture->frame_rate_extension_n = ((buffer[5] >> 5) & 3) + 1;
|
||||
picture->frame_rate_extension_d = (buffer[5] & 0x1f) + 1;
|
||||
|
||||
picture->mpeg1 = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int header_process_picture_coding_extension (mp_mpeg_header_t * picture, unsigned char * buffer)
|
||||
{
|
||||
picture->picture_structure = buffer[2] & 3;
|
||||
picture->top_field_first = buffer[3] >> 7;
|
||||
picture->repeat_first_field = (buffer[3] >> 1) & 1;
|
||||
picture->progressive_frame = buffer[4] >> 7;
|
||||
|
||||
// repeat_first implementation by A'rpi/ESP-team, based on libmpeg3:
|
||||
picture->display_time=100;
|
||||
if(picture->repeat_first_field){
|
||||
if(picture->progressive_sequence){
|
||||
if(picture->top_field_first)
|
||||
picture->display_time+=200;
|
||||
else
|
||||
picture->display_time+=100;
|
||||
} else
|
||||
if(picture->progressive_frame){
|
||||
picture->display_time+=50;
|
||||
}
|
||||
}
|
||||
//temopral hack. We calc time on every field, so if we have 2 fields
|
||||
// interlaced we'll end with double time for 1 frame
|
||||
if( picture->picture_structure!=3 ) picture->display_time/=2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mp_header_process_extension (mp_mpeg_header_t * picture, unsigned char * buffer)
|
||||
{
|
||||
switch (buffer[0] & 0xf0) {
|
||||
case 0x10: /* sequence extension */
|
||||
return header_process_sequence_extension (picture, buffer);
|
||||
case 0x80: /* picture coding extension */
|
||||
return header_process_picture_coding_extension (picture, buffer);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
float mpeg12_aspect_info(mp_mpeg_header_t *picture)
|
||||
{
|
||||
float aspect = 0.0;
|
||||
|
||||
switch(picture->aspect_ratio_information) {
|
||||
case 2: // PAL/NTSC SVCD/DVD 4:3
|
||||
case 8: // PAL VCD 4:3
|
||||
case 12: // NTSC VCD 4:3
|
||||
aspect=4.0/3.0;
|
||||
break;
|
||||
case 3: // PAL/NTSC Widescreen SVCD/DVD 16:9
|
||||
case 6: // (PAL?)/NTSC Widescreen SVCD 16:9
|
||||
aspect=16.0/9.0;
|
||||
break;
|
||||
case 4: // according to ISO-138182-2 Table 6.3
|
||||
aspect=2.21;
|
||||
break;
|
||||
case 1: // VGA 1:1 - do not prescale
|
||||
case 9: // Movie Type ??? / 640x480
|
||||
aspect=0.0;
|
||||
break;
|
||||
default:
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Detected unknown aspect_ratio_information in mpeg sequence header.\n"
|
||||
"Please report the aspect value (%i) along with the movie type (VGA,PAL,NTSC,"
|
||||
"SECAM) and the movie resolution (720x576,352x240,480x480,...) to the MPlayer"
|
||||
" developers, so that we can add support for it!\nAssuming 1:1 aspect for now.\n",
|
||||
picture->aspect_ratio_information);
|
||||
}
|
||||
|
||||
return aspect;
|
||||
}
|
||||
|
||||
//MPEG4 HEADERS
|
||||
unsigned char mp_getbits(unsigned char *buffer, unsigned int from, unsigned char len)
|
||||
{
|
||||
unsigned int n;
|
||||
unsigned char m, u, l, y;
|
||||
|
||||
n = from / 8;
|
||||
m = from % 8;
|
||||
u = 8 - m;
|
||||
l = (len > u ? len - u : 0);
|
||||
|
||||
y = (buffer[n] << m);
|
||||
if(8 > len)
|
||||
y >>= (8-len);
|
||||
if(l)
|
||||
y |= (buffer[n+1] >> (8-l));
|
||||
|
||||
//fprintf(stderr, "GETBITS(%d -> %d): bytes=0x%x 0x%x, n=%d, m=%d, l=%d, u=%d, Y=%d\n",
|
||||
// from, (int) len, (int) buffer[n],(int) buffer[n+1], n, (int) m, (int) l, (int) u, (int) y);
|
||||
return y;
|
||||
}
|
||||
|
||||
static inline unsigned int mp_getbits16(unsigned char *buffer, unsigned int from, unsigned char len)
|
||||
{
|
||||
if(len > 8)
|
||||
return (mp_getbits(buffer, from, len - 8) << 8) | mp_getbits(buffer, from + len - 8, 8);
|
||||
else
|
||||
return mp_getbits(buffer, from, len);
|
||||
}
|
||||
|
||||
#define getbits mp_getbits
|
||||
#define getbits16 mp_getbits16
|
||||
|
||||
static int read_timeinc(mp_mpeg_header_t * picture, unsigned char * buffer, int n)
|
||||
{
|
||||
if(picture->timeinc_bits > 8) {
|
||||
picture->timeinc_unit = getbits(buffer, n, picture->timeinc_bits - 8) << 8;
|
||||
n += picture->timeinc_bits - 8;
|
||||
picture->timeinc_unit |= getbits(buffer, n, 8);
|
||||
n += 8;
|
||||
} else {
|
||||
picture->timeinc_unit = getbits(buffer, n, picture->timeinc_bits);
|
||||
n += picture->timeinc_bits;
|
||||
}
|
||||
//fprintf(stderr, "TIMEINC2: %d, bits: %d\n", picture->timeinc_unit, picture->timeinc_bits);
|
||||
return n;
|
||||
}
|
||||
|
||||
int mp4_header_process_vol(mp_mpeg_header_t * picture, unsigned char * buffer)
|
||||
{
|
||||
unsigned int n, aspect=0, aspectw av_unused=0, aspecth av_unused=0, x=1, v;
|
||||
|
||||
//begins with 0x0000012x
|
||||
picture->fps = 0;
|
||||
picture->timeinc_bits = picture->timeinc_resolution = picture->timeinc_unit = 0;
|
||||
n = 9;
|
||||
if(getbits(buffer, n, 1))
|
||||
n += 7;
|
||||
n++;
|
||||
aspect=getbits(buffer, n, 4);
|
||||
n += 4;
|
||||
if(aspect == 0x0f) {
|
||||
aspectw = getbits(buffer, n, 8);
|
||||
n += 8;
|
||||
aspecth = getbits(buffer, n, 8);
|
||||
n += 8;
|
||||
}
|
||||
|
||||
if(getbits(buffer, n, 1)) {
|
||||
n += 4;
|
||||
if(getbits(buffer, n, 1))
|
||||
n += 79;
|
||||
n++;
|
||||
} else n++;
|
||||
|
||||
n+=3;
|
||||
|
||||
picture->timeinc_resolution = getbits(buffer, n, 8) << 8;
|
||||
n += 8;
|
||||
picture->timeinc_resolution |= getbits(buffer, n, 8);
|
||||
n += 8;
|
||||
|
||||
picture->timeinc_bits = 0;
|
||||
v = picture->timeinc_resolution - 1;
|
||||
while(v && (x<16)) {
|
||||
v>>=1;
|
||||
picture->timeinc_bits++;
|
||||
}
|
||||
picture->timeinc_bits = (picture->timeinc_bits > 1 ? picture->timeinc_bits : 1);
|
||||
|
||||
n++; //marker bit
|
||||
|
||||
if(getbits(buffer, n++, 1)) { //fixed_vop_timeinc
|
||||
n += read_timeinc(picture, buffer, n);
|
||||
|
||||
if(picture->timeinc_unit)
|
||||
picture->fps = (float) picture->timeinc_resolution / (float) picture->timeinc_unit;
|
||||
}
|
||||
|
||||
n++; //marker bit
|
||||
picture->display_picture_width = getbits16(buffer, n, 13);
|
||||
n += 13;
|
||||
n++; //marker bit
|
||||
picture->display_picture_height = getbits16(buffer, n, 13);
|
||||
n += 13;
|
||||
|
||||
//fprintf(stderr, "ASPECT: %d, PARW=%d, PARH=%d, TIMEINCRESOLUTION: %d, FIXED_TIMEINC: %d (number of bits: %d), FPS: %u\n",
|
||||
// aspect, aspectw, aspecth, picture->timeinc_resolution, picture->timeinc_unit, picture->timeinc_bits, picture->fps);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mp4_header_process_vop(mp_mpeg_header_t * picture, unsigned char * buffer)
|
||||
{
|
||||
int n;
|
||||
n = 0;
|
||||
picture->picture_type = getbits(buffer, n, 2);
|
||||
n += 2;
|
||||
while(getbits(buffer, n, 1))
|
||||
n++;
|
||||
n++;
|
||||
getbits(buffer, n, 1);
|
||||
n++;
|
||||
n += read_timeinc(picture, buffer, n);
|
||||
}
|
||||
|
||||
#define min(a, b) ((a) <= (b) ? (a) : (b))
|
||||
|
||||
static unsigned int read_golomb(unsigned char *buffer, unsigned int *init)
|
||||
{
|
||||
unsigned int x, v = 0, v2 = 0, m, len = 0, n = *init;
|
||||
|
||||
while(getbits(buffer, n++, 1) == 0)
|
||||
len++;
|
||||
|
||||
x = len + n;
|
||||
while(n < x)
|
||||
{
|
||||
m = min(x - n, 8);
|
||||
v |= getbits(buffer, n, m);
|
||||
n += m;
|
||||
if(x - n > 8)
|
||||
v <<= 8;
|
||||
}
|
||||
|
||||
v2 = 1;
|
||||
for(n = 0; n < len; n++)
|
||||
v2 <<= 1;
|
||||
v2 = (v2 - 1) + v;
|
||||
|
||||
//fprintf(stderr, "READ_GOLOMB(%u), V=2^%u + %u-1 = %u\n", *init, len, v, v2);
|
||||
*init = x;
|
||||
return v2;
|
||||
}
|
||||
|
||||
inline static int read_golomb_s(unsigned char *buffer, unsigned int *init)
|
||||
{
|
||||
unsigned int v = read_golomb(buffer, init);
|
||||
return (v & 1) ? ((v + 1) >> 1) : -(v >> 1);
|
||||
}
|
||||
|
||||
static int h264_parse_vui(mp_mpeg_header_t * picture, unsigned char * buf, unsigned int n)
|
||||
{
|
||||
unsigned int overscan, vsp_color, chroma, timing, fixed_fps;
|
||||
|
||||
if(getbits(buf, n++, 1))
|
||||
{
|
||||
picture->aspect_ratio_information = getbits(buf, n, 8);
|
||||
n += 8;
|
||||
if(picture->aspect_ratio_information == 255)
|
||||
{
|
||||
picture->display_picture_width = (getbits(buf, n, 8) << 8) | getbits(buf, n + 8, 8);
|
||||
n += 16;
|
||||
|
||||
picture->display_picture_height = (getbits(buf, n, 8) << 8) | getbits(buf, n + 8, 8);
|
||||
n += 16;
|
||||
}
|
||||
}
|
||||
|
||||
if((overscan=getbits(buf, n++, 1)))
|
||||
n++;
|
||||
if((vsp_color=getbits(buf, n++, 1)))
|
||||
{
|
||||
n += 4;
|
||||
if(getbits(buf, n++, 1))
|
||||
n += 24;
|
||||
}
|
||||
if((chroma=getbits(buf, n++, 1)))
|
||||
{
|
||||
read_golomb(buf, &n);
|
||||
read_golomb(buf, &n);
|
||||
}
|
||||
if((timing=getbits(buf, n++, 1)))
|
||||
{
|
||||
picture->timeinc_unit = (getbits(buf, n, 8) << 24) | (getbits(buf, n+8, 8) << 16) | (getbits(buf, n+16, 8) << 8) | getbits(buf, n+24, 8);
|
||||
n += 32;
|
||||
|
||||
picture->timeinc_resolution = (getbits(buf, n, 8) << 24) | (getbits(buf, n+8, 8) << 16) | (getbits(buf, n+16, 8) << 8) | getbits(buf, n+24, 8);
|
||||
n += 32;
|
||||
|
||||
fixed_fps = getbits(buf, n, 1);
|
||||
|
||||
if(picture->timeinc_unit > 0 && picture->timeinc_resolution > 0)
|
||||
picture->fps = (float) picture->timeinc_resolution / (float) picture->timeinc_unit;
|
||||
if(fixed_fps)
|
||||
picture->fps /= 2;
|
||||
}
|
||||
|
||||
//fprintf(stderr, "H264_PARSE_VUI, OVESCAN=%u, VSP_COLOR=%u, CHROMA=%u, TIMING=%u, DISPW=%u, DISPH=%u, TIMERES=%u, TIMEINC=%u, FIXED_FPS=%u\n", overscan, vsp_color, chroma, timing, picture->display_picture_width, picture->display_picture_height,
|
||||
// picture->timeinc_resolution, picture->timeinc_unit, picture->timeinc_unit, fixed_fps);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static int mp_unescape03(unsigned char *buf, int len)
|
||||
{
|
||||
unsigned char *dest;
|
||||
int i, j, skip;
|
||||
|
||||
dest = malloc(len);
|
||||
if(! dest)
|
||||
return 0;
|
||||
|
||||
j = i = skip = 0;
|
||||
while(i <= len-3)
|
||||
{
|
||||
if(buf[i] == 0 && buf[i+1] == 0 && buf[i+2] == 3)
|
||||
{
|
||||
dest[j] = dest[j+1] = 0;
|
||||
j += 2;
|
||||
i += 3;
|
||||
skip++;
|
||||
}
|
||||
else
|
||||
{
|
||||
dest[j] = buf[i];
|
||||
j++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
dest[j] = buf[len-2];
|
||||
dest[j+1] = buf[len-1];
|
||||
len -= skip;
|
||||
memcpy(buf, dest, len);
|
||||
free(dest);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int h264_parse_sps(mp_mpeg_header_t * picture, unsigned char * buf, int len)
|
||||
{
|
||||
unsigned int n = 0, v, i, k, mbh;
|
||||
int frame_mbs_only;
|
||||
|
||||
len = mp_unescape03(buf, len);
|
||||
|
||||
picture->fps = picture->timeinc_unit = picture->timeinc_resolution = 0;
|
||||
n = 24;
|
||||
read_golomb(buf, &n);
|
||||
if(buf[0] >= 100){
|
||||
if(read_golomb(buf, &n) == 3)
|
||||
n++;
|
||||
read_golomb(buf, &n);
|
||||
read_golomb(buf, &n);
|
||||
n++;
|
||||
if(getbits(buf, n++, 1)){
|
||||
for(i = 0; i < 8; i++)
|
||||
{ // scaling list is skipped for now
|
||||
if(getbits(buf, n++, 1))
|
||||
{
|
||||
v = 8;
|
||||
for(k = (i < 6 ? 16 : 64); k && v; k--)
|
||||
v = (v + read_golomb_s(buf, &n)) & 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
read_golomb(buf, &n);
|
||||
v = read_golomb(buf, &n);
|
||||
if(v == 0)
|
||||
read_golomb(buf, &n);
|
||||
else if(v == 1)
|
||||
{
|
||||
getbits(buf, n++, 1);
|
||||
read_golomb(buf, &n);
|
||||
read_golomb(buf, &n);
|
||||
v = read_golomb(buf, &n);
|
||||
for(i = 0; i < v; i++)
|
||||
read_golomb(buf, &n);
|
||||
}
|
||||
read_golomb(buf, &n);
|
||||
getbits(buf, n++, 1);
|
||||
picture->display_picture_width = 16 *(read_golomb(buf, &n)+1);
|
||||
mbh = read_golomb(buf, &n)+1;
|
||||
frame_mbs_only = getbits(buf, n++, 1);
|
||||
picture->display_picture_height = 16 * (2 - frame_mbs_only) * mbh;
|
||||
if(!frame_mbs_only)
|
||||
getbits(buf, n++, 1);
|
||||
getbits(buf, n++, 1);
|
||||
if(getbits(buf, n++, 1))
|
||||
{
|
||||
read_golomb(buf, &n);
|
||||
read_golomb(buf, &n);
|
||||
read_golomb(buf, &n);
|
||||
read_golomb(buf, &n);
|
||||
}
|
||||
if(getbits(buf, n++, 1))
|
||||
n = h264_parse_vui(picture, buf, n);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int mp_vc1_decode_sequence_header(mp_mpeg_header_t * picture, unsigned char * buf, int len)
|
||||
{
|
||||
int n, x;
|
||||
|
||||
len = mp_unescape03(buf, len);
|
||||
|
||||
picture->display_picture_width = picture->display_picture_height = 0;
|
||||
picture->fps = 0;
|
||||
n = 0;
|
||||
x = getbits(buf, n, 2);
|
||||
n += 2;
|
||||
if(x != 3) //not advanced profile
|
||||
return 0;
|
||||
|
||||
getbits16(buf, n, 14);
|
||||
n += 14;
|
||||
picture->display_picture_width = getbits16(buf, n, 12) * 2 + 2;
|
||||
n += 12;
|
||||
picture->display_picture_height = getbits16(buf, n, 12) * 2 + 2;
|
||||
n += 12;
|
||||
getbits(buf, n, 6);
|
||||
n += 6;
|
||||
x = getbits(buf, n, 1);
|
||||
n += 1;
|
||||
if(x) //display info
|
||||
{
|
||||
getbits16(buf, n, 14);
|
||||
n += 14;
|
||||
getbits16(buf, n, 14);
|
||||
n += 14;
|
||||
if(getbits(buf, n++, 1)) //aspect ratio
|
||||
{
|
||||
x = getbits(buf, n, 4);
|
||||
n += 4;
|
||||
if(x == 15)
|
||||
{
|
||||
getbits16(buf, n, 16);
|
||||
n += 16;
|
||||
}
|
||||
}
|
||||
|
||||
if(getbits(buf, n++, 1)) //framerates
|
||||
{
|
||||
int frexp=0, frnum=0, frden=0;
|
||||
|
||||
if(getbits(buf, n++, 1))
|
||||
{
|
||||
frexp = getbits16(buf, n, 16);
|
||||
n += 16;
|
||||
picture->fps = (double) (frexp+1) / 32.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
float frates[] = {0, 24000, 25000, 30000, 50000, 60000, 48000, 72000, 0};
|
||||
float frdivs[] = {0, 1000, 1001, 0};
|
||||
|
||||
frnum = getbits(buf, n, 8);
|
||||
n += 8;
|
||||
frden = getbits(buf, n, 4);
|
||||
n += 4;
|
||||
if((frden == 1 || frden == 2) && (frnum < 8))
|
||||
picture->fps = frates[frnum] / frdivs[frden];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//free(dest);
|
||||
return 1;
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MPLAYER_MPEG_HDR_H
|
||||
#define MPLAYER_MPEG_HDR_H
|
||||
|
||||
typedef struct {
|
||||
// video info:
|
||||
int mpeg1; // 0=mpeg2 1=mpeg1
|
||||
int display_picture_width;
|
||||
int display_picture_height;
|
||||
int aspect_ratio_information;
|
||||
int frame_rate_code;
|
||||
float fps;
|
||||
int frame_rate_extension_n;
|
||||
int frame_rate_extension_d;
|
||||
int bitrate; // 0x3FFFF==VBR
|
||||
// timing:
|
||||
int picture_structure;
|
||||
int progressive_sequence;
|
||||
int repeat_first_field;
|
||||
int progressive_frame;
|
||||
int top_field_first;
|
||||
int display_time; // secs*100
|
||||
//the following are for mpeg4
|
||||
unsigned int timeinc_resolution, timeinc_bits, timeinc_unit;
|
||||
int picture_type;
|
||||
} mp_mpeg_header_t;
|
||||
|
||||
int mp_header_process_sequence_header (mp_mpeg_header_t * picture, const unsigned char * buffer);
|
||||
int mp_header_process_extension (mp_mpeg_header_t * picture, unsigned char * buffer);
|
||||
float mpeg12_aspect_info(mp_mpeg_header_t *picture);
|
||||
int mp4_header_process_vol(mp_mpeg_header_t * picture, unsigned char * buffer);
|
||||
void mp4_header_process_vop(mp_mpeg_header_t * picture, unsigned char * buffer);
|
||||
int h264_parse_sps(mp_mpeg_header_t * picture, unsigned char * buf, int len);
|
||||
int mp_vc1_decode_sequence_header(mp_mpeg_header_t * picture, unsigned char * buf, int len);
|
||||
|
||||
unsigned char mp_getbits(unsigned char *buffer, unsigned int from, unsigned char len);
|
||||
|
||||
#endif /* MPLAYER_MPEG_HDR_H */
|
@ -1,158 +0,0 @@
|
||||
/*
|
||||
* MPEG-ES video parser
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "mp_msg.h"
|
||||
|
||||
#include "stream/stream.h"
|
||||
#include "demuxer.h"
|
||||
#include "parse_es.h"
|
||||
|
||||
//static unsigned char videobuffer[MAX_VIDEO_PACKET_SIZE];
|
||||
unsigned char* videobuffer=NULL;
|
||||
int videobuf_len=0;
|
||||
int next_nal = -1;
|
||||
///! legacy variable, 4 if stream is synced, 0 if not
|
||||
int videobuf_code_len=0;
|
||||
|
||||
#define MAX_SYNCLEN (10 * 1024 * 1024)
|
||||
// sync video stream, and returns next packet code
|
||||
int sync_video_packet(demux_stream_t *ds){
|
||||
if (!videobuf_code_len) {
|
||||
int skipped=0;
|
||||
if (!demux_pattern_3(ds, NULL, MAX_SYNCLEN, &skipped, 0x100)) {
|
||||
if (skipped == MAX_SYNCLEN)
|
||||
mp_msg(MSGT_DEMUXER, MSGL_ERR, "parse_es: could not sync video stream!\n");
|
||||
goto eof_out;
|
||||
}
|
||||
next_nal = demux_getc(ds);
|
||||
if (next_nal < 0)
|
||||
goto eof_out;
|
||||
videobuf_code_len = 4;
|
||||
if(skipped) mp_dbg(MSGT_PARSEES,MSGL_DBG2,"videobuf: %d bytes skipped (next: 0x1%02X)\n",skipped,next_nal);
|
||||
}
|
||||
return 0x100|next_nal;
|
||||
|
||||
eof_out:
|
||||
next_nal = -1;
|
||||
videobuf_code_len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return: packet length
|
||||
int read_video_packet(demux_stream_t *ds){
|
||||
int packet_start;
|
||||
int res, read;
|
||||
|
||||
if (VIDEOBUFFER_SIZE - videobuf_len < 5)
|
||||
return 0;
|
||||
// SYNC STREAM
|
||||
// if(!sync_video_packet(ds)) return 0; // cannot sync (EOF)
|
||||
|
||||
// COPY STARTCODE:
|
||||
packet_start=videobuf_len;
|
||||
videobuffer[videobuf_len+0]=0;
|
||||
videobuffer[videobuf_len+1]=0;
|
||||
videobuffer[videobuf_len+2]=1;
|
||||
videobuffer[videobuf_len+3]=next_nal;
|
||||
videobuf_len+=4;
|
||||
|
||||
// READ PACKET:
|
||||
res = demux_pattern_3(ds, &videobuffer[videobuf_len],
|
||||
VIDEOBUFFER_SIZE - videobuf_len, &read, 0x100);
|
||||
videobuf_len += read;
|
||||
if (!res)
|
||||
goto eof_out;
|
||||
|
||||
videobuf_len-=3;
|
||||
|
||||
mp_dbg(MSGT_PARSEES,MSGL_DBG2,"videobuf: packet 0x1%02X len=%d (total=%d)\n",videobuffer[packet_start+3],videobuf_len-packet_start,videobuf_len);
|
||||
|
||||
// Save next packet code:
|
||||
next_nal = demux_getc(ds);
|
||||
if (next_nal < 0)
|
||||
goto eof_out;
|
||||
videobuf_code_len=4;
|
||||
|
||||
return videobuf_len-packet_start;
|
||||
|
||||
eof_out:
|
||||
next_nal = -1;
|
||||
videobuf_code_len = 0;
|
||||
return videobuf_len - packet_start;
|
||||
}
|
||||
|
||||
// return: next packet code
|
||||
int skip_video_packet(demux_stream_t *ds){
|
||||
|
||||
// SYNC STREAM
|
||||
// if(!sync_video_packet(ds)) return 0; // cannot sync (EOF)
|
||||
|
||||
videobuf_code_len=0; // force resync
|
||||
|
||||
// SYNC AGAIN:
|
||||
return sync_video_packet(ds);
|
||||
}
|
||||
|
||||
/* stripped down version of a52_syncinfo() from liba52
|
||||
* copyright belongs to Michel Lespinasse <walken@zoy.org>
|
||||
* and Aaron Holtzman <aholtzma@ess.engr.uvic.ca> */
|
||||
int mp_a52_framesize(uint8_t * buf, int *srate)
|
||||
{
|
||||
int rate[] = { 32, 40, 48, 56, 64, 80, 96, 112,
|
||||
128, 160, 192, 224, 256, 320, 384, 448,
|
||||
512, 576, 640
|
||||
};
|
||||
uint8_t halfrate[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3 };
|
||||
int frmsizecod, bitrate, half;
|
||||
|
||||
if ((buf[0] != 0x0b) || (buf[1] != 0x77)) /* syncword */
|
||||
return 0;
|
||||
|
||||
if (buf[5] >= 0x60) /* bsid >= 12 */
|
||||
return 0;
|
||||
|
||||
half = halfrate[buf[5] >> 3];
|
||||
|
||||
frmsizecod = buf[4] & 63;
|
||||
if (frmsizecod >= 38)
|
||||
return 0;
|
||||
|
||||
bitrate = rate[frmsizecod >> 1];
|
||||
|
||||
switch (buf[4] & 0xc0) {
|
||||
case 0: /* 48 KHz */
|
||||
*srate = 48000 >> half;
|
||||
return 4 * bitrate;
|
||||
case 0x40: /* 44.1 KHz */
|
||||
*srate = 44100 >> half;
|
||||
return 2 * (320 * bitrate / 147 + (frmsizecod & 1));
|
||||
case 0x80: /* 32 KHz */
|
||||
*srate = 32000 >> half;
|
||||
return 6 * bitrate;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MPLAYER_PARSE_ES_H
|
||||
#define MPLAYER_PARSE_ES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "demuxer.h"
|
||||
|
||||
#define MAX_VIDEO_PACKET_SIZE (224*1024+4)
|
||||
#define VIDEOBUFFER_SIZE 0x100000
|
||||
|
||||
extern unsigned char* videobuffer;
|
||||
extern int videobuf_len;
|
||||
extern unsigned char videobuf_code[4];
|
||||
extern int videobuf_code_len;
|
||||
|
||||
// sync video stream, and returns next packet code
|
||||
int sync_video_packet(demux_stream_t *ds);
|
||||
|
||||
// return: packet length
|
||||
int read_video_packet(demux_stream_t *ds);
|
||||
|
||||
// return: next packet code
|
||||
int skip_video_packet(demux_stream_t *ds);
|
||||
|
||||
int mp_a52_framesize(uint8_t *buf, int *srate);
|
||||
|
||||
#endif /* MPLAYER_PARSE_ES_H */
|
@ -1,173 +0,0 @@
|
||||
/*
|
||||
* MP4 file format parser code
|
||||
*
|
||||
* Copyright (C) 2002 Felix Buenemann <atmosfear at users.sourceforge.net>
|
||||
* Code inspired by libmp4 from http://mpeg4ip.sourceforge.net/.
|
||||
*
|
||||
* 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 <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include "parse_mp4.h"
|
||||
#include "mp_msg.h"
|
||||
#include "stream/stream.h"
|
||||
|
||||
//#define MP4_DUMPATOM
|
||||
|
||||
#define MP4_DL MSGL_V
|
||||
#define freereturn(a,b) free(a); return b
|
||||
|
||||
static int mp4_read_descr_len(stream_t *s)
|
||||
{
|
||||
uint8_t b;
|
||||
uint8_t numBytes = 0;
|
||||
uint32_t length = 0;
|
||||
|
||||
do {
|
||||
b = stream_read_char(s);
|
||||
numBytes++;
|
||||
length = (length << 7) | (b & 0x7F);
|
||||
} while ((b & 0x80) && numBytes < 4);
|
||||
|
||||
//printf("MP4 read desc len: %d\n", length);
|
||||
return length;
|
||||
}
|
||||
|
||||
/* parse the data part of MP4 esds atoms */
|
||||
int mp4_parse_esds(unsigned char *data, int datalen, esds_t *esds) {
|
||||
/* create memory stream from data */
|
||||
stream_t *s = new_memory_stream(data, datalen);
|
||||
uint16_t len;
|
||||
#ifdef MP4_DUMPATOM
|
||||
{int i;
|
||||
printf("ESDS Dump (%dbyte):\n", datalen);
|
||||
for(i = 0; i < datalen; i++)
|
||||
printf("%02X ", data[i]);
|
||||
printf("\nESDS Dumped\n");}
|
||||
#endif
|
||||
memset(esds, 0, sizeof(esds_t));
|
||||
|
||||
esds->version = stream_read_char(s);
|
||||
esds->flags = stream_read_int24(s);
|
||||
mp_msg(MSGT_DEMUX, MP4_DL,
|
||||
"ESDS MPEG4 version: %d flags: 0x%06X\n",
|
||||
esds->version, esds->flags);
|
||||
|
||||
/* get and verify ES_DescrTag */
|
||||
if (stream_read_char(s) == MP4ESDescrTag) {
|
||||
/* read length */
|
||||
len = mp4_read_descr_len(s);
|
||||
|
||||
esds->ESId = stream_read_word(s);
|
||||
esds->streamPriority = stream_read_char(s);
|
||||
mp_msg(MSGT_DEMUX, MP4_DL,
|
||||
"ESDS MPEG4 ES Descriptor (%dBytes):\n"
|
||||
" -> ESId: %d\n"
|
||||
" -> streamPriority: %d\n",
|
||||
len, esds->ESId, esds->streamPriority);
|
||||
|
||||
if (len < (5 + 15)) {
|
||||
freereturn(s,1);
|
||||
}
|
||||
} else {
|
||||
esds->ESId = stream_read_word(s);
|
||||
mp_msg(MSGT_DEMUX, MP4_DL,
|
||||
"ESDS MPEG4 ES Descriptor (%dBytes):\n"
|
||||
" -> ESId: %d\n", 2, esds->ESId);
|
||||
}
|
||||
|
||||
/* get and verify DecoderConfigDescrTab */
|
||||
if (stream_read_char(s) != MP4DecConfigDescrTag) {
|
||||
freereturn(s,1);
|
||||
}
|
||||
|
||||
/* read length */
|
||||
len = mp4_read_descr_len(s);
|
||||
|
||||
esds->objectTypeId = stream_read_char(s);
|
||||
esds->streamType = stream_read_char(s);
|
||||
esds->bufferSizeDB = stream_read_int24(s);
|
||||
esds->maxBitrate = stream_read_dword(s);
|
||||
esds->avgBitrate = stream_read_dword(s);
|
||||
mp_msg(MSGT_DEMUX, MP4_DL,
|
||||
"ESDS MPEG4 Decoder Config Descriptor (%dBytes):\n"
|
||||
" -> objectTypeId: %d\n"
|
||||
" -> streamType: 0x%02X\n"
|
||||
" -> bufferSizeDB: 0x%06X\n"
|
||||
" -> maxBitrate: %.3fkbit/s\n"
|
||||
" -> avgBitrate: %.3fkbit/s\n",
|
||||
len, esds->objectTypeId, esds->streamType,
|
||||
esds->bufferSizeDB, esds->maxBitrate/1000.0,
|
||||
esds->avgBitrate/1000.0);
|
||||
|
||||
esds->decoderConfigLen=0;
|
||||
|
||||
if (len < 15) {
|
||||
freereturn(s,0);
|
||||
}
|
||||
|
||||
/* get and verify DecSpecificInfoTag */
|
||||
if (stream_read_char(s) != MP4DecSpecificDescrTag) {
|
||||
freereturn(s,0);
|
||||
}
|
||||
|
||||
/* read length */
|
||||
esds->decoderConfigLen = len = mp4_read_descr_len(s);
|
||||
|
||||
esds->decoderConfig = malloc(esds->decoderConfigLen);
|
||||
if (esds->decoderConfig) {
|
||||
stream_read(s, esds->decoderConfig, esds->decoderConfigLen);
|
||||
} else {
|
||||
esds->decoderConfigLen = 0;
|
||||
}
|
||||
mp_msg(MSGT_DEMUX, MP4_DL,
|
||||
"ESDS MPEG4 Decoder Specific Descriptor (%dBytes)\n", len);
|
||||
|
||||
/* get and verify SLConfigDescrTag */
|
||||
if(stream_read_char(s) != MP4SLConfigDescrTag) {
|
||||
freereturn(s,0);
|
||||
}
|
||||
|
||||
/* Note: SLConfig is usually constant value 2, size 1Byte */
|
||||
esds->SLConfigLen = len = mp4_read_descr_len(s);
|
||||
esds->SLConfig = malloc(esds->SLConfigLen);
|
||||
if (esds->SLConfig) {
|
||||
stream_read(s, esds->SLConfig, esds->SLConfigLen);
|
||||
} else {
|
||||
esds->SLConfigLen = 0;
|
||||
}
|
||||
mp_msg(MSGT_DEMUX, MP4_DL,
|
||||
"ESDS MPEG4 Sync Layer Config Descriptor (%dBytes)\n"
|
||||
" -> predefined: %d\n", len, esds->SLConfig[0]);
|
||||
|
||||
/* will skip the remainder of the atom */
|
||||
freereturn(s,0);
|
||||
|
||||
}
|
||||
|
||||
/* cleanup all mem occupied by mp4_parse_esds */
|
||||
void mp4_free_esds(esds_t *esds) {
|
||||
if(esds->decoderConfigLen)
|
||||
free(esds->decoderConfig);
|
||||
if(esds->SLConfigLen)
|
||||
free(esds->SLConfig);
|
||||
}
|
||||
|
||||
#undef freereturn
|
||||
#undef MP4_DL
|
@ -1,127 +0,0 @@
|
||||
/*
|
||||
* MP4 file format parser code
|
||||
*
|
||||
* Copyright (C) 2002 Felix Buenemann <atmosfear at users.sourceforge.net>
|
||||
* Code inspired by libmp4 from http://mpeg4ip.sourceforge.net/.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MPLAYER_PARSE_MP4_H
|
||||
#define MPLAYER_PARSE_MP4_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/* one byte tag identifiers */
|
||||
#define MP4ODescrTag 0x01
|
||||
#define MP4IODescrTag 0x02
|
||||
#define MP4ESDescrTag 0x03
|
||||
#define MP4DecConfigDescrTag 0x04
|
||||
#define MP4DecSpecificDescrTag 0x05
|
||||
#define MP4SLConfigDescrTag 0x06
|
||||
#define MP4ContentIdDescrTag 0x07
|
||||
#define MP4SupplContentIdDescrTag 0x08
|
||||
#define MP4IPIPtrDescrTag 0x09
|
||||
#define MP4IPMPPtrDescrTag 0x0A
|
||||
#define MP4IPMPDescrTag 0x0B
|
||||
#define MP4RegistrationDescrTag 0x0D
|
||||
#define MP4ESIDIncDescrTag 0x0E
|
||||
#define MP4ESIDRefDescrTag 0x0F
|
||||
#define MP4FileIODescrTag 0x10
|
||||
#define MP4FileODescrTag 0x11
|
||||
#define MP4ExtProfileLevelDescrTag 0x13
|
||||
#define MP4ExtDescrTagsStart 0x80
|
||||
#define MP4ExtDescrTagsEnd 0xFE
|
||||
|
||||
/* object type identifiers in the ESDS */
|
||||
/* See http://gpac.sourceforge.net/tutorial/mediatypes.htm */
|
||||
/* BIFS stream version 1 */
|
||||
#define MP4OTI_MPEG4Systems1 0x01
|
||||
/* BIFS stream version 2 */
|
||||
#define MP4OTI_MPEG4Systems2 0x02
|
||||
/* MPEG-4 visual stream */
|
||||
#define MP4OTI_MPEG4Visual 0x20
|
||||
/* MPEG-4 audio stream */
|
||||
#define MP4OTI_MPEG4Audio 0x40
|
||||
/* MPEG-2 visual streams with various profiles */
|
||||
#define MP4OTI_MPEG2VisualSimple 0x60
|
||||
#define MP4OTI_MPEG2VisualMain 0x61
|
||||
#define MP4OTI_MPEG2VisualSNR 0x62
|
||||
#define MP4OTI_MPEG2VisualSpatial 0x63
|
||||
#define MP4OTI_MPEG2VisualHigh 0x64
|
||||
#define MP4OTI_MPEG2Visual422 0x65
|
||||
/* MPEG-2 audio stream part 7 ("AAC") with various profiles */
|
||||
#define MP4OTI_MPEG2AudioMain 0x66
|
||||
#define MP4OTI_MPEG2AudioLowComplexity 0x67
|
||||
#define MP4OTI_MPEG2AudioScaleableSamplingRate 0x68
|
||||
/* MPEG-2 audio part 3 ("MP3") */
|
||||
#define MP4OTI_MPEG2AudioPart3 0x69
|
||||
/* MPEG-1 visual visual stream */
|
||||
#define MP4OTI_MPEG1Visual 0x6A
|
||||
/* MPEG-1 audio stream part 3 ("MP3") */
|
||||
#define MP4OTI_MPEG1Audio 0x6B
|
||||
/* JPEG visual stream */
|
||||
#define MP4OTI_JPEG 0x6C
|
||||
/* 3GPP2 */
|
||||
#define MP4OTI_13kVoice 0xE1
|
||||
|
||||
/* I define uint24 here for better understanding */
|
||||
#ifndef uint24_t
|
||||
#define uint24_t uint32_t
|
||||
#endif
|
||||
|
||||
/* esds_t */
|
||||
typedef struct {
|
||||
uint8_t version;
|
||||
uint24_t flags;
|
||||
|
||||
/* 0x03 ESDescrTag */
|
||||
uint16_t ESId;
|
||||
uint8_t streamPriority;
|
||||
|
||||
/* 0x04 DecConfigDescrTag */
|
||||
uint8_t objectTypeId;
|
||||
uint8_t streamType;
|
||||
/* XXX: really streamType is
|
||||
* only 6bit, followed by:
|
||||
* 1bit upStream
|
||||
* 1bit reserved
|
||||
*/
|
||||
uint24_t bufferSizeDB;
|
||||
uint32_t maxBitrate;
|
||||
uint32_t avgBitrate;
|
||||
|
||||
/* 0x05 DecSpecificDescrTag */
|
||||
uint16_t decoderConfigLen;
|
||||
uint8_t *decoderConfig;
|
||||
|
||||
/* 0x06 SLConfigDescrTag */
|
||||
uint8_t SLConfigLen;
|
||||
uint8_t *SLConfig;
|
||||
|
||||
/* TODO: add the missing tags,
|
||||
* I currently have no specs
|
||||
* for them and doubt they
|
||||
* are currently needed ::atmos
|
||||
*/
|
||||
|
||||
} esds_t;
|
||||
|
||||
int mp4_parse_esds(unsigned char *data, int datalen, esds_t *esds);
|
||||
void mp4_free_esds(esds_t *esds);
|
||||
|
||||
#endif /* MPLAYER_PARSE_MP4_H */
|
@ -36,8 +36,6 @@
|
||||
#include "demux_ty_osd.h"
|
||||
#endif
|
||||
#include "stheader.h"
|
||||
#include "parse_es.h"
|
||||
#include "mpeg_hdr.h"
|
||||
|
||||
/* sub_cc (closed captions)*/
|
||||
#include "sub/sub_cc.h"
|
||||
@ -49,64 +47,9 @@
|
||||
#include "demux_rtp.h"
|
||||
#endif
|
||||
|
||||
static mp_mpeg_header_t picture;
|
||||
|
||||
static int telecine=0;
|
||||
static float telecine_cnt=-2.5;
|
||||
|
||||
typedef enum {
|
||||
VIDEO_MPEG12,
|
||||
VIDEO_MPEG4,
|
||||
VIDEO_H264,
|
||||
VIDEO_VC1,
|
||||
VIDEO_OTHER
|
||||
} video_codec_t;
|
||||
|
||||
static video_codec_t find_video_codec(sh_video_t *sh_video)
|
||||
{
|
||||
demux_stream_t *d_video=sh_video->ds;
|
||||
int fmt = d_video->demuxer->file_format;
|
||||
|
||||
if(
|
||||
(fmt == DEMUXER_TYPE_PVA) ||
|
||||
(fmt == DEMUXER_TYPE_MPEG_ES) ||
|
||||
(fmt == DEMUXER_TYPE_MPEG_GXF) ||
|
||||
(fmt == DEMUXER_TYPE_MPEG_PES) ||
|
||||
(
|
||||
(fmt == DEMUXER_TYPE_MPEG_PS || fmt == DEMUXER_TYPE_MPEG_TS) &&
|
||||
((! sh_video->format) || (sh_video->format==0x10000001) || (sh_video->format==0x10000002))
|
||||
) ||
|
||||
(fmt == DEMUXER_TYPE_MPEG_TY)
|
||||
#ifdef CONFIG_LIVE555
|
||||
|| ((fmt == DEMUXER_TYPE_RTP) && demux_is_mpeg_rtp_stream(d_video->demuxer))
|
||||
#endif
|
||||
)
|
||||
return VIDEO_MPEG12;
|
||||
else if((fmt == DEMUXER_TYPE_MPEG4_ES) ||
|
||||
((fmt == DEMUXER_TYPE_MPEG_TS) && (sh_video->format==0x10000004)) ||
|
||||
((fmt == DEMUXER_TYPE_MPEG_PS) && (sh_video->format==0x10000004))
|
||||
)
|
||||
return VIDEO_MPEG4;
|
||||
else if((fmt == DEMUXER_TYPE_H264_ES) ||
|
||||
((fmt == DEMUXER_TYPE_MPEG_TS) && (sh_video->format==0x10000005)) ||
|
||||
((fmt == DEMUXER_TYPE_MPEG_PS) && (sh_video->format==0x10000005))
|
||||
)
|
||||
return VIDEO_H264;
|
||||
else if((fmt == DEMUXER_TYPE_MPEG_PS || fmt == DEMUXER_TYPE_MPEG_TS) &&
|
||||
(sh_video->format==mmioFOURCC('W', 'V', 'C', '1')))
|
||||
return VIDEO_VC1;
|
||||
else if (fmt == DEMUXER_TYPE_ASF && sh_video->bih && sh_video->bih->biCompression == mmioFOURCC('D', 'V', 'R', ' '))
|
||||
return VIDEO_MPEG12;
|
||||
else
|
||||
return VIDEO_OTHER;
|
||||
}
|
||||
|
||||
int video_read_properties(sh_video_t *sh_video){
|
||||
demux_stream_t *d_video=sh_video->ds;
|
||||
video_codec_t video_codec = find_video_codec(sh_video);
|
||||
// Determine image properties:
|
||||
switch(video_codec){
|
||||
case VIDEO_OTHER: {
|
||||
|
||||
if((d_video->demuxer->file_format == DEMUXER_TYPE_ASF) || (d_video->demuxer->file_format == DEMUXER_TYPE_AVI)) {
|
||||
// display info:
|
||||
// in case no strf chunk has been seen in avi, we have no bitmap header
|
||||
@ -115,464 +58,22 @@ switch(video_codec){
|
||||
sh_video->disp_w=sh_video->bih->biWidth;
|
||||
sh_video->disp_h=abs(sh_video->bih->biHeight);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VIDEO_MPEG4: {
|
||||
int pos = 0, vop_cnt=0, units[3];
|
||||
videobuf_len=0; videobuf_code_len=0;
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V,"Searching for Video Object Start code... ");
|
||||
while(1){
|
||||
int i=sync_video_packet(d_video);
|
||||
if(i<=0x11F) break; // found it!
|
||||
if(!i || !skip_video_packet(d_video)){
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\n");
|
||||
if(!videobuffer) {
|
||||
videobuffer = memalign(8, VIDEOBUFFER_SIZE + MP_INPUT_BUFFER_PADDING_SIZE);
|
||||
if (videobuffer) memset(videobuffer+VIDEOBUFFER_SIZE, 0, MP_INPUT_BUFFER_PADDING_SIZE);
|
||||
else {
|
||||
mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"Cannot allocate shared memory.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V,"Searching for Video Object Layer Start code... ");
|
||||
while(1){
|
||||
int i=sync_video_packet(d_video);
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V,"M4V: 0x%X\n",i);
|
||||
if(i>=0x120 && i<=0x12F) break; // found it!
|
||||
if(!i || !read_video_packet(d_video)){
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
pos = videobuf_len+4;
|
||||
if(!read_video_packet(d_video)){
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Can't read Video Object Layer Header\n");
|
||||
return 0;
|
||||
}
|
||||
mp4_header_process_vol(&picture, &(videobuffer[pos]));
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V,"OK! FPS SEEMS TO BE %.3f\nSearching for Video Object Plane Start code... ", sh_video->fps);
|
||||
mp4_init:
|
||||
while(1){
|
||||
int i=sync_video_packet(d_video);
|
||||
if(i==0x1B6) break; // found it!
|
||||
if(!i || !read_video_packet(d_video)){
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
pos = videobuf_len+4;
|
||||
if(!read_video_packet(d_video)){
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Can't read Video Object Plane Header\n");
|
||||
return 0;
|
||||
}
|
||||
mp4_header_process_vop(&picture, &(videobuffer[pos]));
|
||||
sh_video->disp_w = picture.display_picture_width;
|
||||
sh_video->disp_h = picture.display_picture_height;
|
||||
units[vop_cnt] = picture.timeinc_unit;
|
||||
vop_cnt++;
|
||||
//mp_msg(MSGT_DECVIDEO,MSGL_V, "TYPE: %d, unit: %d\n", picture.picture_type, picture.timeinc_unit);
|
||||
if(!picture.fps) {
|
||||
int i, mn, md, mx, diff;
|
||||
if(vop_cnt < 3)
|
||||
goto mp4_init;
|
||||
|
||||
i=0;
|
||||
mn = mx = units[0];
|
||||
for(i=0; i<3; i++) {
|
||||
if(units[i] < mn)
|
||||
mn = units[i];
|
||||
if(units[i] > mx)
|
||||
mx = units[i];
|
||||
}
|
||||
md = mn;
|
||||
for(i=0; i<3; i++) {
|
||||
if((units[i] > mn) && (units[i] < mx))
|
||||
md = units[i];
|
||||
}
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V, "MIN: %d, mid: %d, max: %d\n", mn, md, mx);
|
||||
if(mx - md > md - mn)
|
||||
diff = md - mn;
|
||||
else
|
||||
diff = mx - md;
|
||||
if(diff > 0){
|
||||
picture.fps = ((float)picture.timeinc_resolution) / diff;
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V, "FPS seems to be: %f, resolution: %d, delta_units: %d\n", picture.fps, picture.timeinc_resolution, diff);
|
||||
}
|
||||
}
|
||||
if(picture.fps) {
|
||||
sh_video->fps=picture.fps;
|
||||
sh_video->frametime=1.0/picture.fps;
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_INFO, "FPS seems to be: %f\n", picture.fps);
|
||||
}
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\n");
|
||||
sh_video->format=0x10000004;
|
||||
break;
|
||||
}
|
||||
case VIDEO_H264: {
|
||||
int pos = 0;
|
||||
videobuf_len=0; videobuf_code_len=0;
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V,"Searching for sequence parameter set... ");
|
||||
while(1){
|
||||
int i=sync_video_packet(d_video);
|
||||
if((i&~0x60) == 0x107 && i != 0x107) break; // found it!
|
||||
if(!i || !skip_video_packet(d_video)){
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\n");
|
||||
if(!videobuffer) {
|
||||
videobuffer = memalign(8, VIDEOBUFFER_SIZE + MP_INPUT_BUFFER_PADDING_SIZE);
|
||||
if (videobuffer) memset(videobuffer+VIDEOBUFFER_SIZE, 0, MP_INPUT_BUFFER_PADDING_SIZE);
|
||||
else {
|
||||
mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"Cannot allocate shared memory.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
pos = videobuf_len+4;
|
||||
if(!read_video_packet(d_video)){
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Can't read sequence parameter set\n");
|
||||
return 0;
|
||||
}
|
||||
h264_parse_sps(&picture, &(videobuffer[pos]), videobuf_len - pos);
|
||||
sh_video->disp_w=picture.display_picture_width;
|
||||
sh_video->disp_h=picture.display_picture_height;
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V,"Searching for picture parameter set... ");
|
||||
while(1){
|
||||
int i=sync_video_packet(d_video);
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V,"H264: 0x%X\n",i);
|
||||
if((i&~0x60) == 0x108 && i != 0x108) break; // found it!
|
||||
if(!i || !read_video_packet(d_video)){
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\nSearching for Slice... ");
|
||||
while(1){
|
||||
int i=sync_video_packet(d_video);
|
||||
if((i&~0x60) == 0x101 || (i&~0x60) == 0x102 || (i&~0x60) == 0x105) break; // found it!
|
||||
if(!i || !read_video_packet(d_video)){
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\n");
|
||||
sh_video->format=0x10000005;
|
||||
if(picture.fps) {
|
||||
sh_video->fps=picture.fps;
|
||||
sh_video->frametime=1.0/picture.fps;
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_INFO, "FPS seems to be: %f\n", picture.fps);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VIDEO_MPEG12: {
|
||||
if (d_video->demuxer->file_format == DEMUXER_TYPE_ASF) { // DVR-MS
|
||||
if(!sh_video->bih) return 0;
|
||||
sh_video->format=sh_video->bih->biCompression;
|
||||
}
|
||||
mpeg_header_parser:
|
||||
// Find sequence_header first:
|
||||
videobuf_len=0; videobuf_code_len=0;
|
||||
telecine=0; telecine_cnt=-2.5;
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V,"Searching for sequence header... ");
|
||||
while(1){
|
||||
int i=sync_video_packet(d_video);
|
||||
if(i==0x1B3) break; // found it!
|
||||
if(!i || !skip_video_packet(d_video)){
|
||||
if( mp_msg_test(MSGT_DECVIDEO,MSGL_V) ) mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n");
|
||||
mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"MPEG: FATAL: EOF while searching for sequence header.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\n");
|
||||
// ========= Read & process sequence header & extension ============
|
||||
if(!videobuffer) {
|
||||
videobuffer = memalign(8, VIDEOBUFFER_SIZE + MP_INPUT_BUFFER_PADDING_SIZE);
|
||||
if (videobuffer) memset(videobuffer+VIDEOBUFFER_SIZE, 0, MP_INPUT_BUFFER_PADDING_SIZE);
|
||||
else {
|
||||
mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"Cannot allocate shared memory.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(!read_video_packet(d_video)){
|
||||
mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"FATAL: Cannot read sequence header.\n");
|
||||
return 0;
|
||||
}
|
||||
if(mp_header_process_sequence_header (&picture, &videobuffer[4])) {
|
||||
mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"MPEG: bad sequence header\n");
|
||||
goto mpeg_header_parser;
|
||||
}
|
||||
if(sync_video_packet(d_video)==0x1B5){ // next packet is seq. ext.
|
||||
int pos=videobuf_len;
|
||||
if(!read_video_packet(d_video)){
|
||||
mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"FATAL: Cannot read sequence header extension.\n");
|
||||
return 0;
|
||||
}
|
||||
if(mp_header_process_extension (&picture, &videobuffer[pos+4])) {
|
||||
mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"MPEG: bad sequence header extension\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// display info:
|
||||
sh_video->format=picture.mpeg1?0x10000001:0x10000002; // mpeg video
|
||||
sh_video->fps=picture.fps * picture.frame_rate_extension_n / picture.frame_rate_extension_d;
|
||||
if(!sh_video->fps){
|
||||
sh_video->frametime=0;
|
||||
} else {
|
||||
sh_video->frametime=1.0/sh_video->fps;
|
||||
}
|
||||
sh_video->disp_w=picture.display_picture_width;
|
||||
sh_video->disp_h=picture.display_picture_height;
|
||||
// bitrate:
|
||||
if(picture.bitrate!=0x3FFFF) // unspecified/VBR ?
|
||||
sh_video->i_bps=picture.bitrate * 400 / 8;
|
||||
// info:
|
||||
mp_dbg(MSGT_DECVIDEO,MSGL_DBG2,"mpeg bitrate: %d (%X)\n",picture.bitrate,picture.bitrate);
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_INFO,"VIDEO: %s %dx%d (aspect %d) %5.3f fps %5.1f kbps (%4.1f kbyte/s)\n",
|
||||
picture.mpeg1?"MPEG1":"MPEG2",
|
||||
sh_video->disp_w,sh_video->disp_h,
|
||||
picture.aspect_ratio_information,
|
||||
sh_video->fps,
|
||||
sh_video->i_bps * 8 / 1000.0,
|
||||
sh_video->i_bps / 1000.0 );
|
||||
break;
|
||||
}
|
||||
case VIDEO_VC1: {
|
||||
// Find sequence_header:
|
||||
videobuf_len=0;
|
||||
videobuf_code_len=0;
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_INFO,"Searching for VC1 sequence header... ");
|
||||
while(1){
|
||||
int i=sync_video_packet(d_video);
|
||||
if(i==0x10F) break; // found it!
|
||||
if(!i || !skip_video_packet(d_video)){
|
||||
if( mp_msg_test(MSGT_DECVIDEO,MSGL_V) ) mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n");
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_ERR, "Couldn't find VC-1 sequence header\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_INFO,"found\n");
|
||||
if(!videobuffer) {
|
||||
videobuffer = memalign(8, VIDEOBUFFER_SIZE + MP_INPUT_BUFFER_PADDING_SIZE);
|
||||
if (videobuffer) memset(videobuffer+VIDEOBUFFER_SIZE, 0, MP_INPUT_BUFFER_PADDING_SIZE);
|
||||
else {
|
||||
mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"Cannot allocate shared memory.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(!read_video_packet(d_video)){
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_ERR, "Couldn't read VC-1 sequence header!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
int i=sync_video_packet(d_video);
|
||||
if(i==0x10E) break; // found it!
|
||||
if(!i || !skip_video_packet(d_video)){
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V,"Couldn't find VC-1 entry point sync-code:(\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(!read_video_packet(d_video)){
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_V,"Couldn't read VC-1 entry point sync-code:(\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(mp_vc1_decode_sequence_header(&picture, &videobuffer[4], videobuf_len-4)) {
|
||||
sh_video->bih = calloc(1, sizeof(*sh_video->bih) + videobuf_len);
|
||||
if(sh_video->bih == NULL) {
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Couldn't alloc %zu bytes for VC-1 extradata!\n", sizeof(*sh_video->bih) + videobuf_len);
|
||||
return 0;
|
||||
}
|
||||
sh_video->bih->biSize= sizeof(*sh_video->bih) + videobuf_len;
|
||||
memcpy(sh_video->bih + 1, videobuffer, videobuf_len);
|
||||
sh_video->bih->biCompression = sh_video->format;
|
||||
sh_video->bih->biWidth = sh_video->disp_w = picture.display_picture_width;
|
||||
sh_video->bih->biHeight = sh_video->disp_h = picture.display_picture_height;
|
||||
if(picture.fps > 0) {
|
||||
sh_video->frametime=1.0/picture.fps;
|
||||
sh_video->fps = picture.fps;
|
||||
}
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_INFO,"VIDEO: VC-1 %dx%d, %5.3f fps, header len: %d\n",
|
||||
sh_video->disp_w, sh_video->disp_h, sh_video->fps, videobuf_len);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} // switch(file_format)
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void process_userdata(const unsigned char* buf,int len){
|
||||
int i;
|
||||
/* if the user data starts with "CC", assume it is a CC info packet */
|
||||
if(len>2 && buf[0]=='C' && buf[1]=='C'){
|
||||
// mp_msg(MSGT_DECVIDEO,MSGL_DBG2,"video.c: process_userdata() detected Closed Captions!\n");
|
||||
subcc_process_data(buf+2,len-2);
|
||||
}
|
||||
#ifdef DEMUX_TY_OSD
|
||||
if( len > 2 && buf[ 0 ] == 'T' && buf[ 1 ] == 'Y' )
|
||||
{
|
||||
ty_processuserdata( buf + 2, len - 2 );
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if(verbose<2) return;
|
||||
fprintf(stderr, "user_data: len=%3d %02X %02X %02X %02X '",
|
||||
len, buf[0], buf[1], buf[2], buf[3]);
|
||||
for(i=0;i<len;i++)
|
||||
// if(buf[i]>=32 && buf[i]<127) fputc(buf[i], stderr);
|
||||
if(buf[i]&0x60) fputc(buf[i]&0x7F, stderr);
|
||||
fprintf(stderr, "'\n");
|
||||
}
|
||||
|
||||
int video_read_frame(sh_video_t* sh_video,float* frame_time_ptr,unsigned char** start,int force_fps){
|
||||
demux_stream_t *d_video=sh_video->ds;
|
||||
demuxer_t *demuxer=d_video->demuxer;
|
||||
float frame_time=1;
|
||||
float pts1=d_video->pts;
|
||||
float pts=0;
|
||||
float fps;
|
||||
int picture_coding_type=0;
|
||||
int in_size=0;
|
||||
video_codec_t video_codec = find_video_codec(sh_video);
|
||||
|
||||
*start=NULL;
|
||||
|
||||
if(video_codec == VIDEO_MPEG12){
|
||||
int in_frame=0;
|
||||
//float newfps;
|
||||
//videobuf_len=0;
|
||||
while(videobuf_len<VIDEOBUFFER_SIZE-MAX_VIDEO_PACKET_SIZE){
|
||||
int i=sync_video_packet(d_video);
|
||||
//void* buffer=&videobuffer[videobuf_len+4];
|
||||
int start=videobuf_len+4;
|
||||
if(in_frame){
|
||||
if(i<0x101 || i>=0x1B0){ // not slice code -> end of frame
|
||||
if(!i) return -1; // EOF
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if(i==0x100){
|
||||
pts=d_video->pts;
|
||||
d_video->pts=0;
|
||||
}
|
||||
if(i>=0x101 && i<0x1B0) in_frame=1; // picture startcode
|
||||
else if(!i) return -1; // EOF
|
||||
}
|
||||
if(!read_video_packet(d_video)) return -1; // EOF
|
||||
// process headers:
|
||||
switch(i){
|
||||
case 0x1B3: mp_header_process_sequence_header (&picture, &videobuffer[start]);break;
|
||||
case 0x1B5: mp_header_process_extension (&picture, &videobuffer[start]);break;
|
||||
case 0x1B2: process_userdata (&videobuffer[start], videobuf_len-start);break;
|
||||
case 0x100: picture_coding_type=(videobuffer[start+1] >> 3) & 7;break;
|
||||
}
|
||||
}
|
||||
fps = picture.fps * picture.frame_rate_extension_n / picture.frame_rate_extension_d;
|
||||
|
||||
*start=videobuffer; in_size=videobuf_len;
|
||||
|
||||
// get mpeg fps:
|
||||
if(sh_video->fps!=fps) if(!force_fps && !telecine){
|
||||
mp_msg(MSGT_CPLAYER,MSGL_WARN,"Warning! FPS changed %5.3f -> %5.3f (%f) [%d] \n",sh_video->fps,fps,sh_video->fps-fps,picture.frame_rate_code);
|
||||
sh_video->fps=fps;
|
||||
sh_video->frametime=1.0/fps;
|
||||
}
|
||||
|
||||
// fix mpeg2 frametime:
|
||||
frame_time=(picture.display_time)*0.01f;
|
||||
picture.display_time=100;
|
||||
videobuf_len=0;
|
||||
|
||||
telecine_cnt*=0.9; // drift out error
|
||||
telecine_cnt+=frame_time-5.0/4.0;
|
||||
mp_msg(MSGT_DECVIDEO,MSGL_DBG2,"\r telecine = %3.1f %5.3f \n",frame_time,telecine_cnt);
|
||||
|
||||
if(telecine){
|
||||
frame_time=1;
|
||||
if(telecine_cnt<-1.5 || telecine_cnt>1.5){
|
||||
mp_tmsg(MSGT_DECVIDEO,MSGL_INFO,"\ndemux_mpg: 30000/1001fps NTSC content detected, switching framerate.\n");
|
||||
telecine=0;
|
||||
}
|
||||
} else
|
||||
if(telecine_cnt>-0.5 && telecine_cnt<0.5 && !force_fps){
|
||||
sh_video->fps=sh_video->fps*4/5;
|
||||
sh_video->frametime=sh_video->frametime*5/4;
|
||||
mp_tmsg(MSGT_DECVIDEO,MSGL_INFO,"\ndemux_mpg: 24000/1001fps progressive NTSC content detected, switching framerate.\n");
|
||||
telecine=1;
|
||||
}
|
||||
} else if(video_codec == VIDEO_MPEG4){
|
||||
while(videobuf_len<VIDEOBUFFER_SIZE-MAX_VIDEO_PACKET_SIZE){
|
||||
int i=sync_video_packet(d_video);
|
||||
if(!i) return -1;
|
||||
if(!read_video_packet(d_video)) return -1; // EOF
|
||||
if(i==0x1B6) break;
|
||||
}
|
||||
*start=videobuffer; in_size=videobuf_len;
|
||||
videobuf_len=0;
|
||||
} else if(video_codec == VIDEO_H264){
|
||||
int in_picture = 0;
|
||||
while(videobuf_len<VIDEOBUFFER_SIZE-MAX_VIDEO_PACKET_SIZE){
|
||||
int i=sync_video_packet(d_video);
|
||||
int pos = videobuf_len+4;
|
||||
if(!i) return -1;
|
||||
if(!read_video_packet(d_video)) return -1; // EOF
|
||||
if((i&~0x60) == 0x107 && i != 0x107) {
|
||||
h264_parse_sps(&picture, &(videobuffer[pos]), videobuf_len - pos);
|
||||
if(picture.fps > 0) {
|
||||
sh_video->fps=picture.fps;
|
||||
sh_video->frametime=1.0/picture.fps;
|
||||
}
|
||||
i=sync_video_packet(d_video);
|
||||
if(!i) return -1;
|
||||
if(!read_video_packet(d_video)) return -1; // EOF
|
||||
}
|
||||
|
||||
// here starts the access unit end detection code
|
||||
// see the mail on MPlayer-dev-eng for details:
|
||||
// Date: Sat, 17 Sep 2005 11:24:06 +0200
|
||||
// Subject: Re: [MPlayer-dev-eng] [RFC] h264 ES parser problems
|
||||
// Message-ID: <20050917092406.GA7699@rz.uni-karlsruhe.de>
|
||||
if((i&~0x60) == 0x101 || (i&~0x60) == 0x102 || (i&~0x60) == 0x105)
|
||||
// found VCL NAL with slice header i.e. start of current primary coded
|
||||
// picture, so start scanning for the end now
|
||||
in_picture = 1;
|
||||
if (in_picture) {
|
||||
i = sync_video_packet(d_video) & ~0x60; // code of next packet
|
||||
if(i == 0x106 || i == 0x109) break; // SEI or access unit delim.
|
||||
if(i == 0x101 || i == 0x102 || i == 0x105) {
|
||||
// assuming arbitrary slice ordering is not allowed, the
|
||||
// first_mb_in_slice (golomb encoded) value should be 0 then
|
||||
// for the first VCL NAL in a picture
|
||||
if (demux_peekc(d_video) & 0x80)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*start=videobuffer; in_size=videobuf_len;
|
||||
videobuf_len=0;
|
||||
} else if(video_codec == VIDEO_VC1) {
|
||||
while(videobuf_len<VIDEOBUFFER_SIZE-MAX_VIDEO_PACKET_SIZE) {
|
||||
int i=sync_video_packet(d_video);
|
||||
if(!i) return -1;
|
||||
if(!read_video_packet(d_video)) return -1; // EOF
|
||||
if(i==0x10D) break;
|
||||
}
|
||||
*start=videobuffer;
|
||||
in_size=videobuf_len;
|
||||
videobuf_len=0;
|
||||
} else {
|
||||
// frame-based file formats: (AVI,ASF,MOV)
|
||||
in_size=ds_get_packet(d_video,start);
|
||||
if(in_size<0) return -1; // EOF
|
||||
}
|
||||
|
||||
|
||||
//------------------------ frame decoded. --------------------
|
||||
@ -592,10 +93,7 @@ int video_read_frame(sh_video_t* sh_video,float* frame_time_ptr,unsigned char**
|
||||
frame_time=d_video->pts-pts1;
|
||||
break;
|
||||
case DEMUXER_TYPE_TV:
|
||||
case DEMUXER_TYPE_MOV:
|
||||
case DEMUXER_TYPE_FILM:
|
||||
case DEMUXER_TYPE_VIVO:
|
||||
case DEMUXER_TYPE_OGG:
|
||||
case DEMUXER_TYPE_ASF: {
|
||||
double next_pts = ds_get_next_pts(d_video);
|
||||
double d= (next_pts != MP_NOPTS_VALUE) ? next_pts - d_video->pts : d_video->pts-pts1;
|
||||
@ -633,21 +131,8 @@ int video_read_frame(sh_video_t* sh_video,float* frame_time_ptr,unsigned char**
|
||||
break;
|
||||
}
|
||||
|
||||
if(video_codec == VIDEO_MPEG12){
|
||||
sh_video->pts+=frame_time;
|
||||
if(picture_coding_type==1)
|
||||
d_video->keyframe = true;
|
||||
if(picture_coding_type<=2 && sh_video->i_pts){
|
||||
sh_video->pts=sh_video->i_pts;
|
||||
sh_video->i_pts=pts;
|
||||
} else {
|
||||
if(pts){
|
||||
if(picture_coding_type<=2) sh_video->i_pts=pts;
|
||||
else sh_video->pts=pts;
|
||||
}
|
||||
}
|
||||
} else
|
||||
sh_video->pts=d_video->pts;
|
||||
|
||||
sh_video->pts=d_video->pts;
|
||||
|
||||
if(frame_time_ptr) *frame_time_ptr=frame_time;
|
||||
return in_size;
|
||||
|
@ -4237,10 +4237,6 @@ goto_enable_cache:
|
||||
mpctx->d_video = mpctx->demuxer->video;
|
||||
mpctx->d_sub = mpctx->demuxer->sub;
|
||||
|
||||
if (ts_prog) {
|
||||
int tmp = ts_prog;
|
||||
mp_property_do("switch_program", M_PROPERTY_SET, &tmp, mpctx);
|
||||
}
|
||||
// select audio stream
|
||||
for (int i = 0; i < mpctx->num_sources; i++)
|
||||
select_audio(mpctx->sources[i].demuxer->audio->demuxer, opts->audio_id,
|
||||
@ -4288,7 +4284,7 @@ goto_enable_cache:
|
||||
while (!ds->eof) {
|
||||
unsigned char *start;
|
||||
int in_size = ds_get_packet(ds, &start);
|
||||
if ((mpctx->demuxer->file_format == DEMUXER_TYPE_AVI || mpctx->demuxer->file_format == DEMUXER_TYPE_ASF || mpctx->demuxer->file_format == DEMUXER_TYPE_MOV)
|
||||
if ((mpctx->demuxer->file_format == DEMUXER_TYPE_AVI || mpctx->demuxer->file_format == DEMUXER_TYPE_ASF)
|
||||
&& stream_dump_type == 2)
|
||||
fwrite(&in_size, 1, 4, f);
|
||||
if (in_size > 0) {
|
||||
|
@ -65,23 +65,8 @@ int network_ipv4_only_proxy = 0;
|
||||
|
||||
|
||||
const mime_struct_t mime_type_table[] = {
|
||||
// Flash Video
|
||||
{ "video/x-flv", DEMUXER_TYPE_LAVF_PREFERRED},
|
||||
// do not force any demuxer in this case!
|
||||
// we want the lavf demuxer to be tried first (happens automatically anyway),
|
||||
// but for mov reference files to work we must also try
|
||||
// the native demuxer if lavf fails.
|
||||
{ "video/quicktime", 0 },
|
||||
// MP3 streaming, some MP3 streaming server answer with audio/mpeg
|
||||
{ "audio/mpeg", DEMUXER_TYPE_AUDIO },
|
||||
// MPEG streaming
|
||||
{ "video/mpeg", DEMUXER_TYPE_UNKNOWN },
|
||||
{ "video/x-mpeg", DEMUXER_TYPE_UNKNOWN },
|
||||
{ "video/x-mpeg2", DEMUXER_TYPE_UNKNOWN },
|
||||
// AVI ??? => video/x-msvideo
|
||||
{ "video/x-msvideo", DEMUXER_TYPE_AVI },
|
||||
// MOV => video/quicktime
|
||||
{ "video/quicktime", DEMUXER_TYPE_MOV },
|
||||
// ASF
|
||||
{ "audio/x-ms-wax", DEMUXER_TYPE_ASF },
|
||||
{ "audio/x-ms-wma", DEMUXER_TYPE_ASF },
|
||||
@ -91,7 +76,6 @@ const mime_struct_t mime_type_table[] = {
|
||||
{ "video/x-ms-wma", DEMUXER_TYPE_ASF },
|
||||
{ "application/x-mms-framed", DEMUXER_TYPE_ASF },
|
||||
{ "application/vnd.ms.wms-hdr.asfv1", DEMUXER_TYPE_ASF },
|
||||
{ "application/octet-stream", DEMUXER_TYPE_UNKNOWN },
|
||||
// Playlists
|
||||
{ "video/x-ms-wmx", DEMUXER_TYPE_PLAYLIST },
|
||||
{ "video/x-ms-wvx", DEMUXER_TYPE_PLAYLIST },
|
||||
@ -100,11 +84,6 @@ const mime_struct_t mime_type_table[] = {
|
||||
{ "audio/x-pls", DEMUXER_TYPE_PLAYLIST },
|
||||
// Real Media
|
||||
// { "audio/x-pn-realaudio", DEMUXER_TYPE_REAL },
|
||||
// OGG Streaming
|
||||
{ "application/x-ogg", DEMUXER_TYPE_OGG },
|
||||
// NullSoft Streaming Video
|
||||
{ "video/nsv", DEMUXER_TYPE_NSV},
|
||||
{ "misc/ultravox", DEMUXER_TYPE_NSV},
|
||||
{ NULL, DEMUXER_TYPE_UNKNOWN},
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user