nsvdec.c 25.6 KB
Newer Older
1
/*
2
 * NSV demuxer
3
 * Copyright (c) 2004 The FFmpeg Project
4
 *
5 6
 * first version by Francois Revol <revol@free.fr>
 *
7 8 9
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
10 11
 * modify it under the terms of the GNU Lesser General Public
 * 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 16 17 18 19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * 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

24
#include "libavutil/attributes.h"
25
#include "libavutil/mathematics.h"
26
#include "avformat.h"
27
#include "internal.h"
28
#include "libavutil/dict.h"
29
#include "libavutil/intreadwrite.h"
30 31 32 33 34 35 36 37 38 39 40 41 42

/* max bytes to crawl for trying to resync
 * stupid streaming servers don't start at chunk boundaries...
 */
#define NSV_MAX_RESYNC (500*1024)
#define NSV_MAX_RESYNC_TRIES 300

/*
 * References:
 * (1) http://www.multimedia.cx/nsv-format.txt
 * seems someone came to the same conclusions as me, and updated it:
 * (2) http://www.stud.ktu.lt/~vitslav/nsv/nsv-format.txt
 *     http://www.stud.ktu.lt/~vitslav/nsv/
43 44
 * official docs
 * (3) http://ultravox.aol.com/NSVFormat.rtf
45 46 47 48 49 50 51 52
 * Sample files:
 * (S1) http://www.nullsoft.com/nsv/samples/
 * http://www.nullsoft.com/nsv/samples/faster.nsv
 * http://streamripper.sourceforge.net/openbb/read.php?TID=492&page=4
 */

/*
 * notes on the header (Francois Revol):
53 54
 *
 * It is followed by strings, then a table, but nothing tells
55 56 57 58 59
 * where the table begins according to (1). After checking faster.nsv,
 * I believe NVSf[16-19] gives the size of the strings data
 * (that is the offset of the data table after the header).
 * After checking all samples from (S1) all confirms this.
 *
60
 * Then, about NSVf[12-15], faster.nsf has 179700. When viewing it in VLC,
61 62
 * I noticed there was about 1 NVSs chunk/s, so I ran
 * 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 65 66
 * file length in milliseconds.
 * Let's try that:
 * 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 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
 * index slice duration check (excepts nsvtrailer.nsv):
 * 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
 */

/*
 * TODO:
 * - handle timestamps !!!
 * - use index
 * - mime-type in probe()
 * - seek
 */

#if 0
struct NSVf_header {
    uint32_t chunk_tag; /* 'NSVf' */
    uint32_t chunk_size;
Diego Biurrun's avatar
Diego Biurrun committed
88
    uint32_t file_size; /* max 4GB ??? no one learns anything it seems :^) */
89 90 91 92 93 94 95 96 97 98
    uint32_t file_length; //unknown1;  /* what about MSB of file_size ? */
    uint32_t info_strings_size; /* size of the info strings */ //unknown2;
    uint32_t table_entries;
    uint32_t table_entries_used; /* the left ones should be -1 */
};

struct NSVs_header {
    uint32_t chunk_tag; /* 'NSVs' */
    uint32_t v4cc;      /* or 'NONE' */
    uint32_t a4cc;      /* or 'NONE' */
99 100
    uint16_t vwidth;    /* av_assert0(vwidth%16==0) */
    uint16_t vheight;   /* av_assert0(vheight%16==0) */
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
    uint8_t framerate;  /* value = (framerate&0x80)?frtable[frameratex0x7f]:framerate */
    uint16_t unknown;
};

struct nsv_avchunk_header {
    uint8_t vchunk_size_lsb;
    uint16_t vchunk_size_msb; /* value = (vchunk_size_msb << 4) | (vchunk_size_lsb >> 4) */
    uint16_t achunk_size;
};

struct nsv_pcm_header {
    uint8_t bits_per_sample;
    uint8_t channel_count;
    uint16_t sample_rate;
};
#endif

/* variation from avi.h */
/*typedef struct CodecTag {
    int id;
    unsigned int tag;
} CodecTag;*/

/* tags */

#define T_NSVF MKTAG('N', 'S', 'V', 'f') /* file header */
#define T_NSVS MKTAG('N', 'S', 'V', 's') /* chunk header */
#define T_TOC2 MKTAG('T', 'O', 'C', '2') /* extra index marker */
#define T_NONE MKTAG('N', 'O', 'N', 'E') /* null a/v 4CC */
#define T_SUBT MKTAG('S', 'U', 'B', 'T') /* subtitle aux data */
#define T_ASYN MKTAG('A', 'S', 'Y', 'N') /* async a/v aux marker */
#define T_KEYF MKTAG('K', 'E', 'Y', 'F') /* video keyframe aux marker (addition) */

#define TB_NSVF MKBETAG('N', 'S', 'V', 'f')
#define TB_NSVS MKBETAG('N', 'S', 'V', 's')

137
/* hardcoded stream indexes */
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
#define NSV_ST_VIDEO 0
#define NSV_ST_AUDIO 1
#define NSV_ST_SUBT 2

enum NSVStatus {
    NSV_UNSYNC,
    NSV_FOUND_NSVF,
    NSV_HAS_READ_NSVF,
    NSV_FOUND_NSVS,
    NSV_HAS_READ_NSVS,
    NSV_FOUND_BEEF,
    NSV_GOT_VIDEO,
    NSV_GOT_AUDIO,
};

typedef struct NSVStream {
    int frame_offset; /* current frame (video) or byte (audio) counter
                         (used to compute the pts) */
    int scale;
157
    int rate;
158 159
    int sample_size; /* audio only data */
    int start;
160

161 162 163 164
    int new_frame_offset; /* temporary storage (used during seek) */
    int cum_len; /* temporary storage (used during seek) */
} NSVStream;

165
typedef struct NSVContext {
166 167
    int  base_offset;
    int  NSVf_end;
168
    uint32_t *nsvs_file_offset;
169 170 171 172 173 174 175
    int index_entries;
    enum NSVStatus state;
    AVPacket ahead[2]; /* [v, a] if .data is !NULL there is something */
    /* cached */
    int64_t duration;
    uint32_t vtag, atag;
    uint16_t vwidth, vheight;
176
    int16_t avsync;
177
    AVRational framerate;
178
    uint32_t *nsvs_timestamps;
179 180 181
    //DVDemuxContext* dv_demux;
} NSVContext;

182
static const AVCodecTag nsv_codec_video_tags[] = {
183 184 185 186 187 188 189 190 191
    { AV_CODEC_ID_VP3, MKTAG('V', 'P', '3', ' ') },
    { AV_CODEC_ID_VP3, MKTAG('V', 'P', '3', '0') },
    { AV_CODEC_ID_VP3, MKTAG('V', 'P', '3', '1') },
    { AV_CODEC_ID_VP5, MKTAG('V', 'P', '5', ' ') },
    { AV_CODEC_ID_VP5, MKTAG('V', 'P', '5', '0') },
    { AV_CODEC_ID_VP6, MKTAG('V', 'P', '6', ' ') },
    { AV_CODEC_ID_VP6, MKTAG('V', 'P', '6', '0') },
    { AV_CODEC_ID_VP6, MKTAG('V', 'P', '6', '1') },
    { AV_CODEC_ID_VP6, MKTAG('V', 'P', '6', '2') },
192
    { AV_CODEC_ID_VP8, MKTAG('V', 'P', '8', '0') },
193
/*
194 195
    { AV_CODEC_ID_VP4, MKTAG('V', 'P', '4', ' ') },
    { AV_CODEC_ID_VP4, MKTAG('V', 'P', '4', '0') },
196
*/
197 198 199
    { AV_CODEC_ID_MPEG4, MKTAG('X', 'V', 'I', 'D') }, /* cf sample xvid decoder from nsv_codec_sdk.zip */
    { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', '3') },
    { AV_CODEC_ID_NONE, 0 },
200 201
};

202
static const AVCodecTag nsv_codec_audio_tags[] = {
203 204 205
    { AV_CODEC_ID_MP3,       MKTAG('M', 'P', '3', ' ') },
    { AV_CODEC_ID_AAC,       MKTAG('A', 'A', 'C', ' ') },
    { AV_CODEC_ID_AAC,       MKTAG('A', 'A', 'C', 'P') },
206
    { AV_CODEC_ID_AAC,       MKTAG('V', 'L', 'B', ' ') },
207 208 209
    { AV_CODEC_ID_SPEEX,     MKTAG('S', 'P', 'X', ' ') },
    { AV_CODEC_ID_PCM_U16LE, MKTAG('P', 'C', 'M', ' ') },
    { AV_CODEC_ID_NONE,      0 },
210 211 212 213 214
};

//static int nsv_load_index(AVFormatContext *s);
static int nsv_read_chunk(AVFormatContext *s, int fill_header);

215
#define print_tag(str, tag, size)       \
216
    av_log(NULL, AV_LOG_TRACE, "%s: tag=%c%c%c%c\n", \
217 218 219 220
            str, tag & 0xff,            \
            (tag >> 8) & 0xff,          \
            (tag >> 16) & 0xff,         \
            (tag >> 24) & 0xff);
221 222 223 224 225

/* try to find something we recognize, and set the state accordingly */
static int nsv_resync(AVFormatContext *s)
{
    NSVContext *nsv = s->priv_data;
226
    AVIOContext *pb = s->pb;
Mike Melanson's avatar
Mike Melanson committed
227
    uint32_t v = 0;
228
    int i;
229

230
    av_log(s, AV_LOG_TRACE, "%s(), offset = %"PRId64", state = %d\n", __FUNCTION__, avio_tell(pb), nsv->state);
231

232
    //nsv->state = NSV_UNSYNC;
233

234
    for (i = 0; i < NSV_MAX_RESYNC; i++) {
235
        if (avio_feof(pb)) {
236
            av_log(s, AV_LOG_TRACE, "NSV EOF\n");
237 238 239 240
            nsv->state = NSV_UNSYNC;
            return -1;
        }
        v <<= 8;
241
        v |= avio_r8(pb);
242
        if (i < 8) {
243
            av_log(s, AV_LOG_TRACE, "NSV resync: [%d] = %02x\n", i, v & 0x0FF);
244
        }
245

246
        if ((v & 0x0000ffff) == 0xefbe) { /* BEEF */
247
            av_log(s, AV_LOG_TRACE, "NSV resynced on BEEF after %d bytes\n", i+1);
248 249 250
            nsv->state = NSV_FOUND_BEEF;
            return 0;
        }
251
        /* we read as big-endian, thus the MK*BE* */
252
        if (v == TB_NSVF) { /* NSVf */
253
            av_log(s, AV_LOG_TRACE, "NSV resynced on NSVf after %d bytes\n", i+1);
254 255 256 257
            nsv->state = NSV_FOUND_NSVF;
            return 0;
        }
        if (v == MKBETAG('N', 'S', 'V', 's')) { /* NSVs */
258
            av_log(s, AV_LOG_TRACE, "NSV resynced on NSVs after %d bytes\n", i+1);
259 260 261
            nsv->state = NSV_FOUND_NSVS;
            return 0;
        }
262

263
    }
264
    av_log(s, AV_LOG_TRACE, "NSV sync lost\n");
265 266 267
    return -1;
}

268
static int nsv_parse_NSVf_header(AVFormatContext *s)
269 270
{
    NSVContext *nsv = s->priv_data;
271
    AVIOContext *pb = s->pb;
272
    unsigned int av_unused file_size;
273
    unsigned int size;
274 275 276 277 278
    int64_t duration;
    int strings_size;
    int table_entries;
    int table_entries_used;

279
    av_log(s, AV_LOG_TRACE, "%s()\n", __FUNCTION__);
280 281

    nsv->state = NSV_UNSYNC; /* in case we fail */
282

283
    size = avio_rl32(pb);
284 285 286 287
    if (size < 28)
        return -1;
    nsv->NSVf_end = size;

288 289
    //s->file_size = (uint32_t)avio_rl32(pb);
    file_size = (uint32_t)avio_rl32(pb);
290 291
    av_log(s, AV_LOG_TRACE, "NSV NSVf chunk_size %u\n", size);
    av_log(s, AV_LOG_TRACE, "NSV NSVf file_size %u\n", file_size);
292

293
    nsv->duration = duration = avio_rl32(pb); /* in ms */
294
    av_log(s, AV_LOG_TRACE, "NSV NSVf duration %"PRId64" ms\n", duration);
295 296
    // XXX: store it in AVStreams

297 298 299
    strings_size = avio_rl32(pb);
    table_entries = avio_rl32(pb);
    table_entries_used = avio_rl32(pb);
300
    av_log(s, AV_LOG_TRACE, "NSV NSVf info-strings size: %d, table entries: %d, bis %d\n",
301
            strings_size, table_entries, table_entries_used);
302
    if (avio_feof(pb))
303
        return -1;
304

305
    av_log(s, AV_LOG_TRACE, "NSV got header; filepos %"PRId64"\n", avio_tell(pb));
306 307 308 309 310 311 312

    if (strings_size > 0) {
        char *strings; /* last byte will be '\0' to play safe with str*() */
        char *p, *endp;
        char *token, *value;
        char quote;

313
        p = strings = av_mallocz((size_t)strings_size + 1);
314 315
        if (!p)
            return AVERROR(ENOMEM);
316
        endp = strings + strings_size;
317
        avio_read(pb, strings, strings_size);
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
        while (p < endp) {
            while (*p == ' ')
                p++; /* strip out spaces */
            if (p >= endp-2)
                break;
            token = p;
            p = strchr(p, '=');
            if (!p || p >= endp-2)
                break;
            *p++ = '\0';
            quote = *p++;
            value = p;
            p = strchr(p, quote);
            if (!p || p >= endp)
                break;
            *p++ = '\0';
334
            av_log(s, AV_LOG_TRACE, "NSV NSVf INFO: %s='%s'\n", token, value);
335
            av_dict_set(&s->metadata, token, value, 0);
336 337 338
        }
        av_free(strings);
    }
339
    if (avio_feof(pb))
340
        return -1;
341

342
    av_log(s, AV_LOG_TRACE, "NSV got infos; filepos %"PRId64"\n", avio_tell(pb));
343 344

    if (table_entries_used > 0) {
345
        int i;
346
        nsv->index_entries = table_entries_used;
347
        if((unsigned)table_entries_used >= UINT_MAX / sizeof(uint32_t))
348
            return -1;
349
        nsv->nsvs_file_offset = av_malloc_array((unsigned)table_entries_used, sizeof(uint32_t));
350 351
        if (!nsv->nsvs_file_offset)
            return AVERROR(ENOMEM);
352 353

        for(i=0;i<table_entries_used;i++)
354
            nsv->nsvs_file_offset[i] = avio_rl32(pb) + size;
355 356

        if(table_entries > table_entries_used &&
357
           avio_rl32(pb) == MKTAG('T','O','C','2')) {
358
            nsv->nsvs_timestamps = av_malloc_array((unsigned)table_entries_used, sizeof(uint32_t));
359 360
            if (!nsv->nsvs_timestamps)
                return AVERROR(ENOMEM);
361
            for(i=0;i<table_entries_used;i++) {
362
                nsv->nsvs_timestamps[i] = avio_rl32(pb);
363 364
            }
        }
365 366
    }

367
    av_log(s, AV_LOG_TRACE, "NSV got index; filepos %"PRId64"\n", avio_tell(pb));
368

369
    avio_seek(pb, nsv->base_offset + size, SEEK_SET); /* required for dumbdriving-271.nsv (2 extra bytes) */
370

371
    if (avio_feof(pb))
372 373 374 375 376
        return -1;
    nsv->state = NSV_HAS_READ_NSVF;
    return 0;
}

377
static int nsv_parse_NSVs_header(AVFormatContext *s)
378 379
{
    NSVContext *nsv = s->priv_data;
380
    AVIOContext *pb = s->pb;
381 382
    uint32_t vtag, atag;
    uint16_t vwidth, vheight;
383 384
    AVRational framerate;
    int i;
385 386
    AVStream *st;
    NSVStream *nst;
387
    av_log(s, AV_LOG_TRACE, "%s()\n", __FUNCTION__);
388

389 390 391 392 393
    vtag = avio_rl32(pb);
    atag = avio_rl32(pb);
    vwidth = avio_rl16(pb);
    vheight = avio_rl16(pb);
    i = avio_r8(pb);
394

395
    av_log(s, AV_LOG_TRACE, "NSV NSVs framerate code %2x\n", i);
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
    if(i&0x80) { /* odd way of giving native framerates from docs */
        int t=(i & 0x7F)>>2;
        if(t<16) framerate = (AVRational){1, t+1};
        else     framerate = (AVRational){t-15, 1};

        if(i&1){
            framerate.num *= 1000;
            framerate.den *= 1001;
        }

        if((i&3)==3)      framerate.num *= 24;
        else if((i&3)==2) framerate.num *= 25;
        else              framerate.num *= 30;
    }
    else
        framerate= (AVRational){i, 1};

413
    nsv->avsync = avio_rl16(pb);
414
    nsv->framerate = framerate;
415

416 417
    print_tag("NSV NSVs vtag", vtag, 0);
    print_tag("NSV NSVs atag", atag, 0);
418
    av_log(s, AV_LOG_TRACE, "NSV NSVs vsize %dx%d\n", vwidth, vheight);
419

420 421 422 423 424 425 426
    /* XXX change to ap != NULL ? */
    if (s->nb_streams == 0) { /* streams not yet published, let's do that */
        nsv->vtag = vtag;
        nsv->atag = atag;
        nsv->vwidth = vwidth;
        nsv->vheight = vwidth;
        if (vtag != T_NONE) {
427
            int i;
428
            st = avformat_new_stream(s, NULL);
429 430 431
            if (!st)
                goto fail;

432
            st->id = NSV_ST_VIDEO;
433 434 435 436
            nst = av_mallocz(sizeof(NSVStream));
            if (!nst)
                goto fail;
            st->priv_data = nst;
437 438 439 440 441 442
            st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
            st->codecpar->codec_tag = vtag;
            st->codecpar->codec_id = ff_codec_get_id(nsv_codec_video_tags, vtag);
            st->codecpar->width = vwidth;
            st->codecpar->height = vheight;
            st->codecpar->bits_per_coded_sample = 24; /* depth XXX */
443

444
            avpriv_set_pts_info(st, 64, framerate.den, framerate.num);
445
            st->start_time = 0;
446
            st->duration = av_rescale(nsv->duration, framerate.num, 1000*framerate.den);
447 448 449 450 451 452 453 454 455 456

            for(i=0;i<nsv->index_entries;i++) {
                if(nsv->nsvs_timestamps) {
                    av_add_index_entry(st, nsv->nsvs_file_offset[i], nsv->nsvs_timestamps[i],
                                       0, 0, AVINDEX_KEYFRAME);
                } else {
                    int64_t ts = av_rescale(i*nsv->duration/nsv->index_entries, framerate.num, 1000*framerate.den);
                    av_add_index_entry(st, nsv->nsvs_file_offset[i], ts, 0, 0, AVINDEX_KEYFRAME);
                }
            }
457 458
        }
        if (atag != T_NONE) {
459
            st = avformat_new_stream(s, NULL);
460 461 462
            if (!st)
                goto fail;

463
            st->id = NSV_ST_AUDIO;
464 465 466 467
            nst = av_mallocz(sizeof(NSVStream));
            if (!nst)
                goto fail;
            st->priv_data = nst;
468 469 470
            st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
            st->codecpar->codec_tag = atag;
            st->codecpar->codec_id = ff_codec_get_id(nsv_codec_audio_tags, atag);
471

472
            st->need_parsing = AVSTREAM_PARSE_FULL; /* for PCM we will read a chunk later and put correct info */
473

474
            /* set timebase to common denominator of ms and framerate */
475
            avpriv_set_pts_info(st, 64, 1, framerate.num*1000);
476 477
            st->start_time = 0;
            st->duration = (int64_t)nsv->duration * framerate.num;
478 479 480
        }
    } else {
        if (nsv->vtag != vtag || nsv->atag != atag || nsv->vwidth != vwidth || nsv->vheight != vwidth) {
481
            av_log(s, AV_LOG_TRACE, "NSV NSVs header values differ from the first one!!!\n");
482 483 484 485 486 487 488 489 490 491 492 493
            //return -1;
        }
    }

    nsv->state = NSV_HAS_READ_NSVS;
    return 0;
fail:
    /* XXX */
    nsv->state = NSV_UNSYNC;
    return -1;
}

494
static int nsv_read_header(AVFormatContext *s)
495 496
{
    NSVContext *nsv = s->priv_data;
497
    int i, err;
498

499 500
    av_log(s, AV_LOG_TRACE, "%s()\n", __FUNCTION__);
    av_log(s, AV_LOG_TRACE, "filename '%s'\n", s->filename);
501 502 503

    nsv->state = NSV_UNSYNC;
    nsv->ahead[0].data = nsv->ahead[1].data = NULL;
504

505 506 507
    for (i = 0; i < NSV_MAX_RESYNC_TRIES; i++) {
        if (nsv_resync(s) < 0)
            return -1;
Alex Converse's avatar
Alex Converse committed
508
        if (nsv->state == NSV_FOUND_NSVF) {
509
            err = nsv_parse_NSVf_header(s);
Alex Converse's avatar
Alex Converse committed
510 511 512
            if (err < 0)
                return err;
        }
513 514
            /* we need the first NSVs also... */
        if (nsv->state == NSV_FOUND_NSVS) {
515
            err = nsv_parse_NSVs_header(s);
Alex Converse's avatar
Alex Converse committed
516 517
            if (err < 0)
                return err;
518 519 520 521 522 523 524
            break; /* we just want the first one */
        }
    }
    if (s->nb_streams < 1) /* no luck so far */
        return -1;
    /* now read the first chunk, so we can attempt to decode more info */
    err = nsv_read_chunk(s, 1);
525

526
    av_log(s, AV_LOG_TRACE, "parsed header\n");
527
    return err;
528 529 530 531 532
}

static int nsv_read_chunk(AVFormatContext *s, int fill_header)
{
    NSVContext *nsv = s->priv_data;
533
    AVIOContext *pb = s->pb;
534 535 536 537
    AVStream *st[2] = {NULL, NULL};
    NSVStream *nst;
    AVPacket *pkt;
    int i, err = 0;
Mike Melanson's avatar
Mike Melanson committed
538 539 540 541
    uint8_t auxcount; /* number of aux metadata, also 4 bits of vsize */
    uint32_t vsize;
    uint16_t asize;
    uint16_t auxsize;
542
    int ret;
543

544
    av_log(s, AV_LOG_TRACE, "%s(%d)\n", __FUNCTION__, fill_header);
545

546 547 548 549
    if (nsv->ahead[0].data || nsv->ahead[1].data)
        return 0; //-1; /* hey! eat what you've in your plate first! */

null_chunk_retry:
550
    if (avio_feof(pb))
551
        return -1;
552

553 554 555 556 557
    for (i = 0; i < NSV_MAX_RESYNC_TRIES && nsv->state < NSV_FOUND_NSVS && !err; i++)
        err = nsv_resync(s);
    if (err < 0)
        return err;
    if (nsv->state == NSV_FOUND_NSVS)
558
        err = nsv_parse_NSVs_header(s);
559 560 561 562
    if (err < 0)
        return err;
    if (nsv->state != NSV_HAS_READ_NSVS && nsv->state != NSV_FOUND_BEEF)
        return -1;
563

564 565 566
    auxcount = avio_r8(pb);
    vsize = avio_rl16(pb);
    asize = avio_rl16(pb);
567 568
    vsize = (vsize << 4) | (auxcount >> 4);
    auxcount &= 0x0f;
569
    av_log(s, AV_LOG_TRACE, "NSV CHUNK %d aux, %u bytes video, %d bytes audio\n", auxcount, vsize, asize);
570 571
    /* skip aux stuff */
    for (i = 0; i < auxcount; i++) {
572
        uint32_t av_unused auxtag;
573 574
        auxsize = avio_rl16(pb);
        auxtag = avio_rl32(pb);
575
        av_log(s, AV_LOG_TRACE, "NSV aux data: '%c%c%c%c', %d bytes\n",
576 577
              (auxtag & 0x0ff),
              ((auxtag >> 8) & 0x0ff),
578 579
              ((auxtag >> 16) & 0x0ff),
              ((auxtag >> 24) & 0x0ff),
580
              auxsize);
581
        avio_skip(pb, auxsize);
582
        vsize -= auxsize + sizeof(uint16_t) + sizeof(uint32_t); /* that's becoming brain-dead */
583
    }
584

585
    if (avio_feof(pb))
586 587 588 589 590
        return -1;
    if (!vsize && !asize) {
        nsv->state = NSV_UNSYNC;
        goto null_chunk_retry;
    }
591

592
    /* map back streams to v,a */
593
    if (s->nb_streams > 0)
594
        st[s->streams[0]->id] = s->streams[0];
595
    if (s->nb_streams > 1)
596
        st[s->streams[1]->id] = s->streams[1];
597

598
    if (vsize && st[NSV_ST_VIDEO]) {
599 600
        nst = st[NSV_ST_VIDEO]->priv_data;
        pkt = &nsv->ahead[NSV_ST_VIDEO];
601 602
        if ((ret = av_get_packet(pb, pkt, vsize)) < 0)
            return ret;
603
        pkt->stream_index = st[NSV_ST_VIDEO]->index;//NSV_ST_VIDEO;
604
        pkt->dts = nst->frame_offset;
605
        pkt->flags |= nsv->state == NSV_HAS_READ_NSVS ? AV_PKT_FLAG_KEY : 0; /* keyframe only likely on a sync frame */
606
        for (i = 0; i < FFMIN(8, vsize); i++)
607
            av_log(s, AV_LOG_TRACE, "NSV video: [%d] = %02x\n", i, pkt->data[i]);
608
    }
609
    if(st[NSV_ST_VIDEO])
Michael Niedermayer's avatar
Michael Niedermayer committed
610
        ((NSVStream*)st[NSV_ST_VIDEO]->priv_data)->frame_offset++;
611

612
    if (asize && st[NSV_ST_AUDIO]) {
613 614 615 616
        nst = st[NSV_ST_AUDIO]->priv_data;
        pkt = &nsv->ahead[NSV_ST_AUDIO];
        /* read raw audio specific header on the first audio chunk... */
        /* on ALL audio chunks ?? seems so! */
617
        if (asize && st[NSV_ST_AUDIO]->codecpar->codec_tag == MKTAG('P', 'C', 'M', ' ')/* && fill_header*/) {
618 619 620
            uint8_t bps;
            uint8_t channels;
            uint16_t samplerate;
621 622 623
            bps = avio_r8(pb);
            channels = avio_r8(pb);
            samplerate = avio_rl16(pb);
624 625
            if (!channels || !samplerate)
                return AVERROR_INVALIDDATA;
626
            asize-=4;
627
            av_log(s, AV_LOG_TRACE, "NSV RAWAUDIO: bps %d, nchan %d, srate %d\n", bps, channels, samplerate);
628
            if (fill_header) {
629
                st[NSV_ST_AUDIO]->need_parsing = AVSTREAM_PARSE_NONE; /* we know everything */
630
                if (bps != 16) {
631
                    av_log(s, AV_LOG_TRACE, "NSV AUDIO bit/sample != 16 (%d)!!!\n", bps);
632
                }
633
                bps /= channels; // ???
634
                if (bps == 8)
635
                    st[NSV_ST_AUDIO]->codecpar->codec_id = AV_CODEC_ID_PCM_U8;
636 637
                samplerate /= 4;/* UGH ??? XXX */
                channels = 1;
638 639
                st[NSV_ST_AUDIO]->codecpar->channels = channels;
                st[NSV_ST_AUDIO]->codecpar->sample_rate = samplerate;
640
                av_log(s, AV_LOG_TRACE, "NSV RAWAUDIO: bps %d, nchan %d, srate %d\n", bps, channels, samplerate);
641 642
            }
        }
643 644
        if ((ret = av_get_packet(pb, pkt, asize)) < 0)
            return ret;
645
        pkt->stream_index = st[NSV_ST_AUDIO]->index;//NSV_ST_AUDIO;
646
        pkt->flags |= nsv->state == NSV_HAS_READ_NSVS ? AV_PKT_FLAG_KEY : 0; /* keyframe only likely on a sync frame */
647 648 649
        if( nsv->state == NSV_HAS_READ_NSVS && st[NSV_ST_VIDEO] ) {
            /* on a nsvs frame we have new information on a/v sync */
            pkt->dts = (((NSVStream*)st[NSV_ST_VIDEO]->priv_data)->frame_offset-1);
650 651
            pkt->dts *= (int64_t)1000        * nsv->framerate.den;
            pkt->dts += (int64_t)nsv->avsync * nsv->framerate.num;
652
            av_log(s, AV_LOG_TRACE, "NSV AUDIO: sync:%d, dts:%"PRId64, nsv->avsync, pkt->dts);
653 654
        }
        nst->frame_offset++;
655
    }
656

657 658 659 660 661 662 663 664 665 666
    nsv->state = NSV_UNSYNC;
    return 0;
}


static int nsv_read_packet(AVFormatContext *s, AVPacket *pkt)
{
    NSVContext *nsv = s->priv_data;
    int i, err = 0;

667
    av_log(s, AV_LOG_TRACE, "%s()\n", __FUNCTION__);
668

669
    /* in case we don't already have something to eat ... */
670
    if (!nsv->ahead[0].data && !nsv->ahead[1].data)
671 672 673
        err = nsv_read_chunk(s, 0);
    if (err < 0)
        return err;
674

675 676 677
    /* now pick one of the plates */
    for (i = 0; i < 2; i++) {
        if (nsv->ahead[i].data) {
678
            av_log(s, AV_LOG_TRACE, "%s: using cached packet[%d]\n", __FUNCTION__, i);
679 680 681 682 683 684
            /* avoid the cost of new_packet + memcpy(->data) */
            memcpy(pkt, &nsv->ahead[i], sizeof(AVPacket));
            nsv->ahead[i].data = NULL; /* we ate that one */
            return pkt->size;
        }
    }
685

686
    /* this restaurant is not provisioned :^] */
687 688 689 690 691
    return -1;
}

static int nsv_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
{
692 693 694 695
    NSVContext *nsv = s->priv_data;
    AVStream *st = s->streams[stream_index];
    NSVStream *nst = st->priv_data;
    int index;
696

697 698 699 700
    index = av_index_search_timestamp(st, timestamp, flags);
    if(index < 0)
        return -1;

701 702 703
    if (avio_seek(s->pb, st->index_entries[index].pos, SEEK_SET) < 0)
        return -1;

704 705 706
    nst->frame_offset = st->index_entries[index].timestamp;
    nsv->state = NSV_UNSYNC;
    return 0;
707 708 709 710 711 712
}

static int nsv_read_close(AVFormatContext *s)
{
    NSVContext *nsv = s->priv_data;

713 714
    av_freep(&nsv->nsvs_file_offset);
    av_freep(&nsv->nsvs_timestamps);
715
    if (nsv->ahead[0].data)
716
        av_packet_unref(&nsv->ahead[0]);
717
    if (nsv->ahead[1].data)
718
        av_packet_unref(&nsv->ahead[1]);
719 720 721 722 723
    return 0;
}

static int nsv_probe(AVProbeData *p)
{
724 725
    int i, score = 0;

726 727 728
    /* check file header */
    /* streamed files might not have any header */
    if (p->buf[0] == 'N' && p->buf[1] == 'S' &&
Michael Niedermayer's avatar
Michael Niedermayer committed
729
        p->buf[2] == 'V' && (p->buf[3] == 'f' || p->buf[3] == 's'))
730 731 732 733 734 735
        return AVPROBE_SCORE_MAX;
    /* XXX: do streamed files always start at chunk boundary ?? */
    /* or do we need to search NSVs in the byte stream ? */
    /* seems the servers don't bother starting clean chunks... */
    /* sometimes even the first header is at 9KB or something :^) */
    for (i = 1; i < p->buf_size - 3; i++) {
736
        if (AV_RL32(p->buf + i) == AV_RL32("NSVs")) {
737
            /* Get the chunk size and check if at the end we are getting 0xBEEF */
738 739 740 741 742 743
            int vsize = AV_RL24(p->buf+i+19) >> 4;
            int asize = AV_RL16(p->buf+i+22);
            int offset = i + 23 + asize + vsize + 1;
            if (offset <= p->buf_size - 2 && AV_RL16(p->buf + offset) == 0xBEEF)
                return 4*AVPROBE_SCORE_MAX/5;
            score = AVPROBE_SCORE_MAX/5;
744
        }
745 746
    }
    /* so we'll have more luck on extension... */
747
    if (av_match_ext(p->filename, "nsv"))
748
        return AVPROBE_SCORE_EXTENSION;
749
    /* FIXME: add mime-type check */
750
    return score;
751 752
}

753
AVInputFormat ff_nsv_demuxer = {
754 755 756 757 758 759 760 761
    .name           = "nsv",
    .long_name      = NULL_IF_CONFIG_SMALL("Nullsoft Streaming Video"),
    .priv_data_size = sizeof(NSVContext),
    .read_probe     = nsv_probe,
    .read_header    = nsv_read_header,
    .read_packet    = nsv_read_packet,
    .read_close     = nsv_read_close,
    .read_seek      = nsv_read_seek,
762
};