summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rwxr-xr-xconfigure32
-rw-r--r--libmpdemux/Makefile3
-rw-r--r--libmpdemux/demux_nut.c316
-rw-r--r--libmpdemux/demuxer.c4
-rw-r--r--libmpdemux/demuxer.h3
6 files changed, 358 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index bf5ef17574..9d06fd14cd 100644
--- a/Makefile
+++ b/Makefile
@@ -110,6 +110,7 @@ CODEC_LIBS = $(AV_LIB) \
$(X264_LIB) \
$(MUSEPACK_LIB) \
$(SPEEX_LIB) \
+ $(NUT_LIB) \
ifeq ($(TOOLAME),yes)
CODEC_LIBS += $(TOOLAME_LIB)
diff --git a/configure b/configure
index 87e9dd7d08..c5b7dc37c5 100755
--- a/configure
+++ b/configure
@@ -263,6 +263,7 @@ Codecs:
--disable-real disable RealPlayer DLL support [autodetect]
--disable-xvid disable XviD codec [autodetect]
--disable-x264 disable H.264 encoder [autodetect]
+ --disable-nut disable libnut demuxer [autodetect]
--disable-libavutil disable libavutil [autodetect]
--disable-libavcodec disable libavcodec [autodetect]
--disable-libavformat disable libavformat [autodetect]
@@ -1671,6 +1672,7 @@ _vidix_external=auto
_joystick=no
_xvid=auto
_x264=auto
+_nut=auto
_lirc=auto
_lircc=auto
_gui=no
@@ -1929,6 +1931,8 @@ for ac_option do
--disable-xvid) _xvid=no ;;
--enable-x264) _x264=yes ;;
--disable-x264) _x264=no ;;
+ --enable-nut) _nut=yes ;;
+ --disable-nut) _nut=no ;;
--enable-libavutil) _libavutil=yes ;;
--disable-libavutil) _libavutil=no ;;
--enable-libavutil_so) _libavutil_so=yes ;;
@@ -6518,6 +6522,29 @@ fi
echores "$_x264"
+echocheck "nut"
+if test "$_nut" = auto ; then
+ cat > $TMPC << EOF
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <nut.h>
+int main(void) { (void)nut_error(0); return 0; }
+EOF
+ _ld_nut="-lnut"
+ _nut=no
+ cc_check $_ld_nut && _nut=yes
+fi
+
+if test "$_nut" = yes ; then
+ _def_nut='#define HAVE_LIBNUT 1'
+else
+ _ld_nut=''
+ _def_nut='#undef HAVE_LIBNUT'
+fi
+echores "$_nut"
+
+
# mencoder requires (optional) those libs: libmp3lame
if test "$_mencoder" != no ; then
@@ -7476,6 +7503,8 @@ XVID4 = $_xvid4
XVID_LIB = $_ld_xvid
X264 = $_x264
X264_LIB = $_ld_x264
+LIBNUT = $_nut
+NUT_LIB = $_ld_nut
CONFIG_DTS = $_libdts
DTS_LIB = $_ld_libdts
DECORE_LIB = $_ld_mp3lame
@@ -7667,6 +7696,9 @@ $_def_encore_xvid
/* Define if you are using the X.264 library */
$_def_x264
+/* Define if you are using libnut */
+$_def_nut
+
/* Define to include support for libdv-0.9.5 */
$_def_libdv
diff --git a/libmpdemux/Makefile b/libmpdemux/Makefile
index 0beef8b0e0..d7d6e5074e 100644
--- a/libmpdemux/Makefile
+++ b/libmpdemux/Makefile
@@ -53,6 +53,9 @@ SRCS += demuxer.c \
demux_y4m.c \
demux_mkv.c ebml.c \
+ifeq ($(LIBNUT),yes)
+SRCS += demux_nut.c
+endif
ifeq ($(LIBVORBIS),yes)
SRCS += demux_ogg.c
endif
diff --git a/libmpdemux/demux_nut.c b/libmpdemux/demux_nut.c
new file mode 100644
index 0000000000..a0851eafb5
--- /dev/null
+++ b/libmpdemux/demux_nut.c
@@ -0,0 +1,316 @@
+#include <stdio.h>
+
+#include "config.h"
+#include "mp_msg.h"
+
+#include "stream.h"
+#include "demuxer.h"
+#include "stheader.h"
+
+#define USE_LIBNUT
+#ifdef USE_LIBNUT
+
+#include "nut.h"
+
+typedef struct {
+ int last_pts; // FIXME
+ nut_context_t * nut;
+ nut_stream_header_t * s;
+} nut_priv_t;
+
+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;
+
+ return stream_read(stream, buf, len);
+}
+
+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];
+ nut_priv_t * priv = demuxer->priv = calloc(1, sizeof(nut_priv_t));
+
+ 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) {
+ extern int index_mode;
+ nut_demuxer_opts_t dopts = {
+ .input = {
+ .priv = demuxer->stream,
+ .seek = mp_seek,
+ .read = mp_read,
+ .eof = NULL,
+ .file_pos = stream_tell(demuxer->stream),
+ },
+ .read_index = index_mode
+ };
+ nut_priv_t * priv = demuxer->priv;
+ nut_context_t * nut = priv->nut = nut_demuxer_init(&dopts);
+ nut_stream_header_t * s;
+ int ret;
+ int i;
+
+ if ((ret = nut_read_headers(nut, &s))) {
+ if (ret < 0) mp_msg(MSGT_HEADER, MSGL_ERR, "NUT error: %s\n",
+ nut_error(-ret));
+ nut_demuxer_uninit(nut);
+ free(priv);
+ 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(WAVEFORMATEX) +
+ s[i].codec_specific_len, 1);
+ sh_audio_t* sh_audio = new_sh_audio(demuxer, i);
+ int j;
+
+ sh_audio->wf= wf; sh_audio->ds = demuxer->audio;
+ sh_audio->audio.dwSampleSize = 0; // FIXME
+ sh_audio->audio.dwScale = s[i].time_base.nom;
+ 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_nom / 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_nom / 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(BITMAPINFOHEADER) +
+ s[i].codec_specific_len, 1);
+ sh_video_t * sh_video = new_sh_video(demuxer, i);
+ int j;
+
+ 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.nom;
+ 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(BITMAPINFOHEADER) +
+ 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_t * priv = demuxer->priv;
+ nut_context_t * nut = priv->nut;
+ demux_packet_t *dp;
+ demux_stream_t *ds;
+ nut_packet_t pd;
+ int ret;
+ double pts;
+
+ demuxer->filepos = stream_tell(demuxer->stream);
+ if (stream_eof(demuxer->stream)) return 0;
+
+ while (1) {
+ ret = nut_read_next_packet(nut, &pd);
+ if (ret < 0) {
+ mp_msg(MSGT_HEADER, MSGL_ERR, "NUT error: %s\n",
+ nut_error(-ret));
+ continue;
+ }
+ if (ret == 1) return 0; // EOF
+ if (pd.type == e_frame) break;
+ // else, skip this packet
+ while ((ret = nut_skip_packet(nut, &pd.len))) {
+ if (ret < 0) {
+ mp_msg(MSGT_HEADER, MSGL_ERR,
+ "NUT error: %s\n", nut_error(-ret));
+ break;
+ }
+ if (ret == 1) return 0; // EOF
+ }
+ }
+
+ pts = (double)pd.pts * priv->s[pd.stream].time_base.nom /
+ priv->s[pd.stream].time_base.den;
+
+ if (pd.stream == demuxer->audio->id) {
+ ds = demuxer->audio;
+ if (!demuxer->video->sh) {
+ ((sh_audio_t*)ds->sh)->delay = pts;
+ }
+ }
+ else if (pd.stream == demuxer->video->id) {
+ ds = demuxer->video;
+ }
+ else {
+ while ((ret = nut_skip_packet(nut, &pd.len))) {
+ if (ret < 0) {
+ mp_msg(MSGT_HEADER, MSGL_ERR,
+ "NUT error: %s\n", nut_error(-ret));
+ break;
+ }
+ if (ret == 1) return 0; // EOF
+ }
+ 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->flags= (pd.flags & NUT_FLAG_KEY) ? 0x10 : 0;
+
+ while ((ret = nut_read_frame(nut, &pd.len, dp->buffer))) {
+ if (ret < 0) {
+ mp_msg(MSGT_HEADER, MSGL_ERR,
+ "NUT error: %s\n", nut_error(-ret));
+ break;
+ }
+ if (ret == 1) return 0; // EOF
+ }
+ 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_t * nut = ((nut_priv_t*)demuxer->priv)->nut;
+ nut_priv_t * priv = demuxer->priv;
+ sh_audio_t * sh_audio = demuxer->audio->sh;
+ int nutflags = 0;
+ int ret;
+ const int tmp[] = { 0, -1 };
+
+ if (!(flags & 1)) {
+ nutflags |= 1; // relative
+ if (time_pos > 0) nutflags |= 2; // forwards
+ }
+
+ if (flags & 2) // percent
+ time_pos *= priv->s[0].max_pts *
+ (double)priv->s[0].time_base.nom /
+ priv->s[0].time_base.den;
+
+ ret = nut_seek(nut, time_pos, nutflags, tmp);
+ if (ret < 0)
+ mp_msg(MSGT_HEADER, MSGL_ERR, "NUT error: %s\n", nut_error(-ret));
+ if (sh_audio) resync_audio_stream(sh_audio);
+}
+
+static int demux_control_nut(demuxer_t * demuxer, int cmd, void * arg) {
+ nut_priv_t * priv = demuxer->priv;
+ switch (cmd) {
+ case DEMUXER_CTRL_GET_TIME_LENGTH:
+ *((double *)arg) = priv->s[0].max_pts *
+ (double)priv->s[0].time_base.nom /
+ priv->s[0].time_base.den;
+ return DEMUXER_CTRL_OK;
+ case DEMUXER_CTRL_GET_PERCENT_POS:
+ if (priv->s[0].max_pts == 0)
+ 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_context_t * nut = ((nut_priv_t*)demuxer->priv)->nut;
+ nut_demuxer_uninit(nut);
+ free(((nut_priv_t*)demuxer->priv)->s);
+ free(demuxer->priv);
+ demuxer->priv = NULL;
+}
+
+
+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
+};
+
+#endif // USE_LIBNUT
+
diff --git a/libmpdemux/demuxer.c b/libmpdemux/demuxer.c
index c33a4c2af3..f3616034f8 100644
--- a/libmpdemux/demuxer.c
+++ b/libmpdemux/demuxer.c
@@ -66,6 +66,7 @@ extern demuxer_desc_t demuxer_desc_rtp;
extern demuxer_desc_t demuxer_desc_lavf;
#endif
extern demuxer_desc_t demuxer_desc_aac;
+extern demuxer_desc_t demuxer_desc_nut;
demuxer_desc_t* demuxer_list[] = {
&demuxer_desc_rawaudio,
@@ -120,6 +121,9 @@ demuxer_desc_t* demuxer_list[] = {
&demuxer_desc_rawdv,
#endif
&demuxer_desc_aac,
+#ifdef HAVE_LIBNUT
+ &demuxer_desc_nut,
+#endif
#ifdef HAVE_XMMS
&demuxer_desc_xmms,
#endif
diff --git a/libmpdemux/demuxer.h b/libmpdemux/demuxer.h
index 051a2f3d8c..018e05ac7e 100644
--- a/libmpdemux/demuxer.h
+++ b/libmpdemux/demuxer.h
@@ -54,11 +54,12 @@
#define DEMUXER_TYPE_MPC 40
#define DEMUXER_TYPE_MPEG_PES 41
#define DEMUXER_TYPE_MPEG_GXF 42
+#define DEMUXER_TYPE_NUT 43
// This should always match the higest demuxer type number.
// Unless you want to disallow users to force the demuxer to some types
#define DEMUXER_TYPE_MIN 0
-#define DEMUXER_TYPE_MAX 42
+#define DEMUXER_TYPE_MAX 43
#define DEMUXER_TYPE_DEMUXERS (1<<16)
// A virtual demuxer type for the network code