summaryrefslogtreecommitdiffstats
path: root/libmpdemux/demux_nut.c
diff options
context:
space:
mode:
authorods15 <ods15@b3059339-0415-0410-9bf9-f77b7e298cf2>2006-09-17 09:32:28 +0000
committerods15 <ods15@b3059339-0415-0410-9bf9-f77b7e298cf2>2006-09-17 09:32:28 +0000
commit1b8971d82edbcc01f2c29c0adb4ef884d0253262 (patch)
tree64b56e035cd04c92c5fb79b74d45dabe0d0cf345 /libmpdemux/demux_nut.c
parentc50e7a3ec8622ee195bdddbff10762a907afba13 (diff)
downloadmpv-1b8971d82edbcc01f2c29c0adb4ef884d0253262.tar.bz2
mpv-1b8971d82edbcc01f2c29c0adb4ef884d0253262.tar.xz
Add demux_nut to MPlayer repo
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@19867 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libmpdemux/demux_nut.c')
-rw-r--r--libmpdemux/demux_nut.c316
1 files changed, 316 insertions, 0 deletions
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
+