29238
|
1 /*
|
|
2 * This file is part of MPlayer.
|
|
3 *
|
|
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.
|
|
8 *
|
|
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.
|
|
13 *
|
|
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.
|
|
17 */
|
|
18
|
19861
|
19 #include <stdio.h>
|
20815
|
20 #include <stdlib.h>
|
19861
|
21
|
|
22 #include "config.h"
|
|
23 #include "mp_msg.h"
|
|
24
|
23084
|
25 #include "help_mp.h"
|
|
26
|
22605
|
27 #include "stream/stream.h"
|
19861
|
28 #include "demuxer.h"
|
|
29 #include "stheader.h"
|
|
30
|
20893
|
31 #include <libnut.h>
|
19861
|
32
|
|
33 typedef struct {
|
|
34 int last_pts; // FIXME
|
28099
|
35 nut_context_tt * nut;
|
|
36 nut_stream_header_tt * s;
|
|
37 } nut_priv_tt;
|
19861
|
38
|
|
39 static size_t mp_read(void * h, size_t len, uint8_t * buf) {
|
|
40 stream_t * stream = (stream_t*)h;
|
|
41
|
|
42 if(stream_eof(stream)) return 0;
|
21022
|
43 //len = MIN(len, 5);
|
19861
|
44
|
|
45 return stream_read(stream, buf, len);
|
|
46 }
|
|
47
|
21022
|
48 static int mp_eof(void * h) {
|
|
49 stream_t * stream = (stream_t*)h;
|
|
50 if(stream_eof(stream)) return 1;
|
|
51 return 0;
|
|
52 }
|
|
53
|
19861
|
54 static off_t mp_seek(void * h, long long pos, int whence) {
|
|
55 stream_t * stream = (stream_t*)h;
|
|
56
|
|
57 if (stream->end_pos < stream_tell(stream))
|
|
58 stream->end_pos = stream_tell(stream);
|
|
59
|
|
60 if (whence == SEEK_CUR) pos += stream_tell(stream);
|
|
61 else if (whence == SEEK_END) pos += stream->end_pos;
|
|
62 else if (whence != SEEK_SET) return -1;
|
|
63
|
|
64 if (pos < stream->end_pos && stream->eof) stream_reset(stream);
|
|
65 if (stream_seek(stream, pos) == 0) return -1;
|
|
66
|
|
67 return pos;
|
|
68 }
|
|
69
|
|
70 #define ID_STRING "nut/multimedia container"
|
|
71 #define ID_LENGTH (strlen(ID_STRING) + 1)
|
|
72
|
|
73 static int nut_check_file(demuxer_t * demuxer) {
|
|
74 uint8_t buf[ID_LENGTH];
|
|
75
|
|
76 if (stream_read(demuxer->stream, buf, ID_LENGTH) != ID_LENGTH) return 0;
|
|
77
|
|
78 if (memcmp(buf, ID_STRING, ID_LENGTH)) return 0;
|
|
79
|
|
80 stream_seek(demuxer->stream, 0);
|
|
81 return DEMUXER_TYPE_NUT;
|
|
82 }
|
|
83
|
|
84 static demuxer_t * demux_open_nut(demuxer_t * demuxer) {
|
28099
|
85 nut_demuxer_opts_tt dopts = {
|
19861
|
86 .input = {
|
|
87 .priv = demuxer->stream,
|
|
88 .seek = mp_seek,
|
|
89 .read = mp_read,
|
21022
|
90 .eof = mp_eof,
|
19861
|
91 .file_pos = stream_tell(demuxer->stream),
|
|
92 },
|
19957
|
93 .alloc = { .malloc = NULL },
|
20909
|
94 .read_index = index_mode,
|
|
95 .cache_syncpoints = 1,
|
19861
|
96 };
|
28099
|
97 nut_priv_tt * priv = demuxer->priv = calloc(1, sizeof(nut_priv_tt));
|
|
98 nut_context_tt * nut = priv->nut = nut_demuxer_init(&dopts);
|
|
99 nut_stream_header_tt * s;
|
19861
|
100 int ret;
|
|
101 int i;
|
|
102
|
21022
|
103 while ((ret = nut_read_headers(nut, &s, NULL)) == NUT_ERR_EAGAIN);
|
|
104 if (ret) {
|
20938
|
105 mp_msg(MSGT_HEADER, MSGL_ERR, "NUT error: %s\n", nut_error(ret));
|
19861
|
106 return NULL;
|
|
107 }
|
|
108
|
|
109 priv->s = s;
|
|
110
|
|
111 for (i = 0; s[i].type != -1 && i < 2; i++) switch(s[i].type) {
|
|
112 case NUT_AUDIO_CLASS: {
|
|
113 WAVEFORMATEX *wf =
|
32121
|
114 calloc(sizeof(*wf) +
|
19861
|
115 s[i].codec_specific_len, 1);
|
31609
|
116 sh_audio_t* sh_audio = new_sh_audio(demuxer, i, NULL);
|
28101
|
117 int j;
|
23010
|
118 mp_msg(MSGT_DEMUX, MSGL_INFO, MSGTR_AudioID, "nut", i);
|
19861
|
119
|
|
120 sh_audio->wf= wf; sh_audio->ds = demuxer->audio;
|
|
121 sh_audio->audio.dwSampleSize = 0; // FIXME
|
21723
|
122 sh_audio->audio.dwScale = s[i].time_base.num;
|
19861
|
123 sh_audio->audio.dwRate = s[i].time_base.den;
|
|
124 sh_audio->format = 0;
|
|
125 for (j = 0; j < s[i].fourcc_len && j < 4; j++)
|
|
126 sh_audio->format |= s[i].fourcc[j]<<(j*8);
|
|
127 sh_audio->channels = s[i].channel_count;
|
|
128 sh_audio->samplerate =
|
21723
|
129 s[i].samplerate_num / s[i].samplerate_denom;
|
19861
|
130 sh_audio->i_bps = 0; // FIXME
|
|
131
|
|
132 wf->wFormatTag = sh_audio->format;
|
|
133 wf->nChannels = s[i].channel_count;
|
|
134 wf->nSamplesPerSec =
|
21723
|
135 s[i].samplerate_num / s[i].samplerate_denom;
|
19861
|
136 wf->nAvgBytesPerSec = 0; // FIXME
|
|
137 wf->nBlockAlign = 0; // FIXME
|
|
138 wf->wBitsPerSample = 0; // FIXME
|
|
139 wf->cbSize = s[i].codec_specific_len;
|
|
140 if (s[i].codec_specific_len)
|
|
141 memcpy(wf + 1, s[i].codec_specific,
|
|
142 s[i].codec_specific_len);
|
|
143
|
|
144 demuxer->audio->id = i;
|
|
145 demuxer->audio->sh= demuxer->a_streams[i];
|
|
146 break;
|
|
147 }
|
|
148 case NUT_VIDEO_CLASS: {
|
|
149 BITMAPINFOHEADER * bih =
|
32123
|
150 calloc(sizeof(*bih) +
|
19861
|
151 s[i].codec_specific_len, 1);
|
|
152 sh_video_t * sh_video = new_sh_video(demuxer, i);
|
28101
|
153 int j;
|
23010
|
154 mp_msg(MSGT_DEMUX, MSGL_INFO, MSGTR_VideoID, "nut", i);
|
19861
|
155
|
|
156 sh_video->bih = bih;
|
|
157 sh_video->ds = demuxer->video;
|
|
158 sh_video->disp_w = s[i].width;
|
|
159 sh_video->disp_h = s[i].height;
|
21723
|
160 sh_video->video.dwScale = s[i].time_base.num;
|
19861
|
161 sh_video->video.dwRate = s[i].time_base.den;
|
|
162
|
|
163 sh_video->fps = sh_video->video.dwRate/
|
|
164 (float)sh_video->video.dwScale;
|
|
165 sh_video->frametime = 1./sh_video->fps;
|
|
166 sh_video->format = 0;
|
|
167 for (j = 0; j < s[i].fourcc_len && j < 4; j++)
|
|
168 sh_video->format |= s[i].fourcc[j]<<(j*8);
|
|
169 if (!s[i].sample_height) sh_video->aspect = 0;
|
|
170 else sh_video->aspect =
|
|
171 s[i].sample_width / (float)s[i].sample_height;
|
|
172 sh_video->i_bps = 0; // FIXME
|
|
173
|
32123
|
174 bih->biSize = sizeof(*bih) +
|
19861
|
175 s[i].codec_specific_len;
|
|
176 bih->biWidth = s[i].width;
|
|
177 bih->biHeight = s[i].height;
|
|
178 bih->biBitCount = 0; // FIXME
|
|
179 bih->biSizeImage = 0; // FIXME
|
|
180 bih->biCompression = sh_video->format;
|
|
181
|
|
182 if (s[i].codec_specific_len)
|
|
183 memcpy(bih + 1, s[i].codec_specific,
|
|
184 s[i].codec_specific_len);
|
|
185
|
|
186 demuxer->video->id = i;
|
|
187 demuxer->video->sh = demuxer->v_streams[i];
|
|
188 break;
|
|
189 }
|
|
190 }
|
|
191
|
|
192 return demuxer;
|
|
193 }
|
|
194
|
|
195 static int demux_nut_fill_buffer(demuxer_t * demuxer, demux_stream_t * dsds) {
|
28099
|
196 nut_priv_tt * priv = demuxer->priv;
|
|
197 nut_context_tt * nut = priv->nut;
|
19861
|
198 demux_packet_t *dp;
|
|
199 demux_stream_t *ds;
|
28099
|
200 nut_packet_tt pd;
|
19861
|
201 int ret;
|
|
202 double pts;
|
|
203
|
|
204 demuxer->filepos = stream_tell(demuxer->stream);
|
|
205 if (stream_eof(demuxer->stream)) return 0;
|
|
206
|
21022
|
207 while ((ret = nut_read_next_packet(nut, &pd)) == NUT_ERR_EAGAIN);
|
20938
|
208 if (ret) {
|
|
209 if (ret != NUT_ERR_EOF)
|
|
210 mp_msg(MSGT_HEADER, MSGL_ERR, "NUT error: %s\n",
|
|
211 nut_error(ret));
|
|
212 return 0; // fatal error
|
19861
|
213 }
|
|
214
|
21723
|
215 pts = (double)pd.pts * priv->s[pd.stream].time_base.num /
|
19861
|
216 priv->s[pd.stream].time_base.den;
|
|
217
|
|
218 if (pd.stream == demuxer->audio->id) {
|
|
219 ds = demuxer->audio;
|
|
220 }
|
|
221 else if (pd.stream == demuxer->video->id) {
|
|
222 ds = demuxer->video;
|
|
223 }
|
|
224 else {
|
20926
|
225 uint8_t buf[pd.len];
|
21022
|
226 while ((ret = nut_read_frame(nut, &pd.len, buf)) == NUT_ERR_EAGAIN);
|
20938
|
227 if (ret) {
|
19958
|
228 mp_msg(MSGT_HEADER, MSGL_ERR, "NUT error: %s\n",
|
20938
|
229 nut_error(ret));
|
|
230 return 0; // fatal error
|
19861
|
231 }
|
|
232 return 1;
|
|
233 }
|
|
234
|
|
235 if (pd.stream == 0) priv->last_pts = pd.pts;
|
|
236
|
|
237 dp = new_demux_packet(pd.len);
|
|
238
|
|
239 dp->pts = pts;
|
|
240
|
|
241 dp->pos = demuxer->filepos;
|
|
242 dp->flags= (pd.flags & NUT_FLAG_KEY) ? 0x10 : 0;
|
|
243
|
21022
|
244 {int len = pd.len;
|
|
245 while ((ret = nut_read_frame(nut, &len, dp->buffer + pd.len-len)) == NUT_ERR_EAGAIN);
|
|
246 }
|
20938
|
247 if (ret) {
|
19958
|
248 mp_msg(MSGT_HEADER, MSGL_ERR, "NUT error: %s\n",
|
20938
|
249 nut_error(ret));
|
|
250 return 0; // fatal error
|
19861
|
251 }
|
19958
|
252
|
19861
|
253 ds_add_packet(ds, dp); // append packet to DS stream
|
|
254 return 1;
|
|
255 }
|
|
256
|
|
257 static void demux_seek_nut(demuxer_t * demuxer, float time_pos, float audio_delay, int flags) {
|
28099
|
258 nut_context_tt * nut = ((nut_priv_tt*)demuxer->priv)->nut;
|
|
259 nut_priv_tt * priv = demuxer->priv;
|
19861
|
260 int nutflags = 0;
|
|
261 int ret;
|
|
262 const int tmp[] = { 0, -1 };
|
|
263
|
25883
|
264 if (!(flags & SEEK_ABSOLUTE)) {
|
19861
|
265 nutflags |= 1; // relative
|
|
266 if (time_pos > 0) nutflags |= 2; // forwards
|
|
267 }
|
|
268
|
25883
|
269 if (flags & SEEK_FACTOR)
|
19861
|
270 time_pos *= priv->s[0].max_pts *
|
21723
|
271 (double)priv->s[0].time_base.num /
|
19861
|
272 priv->s[0].time_base.den;
|
|
273
|
21022
|
274 while ((ret = nut_seek(nut, time_pos, nutflags, tmp)) == NUT_ERR_EAGAIN);
|
21023
|
275 priv->last_pts = -1;
|
20971
|
276 if (ret) mp_msg(MSGT_HEADER, MSGL_ERR, "NUT error: %s\n", nut_error(ret));
|
21023
|
277 demuxer->filepos = stream_tell(demuxer->stream);
|
19861
|
278 }
|
|
279
|
|
280 static int demux_control_nut(demuxer_t * demuxer, int cmd, void * arg) {
|
28099
|
281 nut_priv_tt * priv = demuxer->priv;
|
19861
|
282 switch (cmd) {
|
|
283 case DEMUXER_CTRL_GET_TIME_LENGTH:
|
|
284 *((double *)arg) = priv->s[0].max_pts *
|
21723
|
285 (double)priv->s[0].time_base.num /
|
19861
|
286 priv->s[0].time_base.den;
|
|
287 return DEMUXER_CTRL_OK;
|
|
288 case DEMUXER_CTRL_GET_PERCENT_POS:
|
21023
|
289 if (priv->s[0].max_pts == 0 || priv->last_pts == -1)
|
19861
|
290 return DEMUXER_CTRL_DONTKNOW;
|
|
291 *((int *)arg) = priv->last_pts * 100 /
|
|
292 (double)priv->s[0].max_pts;
|
|
293 return DEMUXER_CTRL_OK;
|
|
294 default:
|
|
295 return DEMUXER_CTRL_NOTIMPL;
|
|
296 }
|
|
297 }
|
|
298
|
|
299 static void demux_close_nut(demuxer_t *demuxer) {
|
28099
|
300 nut_priv_tt * priv = demuxer->priv;
|
21011
|
301 if (!priv) return;
|
20925
|
302 nut_demuxer_uninit(priv->nut);
|
19861
|
303 free(demuxer->priv);
|
|
304 demuxer->priv = NULL;
|
|
305 }
|
|
306
|
|
307
|
25707
|
308 const demuxer_desc_t demuxer_desc_nut = {
|
19861
|
309 "NUT demuxer",
|
|
310 "nut",
|
|
311 "libnut",
|
|
312 "Oded Shimon (ods15)",
|
|
313 "NUT demuxer, requires libnut",
|
|
314 DEMUXER_TYPE_NUT,
|
|
315 1, // safe check demuxer
|
|
316 nut_check_file,
|
|
317 demux_nut_fill_buffer,
|
|
318 demux_open_nut,
|
|
319 demux_close_nut,
|
|
320 demux_seek_nut,
|
|
321 demux_control_nut
|
|
322 };
|