comparison nsvdec.c @ 594:89a09ede50ad libavformat

First implementation of nsv demuxer. Get libavformat linked with lavc and lmp3lame is required. BeOS requires no undefined syms on link! (besides it's bad to leave undef syms)
author mmu_man
date Sat, 20 Nov 2004 23:10:07 +0000
parents
children f0066a7fba8a
comparison
equal deleted inserted replaced
593:a1f354e84965 594:89a09ede50ad
1 /*
2 * NSV decoder.
3 * Copyright (c) 2004 The FFmpeg Project.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19 #include "avformat.h"
20 #include "avi.h"
21
22 #define DEBUG
23 //#define DEBUG_DUMP_INDEX // XXX dumbdriving-271.nsv breaks with it commented!!
24 //#define DEBUG_SEEK
25 #define CHECK_SUBSEQUENT_NSVS
26 //#define DISABLE_AUDIO
27
28 /* max bytes to crawl for trying to resync
29 * stupid streaming servers don't start at chunk boundaries...
30 */
31 #define NSV_MAX_RESYNC (500*1024)
32 #define NSV_MAX_RESYNC_TRIES 300
33
34 /*
35 * First version by Francois Revol - revol@free.fr
36 * References:
37 * (1) http://www.multimedia.cx/nsv-format.txt
38 * seems someone came to the same conclusions as me, and updated it:
39 * (2) http://www.stud.ktu.lt/~vitslav/nsv/nsv-format.txt
40 * http://www.stud.ktu.lt/~vitslav/nsv/
41 * Sample files:
42 * (S1) http://www.nullsoft.com/nsv/samples/
43 * http://www.nullsoft.com/nsv/samples/faster.nsv
44 * http://streamripper.sourceforge.net/openbb/read.php?TID=492&page=4
45 */
46
47 /*
48 * notes on the header (Francois Revol):
49 *
50 * It is followed by strings, then a table, but nothing tells
51 * where the table begins according to (1). After checking faster.nsv,
52 * I believe NVSf[16-19] gives the size of the strings data
53 * (that is the offset of the data table after the header).
54 * After checking all samples from (S1) all confirms this.
55 *
56 * Then, about NSVf[12-15], faster.nsf has 179700. When veiwing it in VLC,
57 * I noticed there was about 1 NVSs chunk/s, so I ran
58 * strings faster.nsv | grep NSVs | wc -l
59 * which gave me 180. That leads me to think that NSVf[12-15] might be the
60 * file length in milliseconds.
61 * Let's try that:
62 * for f in *.nsv; do HTIME="$(od -t x4 "$f" | head -1 | sed 's/.* //')"; echo "'$f' $((0x$HTIME))s = $((0x$HTIME/1000/60)):$((0x$HTIME/1000%60))"; done
63 * except for nstrailer (which doesn't have an NSVf header), it repports correct time.
64 *
65 * nsvtrailer.nsv (S1) does not have any NSVf header, only NSVs chunks,
66 * so the header seems to not be mandatory. (for streaming).
67 *
68 * index slice duration check (excepts nsvtrailer.nsv):
69 * for f in [^n]*.nsv; do DUR="$(ffmpeg -i "$f" 2>/dev/null | grep 'NSVf duration' | cut -d ' ' -f 4)"; IC="$(ffmpeg -i "$f" 2>/dev/null | grep 'INDEX ENTRIES' | cut -d ' ' -f 2)"; echo "duration $DUR, slite time $(($DUR/$IC))"; done
70 */
71
72 /*
73 * TODO:
74 * - handle timestamps !!!
75 * - use index
76 * - mime-type in probe()
77 * - seek
78 */
79
80 #ifdef DEBUG
81 #define PRINT(_v) printf _v
82 #else
83 #define PRINT(_v)
84 #endif
85
86 #if 0
87 struct NSVf_header {
88 uint32_t chunk_tag; /* 'NSVf' */
89 uint32_t chunk_size;
90 uint32_t file_size; /* max 4GB ??? noone learns anything it seems :^) */
91 uint32_t file_length; //unknown1; /* what about MSB of file_size ? */
92 uint32_t info_strings_size; /* size of the info strings */ //unknown2;
93 uint32_t table_entries;
94 uint32_t table_entries_used; /* the left ones should be -1 */
95 };
96
97 struct NSVs_header {
98 uint32_t chunk_tag; /* 'NSVs' */
99 uint32_t v4cc; /* or 'NONE' */
100 uint32_t a4cc; /* or 'NONE' */
101 uint16_t vwidth; /* assert(vwidth%16==0) */
102 uint16_t vheight; /* assert(vheight%16==0) */
103 uint8_t framerate; /* value = (framerate&0x80)?frtable[frameratex0x7f]:framerate */
104 uint16_t unknown;
105 };
106
107 struct nsv_avchunk_header {
108 uint8_t vchunk_size_lsb;
109 uint16_t vchunk_size_msb; /* value = (vchunk_size_msb << 4) | (vchunk_size_lsb >> 4) */
110 uint16_t achunk_size;
111 };
112
113 struct nsv_pcm_header {
114 uint8_t bits_per_sample;
115 uint8_t channel_count;
116 uint16_t sample_rate;
117 };
118 #endif
119
120 /* variation from avi.h */
121 /*typedef struct CodecTag {
122 int id;
123 unsigned int tag;
124 } CodecTag;*/
125
126 /* tags */
127
128 #define T_NSVF MKTAG('N', 'S', 'V', 'f') /* file header */
129 #define T_NSVS MKTAG('N', 'S', 'V', 's') /* chunk header */
130 #define T_TOC2 MKTAG('T', 'O', 'C', '2') /* extra index marker */
131 #define T_NONE MKTAG('N', 'O', 'N', 'E') /* null a/v 4CC */
132 #define T_SUBT MKTAG('S', 'U', 'B', 'T') /* subtitle aux data */
133 #define T_ASYN MKTAG('A', 'S', 'Y', 'N') /* async a/v aux marker */
134 #define T_KEYF MKTAG('K', 'E', 'Y', 'F') /* video keyframe aux marker (addition) */
135
136 #define TB_NSVF MKBETAG('N', 'S', 'V', 'f')
137 #define TB_NSVS MKBETAG('N', 'S', 'V', 's')
138
139 /* hardcoded stream indices */
140 #define NSV_ST_VIDEO 0
141 #define NSV_ST_AUDIO 1
142 #define NSV_ST_SUBT 2
143
144 enum NSVStatus {
145 NSV_UNSYNC,
146 NSV_FOUND_NSVF,
147 NSV_HAS_READ_NSVF,
148 NSV_FOUND_NSVS,
149 NSV_HAS_READ_NSVS,
150 NSV_FOUND_BEEF,
151 NSV_GOT_VIDEO,
152 NSV_GOT_AUDIO,
153 };
154
155 typedef struct NSVStream {
156 int frame_offset; /* current frame (video) or byte (audio) counter
157 (used to compute the pts) */
158 int scale;
159 int rate;
160 int sample_size; /* audio only data */
161 int start;
162
163 int new_frame_offset; /* temporary storage (used during seek) */
164 int cum_len; /* temporary storage (used during seek) */
165 } NSVStream;
166
167 typedef struct {
168 int base_offset;
169 int NSVf_end;
170 uint32_t *nsvf_index_data;
171 int index_entries;
172 enum NSVStatus state;
173 AVPacket ahead[2]; /* [v, a] if .data is !NULL there is something */
174 /* cached */
175 int64_t duration;
176 uint32_t vtag, atag;
177 uint16_t vwidth, vheight;
178 //DVDemuxContext* dv_demux;
179 } NSVContext;
180
181 static const CodecTag nsv_codec_video_tags[] = {
182 { CODEC_ID_VP3, MKTAG('V', 'P', '3', ' ') },
183 { CODEC_ID_VP3, MKTAG('V', 'P', '3', '0') },
184 { CODEC_ID_VP3, MKTAG('V', 'P', '3', '1') },
185 /*
186 { CODEC_ID_VP4, MKTAG('V', 'P', '4', ' ') },
187 { CODEC_ID_VP4, MKTAG('V', 'P', '4', '0') },
188 { CODEC_ID_VP5, MKTAG('V', 'P', '5', ' ') },
189 { CODEC_ID_VP5, MKTAG('V', 'P', '5', '0') },
190 { CODEC_ID_VP6, MKTAG('V', 'P', '6', ' ') },
191 { CODEC_ID_VP6, MKTAG('V', 'P', '6', '0') },
192 { CODEC_ID_VP6, MKTAG('V', 'P', '6', '1') },
193 { CODEC_ID_VP6, MKTAG('V', 'P', '6', '2') },
194 */
195 { CODEC_ID_XVID, MKTAG('X', 'V', 'I', 'D') }, /* cf sample xvid decoder from nsv_codec_sdk.zip */
196 { CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', '3') },
197 { 0, 0 },
198 };
199
200 static const CodecTag nsv_codec_audio_tags[] = {
201 { CODEC_ID_MP3, MKTAG('M', 'P', '3', ' ') },
202 { CODEC_ID_AAC, MKTAG('A', 'A', 'C', ' ') },
203 { CODEC_ID_AAC, MKTAG('A', 'A', 'C', 'P') }, /* _CUTTED__MUXED_2 Heads - Out Of The City.nsv */
204 { CODEC_ID_PCM_U16LE, MKTAG('P', 'C', 'M', ' ') },
205 { 0, 0 },
206 };
207
208 static const uint64_t nsv_framerate_table[] = {
209 ((uint64_t)AV_TIME_BASE * 30),
210 ((uint64_t)AV_TIME_BASE * 30000 / 1001), /* 29.97 */
211 ((uint64_t)AV_TIME_BASE * 25),
212 ((uint64_t)AV_TIME_BASE * 24000 / 1001), /* 23.98 */
213 ((uint64_t)AV_TIME_BASE * 30), /* ?? */
214 ((uint64_t)AV_TIME_BASE * 15000 / 1001), /* 14.98 */
215 };
216
217 //static int nsv_load_index(AVFormatContext *s);
218 static int nsv_read_chunk(AVFormatContext *s, int fill_header);
219
220 #ifdef DEBUG
221 static void print_tag(const char *str, unsigned int tag, int size)
222 {
223 printf("%s: tag=%c%c%c%c\n",
224 str, tag & 0xff,
225 (tag >> 8) & 0xff,
226 (tag >> 16) & 0xff,
227 (tag >> 24) & 0xff);
228 }
229 #endif
230
231 /* try to find something we recognize, and set the state accordingly */
232 static int nsv_resync(AVFormatContext *s)
233 {
234 NSVContext *nsv = s->priv_data;
235 ByteIOContext *pb = &s->pb;
236 uint32 v = 0;
237 int i;
238
239 PRINT(("%s(), offset = %Ld, state = %d\n", __FUNCTION__, url_ftell(pb), nsv->state));
240
241 //nsv->state = NSV_UNSYNC;
242
243 for (i = 0; i < NSV_MAX_RESYNC; i++) {
244 if (url_feof(pb)) {
245 PRINT(("NSV EOF\n"));
246 nsv->state = NSV_UNSYNC;
247 return -1;
248 }
249 v <<= 8;
250 v |= get_byte(pb);
251 /*
252 if (i < 8) {
253 PRINT(("NSV resync: [%d] = %02x\n", i, v & 0x0FF));
254 }
255 */
256
257 if ((v & 0x0000ffff) == 0xefbe) { /* BEEF */
258 PRINT(("NSV resynced on BEEF after %d bytes\n", i+1));
259 nsv->state = NSV_FOUND_BEEF;
260 return 0;
261 }
262 /* we read as big endian, thus the MK*BE* */
263 if (v == TB_NSVF) { /* NSVf */
264 PRINT(("NSV resynced on NSVf after %d bytes\n", i+1));
265 nsv->state = NSV_FOUND_NSVF;
266 return 0;
267 }
268 if (v == MKBETAG('N', 'S', 'V', 's')) { /* NSVs */
269 PRINT(("NSV resynced on NSVs after %d bytes\n", i+1));
270 nsv->state = NSV_FOUND_NSVS;
271 return 0;
272 }
273
274 }
275 PRINT(("NSV sync lost\n"));
276 return -1;
277 }
278
279 static int nsv_parse_NSVf_header(AVFormatContext *s, AVFormatParameters *ap)
280 {
281 NSVContext *nsv = s->priv_data;
282 ByteIOContext *pb = &s->pb;
283 uint32_t tag, tag1, handler;
284 int codec_type, stream_index, frame_period, bit_rate, scale, rate;
285 unsigned int file_size, size, nb_frames;
286 int64_t duration;
287 int strings_size;
288 int table_entries;
289 int table_entries_used;
290 int i, n;
291 AVStream *st;
292 NSVStream *ast;
293
294 PRINT(("%s()\n", __FUNCTION__));
295
296 nsv->state = NSV_UNSYNC; /* in case we fail */
297
298 size = get_le32(pb);
299 if (size < 28)
300 return -1;
301 nsv->NSVf_end = size;
302
303 //s->file_size = (uint32_t)get_le32(pb);
304 file_size = (uint32_t)get_le32(pb);
305 PRINT(("NSV NSVf chunk_size %ld\n", size));
306 PRINT(("NSV NSVf file_size %Ld\n", file_size));
307
308 duration = get_le32(pb); /* in ms */
309 nsv->duration = duration * AV_TIME_BASE / 1000; /* convert */
310 PRINT(("NSV NSVf duration %Ld ms\n", duration));
311 // XXX: store it in AVStreams
312
313 strings_size = get_le32(pb);
314 table_entries = get_le32(pb);
315 table_entries_used = get_le32(pb);
316 PRINT(("NSV NSVf info-strings size: %d, table entries: %d, bis %d\n",
317 strings_size, table_entries, table_entries_used));
318 if (url_feof(pb))
319 return -1;
320
321 PRINT(("NSV got header; filepos %Ld\n", url_ftell(pb)));
322
323 if (strings_size > 0) {
324 char *strings; /* last byte will be '\0' to play safe with str*() */
325 char *p, *endp;
326 char *token, *value;
327 char quote;
328
329 p = strings = av_mallocz(strings_size + 1);
330 endp = strings + strings_size;
331 get_buffer(pb, strings, strings_size);
332 while (p < endp) {
333 while (*p == ' ')
334 p++; /* strip out spaces */
335 if (p >= endp-2)
336 break;
337 token = p;
338 p = strchr(p, '=');
339 if (!p || p >= endp-2)
340 break;
341 *p++ = '\0';
342 quote = *p++;
343 value = p;
344 p = strchr(p, quote);
345 if (!p || p >= endp)
346 break;
347 *p++ = '\0';
348 PRINT(("NSV NSVf INFO: %s='%s'\n", token, value));
349 if (!strcmp(token, "ASPECT")) {
350 /* don't care */
351 } else if (!strcmp(token, "CREATOR") || !strcmp(token, "Author")) {
352 strncpy(s->author, value, 512-1);
353 } else if (!strcmp(token, "Copyright")) {
354 strncpy(s->copyright, value, 512-1);
355 } else if (!strcmp(token, "TITLE") || !strcmp(token, "Title")) {
356 strncpy(s->title, value, 512-1);
357 }
358 }
359 av_free(strings);
360 }
361 if (url_feof(pb))
362 return -1;
363
364 PRINT(("NSV got infos; filepos %Ld\n", url_ftell(pb)));
365
366 if (table_entries_used > 0) {
367 nsv->index_entries = table_entries_used;
368 nsv->nsvf_index_data = av_malloc(table_entries * sizeof(uint32_t));
369 get_buffer(pb, nsv->nsvf_index_data, table_entries * sizeof(uint32_t));
370 }
371
372 PRINT(("NSV got index; filepos %Ld\n", url_ftell(pb)));
373
374 #ifdef DEBUG_DUMP_INDEX
375 #define V(v) ((v<0x20 || v > 127)?'.':v)
376 /* dump index */
377 PRINT(("NSV %d INDEX ENTRIES:\n", table_entries));
378 PRINT(("NSV [dataoffset][fileoffset]\n", table_entries));
379 for (i = 0; i < table_entries; i++) {
380 unsigned char b[8];
381 url_fseek(pb, size + nsv->nsvf_index_data[i], SEEK_SET);
382 get_buffer(pb, b, 8);
383 PRINT(("NSV [0x%08lx][0x%08lx]: %02x %02x %02x %02x %02x %02x %02x %02x"
384 "%c%c%c%c%c%c%c%c\n",
385 nsv->nsvf_index_data[i], size + nsv->nsvf_index_data[i],
386 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
387 V(b[0]), V(b[1]), V(b[2]), V(b[3]), V(b[4]), V(b[5]), V(b[6]), V(b[7]) ));
388 }
389 //url_fseek(pb, size, SEEK_SET); /* go back to end of header */
390 #undef V
391 #endif
392
393 url_fseek(pb, nsv->base_offset + size, SEEK_SET); /* required for dumbdriving-271.nsv (2 extra bytes) */
394
395 if (url_feof(pb))
396 return -1;
397 nsv->state = NSV_HAS_READ_NSVF;
398 return 0;
399 }
400
401 static int nsv_parse_NSVs_header(AVFormatContext *s, AVFormatParameters *ap)
402 {
403 NSVContext *nsv = s->priv_data;
404 ByteIOContext *pb = &s->pb;
405 uint32_t vtag, atag;
406 uint16_t vwidth, vheight;
407 uint32_t framerate;
408 uint16_t unknown;
409 AVStream *st;
410 NSVStream *nst;
411 PRINT(("%s()\n", __FUNCTION__));
412
413 vtag = get_le32(pb);
414 atag = get_le32(pb);
415 vwidth = get_le16(pb);
416 vheight = get_le16(pb);
417 framerate = (uint8_t)get_byte(pb);
418 /* XXX how big must the table be ? */
419 /* seems there is more to that... */
420 PRINT(("NSV NSVs framerate code %2x\n", framerate));
421 framerate = (framerate & 0x80)?(nsv_framerate_table[framerate & 0x7F]):(framerate*AV_TIME_BASE);
422 unknown = get_le16(pb);
423 #ifdef DEBUG
424 print_tag("NSV NSVs vtag", vtag, 0);
425 print_tag("NSV NSVs atag", atag, 0);
426 PRINT(("NSV NSVs vsize %dx%d\n", vwidth, vheight));
427 PRINT(("NSV NSVs framerate %2x\n", framerate));
428 #endif
429
430 /* XXX change to ap != NULL ? */
431 if (s->nb_streams == 0) { /* streams not yet published, let's do that */
432 nsv->vtag = vtag;
433 nsv->atag = atag;
434 nsv->vwidth = vwidth;
435 nsv->vheight = vwidth;
436 if (vtag != T_NONE) {
437 st = av_new_stream(s, NSV_ST_VIDEO);
438 if (!st)
439 goto fail;
440
441 nst = av_mallocz(sizeof(NSVStream));
442 if (!nst)
443 goto fail;
444 st->priv_data = nst;
445 st->codec.codec_type = CODEC_TYPE_VIDEO;
446 st->codec.codec_tag = vtag;
447 st->codec.codec_id = codec_get_id(nsv_codec_video_tags, vtag);
448 st->codec.width = vwidth;
449 st->codec.height = vheight;
450 st->codec.bits_per_sample = 24; /* depth XXX */
451
452 st->codec.frame_rate = framerate;
453 st->codec.frame_rate_base = AV_TIME_BASE;
454 av_set_pts_info(st, 64, AV_TIME_BASE, framerate);
455 st->start_time = 0;
456 st->duration = nsv->duration;
457 }
458 if (atag != T_NONE) {
459 #ifndef DISABLE_AUDIO
460 st = av_new_stream(s, NSV_ST_AUDIO);
461 if (!st)
462 goto fail;
463
464 nst = av_mallocz(sizeof(NSVStream));
465 if (!nst)
466 goto fail;
467 st->priv_data = nst;
468 st->codec.codec_type = CODEC_TYPE_AUDIO;
469 st->codec.codec_tag = atag;
470 st->codec.codec_id = codec_get_id(nsv_codec_audio_tags, atag);
471 st->start_time = 0;
472 st->duration = nsv->duration;
473
474 st->need_parsing = 1; /* for PCM we will read a chunk later and put correct info */
475 /* XXX:FIXME */
476 //st->codec.channels = 2; //XXX:channels;
477 //st->codec.sample_rate = 1000;
478 //av_set_pts_info(st, 64, 1, st->codec.sample_rate);
479
480 #endif
481 }
482 #ifdef CHECK_SUBSEQUENT_NSVS
483 } else {
484 if (nsv->vtag != vtag || nsv->atag != atag || nsv->vwidth != vwidth || nsv->vheight != vwidth) {
485 PRINT(("NSV NSVs header values differ from the first one!!!\n"));
486 //return -1;
487 }
488 #endif /* CHECK_SUBSEQUENT_NSVS */
489 }
490
491 nsv->state = NSV_HAS_READ_NSVS;
492 return 0;
493 fail:
494 /* XXX */
495 nsv->state = NSV_UNSYNC;
496 return -1;
497 }
498
499 static int nsv_read_header(AVFormatContext *s, AVFormatParameters *ap)
500 {
501 NSVContext *nsv = s->priv_data;
502 ByteIOContext *pb = &s->pb;
503 uint32_t tag, tag1, handler;
504 int codec_type, stream_index, frame_period, bit_rate, scale, rate;
505 unsigned int size, nb_frames;
506 int table_entries;
507 int i, n, err;
508 AVStream *st;
509 NSVStream *ast;
510
511 PRINT(("%s()\n", __FUNCTION__));
512 PRINT(("filename '%s'\n", s->filename));
513
514 nsv->state = NSV_UNSYNC;
515 nsv->ahead[0].data = nsv->ahead[1].data = NULL;
516
517 for (i = 0; i < NSV_MAX_RESYNC_TRIES; i++) {
518 if (nsv_resync(s) < 0)
519 return -1;
520 if (nsv->state == NSV_FOUND_NSVF)
521 err = nsv_parse_NSVf_header(s, ap);
522 /* we need the first NSVs also... */
523 if (nsv->state == NSV_FOUND_NSVS) {
524 err = nsv_parse_NSVs_header(s, ap);
525 break; /* we just want the first one */
526 }
527 }
528 if (s->nb_streams < 1) /* no luck so far */
529 return -1;
530 /* now read the first chunk, so we can attempt to decode more info */
531 err = nsv_read_chunk(s, 1);
532
533 PRINT(("parsed header\n"));
534 return 0;
535 }
536
537 static int nsv_read_chunk(AVFormatContext *s, int fill_header)
538 {
539 NSVContext *nsv = s->priv_data;
540 ByteIOContext *pb = &s->pb;
541 AVStream *st[2] = {NULL, NULL};
542 NSVStream *nst;
543 AVPacket *pkt;
544 uint32 v = 0;
545 int i, err = 0;
546 uint8 auxcount; /* number of aux metadata, also 4 bits of vsize */
547 uint32 vsize;
548 uint16 asize;
549 uint16 auxsize;
550 uint32 auxtag;
551
552 PRINT(("%s(%d)\n", __FUNCTION__, fill_header));
553
554 if (nsv->ahead[0].data || nsv->ahead[1].data)
555 return 0; //-1; /* hey! eat what you've in your plate first! */
556
557 null_chunk_retry:
558 if (url_feof(pb))
559 return -1;
560
561 for (i = 0; i < NSV_MAX_RESYNC_TRIES && nsv->state < NSV_FOUND_NSVS && !err; i++)
562 err = nsv_resync(s);
563 if (err < 0)
564 return err;
565 if (nsv->state == NSV_FOUND_NSVS)
566 err = nsv_parse_NSVs_header(s, NULL);
567 if (err < 0)
568 return err;
569 if (nsv->state != NSV_HAS_READ_NSVS && nsv->state != NSV_FOUND_BEEF)
570 return -1;
571
572 auxcount = get_byte(pb);
573 vsize = get_le16(pb);
574 asize = get_le16(pb);
575 vsize = (vsize << 4) | (auxcount >> 4);
576 auxcount &= 0x0f;
577 PRINT(("NSV CHUNK %d aux, %ld bytes video, %d bytes audio\n", auxcount, vsize, asize));
578 /* skip aux stuff */
579 for (i = 0; i < auxcount; i++) {
580 auxsize = get_le16(pb);
581 auxtag = get_le32(pb);
582 PRINT(("NSV aux data: '%c%c%c%c', %d bytes\n",
583 (auxtag & 0x0ff),
584 ((auxtag >> 8) & 0x0ff),
585 ((auxtag >> 16) & 0x0ff),
586 ((auxtag >> 24) & 0x0ff),
587 auxsize));
588 url_fskip(pb, auxsize);
589 vsize -= auxsize + sizeof(uint16) + sizeof(uint32); /* that's becoming braindead */
590 }
591
592 if (url_feof(pb))
593 return -1;
594 if (!vsize && !asize) {
595 nsv->state = NSV_UNSYNC;
596 goto null_chunk_retry;
597 }
598
599 /* map back streams to v,a */
600 if (s->streams[0])
601 st[s->streams[0]->id] = s->streams[0];
602 if (s->streams[1])
603 st[s->streams[1]->id] = s->streams[1];
604
605 if (vsize/* && st[NSV_ST_VIDEO]*/) {
606 nst = st[NSV_ST_VIDEO]->priv_data;
607 pkt = &nsv->ahead[NSV_ST_VIDEO];
608 av_new_packet(pkt, vsize);
609 get_buffer(pb, pkt->data, vsize);
610 pkt->stream_index = st[NSV_ST_VIDEO]->index;//NSV_ST_VIDEO;
611 pkt->dts = nst->frame_offset++;
612 pkt->flags |= PKT_FLAG_KEY; /* stupid format has no way to tell XXX: try the index */
613 /*
614 for (i = 0; i < MIN(8, vsize); i++)
615 PRINT(("NSV video: [%d] = %02x\n", i, pkt->data[i]));
616 */
617 }
618 if (asize/*st[NSV_ST_AUDIO]*/) {
619 nst = st[NSV_ST_AUDIO]->priv_data;
620 pkt = &nsv->ahead[NSV_ST_AUDIO];
621 /* read raw audio specific header on the first audio chunk... */
622 /* on ALL audio chunks ?? seems so! */
623 if (asize && st[NSV_ST_AUDIO]->codec.codec_tag == MKTAG('P', 'C', 'M', ' ')/* && fill_header*/) {
624 uint8_t bps;
625 uint8_t channels;
626 uint16_t samplerate;
627 bps = get_byte(pb);
628 channels = get_byte(pb);
629 samplerate = get_le16(pb);
630 asize-=4;
631 PRINT(("NSV RAWAUDIO: bps %d, nchan %d, srate %ld\n", bps, channels, samplerate));
632 if (fill_header) {
633 st[NSV_ST_AUDIO]->need_parsing = 0; /* we know everything */
634 if (bps != 16) {
635 PRINT(("NSV AUDIO bit/sample != 16 (%d)!!!\n", bps));
636 }
637 bps /= channels; // ???
638 if (bps == 8)
639 st[NSV_ST_AUDIO]->codec.codec_id = CODEC_ID_PCM_U8;
640 samplerate /= 4;/* UGH ??? XXX */
641 channels = 1;
642 st[NSV_ST_AUDIO]->codec.channels = channels;
643 st[NSV_ST_AUDIO]->codec.sample_rate = samplerate;
644 av_set_pts_info(st[NSV_ST_AUDIO], 64, 1,
645 st[NSV_ST_AUDIO]->codec.sample_rate);
646 PRINT(("NSV RAWAUDIO: bps %d, nchan %d, srate %ld\n", bps, channels, samplerate));
647 }
648 }
649 av_new_packet(pkt, asize);
650 if (asize)
651 get_buffer(pb, pkt->data, asize);
652 pkt->stream_index = st[NSV_ST_AUDIO]->index;//NSV_ST_AUDIO;
653 //pkt->dts = nst->frame_offset;
654 //if (nst->sample_size)
655 // pkt->dts /= nst->sample_size;
656 nst->frame_offset += asize; // XXX: that's valid only for PCM !?
657 }
658
659 //pkt->flags |= PKT_FLAG_KEY;
660 nsv->state = NSV_UNSYNC;
661 return 0;
662 }
663
664
665 static int nsv_read_packet(AVFormatContext *s, AVPacket *pkt)
666 {
667 NSVContext *nsv = s->priv_data;
668 ByteIOContext *pb = &s->pb;
669 int i, err = 0;
670
671 PRINT(("%s()\n", __FUNCTION__));
672
673 /* in case we don't already have something to eat ... */
674 if (nsv->ahead[0].data == NULL && nsv->ahead[1].data == NULL)
675 err = nsv_read_chunk(s, 0);
676 if (err < 0)
677 return err;
678
679 /* now pick one of the plates */
680 for (i = 0; i < 2; i++) {
681 if (nsv->ahead[i].data) {
682 PRINT(("%s: using cached packet[%d]\n", __FUNCTION__, i));
683 /* avoid the cost of new_packet + memcpy(->data) */
684 memcpy(pkt, &nsv->ahead[i], sizeof(AVPacket));
685 nsv->ahead[i].data = NULL; /* we ate that one */
686 return pkt->size;
687 }
688 }
689
690 /* this restaurant is not approvisionned :^] */
691 return -1;
692 }
693
694 static int nsv_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
695 {
696 NSVContext *avi = s->priv_data;
697 AVStream *st;
698 NSVStream *ast;
699 int frame_number, i;
700 int64_t pos;
701
702 return -1;
703 }
704
705 static int nsv_read_close(AVFormatContext *s)
706 {
707 int i;
708 NSVContext *nsv = s->priv_data;
709
710 if (nsv->index_entries)
711 av_free(nsv->nsvf_index_data);
712
713 #if 0
714
715 for(i=0;i<s->nb_streams;i++) {
716 AVStream *st = s->streams[i];
717 NSVStream *ast = st->priv_data;
718 if(ast){
719 av_free(ast->index_entries);
720 av_free(ast);
721 }
722 av_free(st->codec.extradata);
723 av_free(st->codec.palctrl);
724 }
725
726 #endif
727 return 0;
728 }
729
730 static int nsv_probe(AVProbeData *p)
731 {
732 int i;
733 PRINT(("nsv_probe(), buf_size %d\n", p->buf_size));
734 /* check file header */
735 if (p->buf_size <= 32)
736 return 0;
737 if (p->buf[0] == 'N' && p->buf[1] == 'S' &&
738 p->buf[2] == 'V' && p->buf[3] == 'f')
739 return AVPROBE_SCORE_MAX;
740 /* streamed files might not have any header */
741 if (p->buf[0] == 'N' && p->buf[1] == 'S' &&
742 p->buf[2] == 'V' && p->buf[3] == 's')
743 return AVPROBE_SCORE_MAX;
744 /* XXX: do streamed files always start at chunk boundary ?? */
745 /* or do we need to search NSVs in the byte stream ? */
746 /* seems the servers don't bother starting clean chunks... */
747 /* sometimes even the first header is at 9KB or something :^) */
748 for (i = 1; i < p->buf_size - 3; i++) {
749 if (p->buf[i+0] == 'N' && p->buf[i+1] == 'S' &&
750 p->buf[i+2] == 'V' && p->buf[i+3] == 's')
751 return AVPROBE_SCORE_MAX-20;
752 }
753 /* so we'll have more luck on extension... */
754 if (match_ext(p->filename, "nsv"))
755 return AVPROBE_SCORE_MAX-20;
756 /* FIXME: add mime-type check */
757 return 0;
758 }
759
760 static AVInputFormat nsv_iformat = {
761 "nsv",
762 "NullSoft Video format",
763 sizeof(NSVContext),
764 nsv_probe,
765 nsv_read_header,
766 nsv_read_packet,
767 nsv_read_close,
768 nsv_read_seek,
769 };
770
771 int nsvdec_init(void)
772 {
773 av_register_input_format(&nsv_iformat);
774 return 0;
775 }