From 1b8971d82edbcc01f2c29c0adb4ef884d0253262 Mon Sep 17 00:00:00 2001 From: ods15 Date: Sun, 17 Sep 2006 09:32:28 +0000 Subject: Add demux_nut to MPlayer repo git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@19867 b3059339-0415-0410-9bf9-f77b7e298cf2 --- libmpdemux/Makefile | 3 + libmpdemux/demux_nut.c | 316 +++++++++++++++++++++++++++++++++++++++++++++++++ libmpdemux/demuxer.c | 4 + libmpdemux/demuxer.h | 3 +- 4 files changed, 325 insertions(+), 1 deletion(-) create mode 100644 libmpdemux/demux_nut.c (limited to 'libmpdemux') 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 + +#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 -- cgit v1.2.3