📄 utils.c
字号:
if (pktl) { /* read packet from packet buffer, if there is data */ *pkt = pktl->pkt; s->packet_buffer = pktl->next; av_free(pktl); return 0; } else { return s->iformat->read_packet(s, pkt); }}/*******************************************************//* return TRUE if the stream has accurate timings for at least one component */static int av_has_timings(AVFormatContext *ic){ int i; AVStream *st; for(i = 0;i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->start_time != AV_NOPTS_VALUE && st->duration != AV_NOPTS_VALUE) return 1; } return 0;}/* estimate the stream timings from the one of each components. Also compute the global bitrate if possible */static void av_update_stream_timings(AVFormatContext *ic){ int64_t start_time, end_time, end_time1; int i; AVStream *st; start_time = MAXINT64; end_time = MININT64; for(i = 0;i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->start_time != AV_NOPTS_VALUE) { if (st->start_time < start_time) start_time = st->start_time; if (st->duration != AV_NOPTS_VALUE) { end_time1 = st->start_time + st->duration; if (end_time1 > end_time) end_time = end_time1; } } } if (start_time != MAXINT64) { ic->start_time = start_time; if (end_time != MAXINT64) { ic->duration = end_time - start_time; if (ic->file_size > 0) { /* compute the bit rate */ ic->bit_rate = (double)ic->file_size * 8.0 * AV_TIME_BASE / (double)ic->duration; } } }}static void fill_all_stream_timings(AVFormatContext *ic){ int i; AVStream *st; av_update_stream_timings(ic); for(i = 0;i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->start_time == AV_NOPTS_VALUE) { st->start_time = ic->start_time; st->duration = ic->duration; } }}static void av_estimate_timings_from_bit_rate(AVFormatContext *ic){ int64_t filesize, duration; int bit_rate, i; AVStream *st; /* if bit_rate is already set, we believe it */ if (ic->bit_rate == 0) { bit_rate = 0; for(i=0;i<ic->nb_streams;i++) { st = ic->streams[i]; bit_rate += st->codec.bit_rate; } ic->bit_rate = bit_rate; } /* if duration is already set, we believe it */ if (ic->duration == AV_NOPTS_VALUE && ic->bit_rate != 0 && ic->file_size != 0) { filesize = ic->file_size; if (filesize > 0) { duration = (int64_t)((8 * AV_TIME_BASE * (double)filesize) / (double)ic->bit_rate); for(i = 0; i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->start_time == AV_NOPTS_VALUE || st->duration == AV_NOPTS_VALUE) { st->start_time = 0; st->duration = duration; } } } }}static void flush_packet_queue(AVFormatContext *s){ AVPacketList *pktl; for(;;) { pktl = s->packet_buffer; if (!pktl) break; s->packet_buffer = pktl->next; av_free_packet(&pktl->pkt); av_free(pktl); }}#define DURATION_MAX_READ_SIZE 250000/* only usable for MPEG-PS streams */static void av_estimate_timings_from_pts(AVFormatContext *ic){ AVPacket pkt1, *pkt = &pkt1; AVStream *st; int read_size, i, ret; int64_t start_time, end_time, end_time1; int64_t filesize, offset, duration; /* we read the first packets to get the first PTS (not fully accurate, but it is enough now) */ url_fseek(&ic->pb, 0, SEEK_SET); read_size = 0; for(;;) { if (read_size >= DURATION_MAX_READ_SIZE) break; /* if all info is available, we can stop */ for(i = 0;i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->start_time == AV_NOPTS_VALUE) break; } if (i == ic->nb_streams) break; ret = av_read_packet(ic, pkt); if (ret != 0) break; read_size += pkt->size; st = ic->streams[pkt->stream_index]; if (pkt->pts != AV_NOPTS_VALUE) { if (st->start_time == AV_NOPTS_VALUE) st->start_time = (int64_t)((double)pkt->pts * ic->pts_num * (double)AV_TIME_BASE / ic->pts_den); } av_free_packet(pkt); } /* we compute the minimum start_time and use it as default */ start_time = MAXINT64; for(i = 0; i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->start_time != AV_NOPTS_VALUE && st->start_time < start_time) start_time = st->start_time; } if (start_time != MAXINT64) ic->start_time = start_time; /* estimate the end time (duration) */ /* XXX: may need to support wrapping */ filesize = ic->file_size; offset = filesize - DURATION_MAX_READ_SIZE; if (offset < 0) offset = 0; /* flush packet queue */ flush_packet_queue(ic); url_fseek(&ic->pb, offset, SEEK_SET); read_size = 0; for(;;) { if (read_size >= DURATION_MAX_READ_SIZE) break; /* if all info is available, we can stop */ for(i = 0;i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->duration == AV_NOPTS_VALUE) break; } if (i == ic->nb_streams) break; ret = av_read_packet(ic, pkt); if (ret != 0) break; read_size += pkt->size; st = ic->streams[pkt->stream_index]; if (pkt->pts != AV_NOPTS_VALUE) { end_time = (int64_t)((double)pkt->pts * ic->pts_num * (double)AV_TIME_BASE / ic->pts_den); duration = end_time - st->start_time; if (duration > 0) { if (st->duration == AV_NOPTS_VALUE || st->duration < duration) st->duration = duration; } } av_free_packet(pkt); } /* estimate total duration */ end_time = MININT64; for(i = 0;i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->duration != AV_NOPTS_VALUE) { end_time1 = st->start_time + st->duration; if (end_time1 > end_time) end_time = end_time1; } } /* update start_time (new stream may have been created, so we do it at the end */ if (ic->start_time != AV_NOPTS_VALUE) { for(i = 0; i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->start_time == AV_NOPTS_VALUE) st->start_time = ic->start_time; } } if (end_time != MININT64) { /* put dummy values for duration if needed */ for(i = 0;i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->duration == AV_NOPTS_VALUE && st->start_time != AV_NOPTS_VALUE) st->duration = end_time - st->start_time; } ic->duration = end_time - ic->start_time; } url_fseek(&ic->pb, 0, SEEK_SET);}static void av_estimate_timings(AVFormatContext *ic){ URLContext *h; int64_t file_size; /* get the file size, if possible */ if (ic->iformat->flags & AVFMT_NOFILE) { file_size = 0; } else { h = url_fileno(&ic->pb); file_size = url_filesize(h); if (file_size < 0) file_size = 0; } ic->file_size = file_size; if (ic->iformat == &mpegps_demux) { /* get accurate estimate from the PTSes */ av_estimate_timings_from_pts(ic); } else if (av_has_timings(ic)) { /* at least one components has timings - we use them for all the components */ fill_all_stream_timings(ic); } else { /* less precise: use bit rate info */ av_estimate_timings_from_bit_rate(ic); } av_update_stream_timings(ic);#if 0 { int i; AVStream *st; for(i = 0;i < ic->nb_streams; i++) { st = ic->streams[i]; printf("%d: start_time: %0.3f duration: %0.3f\n", i, (double)st->start_time / AV_TIME_BASE, (double)st->duration / AV_TIME_BASE); } printf("stream: start_time: %0.3f duration: %0.3f bitrate=%d kb/s\n", (double)ic->start_time / AV_TIME_BASE, (double)ic->duration / AV_TIME_BASE, ic->bit_rate / 1000); }#endif}/* state for codec information */#define CSTATE_NOTFOUND 0#define CSTATE_DECODING 1#define CSTATE_FOUND 2static int has_codec_parameters(AVCodecContext *enc){ int val; switch(enc->codec_type) { case CODEC_TYPE_AUDIO: val = enc->sample_rate; break; case CODEC_TYPE_VIDEO: val = enc->width; break; default: val = 1; break; } return (val != 0);}/** * Read the beginning of a media file to get stream information. This * is useful for file formats with no headers such as MPEG. This * function also compute the real frame rate in case of mpeg2 repeat * frame mode. * * @param ic media file handle * @return >=0 if OK. AVERROR_xxx if error. */int av_find_stream_info(AVFormatContext *ic){ int i, count, ret, got_picture, size, read_size; AVCodec *codec; AVStream *st; AVPacket *pkt; AVFrame picture; AVPacketList *pktl=NULL, **ppktl; short samples[AVCODEC_MAX_AUDIO_FRAME_SIZE / 2]; uint8_t *ptr; int min_read_size, max_read_size; /* typical mpeg ts rate is 40 Mbits. DVD rate is about 10 Mbits. We read at most 0.2 second of file to find all streams */ /* XXX: base it on stream bitrate when possible */ if (ic->iformat == &mpegts_demux) { /* maximum number of bytes we accept to read to find all the streams in a file */ min_read_size = 6000000; } else { min_read_size = 250000; } /* max read size is 2 seconds of video max */ max_read_size = min_read_size * 10; /* set initial codec state */ for(i=0;i<ic->nb_streams;i++) { st = ic->streams[i]; if (has_codec_parameters(&st->codec)) st->codec_info_state = CSTATE_FOUND; else st->codec_info_state = CSTATE_NOTFOUND; st->codec_info_nb_repeat_frames = 0; st->codec_info_nb_real_frames = 0; } count = 0; read_size = 0; ppktl = &ic->packet_buffer; for(;;) { /* check if one codec still needs to be handled */ for(i=0;i<ic->nb_streams;i++) { st = ic->streams[i]; if (st->codec_info_state != CSTATE_FOUND) break; } if (i == ic->nb_streams) { /* NOTE: if the format has no header, then we need to read some packets to get most of the streams, so we cannot stop here */ if (!(ic->ctx_flags & AVFMTCTX_NOHEADER) || read_size >= min_read_size) { /* if we found the info for all the codecs, we can stop */ ret = count; break; } } else { /* we did not get all the codec info, but we read too much data */ if (read_size >= max_read_size) { ret = count; break; } } pktl = av_mallocz(sizeof(AVPacketList)); if (!pktl) { ret = AVERROR_NOMEM; break; } /* add the packet in the buffered packet list */ *ppktl = pktl; ppktl = &pktl->next; /* NOTE: a new stream can be added there if no header in file (AVFMTCTX_NOHEADER) */ pkt = &pktl->pkt; if (ic->iformat->read_packet(ic, pkt) < 0) { /* EOF or error */ ret = -1; /* we could not have all the codec parameters before EOF */ if ((ic->ctx_flags & AVFMTCTX_NOHEADER) && i == ic->nb_streams) ret = 0; break; } read_size += pkt->size; /* open new codecs */ for(i=0;i<ic->nb_streams;i++) { st = ic->streams[i]; if (st->codec_info_state == CSTATE_NOTFOUND) { /* set to found in case of error */ st->codec_info_state = CSTATE_FOUND; codec = avcodec_find_decoder(st->codec.codec_id); if (codec) { if(codec->capabilities & CODEC_CAP_TRUNCATED) st->codec.flags |= CODEC_FLAG_TRUNCATED; ret = avcodec_open(&st->codec, codec); if (ret >= 0) st->codec_info_state = CSTATE_DECODING; } } } st = ic->streams[pkt->stream_index];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -