📄 utils.c
字号:
/* free previous packet */ if (ic->cur_st && ic->cur_st->parser) av_free_packet(&ic->cur_pkt); ic->cur_st = NULL; /* flush packet queue */ flush_packet_queue(ic); for(i=0;i<ic->nb_streams;i++) { st = ic->streams[i]; if (st->parser) { av_parser_close(st->parser); st->parser= NULL; } } /* 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 = av_rescale(pkt->pts, st->time_base.num * (int64_t)AV_TIME_BASE, st->time_base.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; 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 = av_rescale(pkt->pts, st->time_base.num * (int64_t)AV_TIME_BASE, st->time_base.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}static 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);}static int try_decode_frame(AVStream *st, const uint8_t *data, int size){ int16_t *samples; AVCodec *codec; int got_picture, ret; AVFrame picture; codec = avcodec_find_decoder(st->codec.codec_id); if (!codec) return -1; ret = avcodec_open(&st->codec, codec); if (ret < 0) return ret; switch(st->codec.codec_type) { case CODEC_TYPE_VIDEO: ret = avcodec_decode_video(&st->codec, &picture, &got_picture, (uint8_t *)data, size); break; case CODEC_TYPE_AUDIO: samples = av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE); if (!samples) goto fail; ret = avcodec_decode_audio(&st->codec, samples, &got_picture, (uint8_t *)data, size); av_free(samples); break; default: break; } fail: avcodec_close(&st->codec); return ret;}/* absolute maximum size we read until we abort */#define MAX_READ_SIZE 5000000/* maximum duration until we stop analysing the stream */#define MAX_STREAM_DURATION ((int)(AV_TIME_BASE * 1.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, read_size; AVStream *st; AVPacket pkt1, *pkt; AVPacketList *pktl=NULL, **ppktl; 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 (!has_codec_parameters(&st->codec)) 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)) { /* 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; } } /* NOTE: a new stream can be added there if no header in file (AVFMTCTX_NOHEADER) */ ret = av_read_frame_internal(ic, &pkt1); if (ret < 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; } pktl = av_mallocz(sizeof(AVPacketList)); if (!pktl) { ret = AVERROR_NOMEM; break; } /* add the packet in the buffered packet list */ *ppktl = pktl; ppktl = &pktl->next; pkt = &pktl->pkt; *pkt = pkt1; /* duplicate the packet */ if (av_dup_packet(pkt) < 0) { ret = AVERROR_NOMEM; break; } read_size += pkt->size; st = ic->streams[pkt->stream_index]; st->codec_info_duration += pkt->duration; if (pkt->duration != 0) st->codec_info_nb_frames++; /* if still no information, we try to open the codec and to decompress the frame. We try to avoid that in most cases as it takes longer and uses more memory. For MPEG4, we need to decompress for Quicktime. */ if (!has_codec_parameters(&st->codec) && (st->codec.codec_id == CODEC_ID_FLV1 || st->codec.codec_id == CODEC_ID_H264 || st->codec.codec_id == CODEC_ID_H263 || st->codec.codec_id == CODEC_ID_VORBIS || (st->codec.codec_id == CODEC_ID_MPEG4 && !st->need_parsing))) try_decode_frame(st, pkt->data, pkt->size); if (st->codec_info_duration >= MAX_STREAM_DURATION) { break; } count++; } /* set real frame rate info */ for(i=0;i<ic->nb_streams;i++) { st = ic->streams[i]; if (st->codec.codec_type == CODEC_TYPE_VIDEO) { /* compute the real frame rate for telecine */ if ((st->codec.codec_id == CODEC_ID_MPEG1VIDEO || st->codec.codec_id == CODEC_ID_MPEG2VIDEO) && st->codec.sub_id == 2) { if (st->codec_info_nb_frames >= 20) { float coded_frame_rate, est_frame_rate; est_frame_rate = ((double)st->codec_info_nb_frames * AV_TIME_BASE) / (double)st->codec_info_duration ; coded_frame_rate = (double)st->codec.frame_rate / (double)st->codec.frame_rate_base;#if 0 printf("telecine: coded_frame_rate=%0.3f est_frame_rate=%0.3f\n", coded_frame_rate, est_frame_rate);#endif /* if we detect that it could be a telecine, we signal it. It would be better to do it at a higher level as it can change in a film */ if (coded_frame_rate >= 24.97 && (est_frame_rate >= 23.5 && est_frame_rate < 24.5)) { st->r_frame_rate = 24024; st->r_frame_rate_base = 1001; } } } /* if no real frame rate, use the codec one */ if (!st->r_frame_rate){ st->r_frame_rate = st->codec.frame_rate; st->r_frame_rate_base = st->codec.frame_rate_base; } } } av_estimate_timings(ic);#if 0 /* correct DTS for b frame streams with no timestamps */ for(i=0;i<ic->nb_streams;i++) { st = ic->streams[i]; if (st->codec.codec_type == CODEC_TYPE_VIDEO) { if(b-frames){ ppktl = &ic->packet_buffer; while(ppkt1){ if(ppkt1->stream_index != i) continue; if(ppkt1->pkt->dts < 0) break; if(ppkt1->pkt->pts != AV_NOPTS_VALUE) break; ppkt1->pkt->dts -= delta; ppkt1= ppkt1->next; } if(ppkt1) continue; st->cur_dts -= delta; } } }#endif return ret;}/*******************************************************//** * start playing a network based stream (e.g. RTSP stream) at the * current position */int av_read_play(AVFormatContext *s){ if (!s->iformat->read_play) return AVERROR_NOTSUPP; return s->iformat->read_play(s);}/** * pause a network based stream (e.g. RTSP stream). Use av_read_play() * to resume it. */int av_read_pause(AVFormatContext *s){ if (!s->iformat->read_pause) return AVERROR_NOTSUPP; return s->iformat->read_pause(s);}/** * Close a media file (but not its codecs) * * @param s media file handle */void av_close_input_file(AVFormatContext *s){ int i, must_open_file; AVStream *st; /* free previous packet */ if (s->cur_st && s->cur_st->parser) av_free_packet(&s->cur_pkt); if (s->iformat->read_close) s->iformat->read_close(s); for(i=0;i<s->nb_streams;i++) { /* free all data in a stream component */ st = s->streams[i]; if (st->parser) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -