00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "avformat.h"
00022 #include "riff.h"
00023
00024
00025
00026
00027 #define CHECK_SUBSEQUENT_NSVS
00028
00029
00030
00031
00032
00033 #define NSV_MAX_RESYNC (500*1024)
00034 #define NSV_MAX_RESYNC_TRIES 300
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084 #ifdef DEBUG
00085 #define PRINT(_v) printf _v
00086 #else
00087 #define PRINT(_v)
00088 #endif
00089
00090 #if 0
00091 struct NSVf_header {
00092 uint32_t chunk_tag;
00093 uint32_t chunk_size;
00094 uint32_t file_size;
00095 uint32_t file_length;
00096 uint32_t info_strings_size;
00097 uint32_t table_entries;
00098 uint32_t table_entries_used;
00099 };
00100
00101 struct NSVs_header {
00102 uint32_t chunk_tag;
00103 uint32_t v4cc;
00104 uint32_t a4cc;
00105 uint16_t vwidth;
00106 uint16_t vheight;
00107 uint8_t framerate;
00108 uint16_t unknown;
00109 };
00110
00111 struct nsv_avchunk_header {
00112 uint8_t vchunk_size_lsb;
00113 uint16_t vchunk_size_msb;
00114 uint16_t achunk_size;
00115 };
00116
00117 struct nsv_pcm_header {
00118 uint8_t bits_per_sample;
00119 uint8_t channel_count;
00120 uint16_t sample_rate;
00121 };
00122 #endif
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132 #define T_NSVF MKTAG('N', 'S', 'V', 'f')
00133 #define T_NSVS MKTAG('N', 'S', 'V', 's')
00134 #define T_TOC2 MKTAG('T', 'O', 'C', '2')
00135 #define T_NONE MKTAG('N', 'O', 'N', 'E')
00136 #define T_SUBT MKTAG('S', 'U', 'B', 'T')
00137 #define T_ASYN MKTAG('A', 'S', 'Y', 'N')
00138 #define T_KEYF MKTAG('K', 'E', 'Y', 'F')
00139
00140 #define TB_NSVF MKBETAG('N', 'S', 'V', 'f')
00141 #define TB_NSVS MKBETAG('N', 'S', 'V', 's')
00142
00143
00144 #define NSV_ST_VIDEO 0
00145 #define NSV_ST_AUDIO 1
00146 #define NSV_ST_SUBT 2
00147
00148 enum NSVStatus {
00149 NSV_UNSYNC,
00150 NSV_FOUND_NSVF,
00151 NSV_HAS_READ_NSVF,
00152 NSV_FOUND_NSVS,
00153 NSV_HAS_READ_NSVS,
00154 NSV_FOUND_BEEF,
00155 NSV_GOT_VIDEO,
00156 NSV_GOT_AUDIO,
00157 };
00158
00159 typedef struct NSVStream {
00160 int frame_offset;
00161
00162 int scale;
00163 int rate;
00164 int sample_size;
00165 int start;
00166
00167 int new_frame_offset;
00168 int cum_len;
00169 } NSVStream;
00170
00171 typedef struct {
00172 int base_offset;
00173 int NSVf_end;
00174 uint32_t *nsvf_index_data;
00175 int index_entries;
00176 enum NSVStatus state;
00177 AVPacket ahead[2];
00178
00179 int64_t duration;
00180 uint32_t vtag, atag;
00181 uint16_t vwidth, vheight;
00182 int16_t avsync;
00183 AVRational framerate;
00184
00185 } NSVContext;
00186
00187 static const AVCodecTag nsv_codec_video_tags[] = {
00188 { CODEC_ID_VP3, MKTAG('V', 'P', '3', ' ') },
00189 { CODEC_ID_VP3, MKTAG('V', 'P', '3', '0') },
00190 { CODEC_ID_VP3, MKTAG('V', 'P', '3', '1') },
00191 { CODEC_ID_VP5, MKTAG('V', 'P', '5', ' ') },
00192 { CODEC_ID_VP5, MKTAG('V', 'P', '5', '0') },
00193 { CODEC_ID_VP6, MKTAG('V', 'P', '6', ' ') },
00194 { CODEC_ID_VP6, MKTAG('V', 'P', '6', '0') },
00195 { CODEC_ID_VP6, MKTAG('V', 'P', '6', '1') },
00196 { CODEC_ID_VP6, MKTAG('V', 'P', '6', '2') },
00197
00198
00199
00200
00201 { CODEC_ID_MPEG4, MKTAG('X', 'V', 'I', 'D') },
00202 { CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', '3') },
00203 { 0, 0 },
00204 };
00205
00206 static const AVCodecTag nsv_codec_audio_tags[] = {
00207 { CODEC_ID_MP3, MKTAG('M', 'P', '3', ' ') },
00208 { CODEC_ID_AAC, MKTAG('A', 'A', 'C', ' ') },
00209 { CODEC_ID_AAC, MKTAG('A', 'A', 'C', 'P') },
00210 { CODEC_ID_PCM_U16LE, MKTAG('P', 'C', 'M', ' ') },
00211 { 0, 0 },
00212 };
00213
00214
00215 static int nsv_read_chunk(AVFormatContext *s, int fill_header);
00216
00217 #ifdef DEBUG
00218 static void print_tag(const char *str, unsigned int tag, int size)
00219 {
00220 printf("%s: tag=%c%c%c%c\n",
00221 str, tag & 0xff,
00222 (tag >> 8) & 0xff,
00223 (tag >> 16) & 0xff,
00224 (tag >> 24) & 0xff);
00225 }
00226 #endif
00227
00228
00229 static int nsv_resync(AVFormatContext *s)
00230 {
00231 NSVContext *nsv = s->priv_data;
00232 ByteIOContext *pb = s->pb;
00233 uint32_t v = 0;
00234 int i;
00235
00236 PRINT(("%s(), offset = %"PRId64", state = %d\n", __FUNCTION__, url_ftell(pb), nsv->state));
00237
00238
00239
00240 for (i = 0; i < NSV_MAX_RESYNC; i++) {
00241 if (url_feof(pb)) {
00242 PRINT(("NSV EOF\n"));
00243 nsv->state = NSV_UNSYNC;
00244 return -1;
00245 }
00246 v <<= 8;
00247 v |= get_byte(pb);
00248
00249
00250
00251
00252
00253
00254 if ((v & 0x0000ffff) == 0xefbe) {
00255 PRINT(("NSV resynced on BEEF after %d bytes\n", i+1));
00256 nsv->state = NSV_FOUND_BEEF;
00257 return 0;
00258 }
00259
00260 if (v == TB_NSVF) {
00261 PRINT(("NSV resynced on NSVf after %d bytes\n", i+1));
00262 nsv->state = NSV_FOUND_NSVF;
00263 return 0;
00264 }
00265 if (v == MKBETAG('N', 'S', 'V', 's')) {
00266 PRINT(("NSV resynced on NSVs after %d bytes\n", i+1));
00267 nsv->state = NSV_FOUND_NSVS;
00268 return 0;
00269 }
00270
00271 }
00272 PRINT(("NSV sync lost\n"));
00273 return -1;
00274 }
00275
00276 static int nsv_parse_NSVf_header(AVFormatContext *s, AVFormatParameters *ap)
00277 {
00278 NSVContext *nsv = s->priv_data;
00279 ByteIOContext *pb = s->pb;
00280 unsigned int file_size, size;
00281 int64_t duration;
00282 int strings_size;
00283 int table_entries;
00284 int table_entries_used;
00285
00286 PRINT(("%s()\n", __FUNCTION__));
00287
00288 nsv->state = NSV_UNSYNC;
00289
00290 size = get_le32(pb);
00291 if (size < 28)
00292 return -1;
00293 nsv->NSVf_end = size;
00294
00295
00296 file_size = (uint32_t)get_le32(pb);
00297 PRINT(("NSV NSVf chunk_size %u\n", size));
00298 PRINT(("NSV NSVf file_size %u\n", file_size));
00299
00300 nsv->duration = duration = get_le32(pb);
00301 PRINT(("NSV NSVf duration %"PRId64" ms\n", duration));
00302
00303
00304 strings_size = get_le32(pb);
00305 table_entries = get_le32(pb);
00306 table_entries_used = get_le32(pb);
00307 PRINT(("NSV NSVf info-strings size: %d, table entries: %d, bis %d\n",
00308 strings_size, table_entries, table_entries_used));
00309 if (url_feof(pb))
00310 return -1;
00311
00312 PRINT(("NSV got header; filepos %"PRId64"\n", url_ftell(pb)));
00313
00314 if (strings_size > 0) {
00315 char *strings;
00316 char *p, *endp;
00317 char *token, *value;
00318 char quote;
00319
00320 p = strings = av_mallocz(strings_size + 1);
00321 endp = strings + strings_size;
00322 get_buffer(pb, strings, strings_size);
00323 while (p < endp) {
00324 while (*p == ' ')
00325 p++;
00326 if (p >= endp-2)
00327 break;
00328 token = p;
00329 p = strchr(p, '=');
00330 if (!p || p >= endp-2)
00331 break;
00332 *p++ = '\0';
00333 quote = *p++;
00334 value = p;
00335 p = strchr(p, quote);
00336 if (!p || p >= endp)
00337 break;
00338 *p++ = '\0';
00339 PRINT(("NSV NSVf INFO: %s='%s'\n", token, value));
00340 av_metadata_set(&s->metadata, token, value);
00341 }
00342 av_free(strings);
00343 }
00344 if (url_feof(pb))
00345 return -1;
00346
00347 PRINT(("NSV got infos; filepos %"PRId64"\n", url_ftell(pb)));
00348
00349 if (table_entries_used > 0) {
00350 nsv->index_entries = table_entries_used;
00351 if((unsigned)table_entries >= UINT_MAX / sizeof(uint32_t))
00352 return -1;
00353 nsv->nsvf_index_data = av_malloc(table_entries * sizeof(uint32_t));
00354 #warning "FIXME: Byteswap buffer as needed"
00355 get_buffer(pb, (unsigned char *)nsv->nsvf_index_data, table_entries * sizeof(uint32_t));
00356 }
00357
00358 PRINT(("NSV got index; filepos %"PRId64"\n", url_ftell(pb)));
00359
00360 #ifdef DEBUG_DUMP_INDEX
00361 #define V(v) ((v<0x20 || v > 127)?'.':v)
00362
00363 PRINT(("NSV %d INDEX ENTRIES:\n", table_entries));
00364 PRINT(("NSV [dataoffset][fileoffset]\n", table_entries));
00365 for (i = 0; i < table_entries; i++) {
00366 unsigned char b[8];
00367 url_fseek(pb, size + nsv->nsvf_index_data[i], SEEK_SET);
00368 get_buffer(pb, b, 8);
00369 PRINT(("NSV [0x%08lx][0x%08lx]: %02x %02x %02x %02x %02x %02x %02x %02x"
00370 "%c%c%c%c%c%c%c%c\n",
00371 nsv->nsvf_index_data[i], size + nsv->nsvf_index_data[i],
00372 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
00373 V(b[0]), V(b[1]), V(b[2]), V(b[3]), V(b[4]), V(b[5]), V(b[6]), V(b[7]) ));
00374 }
00375
00376 #undef V
00377 #endif
00378
00379 url_fseek(pb, nsv->base_offset + size, SEEK_SET);
00380
00381 if (url_feof(pb))
00382 return -1;
00383 nsv->state = NSV_HAS_READ_NSVF;
00384 return 0;
00385 }
00386
00387 static int nsv_parse_NSVs_header(AVFormatContext *s, AVFormatParameters *ap)
00388 {
00389 NSVContext *nsv = s->priv_data;
00390 ByteIOContext *pb = s->pb;
00391 uint32_t vtag, atag;
00392 uint16_t vwidth, vheight;
00393 AVRational framerate;
00394 int i;
00395 AVStream *st;
00396 NSVStream *nst;
00397 PRINT(("%s()\n", __FUNCTION__));
00398
00399 vtag = get_le32(pb);
00400 atag = get_le32(pb);
00401 vwidth = get_le16(pb);
00402 vheight = get_le16(pb);
00403 i = get_byte(pb);
00404
00405 PRINT(("NSV NSVs framerate code %2x\n", i));
00406 if(i&0x80) {
00407 int t=(i & 0x7F)>>2;
00408 if(t<16) framerate = (AVRational){1, t+1};
00409 else framerate = (AVRational){t-15, 1};
00410
00411 if(i&1){
00412 framerate.num *= 1000;
00413 framerate.den *= 1001;
00414 }
00415
00416 if((i&3)==3) framerate.num *= 24;
00417 else if((i&3)==2) framerate.num *= 25;
00418 else framerate.num *= 30;
00419 }
00420 else
00421 framerate= (AVRational){i, 1};
00422
00423 nsv->avsync = get_le16(pb);
00424 nsv->framerate = framerate;
00425 #ifdef DEBUG
00426 print_tag("NSV NSVs vtag", vtag, 0);
00427 print_tag("NSV NSVs atag", atag, 0);
00428 PRINT(("NSV NSVs vsize %dx%d\n", vwidth, vheight));
00429 #endif
00430
00431
00432 if (s->nb_streams == 0) {
00433 nsv->vtag = vtag;
00434 nsv->atag = atag;
00435 nsv->vwidth = vwidth;
00436 nsv->vheight = vwidth;
00437 if (vtag != T_NONE) {
00438 st = av_new_stream(s, NSV_ST_VIDEO);
00439 if (!st)
00440 goto fail;
00441
00442 nst = av_mallocz(sizeof(NSVStream));
00443 if (!nst)
00444 goto fail;
00445 st->priv_data = nst;
00446 st->codec->codec_type = CODEC_TYPE_VIDEO;
00447 st->codec->codec_tag = vtag;
00448 st->codec->codec_id = codec_get_id(nsv_codec_video_tags, vtag);
00449 st->codec->width = vwidth;
00450 st->codec->height = vheight;
00451 st->codec->bits_per_coded_sample = 24;
00452
00453 av_set_pts_info(st, 64, framerate.den, framerate.num);
00454 st->start_time = 0;
00455 st->duration = av_rescale(nsv->duration, framerate.num, 1000*framerate.den);
00456 }
00457 if (atag != T_NONE) {
00458 #ifndef DISABLE_AUDIO
00459 st = av_new_stream(s, NSV_ST_AUDIO);
00460 if (!st)
00461 goto fail;
00462
00463 nst = av_mallocz(sizeof(NSVStream));
00464 if (!nst)
00465 goto fail;
00466 st->priv_data = nst;
00467 st->codec->codec_type = CODEC_TYPE_AUDIO;
00468 st->codec->codec_tag = atag;
00469 st->codec->codec_id = codec_get_id(nsv_codec_audio_tags, atag);
00470
00471 st->need_parsing = AVSTREAM_PARSE_FULL;
00472
00473
00474 av_set_pts_info(st, 64, 1, framerate.num*1000);
00475 st->start_time = 0;
00476 st->duration = (int64_t)nsv->duration * framerate.num;
00477 #endif
00478 }
00479 #ifdef CHECK_SUBSEQUENT_NSVS
00480 } else {
00481 if (nsv->vtag != vtag || nsv->atag != atag || nsv->vwidth != vwidth || nsv->vheight != vwidth) {
00482 PRINT(("NSV NSVs header values differ from the first one!!!\n"));
00483
00484 }
00485 #endif
00486 }
00487
00488 nsv->state = NSV_HAS_READ_NSVS;
00489 return 0;
00490 fail:
00491
00492 nsv->state = NSV_UNSYNC;
00493 return -1;
00494 }
00495
00496 static int nsv_read_header(AVFormatContext *s, AVFormatParameters *ap)
00497 {
00498 NSVContext *nsv = s->priv_data;
00499 int i, err;
00500
00501 PRINT(("%s()\n", __FUNCTION__));
00502 PRINT(("filename '%s'\n", s->filename));
00503
00504 nsv->state = NSV_UNSYNC;
00505 nsv->ahead[0].data = nsv->ahead[1].data = NULL;
00506
00507 for (i = 0; i < NSV_MAX_RESYNC_TRIES; i++) {
00508 if (nsv_resync(s) < 0)
00509 return -1;
00510 if (nsv->state == NSV_FOUND_NSVF)
00511 err = nsv_parse_NSVf_header(s, ap);
00512
00513 if (nsv->state == NSV_FOUND_NSVS) {
00514 err = nsv_parse_NSVs_header(s, ap);
00515 break;
00516 }
00517 }
00518 if (s->nb_streams < 1)
00519 return -1;
00520
00521 err = nsv_read_chunk(s, 1);
00522
00523 PRINT(("parsed header\n"));
00524 return 0;
00525 }
00526
00527 static int nsv_read_chunk(AVFormatContext *s, int fill_header)
00528 {
00529 NSVContext *nsv = s->priv_data;
00530 ByteIOContext *pb = s->pb;
00531 AVStream *st[2] = {NULL, NULL};
00532 NSVStream *nst;
00533 AVPacket *pkt;
00534 int i, err = 0;
00535 uint8_t auxcount;
00536 uint32_t vsize;
00537 uint16_t asize;
00538 uint16_t auxsize;
00539 uint32_t auxtag;
00540
00541 PRINT(("%s(%d)\n", __FUNCTION__, fill_header));
00542
00543 if (nsv->ahead[0].data || nsv->ahead[1].data)
00544 return 0;
00545
00546 null_chunk_retry:
00547 if (url_feof(pb))
00548 return -1;
00549
00550 for (i = 0; i < NSV_MAX_RESYNC_TRIES && nsv->state < NSV_FOUND_NSVS && !err; i++)
00551 err = nsv_resync(s);
00552 if (err < 0)
00553 return err;
00554 if (nsv->state == NSV_FOUND_NSVS)
00555 err = nsv_parse_NSVs_header(s, NULL);
00556 if (err < 0)
00557 return err;
00558 if (nsv->state != NSV_HAS_READ_NSVS && nsv->state != NSV_FOUND_BEEF)
00559 return -1;
00560
00561 auxcount = get_byte(pb);
00562 vsize = get_le16(pb);
00563 asize = get_le16(pb);
00564 vsize = (vsize << 4) | (auxcount >> 4);
00565 auxcount &= 0x0f;
00566 PRINT(("NSV CHUNK %d aux, %u bytes video, %d bytes audio\n", auxcount, vsize, asize));
00567
00568 for (i = 0; i < auxcount; i++) {
00569 auxsize = get_le16(pb);
00570 auxtag = get_le32(pb);
00571 PRINT(("NSV aux data: '%c%c%c%c', %d bytes\n",
00572 (auxtag & 0x0ff),
00573 ((auxtag >> 8) & 0x0ff),
00574 ((auxtag >> 16) & 0x0ff),
00575 ((auxtag >> 24) & 0x0ff),
00576 auxsize));
00577 url_fskip(pb, auxsize);
00578 vsize -= auxsize + sizeof(uint16_t) + sizeof(uint32_t);
00579 }
00580
00581 if (url_feof(pb))
00582 return -1;
00583 if (!vsize && !asize) {
00584 nsv->state = NSV_UNSYNC;
00585 goto null_chunk_retry;
00586 }
00587
00588
00589 if (s->streams[0])
00590 st[s->streams[0]->id] = s->streams[0];
00591 if (s->streams[1])
00592 st[s->streams[1]->id] = s->streams[1];
00593
00594 if (vsize) {
00595 nst = st[NSV_ST_VIDEO]->priv_data;
00596 pkt = &nsv->ahead[NSV_ST_VIDEO];
00597 av_get_packet(pb, pkt, vsize);
00598 pkt->stream_index = st[NSV_ST_VIDEO]->index;
00599 pkt->dts = nst->frame_offset;
00600 pkt->flags |= nsv->state == NSV_HAS_READ_NSVS ? PKT_FLAG_KEY : 0;
00601
00602
00603
00604
00605 }
00606 if(st[NSV_ST_VIDEO])
00607 ((NSVStream*)st[NSV_ST_VIDEO]->priv_data)->frame_offset++;
00608
00609 if (asize) {
00610 nst = st[NSV_ST_AUDIO]->priv_data;
00611 pkt = &nsv->ahead[NSV_ST_AUDIO];
00612
00613
00614 if (asize && st[NSV_ST_AUDIO]->codec->codec_tag == MKTAG('P', 'C', 'M', ' ')) {
00615 uint8_t bps;
00616 uint8_t channels;
00617 uint16_t samplerate;
00618 bps = get_byte(pb);
00619 channels = get_byte(pb);
00620 samplerate = get_le16(pb);
00621 asize-=4;
00622 PRINT(("NSV RAWAUDIO: bps %d, nchan %d, srate %d\n", bps, channels, samplerate));
00623 if (fill_header) {
00624 st[NSV_ST_AUDIO]->need_parsing = AVSTREAM_PARSE_NONE;
00625 if (bps != 16) {
00626 PRINT(("NSV AUDIO bit/sample != 16 (%d)!!!\n", bps));
00627 }
00628 bps /= channels;
00629 if (bps == 8)
00630 st[NSV_ST_AUDIO]->codec->codec_id = CODEC_ID_PCM_U8;
00631 samplerate /= 4;
00632 channels = 1;
00633 st[NSV_ST_AUDIO]->codec->channels = channels;
00634 st[NSV_ST_AUDIO]->codec->sample_rate = samplerate;
00635 PRINT(("NSV RAWAUDIO: bps %d, nchan %d, srate %d\n", bps, channels, samplerate));
00636 }
00637 }
00638 av_get_packet(pb, pkt, asize);
00639 pkt->stream_index = st[NSV_ST_AUDIO]->index;
00640 pkt->flags |= nsv->state == NSV_HAS_READ_NSVS ? PKT_FLAG_KEY : 0;
00641 if( nsv->state == NSV_HAS_READ_NSVS && st[NSV_ST_VIDEO] ) {
00642
00643 pkt->dts = (((NSVStream*)st[NSV_ST_VIDEO]->priv_data)->frame_offset-1);
00644 pkt->dts *= (int64_t)1000 * nsv->framerate.den;
00645 pkt->dts += (int64_t)nsv->avsync * nsv->framerate.num;
00646 PRINT(("NSV AUDIO: sync:%d, dts:%"PRId64, nsv->avsync, pkt->dts));
00647 }
00648 nst->frame_offset++;
00649 }
00650
00651 nsv->state = NSV_UNSYNC;
00652 return 0;
00653 }
00654
00655
00656 static int nsv_read_packet(AVFormatContext *s, AVPacket *pkt)
00657 {
00658 NSVContext *nsv = s->priv_data;
00659 int i, err = 0;
00660
00661 PRINT(("%s()\n", __FUNCTION__));
00662
00663
00664 if (nsv->ahead[0].data == NULL && nsv->ahead[1].data == NULL)
00665 err = nsv_read_chunk(s, 0);
00666 if (err < 0)
00667 return err;
00668
00669
00670 for (i = 0; i < 2; i++) {
00671 if (nsv->ahead[i].data) {
00672 PRINT(("%s: using cached packet[%d]\n", __FUNCTION__, i));
00673
00674 memcpy(pkt, &nsv->ahead[i], sizeof(AVPacket));
00675 nsv->ahead[i].data = NULL;
00676 return pkt->size;
00677 }
00678 }
00679
00680
00681 return -1;
00682 }
00683
00684 static int nsv_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
00685 {
00686 #if 0
00687 NSVContext *avi = s->priv_data;
00688 AVStream *st;
00689 NSVStream *ast;
00690 int frame_number, i;
00691 int64_t pos;
00692 #endif
00693
00694 return -1;
00695 }
00696
00697 static int nsv_read_close(AVFormatContext *s)
00698 {
00699
00700 NSVContext *nsv = s->priv_data;
00701
00702 if (nsv->index_entries)
00703 av_free(nsv->nsvf_index_data);
00704
00705 #if 0
00706
00707 for(i=0;i<s->nb_streams;i++) {
00708 AVStream *st = s->streams[i];
00709 NSVStream *ast = st->priv_data;
00710 if(ast){
00711 av_free(ast->index_entries);
00712 av_free(ast);
00713 }
00714 av_free(st->codec->palctrl);
00715 }
00716
00717 #endif
00718 return 0;
00719 }
00720
00721 static int nsv_probe(AVProbeData *p)
00722 {
00723 int i;
00724
00725
00726
00727 if (p->buf[0] == 'N' && p->buf[1] == 'S' &&
00728 p->buf[2] == 'V' && (p->buf[3] == 'f' || p->buf[3] == 's'))
00729 return AVPROBE_SCORE_MAX;
00730
00731
00732
00733
00734 for (i = 1; i < p->buf_size - 3; i++) {
00735 if (p->buf[i+0] == 'N' && p->buf[i+1] == 'S' &&
00736 p->buf[i+2] == 'V' && p->buf[i+3] == 's')
00737 return AVPROBE_SCORE_MAX-20;
00738 }
00739
00740 if (match_ext(p->filename, "nsv"))
00741 return AVPROBE_SCORE_MAX/2;
00742
00743 return 0;
00744 }
00745
00746 AVInputFormat nsv_demuxer = {
00747 "nsv",
00748 NULL_IF_CONFIG_SMALL("Nullsoft Streaming Video"),
00749 sizeof(NSVContext),
00750 nsv_probe,
00751 nsv_read_header,
00752 nsv_read_packet,
00753 nsv_read_close,
00754 nsv_read_seek,
00755 };