stream/tv: move new_handle() function from header to tv.c
[mplayer.git] / libmpdemux / demux_nut.c
blobefa20e0c47aaaa44d90130b9ef48b7123a707608
1 /*
2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include <stdio.h>
20 #include <stdlib.h>
22 #include "config.h"
23 #include "mp_msg.h"
26 #include "stream/stream.h"
27 #include "demuxer.h"
28 #include "stheader.h"
30 #include <libnut.h>
32 typedef struct {
33 int last_pts; // FIXME
34 nut_context_tt * nut;
35 nut_stream_header_tt * s;
36 } nut_priv_tt;
38 static size_t mp_read(void * h, size_t len, uint8_t * buf) {
39 stream_t * stream = (stream_t*)h;
41 if(stream_eof(stream)) return 0;
42 //len = MIN(len, 5);
44 return stream_read(stream, buf, len);
47 static int mp_eof(void * h) {
48 stream_t * stream = (stream_t*)h;
49 if(stream_eof(stream)) return 1;
50 return 0;
53 static off_t mp_seek(void * h, long long pos, int whence) {
54 stream_t * stream = (stream_t*)h;
56 if (stream->end_pos < stream_tell(stream))
57 stream->end_pos = stream_tell(stream);
59 if (whence == SEEK_CUR) pos += stream_tell(stream);
60 else if (whence == SEEK_END) pos += stream->end_pos;
61 else if (whence != SEEK_SET) return -1;
63 if (pos < stream->end_pos && stream->eof) stream_reset(stream);
64 if (stream_seek(stream, pos) == 0) return -1;
66 return pos;
69 #define ID_STRING "nut/multimedia container"
70 #define ID_LENGTH (strlen(ID_STRING) + 1)
72 static int nut_check_file(demuxer_t * demuxer) {
73 uint8_t buf[ID_LENGTH];
75 if (stream_read(demuxer->stream, buf, ID_LENGTH) != ID_LENGTH) return 0;
77 if (memcmp(buf, ID_STRING, ID_LENGTH)) return 0;
79 stream_seek(demuxer->stream, 0);
80 return DEMUXER_TYPE_NUT;
83 static demuxer_t * demux_open_nut(demuxer_t * demuxer) {
84 nut_demuxer_opts_tt dopts = {
85 .input = {
86 .priv = demuxer->stream,
87 .seek = mp_seek,
88 .read = mp_read,
89 .eof = mp_eof,
90 .file_pos = stream_tell(demuxer->stream),
92 .alloc = { .malloc = NULL },
93 .read_index = index_mode,
94 .cache_syncpoints = 1,
96 nut_priv_tt * priv = demuxer->priv = calloc(1, sizeof(nut_priv_tt));
97 nut_context_tt * nut = priv->nut = nut_demuxer_init(&dopts);
98 nut_stream_header_tt * s;
99 int ret;
100 int i;
102 while ((ret = nut_read_headers(nut, &s, NULL)) == NUT_ERR_EAGAIN);
103 if (ret) {
104 mp_msg(MSGT_HEADER, MSGL_ERR, "NUT error: %s\n", nut_error(ret));
105 return NULL;
108 priv->s = s;
110 for (i = 0; s[i].type != -1 && i < 2; i++) switch(s[i].type) {
111 case NUT_AUDIO_CLASS: {
112 WAVEFORMATEX *wf =
113 calloc(sizeof(*wf) +
114 s[i].codec_specific_len, 1);
115 sh_audio_t* sh_audio = new_sh_audio(demuxer, i);
116 int j;
117 mp_tmsg(MSGT_DEMUX, MSGL_INFO, "[%s] Audio stream found, -aid %d\n", "nut", i);
119 sh_audio->wf= wf; sh_audio->ds = demuxer->audio;
120 sh_audio->audio.dwSampleSize = 0; // FIXME
121 sh_audio->audio.dwScale = s[i].time_base.num;
122 sh_audio->audio.dwRate = s[i].time_base.den;
123 sh_audio->format = 0;
124 for (j = 0; j < s[i].fourcc_len && j < 4; j++)
125 sh_audio->format |= s[i].fourcc[j]<<(j*8);
126 sh_audio->channels = s[i].channel_count;
127 sh_audio->samplerate =
128 s[i].samplerate_num / s[i].samplerate_denom;
129 sh_audio->i_bps = 0; // FIXME
131 wf->wFormatTag = sh_audio->format;
132 wf->nChannels = s[i].channel_count;
133 wf->nSamplesPerSec =
134 s[i].samplerate_num / s[i].samplerate_denom;
135 wf->nAvgBytesPerSec = 0; // FIXME
136 wf->nBlockAlign = 0; // FIXME
137 wf->wBitsPerSample = 0; // FIXME
138 wf->cbSize = s[i].codec_specific_len;
139 if (s[i].codec_specific_len)
140 memcpy(wf + 1, s[i].codec_specific,
141 s[i].codec_specific_len);
143 demuxer->audio->id = i;
144 demuxer->audio->sh= demuxer->a_streams[i];
145 break;
147 case NUT_VIDEO_CLASS: {
148 BITMAPINFOHEADER * bih =
149 calloc(sizeof(*bih) +
150 s[i].codec_specific_len, 1);
151 sh_video_t * sh_video = new_sh_video(demuxer, i);
152 int j;
153 mp_tmsg(MSGT_DEMUX, MSGL_INFO, "[%s] Video stream found, -vid %d\n", "nut", i);
155 sh_video->bih = bih;
156 sh_video->ds = demuxer->video;
157 sh_video->disp_w = s[i].width;
158 sh_video->disp_h = s[i].height;
159 sh_video->video.dwScale = s[i].time_base.num;
160 sh_video->video.dwRate = s[i].time_base.den;
162 sh_video->fps = sh_video->video.dwRate/
163 (float)sh_video->video.dwScale;
164 sh_video->frametime = 1./sh_video->fps;
165 sh_video->format = 0;
166 for (j = 0; j < s[i].fourcc_len && j < 4; j++)
167 sh_video->format |= s[i].fourcc[j]<<(j*8);
168 if (!s[i].sample_height) sh_video->aspect = 0;
169 else sh_video->aspect =
170 s[i].sample_width / (float)s[i].sample_height;
171 sh_video->i_bps = 0; // FIXME
173 bih->biSize = sizeof(*bih) +
174 s[i].codec_specific_len;
175 bih->biWidth = s[i].width;
176 bih->biHeight = s[i].height;
177 bih->biBitCount = 0; // FIXME
178 bih->biSizeImage = 0; // FIXME
179 bih->biCompression = sh_video->format;
181 if (s[i].codec_specific_len)
182 memcpy(bih + 1, s[i].codec_specific,
183 s[i].codec_specific_len);
185 demuxer->video->id = i;
186 demuxer->video->sh = demuxer->v_streams[i];
187 break;
191 return demuxer;
194 static int demux_nut_fill_buffer(demuxer_t * demuxer, demux_stream_t * dsds) {
195 nut_priv_tt * priv = demuxer->priv;
196 nut_context_tt * nut = priv->nut;
197 demux_packet_t *dp;
198 demux_stream_t *ds;
199 nut_packet_tt pd;
200 int ret;
201 double pts;
203 demuxer->filepos = stream_tell(demuxer->stream);
204 if (stream_eof(demuxer->stream)) return 0;
206 while ((ret = nut_read_next_packet(nut, &pd)) == NUT_ERR_EAGAIN);
207 if (ret) {
208 if (ret != NUT_ERR_EOF)
209 mp_msg(MSGT_HEADER, MSGL_ERR, "NUT error: %s\n",
210 nut_error(ret));
211 return 0; // fatal error
214 pts = (double)pd.pts * priv->s[pd.stream].time_base.num /
215 priv->s[pd.stream].time_base.den;
217 if (pd.stream == demuxer->audio->id) {
218 ds = demuxer->audio;
220 else if (pd.stream == demuxer->video->id) {
221 ds = demuxer->video;
223 else {
224 uint8_t buf[pd.len];
225 while ((ret = nut_read_frame(nut, &pd.len, buf)) == NUT_ERR_EAGAIN);
226 if (ret) {
227 mp_msg(MSGT_HEADER, MSGL_ERR, "NUT error: %s\n",
228 nut_error(ret));
229 return 0; // fatal error
231 return 1;
234 if (pd.stream == 0) priv->last_pts = pd.pts;
236 dp = new_demux_packet(pd.len);
238 dp->pts = pts;
240 dp->pos = demuxer->filepos;
241 dp->flags= (pd.flags & NUT_FLAG_KEY) ? 0x10 : 0;
243 {int len = pd.len;
244 while ((ret = nut_read_frame(nut, &len, dp->buffer + pd.len-len)) == NUT_ERR_EAGAIN);
246 if (ret) {
247 mp_msg(MSGT_HEADER, MSGL_ERR, "NUT error: %s\n",
248 nut_error(ret));
249 return 0; // fatal error
252 ds_add_packet(ds, dp); // append packet to DS stream
253 return 1;
256 static void demux_seek_nut(demuxer_t * demuxer, float time_pos, float audio_delay, int flags) {
257 nut_context_tt * nut = ((nut_priv_tt*)demuxer->priv)->nut;
258 nut_priv_tt * priv = demuxer->priv;
259 int nutflags = 0;
260 int ret;
261 const int tmp[] = { 0, -1 };
263 if (!(flags & SEEK_ABSOLUTE)) {
264 nutflags |= 1; // relative
265 if (time_pos > 0) nutflags |= 2; // forwards
268 if (flags & SEEK_FACTOR)
269 time_pos *= priv->s[0].max_pts *
270 (double)priv->s[0].time_base.num /
271 priv->s[0].time_base.den;
273 while ((ret = nut_seek(nut, time_pos, nutflags, tmp)) == NUT_ERR_EAGAIN);
274 priv->last_pts = -1;
275 if (ret) mp_msg(MSGT_HEADER, MSGL_ERR, "NUT error: %s\n", nut_error(ret));
276 demuxer->filepos = stream_tell(demuxer->stream);
279 static int demux_control_nut(demuxer_t * demuxer, int cmd, void * arg) {
280 nut_priv_tt * priv = demuxer->priv;
281 switch (cmd) {
282 case DEMUXER_CTRL_GET_TIME_LENGTH:
283 *((double *)arg) = priv->s[0].max_pts *
284 (double)priv->s[0].time_base.num /
285 priv->s[0].time_base.den;
286 return DEMUXER_CTRL_OK;
287 case DEMUXER_CTRL_GET_PERCENT_POS:
288 if (priv->s[0].max_pts == 0 || priv->last_pts == -1)
289 return DEMUXER_CTRL_DONTKNOW;
290 *((int *)arg) = priv->last_pts * 100 /
291 (double)priv->s[0].max_pts;
292 return DEMUXER_CTRL_OK;
293 default:
294 return DEMUXER_CTRL_NOTIMPL;
298 static void demux_close_nut(demuxer_t *demuxer) {
299 nut_priv_tt * priv = demuxer->priv;
300 if (!priv) return;
301 nut_demuxer_uninit(priv->nut);
302 free(demuxer->priv);
303 demuxer->priv = NULL;
307 const demuxer_desc_t demuxer_desc_nut = {
308 "NUT demuxer",
309 "nut",
310 "libnut",
311 "Oded Shimon (ods15)",
312 "NUT demuxer, requires libnut",
313 DEMUXER_TYPE_NUT,
314 1, // safe check demuxer
315 nut_check_file,
316 demux_nut_fill_buffer,
317 demux_open_nut,
318 demux_close_nut,
319 demux_seek_nut,
320 demux_control_nut