Mercurial > libavformat.hg
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 */ |