comparison utils.c @ 192:0316a506aeb0 libavformat

initial duration/start_time generic support - displays stream duration and average total bitrate when using an input file
author bellard
date Fri, 08 Aug 2003 18:02:23 +0000
parents b6fa8a3b78c6
children 5079b6e20e91
comparison
equal deleted inserted replaced
191:efb35207fb1b 192:0316a506aeb0
319 ic = av_mallocz(sizeof(AVFormatContext)); 319 ic = av_mallocz(sizeof(AVFormatContext));
320 if (!ic) { 320 if (!ic) {
321 err = AVERROR_NOMEM; 321 err = AVERROR_NOMEM;
322 goto fail; 322 goto fail;
323 } 323 }
324 ic->duration = AV_NOPTS_VALUE;
325 ic->start_time = AV_NOPTS_VALUE;
324 pstrcpy(ic->filename, sizeof(ic->filename), filename); 326 pstrcpy(ic->filename, sizeof(ic->filename), filename);
325 pd->filename = ic->filename; 327 pd->filename = ic->filename;
326 pd->buf = buf; 328 pd->buf = buf;
327 pd->buf_size = 0; 329 pd->buf_size = 0;
328 330
435 av_free(pktl); 437 av_free(pktl);
436 return 0; 438 return 0;
437 } else { 439 } else {
438 return s->iformat->read_packet(s, pkt); 440 return s->iformat->read_packet(s, pkt);
439 } 441 }
442 }
443
444
445 /* return TRUE if the stream has accurate timings for at least one component */
446 static int av_has_timings(AVFormatContext *ic)
447 {
448 int i;
449 AVStream *st;
450
451 for(i = 0;i < ic->nb_streams; i++) {
452 st = ic->streams[i];
453 if (st->start_time != AV_NOPTS_VALUE &&
454 st->duration != AV_NOPTS_VALUE)
455 return 1;
456 }
457 return 0;
458 }
459
460 /* estimate the stream timings from the one of each components. Also
461 compute the global bitrate if possible */
462 static void av_update_stream_timings(AVFormatContext *ic)
463 {
464 int64_t start_time, end_time, end_time1;
465 int i;
466 AVStream *st;
467
468 start_time = MAXINT64;
469 end_time = MININT64;
470 for(i = 0;i < ic->nb_streams; i++) {
471 st = ic->streams[i];
472 if (st->start_time != AV_NOPTS_VALUE) {
473 if (st->start_time < start_time)
474 start_time = st->start_time;
475 if (st->duration != AV_NOPTS_VALUE) {
476 end_time1 = st->start_time + st->duration;
477 if (end_time1 > end_time)
478 end_time = end_time1;
479 }
480 }
481 }
482 if (start_time != MAXINT64) {
483 ic->start_time = start_time;
484 if (end_time != MAXINT64) {
485 ic->duration = end_time - start_time;
486 if (ic->file_size > 0) {
487 /* compute the bit rate */
488 ic->bit_rate = (double)ic->file_size * 8.0 * AV_TIME_BASE /
489 (double)ic->duration;
490 }
491 }
492 }
493
494 }
495
496 static void fill_all_stream_timings(AVFormatContext *ic)
497 {
498 int i;
499 AVStream *st;
500
501 av_update_stream_timings(ic);
502 for(i = 0;i < ic->nb_streams; i++) {
503 st = ic->streams[i];
504 if (st->start_time == AV_NOPTS_VALUE) {
505 st->start_time = ic->start_time;
506 st->duration = ic->duration;
507 }
508 }
509 }
510
511 static void av_estimate_timings_from_bit_rate(AVFormatContext *ic)
512 {
513 int64_t filesize, duration;
514 int bit_rate, i;
515 AVStream *st;
516
517 /* if bit_rate is already set, we believe it */
518 if (ic->bit_rate == 0) {
519 bit_rate = 0;
520 for(i=0;i<ic->nb_streams;i++) {
521 st = ic->streams[i];
522 bit_rate += st->codec.bit_rate;
523 }
524 ic->bit_rate = bit_rate;
525 }
526
527 /* if duration is already set, we believe it */
528 if (ic->duration == AV_NOPTS_VALUE &&
529 ic->bit_rate != 0 &&
530 ic->file_size != 0) {
531 filesize = ic->file_size;
532 if (filesize > 0) {
533 duration = (int64_t)((8 * AV_TIME_BASE * (double)filesize) / (double)ic->bit_rate);
534 for(i = 0; i < ic->nb_streams; i++) {
535 st = ic->streams[i];
536 if (st->start_time == AV_NOPTS_VALUE ||
537 st->duration == AV_NOPTS_VALUE) {
538 st->start_time = 0;
539 st->duration = duration;
540 }
541 }
542 }
543 }
544 }
545
546 static void flush_packet_queue(AVFormatContext *s)
547 {
548 AVPacketList *pktl;
549
550 for(;;) {
551 pktl = s->packet_buffer;
552 if (!pktl)
553 break;
554 s->packet_buffer = pktl->next;
555 av_free(pktl);
556 }
557 }
558
559 #define DURATION_MAX_READ_SIZE 250000
560
561 /* only usable for MPEG-PS streams */
562 static void av_estimate_timings_from_pts(AVFormatContext *ic)
563 {
564 AVPacket pkt1, *pkt = &pkt1;
565 AVStream *st;
566 int read_size, i, ret;
567 int64_t start_time, end_time, end_time1;
568 int64_t filesize, offset, duration;
569
570 /* we read the first packets to get the first PTS (not fully
571 accurate, but it is enough now) */
572 url_fseek(&ic->pb, 0, SEEK_SET);
573 read_size = 0;
574 for(;;) {
575 if (read_size >= DURATION_MAX_READ_SIZE)
576 break;
577 /* if all info is available, we can stop */
578 for(i = 0;i < ic->nb_streams; i++) {
579 st = ic->streams[i];
580 if (st->start_time == AV_NOPTS_VALUE)
581 break;
582 }
583 if (i == ic->nb_streams)
584 break;
585
586 ret = av_read_packet(ic, pkt);
587 if (ret != 0)
588 break;
589 read_size += pkt->size;
590 st = ic->streams[pkt->stream_index];
591 if (pkt->pts != AV_NOPTS_VALUE) {
592 if (st->start_time == AV_NOPTS_VALUE)
593 st->start_time = (int64_t)((double)pkt->pts * ic->pts_num * (double)AV_TIME_BASE / ic->pts_den);
594 }
595 av_free_packet(pkt);
596 }
597
598 /* we compute the minimum start_time and use it as default */
599 start_time = MAXINT64;
600 for(i = 0; i < ic->nb_streams; i++) {
601 st = ic->streams[i];
602 if (st->start_time != AV_NOPTS_VALUE &&
603 st->start_time < start_time)
604 start_time = st->start_time;
605 }
606 printf("start=%lld\n", start_time);
607 if (start_time != MAXINT64)
608 ic->start_time = start_time;
609
610 /* estimate the end time (duration) */
611 /* XXX: may need to support wrapping */
612 filesize = ic->file_size;
613 offset = filesize - DURATION_MAX_READ_SIZE;
614 if (offset < 0)
615 offset = 0;
616
617 /* flush packet queue */
618 flush_packet_queue(ic);
619
620 url_fseek(&ic->pb, offset, SEEK_SET);
621 read_size = 0;
622 for(;;) {
623 if (read_size >= DURATION_MAX_READ_SIZE)
624 break;
625 /* if all info is available, we can stop */
626 for(i = 0;i < ic->nb_streams; i++) {
627 st = ic->streams[i];
628 if (st->duration == AV_NOPTS_VALUE)
629 break;
630 }
631 if (i == ic->nb_streams)
632 break;
633
634 ret = av_read_packet(ic, pkt);
635 if (ret != 0)
636 break;
637 read_size += pkt->size;
638 st = ic->streams[pkt->stream_index];
639 if (pkt->pts != AV_NOPTS_VALUE) {
640 end_time = (int64_t)((double)pkt->pts * ic->pts_num * (double)AV_TIME_BASE / ic->pts_den);
641 duration = end_time - st->start_time;
642 if (duration > 0) {
643 if (st->duration == AV_NOPTS_VALUE ||
644 st->duration < duration)
645 st->duration = duration;
646 }
647 }
648 av_free_packet(pkt);
649 }
650
651 /* estimate total duration */
652 end_time = MININT64;
653 for(i = 0;i < ic->nb_streams; i++) {
654 st = ic->streams[i];
655 if (st->duration != AV_NOPTS_VALUE) {
656 end_time1 = st->start_time + st->duration;
657 if (end_time1 > end_time)
658 end_time = end_time1;
659 }
660 }
661
662 /* update start_time (new stream may have been created, so we do
663 it at the end */
664 if (ic->start_time != AV_NOPTS_VALUE) {
665 for(i = 0; i < ic->nb_streams; i++) {
666 st = ic->streams[i];
667 if (st->start_time == AV_NOPTS_VALUE)
668 st->start_time = ic->start_time;
669 }
670 }
671
672 if (end_time != MININT64) {
673 /* put dummy values for duration if needed */
674 for(i = 0;i < ic->nb_streams; i++) {
675 st = ic->streams[i];
676 if (st->duration == AV_NOPTS_VALUE &&
677 st->start_time != AV_NOPTS_VALUE)
678 st->duration = end_time - st->start_time;
679 }
680 ic->duration = end_time - ic->start_time;
681 }
682
683 url_fseek(&ic->pb, 0, SEEK_SET);
684 }
685
686 static void av_estimate_timings(AVFormatContext *ic)
687 {
688 URLContext *h;
689 int64_t file_size;
690
691 /* get the file size, if possible */
692 if (ic->iformat->flags & AVFMT_NOFILE) {
693 file_size = 0;
694 } else {
695 h = url_fileno(&ic->pb);
696 file_size = url_filesize(h);
697 if (file_size < 0)
698 file_size = 0;
699 }
700 ic->file_size = file_size;
701
702 if (ic->iformat == &mpegps_demux) {
703 /* get accurate estimate from the PTSes */
704 av_estimate_timings_from_pts(ic);
705 } else if (av_has_timings(ic)) {
706 /* at least one components has timings - we use them for all
707 the components */
708 fill_all_stream_timings(ic);
709 } else {
710 /* less precise: use bit rate info */
711 av_estimate_timings_from_bit_rate(ic);
712 }
713 av_update_stream_timings(ic);
714
715 #if 0
716 {
717 int i;
718 AVStream *st;
719 for(i = 0;i < ic->nb_streams; i++) {
720 st = ic->streams[i];
721 printf("%d: start_time: %0.3f duration: %0.3f\n",
722 i, (double)st->start_time / AV_TIME_BASE,
723 (double)st->duration / AV_TIME_BASE);
724 }
725 printf("stream: start_time: %0.3f duration: %0.3f bitrate=%d kb/s\n",
726 (double)ic->start_time / AV_TIME_BASE,
727 (double)ic->duration / AV_TIME_BASE,
728 ic->bit_rate / 1000);
729 }
730 #endif
440 } 731 }
441 732
442 /* state for codec information */ 733 /* state for codec information */
443 #define CSTATE_NOTFOUND 0 734 #define CSTATE_NOTFOUND 0
444 #define CSTATE_DECODING 1 735 #define CSTATE_DECODING 1
660 st->r_frame_rate_base = st->codec.frame_rate_base; 951 st->r_frame_rate_base = st->codec.frame_rate_base;
661 } 952 }
662 } 953 }
663 } 954 }
664 955
956
957 av_estimate_timings(ic);
665 return ret; 958 return ret;
666 } 959 }
667 960
668 /** 961 /**
669 * Close a media file (but not its codecs) 962 * Close a media file (but not its codecs)
723 return NULL; 1016 return NULL;
724 avcodec_get_context_defaults(&st->codec); 1017 avcodec_get_context_defaults(&st->codec);
725 1018
726 st->index = s->nb_streams; 1019 st->index = s->nb_streams;
727 st->id = id; 1020 st->id = id;
1021 st->start_time = AV_NOPTS_VALUE;
1022 st->duration = AV_NOPTS_VALUE;
728 s->streams[s->nb_streams++] = st; 1023 s->streams[s->nb_streams++] = st;
729 return st; 1024 return st;
730 } 1025 }
731 1026
732 /************************************************************/ 1027 /************************************************************/
872 fprintf(stderr, "%s #%d, %s, %s '%s':\n", 1167 fprintf(stderr, "%s #%d, %s, %s '%s':\n",
873 is_output ? "Output" : "Input", 1168 is_output ? "Output" : "Input",
874 index, 1169 index,
875 is_output ? ic->oformat->name : ic->iformat->name, 1170 is_output ? ic->oformat->name : ic->iformat->name,
876 is_output ? "to" : "from", url); 1171 is_output ? "to" : "from", url);
1172 if (!is_output) {
1173 printf(" Duration: ");
1174 if (ic->duration != AV_NOPTS_VALUE) {
1175 int hours, mins, secs, us;
1176 secs = ic->duration / AV_TIME_BASE;
1177 us = ic->duration % AV_TIME_BASE;
1178 mins = secs / 60;
1179 secs %= 60;
1180 hours = mins / 60;
1181 mins %= 60;
1182 printf("%02d:%02d:%02d.%01d", hours, mins, secs,
1183 (10 * us) / AV_TIME_BASE);
1184 } else {
1185 printf("N/A");
1186 }
1187 printf(", bitrate: ");
1188 if (ic->bit_rate) {
1189 printf("%d kb/s", ic->bit_rate / 1000);
1190 } else {
1191 printf("N/A");
1192 }
1193 printf("\n");
1194 }
877 for(i=0;i<ic->nb_streams;i++) { 1195 for(i=0;i<ic->nb_streams;i++) {
878 AVStream *st = ic->streams[i]; 1196 AVStream *st = ic->streams[i];
879 avcodec_string(buf, sizeof(buf), &st->codec, is_output); 1197 avcodec_string(buf, sizeof(buf), &st->codec, is_output);
880 fprintf(stderr, " Stream #%d.%d", index, i); 1198 fprintf(stderr, " Stream #%d.%d", index, i);
881 /* the pid is an important information, so we display it */ 1199 /* the pid is an important information, so we display it */