1 /*
2 * NSV demuxer
3 * Copyright (c) 2004 The FFmpeg Project
4 *
5 * first version by Francois Revol <revol@free.fr>
6 *
7 * This file is part of FFmpeg.
8 *
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
30
31 /* max bytes to crawl for trying to resync
32 * stupid streaming servers don't start at chunk boundaries...
33 */
34 #define NSV_MAX_RESYNC (500*1024)
35 #define NSV_MAX_RESYNC_TRIES 300
36
37 /*
38 * References:
39 * (1) http://www.multimedia.cx/nsv-format.txt
40 * seems someone came to the same conclusions as me, and updated it:
41 * (2) http://www.stud.ktu.lt/~vitslav/nsv/nsv-format.txt
42 * http://www.stud.ktu.lt/~vitslav/nsv/
43 * official docs
44 * (3) http://ultravox.aol.com/NSVFormat.rtf
45 * Sample files:
46 * (S1) http://www.nullsoft.com/nsv/samples/
47 * http://www.nullsoft.com/nsv/samples/faster.nsv
48 * http://streamripper.sourceforge.net/openbb/read.php?TID=492&page=4
49 */
50
51 /*
52 * notes on the header (Francois Revol):
53 *
54 * It is followed by strings, then a table, but nothing tells
55 * where the table begins according to (1). After checking faster.nsv,
56 * I believe NVSf[16-19] gives the size of the strings data
57 * (that is the offset of the data table after the header).
58 * After checking all samples from (S1) all confirms this.
59 *
60 * Then, about NSVf[12-15], faster.nsf has 179700. When viewing it in VLC,
61 * I noticed there was about 1 NVSs chunk/s, so I ran
62 * strings faster.nsv | grep NSVs | wc -l
63 * which gave me 180. That leads me to think that NSVf[12-15] might be the
64 * file length in milliseconds.
65 * Let's try that:
66 * 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
67 * except for nsvtrailer (which doesn't have an NSVf header), it reports correct time.
68 *
69 * nsvtrailer.nsv (S1) does not have any NSVf header, only NSVs chunks,
70 * so the header seems to not be mandatory. (for streaming).
71 *
72 * index slice duration check (excepts nsvtrailer.nsv):
73 * 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
74 */
75
76 /*
77 * TODO:
78 * - handle timestamps !!!
79 * - use index
80 * - mime-type in probe()
81 * - seek
82 */
83
84 #if 0
85 struct NSVf_header {
86 uint32_t chunk_tag; /* 'NSVf' */
87 uint32_t chunk_size;
88 uint32_t file_size; /* max 4GB ??? no one learns anything it seems :^) */
89 uint32_t file_length; //unknown1; /* what about MSB of file_size ? */
90 uint32_t info_strings_size; /* size of the info strings */ //unknown2;
91 uint32_t table_entries;
92 uint32_t table_entries_used; /* the left ones should be -1 */
93 };
94
95 struct NSVs_header {
96 uint32_t chunk_tag; /* 'NSVs' */
97 uint32_t v4cc; /* or 'NONE' */
98 uint32_t a4cc; /* or 'NONE' */
99 uint16_t vwidth; /* av_assert0(vwidth%16==0) */
100 uint16_t vheight; /* av_assert0(vheight%16==0) */
101 uint8_t framerate;
/* value = (framerate&0x80)?frtable[frameratex0x7f]:framerate */
102 uint16_t unknown;
103 };
104
105 struct nsv_avchunk_header {
107 uint16_t vchunk_size_msb; /* value = (vchunk_size_msb << 4) | (vchunk_size_lsb >> 4) */
108 uint16_t achunk_size;
109 };
110
111 struct nsv_pcm_header {
115 };
116 #endif
117
118 /* variation from avi.h */
119 /*typedef struct CodecTag {
120 int id;
121 unsigned int tag;
122 } CodecTag;*/
123
124 /* tags */
125
126 #define T_NSVF MKTAG('N', 'S', 'V', 'f') /* file header */
127 #define T_NSVS MKTAG('N', 'S', 'V', 's') /* chunk header */
128 #define T_TOC2 MKTAG('T', 'O', 'C', '2') /* extra index marker */
129 #define T_NONE MKTAG('N', 'O', 'N', 'E') /* null a/v 4CC */
130 #define T_SUBT MKTAG('S', 'U', 'B', 'T') /* subtitle aux data */
131 #define T_ASYN MKTAG('A', 'S', 'Y', 'N') /* async a/v aux marker */
132 #define T_KEYF MKTAG('K', 'E', 'Y', 'F') /* video keyframe aux marker (addition) */
133
134 #define TB_NSVF MKBETAG('N', 'S', 'V', 'f')
135 #define TB_NSVS MKBETAG('N', 'S', 'V', 's')
136
137 /* hardcoded stream indexes */
138 #define NSV_ST_VIDEO 0
139 #define NSV_ST_AUDIO 1
140 #define NSV_ST_SUBT 2
141
151 };
152
155 (used to compute the pts) */
160
162 int cum_len;
/* temporary storage (used during seek) */
164
172 /* cached */
181
193 /*
194 { AV_CODEC_ID_VP4, MKTAG('V', 'P', '4', ' ') },
195 { AV_CODEC_ID_VP4, MKTAG('V', 'P', '4', '0') },
196 */
200 };
201
210 };
211
212 //static int nsv_load_index(AVFormatContext *s);
215
216 /* try to find something we recognize, and set the state accordingly */
218 {
221 uint32_t v = 0;
223
228 return -1;
229 }
230 v <<= 8;
234 }
235
236 if ((v & 0x0000ffff) == 0xefbe) { /* BEEF */
239 return 0;
240 }
241 /* we read as big-endian, thus the MK*BE* */
245 return 0;
246 }
247 if (v ==
MKBETAG(
'N',
'S',
'V',
's')) {
/* NSVs */
250 return 0;
251 }
252
253 }
255 return -1;
256 }
257
259 {
265 int strings_size;
266 int table_entries;
267 int table_entries_used;
268
270
273 return 0;
274 }
276
279 return -1;
281
285
288 // XXX: store it in AVStreams
289
294 strings_size, table_entries, table_entries_used);
296 return -1;
297
299
300 if (strings_size > 0) {
301 char *strings; /* last byte will be '0円' to play safe with str*() */
302 char *p, *endp;
304 char quote;
305
306 p = strings =
av_mallocz((
size_t)strings_size + 1);
307 if (!p)
309 endp = strings + strings_size;
311 while (p < endp) {
312 while (*p == ' ')
313 p++; /* strip out spaces */
314 if (p >= endp-2)
315 break;
316 token = p;
317 p = strchr(p, '=');
318 if (!p || p >= endp-2)
319 break;
320 *p++ = '0円';
321 quote = *p++;
323 p = strchr(p, quote);
324 if (!p || p >= endp)
325 break;
326 *p++ = '0円';
329 }
331 }
333 return -1;
334
336
337 if (table_entries_used > 0) {
340 if((unsigned)table_entries_used >= UINT_MAX / sizeof(uint32_t))
341 return -1;
345
346 for(
i=0;
i<table_entries_used;
i++) {
350 }
351
352 if(table_entries > table_entries_used &&
357 for(
i=0;
i<table_entries_used;
i++) {
359 }
360 }
361 }
362
364
366
368 return -1;
370 return 0;
371 }
372
374 {
377 uint32_t vtag, atag;
378 uint16_t vwidth, vheight;
383
389
391 if(
i&0x80) {
/* odd way of giving native framerates from docs */
395
399 }
400
404 }
405 else
407
410
412
413 /* XXX change to ap != NULL ? */
414 if (
s->nb_streams == 0) {
/* streams not yet published, let's do that */
422 if (!st)
424
427 if (!nst)
436
440
445 } else {
448 }
449 }
450 }
453 if (!st)
455
458 if (!nst)
464
466
467 /* set timebase to common denominator of ms and framerate */
471 }
472 } else {
475 //return -1;
476 }
477 }
478
480 return 0;
482 /* XXX */
484 return -1;
485 }
486
488 {
491
494
497 if (err < 0)
501 if (err < 0)
503 }
504 /* we need the first NSVs also... */
507 if (err < 0)
509 break; /* we just want the first one */
510 }
511 }
512 if (
s->nb_streams < 1) {
/* no luck so far */
515 }
516
517 /* now read the first chunk, so we can attempt to decode more info */
520 if (err < 0)
522
524 return err;
525 }
526
528 {
535 uint8_t auxcount;
/* number of aux metadata, also 4 bits of vsize */
536 uint32_t vsize;
537 uint16_t asize;
538 uint16_t auxsize;
540
542 return 0; //-1; /* hey! eat what you've in your plate first! */
543
544 null_chunk_retry:
546 return -1;
547
550 if (err < 0)
551 return err;
554 if (err < 0)
555 return err;
557 return -1;
558
562 vsize = (vsize << 4) | (auxcount >> 4);
563 auxcount &= 0x0f;
564 av_log(
s,
AV_LOG_TRACE,
"NSV CHUNK %d aux, %"PRIu32
" bytes video, %d bytes audio\n", auxcount, vsize, asize);
565 /* skip aux stuff */
566 for (
i = 0;
i < auxcount;
i++) {
571 vsize -= auxsize + sizeof(uint16_t) + sizeof(uint32_t); /* that's becoming brain-dead */
572 }
573
575 return -1;
576 if (!vsize && !asize) {
578 goto null_chunk_retry;
579 }
580
581 /* map back streams to v,a */
582 if (
s->nb_streams > 0)
583 st[
s->streams[0]->id] =
s->streams[0];
584 if (
s->nb_streams > 1)
585 st[
s->streams[1]->id] =
s->streams[1];
586
595 for (
i = 0;
i <
FFMIN(8, vsize);
i++)
597 }
600
604 /* read raw audio specific header on the first audio chunk... */
605 /* on ALL audio chunks ?? seems so! */
606 if (asize && st[
NSV_ST_AUDIO]->codecpar->codec_tag ==
MKTAG(
'P',
'C',
'M',
' ')
/* && fill_header*/) {
609 uint16_t samplerate;
615 asize-=4;
617 if (fill_header) {
621 }
625 samplerate /= 4;/* UGH ??? XXX */
630 }
631 }
637 /* on a nsvs frame we have new information on a/v sync */
642 }
644 }
645
647 return 0;
648 }
649
650
652 {
655
656 /* in case we don't already have something to eat ... */
659 if (err < 0)
660 return err;
661
662 /* now pick one of the plates */
663 for (
i = 0;
i < 2;
i++) {
666 return 0;
667 }
668 }
669
670 /* this restaurant is not provisioned :^] */
671 return -1;
672 }
673
675 {
680
683 return -1;
684
686 return -1;
687
690 return 0;
691 }
692
694 {
696
703 return 0;
704 }
705
707 {
709
710 /* check file header */
711 /* streamed files might not have any header */
712 if (p->
buf[0] ==
'N' && p->
buf[1] ==
'S' &&
713 p->
buf[2] ==
'V' && (p->
buf[3] ==
'f' || p->
buf[3] ==
's'))
715 /* XXX: do streamed files always start at chunk boundary ?? */
716 /* or do we need to search NSVs in the byte stream ? */
717 /* seems the servers don't bother starting clean chunks... */
718 /* sometimes even the first header is at 9KB or something :^) */
721 /* Get the chunk size and check if at the end we are getting 0xBEEF */
724 int offset =
i + 23 + asize + vsize + 1;
728 }
729 }
730 /* so we'll have more luck on extension... */
733 /* FIXME: add mime-type check */
734 return score;
735 }
736
746 };