📄 utils.c
字号:
} } /* 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 = pkt->pts; } av_free_packet(pkt); } /* 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; 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 && st->start_time != AV_NOPTS_VALUE) { end_time = pkt->pts; 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); } fill_all_stream_timings(ic); url_fseek(ic->pb, old_offset, SEEK_SET); for(i=0; i<ic->nb_streams; i++){ st= ic->streams[i]; st->cur_dts= st->first_dts; st->last_IP_pts = AV_NOPTS_VALUE; }}static void av_estimate_timings(AVFormatContext *ic, offset_t old_offset){ int64_t file_size; /* get the file size, if possible */ if (ic->iformat->flags & AVFMT_NOFILE) { file_size = 0; } else { file_size = url_fsize(ic->pb); if (file_size < 0) file_size = 0; } ic->file_size = file_size; if ((!strcmp(ic->iformat->name, "mpeg") || !strcmp(ic->iformat->name, "mpegts")) && file_size && !url_is_streamed(ic->pb)) { /* get accurate estimate from the PTSes */ av_estimate_timings_from_pts(ic, old_offset); } else if (av_has_duration(ic)) { /* at least one component has timings - we use them for all the components */ fill_all_stream_timings(ic); } else { /* less precise: use bitrate 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 && enc->channels; if(!enc->frame_size && (enc->codec_id == CODEC_ID_VORBIS || enc->codec_id == CODEC_ID_AAC)) return 0; break; case CODEC_TYPE_VIDEO: val = enc->width && enc->pix_fmt != PIX_FMT_NONE; break; default: val = 1; break; } return enc->codec_id != CODEC_ID_NONE && val != 0;}static int try_decode_frame(AVStream *st, const uint8_t *data, int size){ int16_t *samples; AVCodec *codec; int got_picture, data_size, ret=0; AVFrame picture; if(!st->codec->codec){ codec = avcodec_find_decoder(st->codec->codec_id); if (!codec) return -1; ret = avcodec_open(st->codec, codec); if (ret < 0) return ret; } if(!has_codec_parameters(st->codec)){ switch(st->codec->codec_type) { case CODEC_TYPE_VIDEO: ret = avcodec_decode_video(st->codec, &picture, &got_picture, data, size); break; case CODEC_TYPE_AUDIO: data_size = FFMAX(size, AVCODEC_MAX_AUDIO_FRAME_SIZE); samples = av_malloc(data_size); if (!samples) goto fail; ret = avcodec_decode_audio2(st->codec, samples, &data_size, data, size); av_free(samples); break; default: break; } } fail: return ret;}unsigned int codec_get_tag(const AVCodecTag *tags, int id){ while (tags->id != CODEC_ID_NONE) { if (tags->id == id) return tags->tag; tags++; } return 0;}enum CodecID codec_get_id(const AVCodecTag *tags, unsigned int tag){ int i; for(i=0; tags[i].id != CODEC_ID_NONE;i++) { if(tag == tags[i].tag) return tags[i].id; } for(i=0; tags[i].id != CODEC_ID_NONE; i++) { if( toupper((tag >> 0)&0xFF) == toupper((tags[i].tag >> 0)&0xFF) && toupper((tag >> 8)&0xFF) == toupper((tags[i].tag >> 8)&0xFF) && toupper((tag >>16)&0xFF) == toupper((tags[i].tag >>16)&0xFF) && toupper((tag >>24)&0xFF) == toupper((tags[i].tag >>24)&0xFF)) return tags[i].id; } return CODEC_ID_NONE;}unsigned int av_codec_get_tag(const AVCodecTag *tags[4], enum CodecID id){ int i; for(i=0; tags && tags[i]; i++){ int tag= codec_get_tag(tags[i], id); if(tag) return tag; } return 0;}enum CodecID av_codec_get_id(const AVCodecTag *tags[4], unsigned int tag){ int i; for(i=0; tags && tags[i]; i++){ enum CodecID id= codec_get_id(tags[i], tag); if(id!=CODEC_ID_NONE) return id; } return CODEC_ID_NONE;}static void compute_chapters_end(AVFormatContext *s){ unsigned int i; for (i=0; i+1<s->nb_chapters; i++) if (s->chapters[i]->end == AV_NOPTS_VALUE) { assert(s->chapters[i]->start <= s->chapters[i+1]->start); assert(!av_cmp_q(s->chapters[i]->time_base, s->chapters[i+1]->time_base)); s->chapters[i]->end = s->chapters[i+1]->start; } if (s->nb_chapters && s->chapters[i]->end == AV_NOPTS_VALUE) { assert(s->start_time != AV_NOPTS_VALUE); assert(s->duration > 0); s->chapters[i]->end = av_rescale_q(s->start_time + s->duration, AV_TIME_BASE_Q, s->chapters[i]->time_base); }}/* absolute maximum size we read until we abort */#define MAX_READ_SIZE 5000000#define MAX_STD_TIMEBASES (60*12+5)static int get_std_framerate(int i){#ifndef __CW32__ if(i<60*12) return i*1001; else return ((int[]){24,30,60,12,15})[i-60*12]*1000*12;#else const int t[] = {24,30,60,12,15}; if(i<60*12) return i*1001; else return t[i-60*12]*1000*12;#endif}/* * Is the time base unreliable. * This is a heuristic to balance between quick acceptance of the values in * the headers vs. some extra checks. * Old DivX and Xvid often have nonsense timebases like 1fps or 2fps. * MPEG-2 commonly misuses field repeat flags to store different framerates. * And there are "variable" fps files this needs to detect as well. */static int tb_unreliable(AVCodecContext *c){ if( c->time_base.den >= 101L*c->time_base.num || c->time_base.den < 5L*c->time_base.num/* || c->codec_tag == ff_get_fourcc("DIVX") || c->codec_tag == ff_get_fourcc("XVID")*/ || c->codec_id == CODEC_ID_MPEG2VIDEO) return 1; return 0;}int av_find_stream_info(AVFormatContext *ic){ int i, count, ret, read_size, j; AVStream *st; AVPacket pkt1, *pkt; int64_t last_dts[MAX_STREAMS]; int duration_count[MAX_STREAMS]={0}; double (*duration_error)[MAX_STD_TIMEBASES]; offset_t old_offset = url_ftell(ic->pb); int64_t codec_info_duration[MAX_STREAMS]={0}; int codec_info_nb_frames[MAX_STREAMS]={0}; duration_error = av_mallocz(MAX_STREAMS * sizeof(*duration_error)); if (!duration_error) return AVERROR(ENOMEM); for(i=0;i<ic->nb_streams;i++) { st = ic->streams[i]; if(st->codec->codec_type == CODEC_TYPE_VIDEO){/* if(!st->time_base.num) st->time_base= */ if(!st->codec->time_base.num) st->codec->time_base= st->time_base; } //only for the split stuff if (!st->parser) { st->parser = av_parser_init(st->codec->codec_id); if(st->need_parsing == AVSTREAM_PARSE_HEADERS && st->parser){ st->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES; } } } for(i=0;i<MAX_STREAMS;i++){ last_dts[i]= AV_NOPTS_VALUE; } count = 0; read_size = 0; 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; /* variable fps and no guess at the real fps */ if( tb_unreliable(st->codec) && duration_count[i]<20 && st->codec->codec_type == CODEC_TYPE_VIDEO) break; if(st->parser && st->parser->parser->split && !st->codec->extradata) break; if(st->first_dts == AV_NOPTS_VALUE) 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; } } /* 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 */ for(i=0;i<ic->nb_streams;i++) { st = ic->streams[i]; if (!has_codec_parameters(st->codec)){ char buf[256]; avcodec_string(buf, sizeof(buf), st->codec, 0); av_log(ic, AV_LOG_INFO, "Could not find codec parameters (%s)\n", buf); } else { ret = 0; } } break; } pkt= add_to_pktbuf(&ic->packet_buffer, &pkt1); if(av_dup_packet(pkt) < 0) return AVERROR(ENOMEM); read_size += pkt->size; st = ic->streams[pkt->stream_index]; if(codec_info_nb_frames[st->index]>1) codec_info_duration[st->index] += pkt->duration; if (pkt->duration != 0) codec_info_nb_frames[st->index]++; { int index= pkt->stream_index; int64_t last= last_dts[index]; int64_t duration= pkt->dts - last; if(pkt->dts != AV_NOPTS_VALUE && last != AV_NOPTS_VALUE && duration>0){ double dur= duration * av_q2d(st->time_base);// if(st->codec->codec_type == CODEC_TYPE_VIDEO)// av_log(NULL, AV_LOG_ERROR, "%f\n", dur); if(duration_count[index] < 2) memset(duration_error[index], 0, sizeof(*duration_error)); for(i=1; i<MAX_STD_TIMEBASES; i++){ int framerate= get_std_framerate(i); int ticks= lrintf(dur*framerate/(1001*12)); double error= dur - ticks*1001*12/(double)framerate; duration_error[index][i] += error*error; } duration_count[index]++; } if(last == AV_NOPTS_VALUE || duration_count[index]<=1) last_dts[pkt->stream_index]= pkt->dts; } if(st->parser && st->parser->parser->split && !st->codec->extradata){ int i= st->parser->parser->split(st->codec, pkt->data, pkt->size); if(i){ st->codec->extradata_size= i; st->codec->extradata= av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); memcpy(st->codec->extradata, pkt->data, st->codec->extradata_size); memset(st->codec->extradata + i, 0, FF_INPUT_BUFFER_PADDING_SIZE); } } /* if still no information, we try to open the codec and to decompress the frame. We try to avoid that in most case
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -