ffmpeg 소스 분석의 4 -----avformatopen_input() 아래

14746 단어 오디오 비디오
전편에서 Initinput에서 미디어 파일을 열면 나머지 절차를 분석합니다.코드 보기
static int init_input(AVFormatContext *s, const char *filename, AVDictionary **options)
{
    int ret;
    AVProbeData pd = {filename, NULL, 0};

    if (s->pb) {
        s->flags |= AVFMT_FLAG_CUSTOM_IO;
        if (!s->iformat)
            return av_probe_input_buffer(s->pb, &s->iformat, filename, s, 0, 0);
        else if (s->iformat->flags & AVFMT_NOFILE)
            av_log(s, AV_LOG_WARNING, "Custom AVIOContext makes no sense and "
                                      "will be ignored with AVFMT_NOFILE format.
"); return 0; } if ( (s->iformat && s->iformat->flags & AVFMT_NOFILE) || (!s->iformat && (s->iformat = av_probe_input_format(&pd, 0)))) return 0; //avio_open2 libavformat/aviobuf.c avio.h //Create and initialize a AVIOContext for accessing the resource indicated by url if ((ret = avio_open2(&s->pb, filename, AVIO_FLAG_READ, &s->interrupt_callback, options)) < 0) return ret; if (s->iformat) return 0; av_log(0,AV_LOG_INFO," : av_probe_input_buffer
"); return av_probe_input_buffer(s->pb, &s->iformat, filename, s, 0, 0); }

자 avprobe_input_buffer():
int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt,
                          const char *filename, void *logctx,
                          unsigned int offset, unsigned int max_probe_size)
{
    AVProbeData pd = { filename ? filename : "", NULL, -offset };
    unsigned char *buf = NULL;
    int ret = 0, probe_size;

    if (!max_probe_size) {
        max_probe_size = PROBE_BUF_MAX;
    } else if (max_probe_size > PROBE_BUF_MAX) {
        max_probe_size = PROBE_BUF_MAX;
    } else if (max_probe_size < PROBE_BUF_MIN) {
        return AVERROR(EINVAL);
    }

    if (offset >= max_probe_size) {
        return AVERROR(EINVAL);
    }

    for(probe_size= PROBE_BUF_MIN; probe_size<=max_probe_size && !*fmt;
        probe_size = FFMIN(probe_size<<1, FFMAX(max_probe_size, probe_size+1))) {
        int score = probe_size < max_probe_size ? AVPROBE_SCORE_MAX/4 : 0;
        int buf_offset = (probe_size == PROBE_BUF_MIN) ? 0 : probe_size>>1;
        void *buftmp;

        if (probe_size < offset) {
            continue;
        }

        /* read probe data */
        buftmp = av_realloc(buf, probe_size + AVPROBE_PADDING_SIZE);
        if(!buftmp){
            av_free(buf);
            return AVERROR(ENOMEM);
        }
        buf=buftmp;
        if ((ret = avio_read(pb, buf + buf_offset, probe_size - buf_offset)) < 0) {
            /* fail if error was not end of file, otherwise, lower score */
            if (ret != AVERROR_EOF) {
                av_free(buf);
                return ret;
            }
            score = 0;
            ret = 0;            /* error was end of file, nothing read */
        }
        pd.buf_size += ret;
        pd.buf = &buf[offset];

        memset(pd.buf + pd.buf_size, 0, AVPROBE_PADDING_SIZE);

        /* guess file format */
        *fmt = av_probe_input_format2(&pd, 1, &score);
        if(*fmt){
            if(score <= AVPROBE_SCORE_MAX/4){ //this can only be true in the last iteration
                av_log(logctx, AV_LOG_WARNING, "Format %s detected only with low score of %d, misdetection possible!
", (*fmt)->name, score); }else av_log(logctx, AV_LOG_DEBUG, "Format %s probed with size=%d and score=%d
", (*fmt)->name, probe_size, score); } } if (!*fmt) { av_free(buf); return AVERROR_INVALIDDATA; } /* rewind. reuse probe buffer to avoid seeking */ if ((ret = ffio_rewind_with_probe_data(pb, buf, pd.buf_size)) < 0) av_free(buf); return ret; }

이 함수에 av 사용probe_input_format2에서 av 를 호출했습니다probe_input_format3 코드 보기
AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score_ret)
{
    AVProbeData lpd = *pd;
    AVInputFormat *fmt1 = NULL, *fmt;
    int score, nodat = 0, score_max=0;

    if (lpd.buf_size > 10 && ff_id3v2_match(lpd.buf, ID3v2_DEFAULT_MAGIC)) {
        int id3len = ff_id3v2_tag_len(lpd.buf);
        if (lpd.buf_size > id3len + 16) {
            lpd.buf += id3len;
            lpd.buf_size -= id3len;
        }else
            nodat = 1;
    }
	//            AVInputFormat     VC1       AVInputFormat ff_mpegts_demuxer:    libavformat/mpegts.c 
    fmt = NULL;
    while ((fmt1 = av_iformat_next(fmt1))) {
        if (!is_opened == !(fmt1->flags & AVFMT_NOFILE))
            continue;
        score = 0;
        if (fmt1->read_probe) {
            score = fmt1->read_probe(&lpd);
            if(fmt1->extensions && av_match_ext(lpd.filename, fmt1->extensions))
                score = FFMAX(score, nodat ? AVPROBE_SCORE_MAX/4-1 : 1);
        } else if (fmt1->extensions) {
            if (av_match_ext(lpd.filename, fmt1->extensions)) {
                score = 50;
            }
        }
        if (score > score_max) {
            score_max = score;
            fmt = fmt1;
        }else if (score == score_max)
            fmt = NULL;
    }
    *score_ret= score_max;

    return fmt;
}

이 함수는 등록된 전역 체인 테이블 구조에서 AVInputFormat 구조를 찾았고 입력 파일의 구체적인 형식에 따라 프로그램이 자동으로 완성했다.이 절차를 거쳐 avformatopen_input의 남은 절차
int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options)
{
    AVFormatContext *s = *ps;
    int ret = 0;
    AVFormatParameters ap = { { 0 } };
    AVDictionary *tmp = NULL;
	//avformat_alloc_context()  libavformat/options.c      AVFormatContext            
    if (!s && !(s = avformat_alloc_context()))
        return AVERROR(ENOMEM);
    if (fmt)
        s->iformat = fmt;

    if (options)
        av_dict_copy(&tmp, *options, 0);

    if ((ret = av_opt_set_dict(s, &tmp)) < 0)
        goto fail;
	//init_input   AVInputFormat    AVInputformat read_header()    AVFormatContext          AVStream  
    if ((ret = init_input(s, filename, &tmp)) < 0)
        goto fail;

    /* check filename in case an image number is expected */
    if (s->iformat->flags & AVFMT_NEEDNUMBER) {
        if (!av_filename_number_test(filename)) {
            ret = AVERROR(EINVAL);
            goto fail;
        }
    }

    s->duration = s->start_time = AV_NOPTS_VALUE;
    av_strlcpy(s->filename, filename, sizeof(s->filename));

    /* allocate private data */
    if (s->iformat->priv_data_size > 0) {
        if (!(s->priv_data = av_mallocz(s->iformat->priv_data_size))) {
            ret = AVERROR(ENOMEM);
            goto fail;
        }
        if (s->iformat->priv_class) {
            *(const AVClass**)s->priv_data = s->iformat->priv_class;
            av_opt_set_defaults(s->priv_data);
            if ((ret = av_opt_set_dict(s->priv_data, &tmp)) < 0)
                goto fail;
        }
    }

    /* e.g. AVFMT_NOFILE formats will not have a AVIOContext */
    if (s->pb)
        ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC);
	//----  VC1   read_header    ff_raw_video_read_header      libavformat/rawdec.c         
    if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header){
        if ((ret = s->iformat->read_header(s, &ap)) < 0)
            goto fail;
	}

    if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->pb && !s->data_offset)
        s->data_offset = avio_tell(s->pb);

    s->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;

    if (options) {
        av_dict_free(options);
        *options = tmp;
    }
    *ps = s;
    return 0;

fail:
    av_dict_free(&tmp);
    if (s->pb && !(s->flags & AVFMT_FLAG_CUSTOM_IO))
        avio_close(s->pb);
    avformat_free_context(s);
    *ps = NULL;
    return ret;
}

경과avprobe_input_format3에서 적합한 AVInputFormat 구조를 찾은 후 s->iformat 구성원을 부여한 후 AVInputFormat의read 를 호출합니다header () 함수는vc1 원본을 예로 삼아libavformat/mpegts에 일치합니다.c의 AVInputFormat ffmpegts_demuxer 구조이고 이 대상의read헤더 포인터가 mpegts 를 가리켰다read_헤더는 다음과 같습니다.
AVInputFormat ff_mpegts_demuxer = {
    .name           = "mpegts",
    .long_name      = NULL_IF_CONFIG_SMALL("MPEG-2 transport stream format"),
    .priv_data_size = sizeof(MpegTSContext),
    .read_probe     = mpegts_probe,
    .read_header    = mpegts_read_header,
    .read_packet    = mpegts_read_packet,
    .read_close     = mpegts_read_close,
    .read_timestamp = mpegts_get_pcr,
    .flags = AVFMT_SHOW_IDS|AVFMT_TS_DISCONT,
#ifdef USE_SYNCPOINT_SEARCH
    .read_seek2 = read_seek2,
#endif
};

mpegts를 보러...read_헤더 함수
static int mpegts_read_header(AVFormatContext *s,
                              AVFormatParameters *ap)
{
    MpegTSContext *ts = s->priv_data;
    AVIOContext *pb = s->pb;
    uint8_t buf[8*1024];
    int len;
    int64_t pos;

	av_log(s,AV_LOG_INFO,"  mpegts_read_header 
"); //av_log(s,AV_LOG_INFO,"stream :%d
",s->streams[0]); /* read the first 8192 bytes to get packet size */ pos = avio_tell(pb); len = avio_read(pb, buf, sizeof(buf)); if (len != sizeof(buf)) goto fail; ts->raw_packet_size = get_packet_size(buf, sizeof(buf)); if (ts->raw_packet_size <= 0) { av_log(s, AV_LOG_WARNING, "Could not detect TS packet size, defaulting to non-FEC/DVHS
"); ts->raw_packet_size = TS_PACKET_SIZE; } ts->stream = s; ts->auto_guess = 0; if (s->iformat == &ff_mpegts_demuxer) { /* normal demux */ /* first do a scan to get all the services */ /* NOTE: We attempt to seek on non-seekable files as well, as the * probe buffer usually is big enough. Only warn if the seek failed * on files where the seek should work. */ if (avio_seek(pb, pos, SEEK_SET) < 0) av_log(s, pb->seekable ? AV_LOG_ERROR : AV_LOG_INFO, "Unable to seek back to the start
"); mpegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1); mpegts_open_section_filter(ts, PAT_PID, pat_cb, ts, 1); // s->streams handle_packets(ts, s->probesize / ts->raw_packet_size); /* if could not find service, enable auto_guess */ ts->auto_guess = 1; av_dlog(ts->stream, "tuning done
"); /* only flag NOHEADER if we are in file mode, in streaming mode scanning may take too long for users */ if (!url_is_streamed(pb)) s->ctx_flags |= AVFMTCTX_NOHEADER; } else { AVStream *st; int pcr_pid, pid, nb_packets, nb_pcrs, ret, pcr_l; int64_t pcrs[2], pcr_h; int packet_count[2]; uint8_t packet[TS_PACKET_SIZE]; /* only read packets */ st = avformat_new_stream(s, NULL); if (!st) goto fail; avpriv_set_pts_info(st, 60, 1, 27000000); st->codec->codec_type = AVMEDIA_TYPE_DATA; st->codec->codec_id = CODEC_ID_MPEG2TS; /* we iterate until we find two PCRs to estimate the bitrate */ pcr_pid = -1; nb_pcrs = 0; nb_packets = 0; for(;;) { ret = read_packet(s, packet, ts->raw_packet_size); if (ret < 0) return -1; pid = AV_RB16(packet + 1) & 0x1fff; if ((pcr_pid == -1 || pcr_pid == pid) && parse_pcr(&pcr_h, &pcr_l, packet) == 0) { pcr_pid = pid; packet_count[nb_pcrs] = nb_packets; pcrs[nb_pcrs] = pcr_h * 300 + pcr_l; nb_pcrs++; if (nb_pcrs >= 2) break; } nb_packets++; } /* NOTE1: the bitrate is computed without the FEC */ /* NOTE2: it is only the bitrate of the start of the stream */ ts->pcr_incr = (pcrs[1] - pcrs[0]) / (packet_count[1] - packet_count[0]); ts->cur_pcr = pcrs[0] - ts->pcr_incr * packet_count[0]; s->bit_rate = (TS_PACKET_SIZE * 8) * 27e6 / ts->pcr_incr; st->codec->bit_rate = s->bit_rate; st->start_time = ts->cur_pcr; av_dlog(ts->stream, "start=%0.3f pcr=%0.3f incr=%d
", st->start_time / 1000000.0, pcrs[0] / 27e6, ts->pcr_incr); } avio_seek(pb, pos, SEEK_SET); return 0; fail: return -1; }

추적 avformatnew_stream은 다음과 같습니다.
AVStream *avformat_new_stream(AVFormatContext *s, AVCodec *c)
{
    AVStream *st;
    int i;
    AVStream **streams;

    if (s->nb_streams >= INT_MAX/sizeof(*streams))
        return NULL;
    streams = av_realloc(s->streams, (s->nb_streams + 1) * sizeof(*streams));
    if (!streams)
        return NULL;
    s->streams = streams;

    st = av_mallocz(sizeof(AVStream));
    if (!st)
        return NULL;
    if (!(st->info = av_mallocz(sizeof(*st->info)))) {
        av_free(st);
        return NULL;
    }

    st->codec = avcodec_alloc_context3(c);
    if (s->iformat) {
        /* no default bitrate if decoding */
        st->codec->bit_rate = 0;
    }
    st->index = s->nb_streams;
    st->start_time = AV_NOPTS_VALUE;
    st->duration = AV_NOPTS_VALUE;
        /* we set the current DTS to 0 so that formats without any timestamps
           but durations get some timestamps, formats with some unknown
           timestamps have their first few packets buffered and the
           timestamps corrected before they are returned to the user */
    st->cur_dts = 0;
    st->first_dts = AV_NOPTS_VALUE;
    st->probe_packets = MAX_PROBE_PACKETS;

    /* default pts setting is MPEG-like */
    avpriv_set_pts_info(st, 33, 1, 90000);
    st->last_IP_pts = AV_NOPTS_VALUE;
    for(i=0; ipts_buffer[i]= AV_NOPTS_VALUE;
    st->reference_dts = AV_NOPTS_VALUE;

    st->sample_aspect_ratio = (AVRational){0,1};

    s->streams[s->nb_streams++] = st;
    return st;
}

여기 AVStream에 공간을 분배하고 AVcodecContext에 공간을 분배합니다. 허허, 뭘 발견했어요?여기서 또 하나의 문제는 if판단에서 avformat을 걷지 못한다는 점입니다.new_stream 프로세스를 따라handlePackets 프로세스의 구체적인 분석은 여러분께 남겨드리겠습니다.

좋은 웹페이지 즐겨찾기