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