ffmpeg源码学习笔记五

14.read_frame_internal

static int read_frame_internal(AVFormatContext *s, AVPacket *pkt)
{
    ...
    //初始化packet
    av_init_packet(pkt);

    while (!got_packet && !s->parse_queue) {

        ...
        /* read next packet */
        /*
        这个会调用format的read packet.
        例如mkv的,稍后再对这个API进行深入剖析,这个API每次读取一个block data<==>AVPacket
        AVInputFormat ff_matroska_demuxer = {
            ...
			.read_packet    = matroska_read_packet,
            ...
		};
        */
        ret = ff_read_packet(s, &cur_pkt);
        if (ret < 0) {
            if (ret == AVERROR(EAGAIN))
                return ret;
            /* flush the parsers */
            for (i = 0; i < s->nb_streams; i++) {
                st = s->streams[i];
                if (st->parser && st->need_parsing)
                    parse_packet(s, NULL, st->index);
            }
            /* all remaining packets are now in parse_queue =>
             * really terminate parsing */
            break;
        }
        ret = 0;
        st  = s->streams[cur_pkt.stream_index];

        ...
}

15.matroska_read_packet 

static int matroska_read_packet(AVFormatContext *s, AVPacket *pkt)
{
    MatroskaDemuxContext *matroska = s->priv_data;

    /*
    从之前读取好的avpacket中,将packet[0] copy给pkt
    static int matroska_deliver_packet(MatroskaDemuxContext *matroska,
									   AVPacket *pkt)
	{
        //第一次读,matroska->num_packets 为0,返回-1
		if (matroska->num_packets > 0) {
            //如果num_packets >0 说明有parse好的AVPacket,直接copy
			memcpy(pkt, matroska->packets[0], sizeof(AVPacket));
			av_free(matroska->packets[0]);
			if (matroska->num_packets > 1) {
				void *newpackets;
                //如果有多个,把指针数组往前移.
				memmove(&matroska->packets[0], &matroska->packets[1],
						(matroska->num_packets - 1) * sizeof(AVPacket *));
                //把指针数组进行调整,调整前数组大小是num_packets,调整之后,
                //数组大小为num_packets -1 
				newpackets = av_realloc(matroska->packets,
										(matroska->num_packets - 1) *
										sizeof(AVPacket *));
				if (newpackets)
					matroska->packets = newpackets;
			} else {
                //如果只有一个,会直接释放数组
				av_freep(&matroska->packets);
				matroska->prev_pkt = NULL;
			}
            //num减1
			matroska->num_packets--;
			return 0;
		}
	
		return -1;
	}
    */
    while (matroska_deliver_packet(matroska, pkt)) {
        //第一次读,while条件是-1,需要重新parse cluster,读取avpacket,
        //下面介绍 matroska_parse_cluster
        int64_t pos = avio_tell(matroska->ctx->pb);
        if (matroska->done)
            return AVERROR_EOF;
        if (matroska_parse_cluster(matroska) < 0)
            matroska_resync(matroska, pos);
    }

    return 0;
}


static int matroska_parse_cluster(MatroskaDemuxContext *matroska)
{
    ...
    /*
    	static EbmlSyntax matroska_cluster[] = {
		{ MATROSKA_ID_CLUSTERTIMECODE, EBML_UINT, 0,                     offsetof(MatroskaCluster, timecode) },
		{ MATROSKA_ID_BLOCKGROUP,      EBML_NEST, sizeof(MatroskaBlock), offsetof(MatroskaCluster, blocks), { .n = matroska_blockgroup } },
		{ MATROSKA_ID_SIMPLEBLOCK,     EBML_PASS, sizeof(MatroskaBlock), offsetof(MatroskaCluster, blocks), { .n = matroska_blockgroup } },
		{ MATROSKA_ID_CLUSTERPOSITION, EBML_NONE },
		{ MATROSKA_ID_CLUSTERPREVSIZE, EBML_NONE },
		{ 0 }
	};
	
	static EbmlSyntax matroska_clusters[] = {
		{ MATROSKA_ID_CLUSTER,  EBML_NEST, 0, 0, { .n = matroska_cluster } },
		{ MATROSKA_ID_INFO,     EBML_NONE },
		{ MATROSKA_ID_CUES,     EBML_NONE },
		{ MATROSKA_ID_TAGS,     EBML_NONE },
		{ MATROSKA_ID_SEEKHEAD, EBML_NONE },
		{ 0 }
	};
    只需要parse matroska_cluster 的ebml item以及其子ebml item.
    一个cluster通常包含多个 block group或者 多个simple block.
    ebml_parse这个API前面有介绍过,现在跳过.
    */
    res         = ebml_parse(matroska, matroska_clusters, &cluster);
    blocks_list = &cluster.blocks;
    blocks      = blocks_list->elem;
    //对每一个block parse,下面介绍 matroska_parse_block
    for (i = 0; i < blocks_list->nb_elem; i++)
        if (blocks[i].bin.size > 0 && blocks[i].bin.data) {
            int is_keyframe = blocks[i].non_simple ? !blocks[i].reference : -1;
            res = matroska_parse_block(matroska, blocks[i].bin.data,
                                       blocks[i].bin.size, blocks[i].bin.pos,
                                       cluster.timecode, blocks[i].duration,
                                       is_keyframe, NULL, 0, 0, pos,
                                       blocks[i].discard_padding);
        }
    ebml_free(matroska_cluster, &cluster);
    return res;
}


static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
                                int size, int64_t pos, uint64_t cluster_time,
                                uint64_t block_duration, int is_keyframe,
                                uint8_t *additional, uint64_t additional_id, int additional_size,
                                int64_t cluster_pos, int64_t discard_padding)
{
   ...
    //找到这个block 中num 对应的track,matroska中,一个block只能对应一个track.
    //前面在parse track时候,有将track信息保存在matroska中
    track = matroska_find_track_by_num(matroska, num);
    if (!track || !track->stream) {
        av_log(matroska->ctx, AV_LOG_INFO,
               "Invalid stream %"PRIu64" or size %u\n", num, size);
        return AVERROR_INVALIDDATA;
    } else if (size <= 3)
        return 0;
    st = track->stream;
    if (st->discard >= AVDISCARD_ALL)
        return res;    
    av_assert1(block_duration != AV_NOPTS_VALUE);

    block_time = sign_extend(AV_RB16(data), 16);//读取block_time 的偏移量

    //跳过已经parse过的内容
    data      += 2;
    flags      = *data++;
    size      -= 3;
    if (is_keyframe == -1)
        is_keyframe = flags & 0x80 ? AV_PKT_FLAG_KEY : 0;

    //根据cluster time和 block_time(偏移量) 计算当前block的 timecode.
    if (cluster_time != (uint64_t) -1 &&
        (block_time >= 0 || cluster_time >= -block_time)) {
        timecode = cluster_time + block_time - track->codec_delay;
        if (track->type == MATROSKA_TRACK_TYPE_SUBTITLE &&
            timecode < track->end_timecode)
            is_keyframe = 0;  /* overlapping subtitles are not key frame */
        if (is_keyframe)
            av_add_index_entry(st, cluster_pos, timecode, 0, 0,
                               AVINDEX_KEYFRAME);
    }

      ...
    //parse lace,带蕾丝是ebml里的一种比较常见的数据储存.通常将多个frame,放在一个block中
    //每个frame 由一个蕾丝组成,这个API就是找到每个蕾丝的边界
    //有3中蕾丝类型.具体参考matroska官方文档. 如果不带lace,
    //可以将这个block当着一个lace.
    res = matroska_parse_laces(matroska, &data, &size, (flags & 0x06) >> 1,
                               &lace_size, &laces);

    ...

    //对每个lace parse
    for (n = 0; n < laces; n++) {
        //计算每个lace的duration
        int64_t lace_duration = block_duration*(n+1) / laces - block_duration*n / laces;

        if (lace_size[n] > size) {
            av_log(matroska->ctx, AV_LOG_ERROR, "Invalid packet size\n");
            break;
        }

        if ((st->codec->codec_id == AV_CODEC_ID_RA_288 ||
             st->codec->codec_id == AV_CODEC_ID_COOK   ||
             st->codec->codec_id == AV_CODEC_ID_SIPR   ||
             st->codec->codec_id == AV_CODEC_ID_ATRAC3) &&
            st->codec->block_align && track->audio.sub_packet_size) {
            res = matroska_parse_rm_audio(matroska, track, st, data,
                                          lace_size[n],
                                          timecode, pos);
            if (res)
                goto end;

        } else if (st->codec->codec_id == AV_CODEC_ID_WEBVTT) {
            res = matroska_parse_webvtt(matroska, track, st,
                                        data, lace_size[n],
                                        timecode, lace_duration,
                                        pos);
            if (res)
                goto end;
        } else {
            //接下来介绍 matroska_parse_frame
            res = matroska_parse_frame(matroska, track, st, data, lace_size[n],
                                       timecode, lace_duration, pos,
                                       !n ? is_keyframe : 0,
                                       additional, additional_id, additional_size,
                                       discard_padding);
            if (res)
                goto end;
        }

         ...
    }

...
}



static int matroska_parse_frame(MatroskaDemuxContext *matroska,
                                MatroskaTrack *track, AVStream *st,
                                uint8_t *data, int pkt_size,
                                uint64_t timecode, uint64_t lace_duration,
                                int64_t pos, int is_keyframe,
                                uint8_t *additional, uint64_t additional_id, int additional_size,
                                int64_t discard_padding)
{
    MatroskaTrackEncoding *encodings = track->encodings.elem;
    uint8_t *pkt_data = data;
    int offset = 0, res;
    AVPacket *pkt;

    //有些block data数据是压缩的,在送到decoder之前,需要解压缩,需要预处理
    //是否压缩,以及压缩类型,在read_header 中都能获取
    if (encodings && !encodings->type && encodings->scope & 1) {
        res = matroska_decode_buffer(&pkt_data, &pkt_size, track);
        if (res < 0)
            return res;
    }

    

    ...
    //特定的codec类型处理
    ...


    //分配AVPacket
    pkt = av_mallocz(sizeof(AVPacket));
    /* XXX: prevent data copy... */
    if (av_new_packet(pkt, pkt_size + offset) < 0) {
        av_free(pkt);
        res = AVERROR(ENOMEM);
        goto fail;
    }

    if (st->codec->codec_id == AV_CODEC_ID_PRORES && offset == 8) {
        uint8_t *buf = pkt->data;
        bytestream_put_be32(&buf, pkt_size);
        bytestream_put_be32(&buf, MKBETAG('i', 'c', 'p', 'f'));
    }

    memcpy(pkt->data + offset, pkt_data, pkt_size);

    ...
    //一坨子操作就是填充AVPacket
    ...

    //将pkt添加到matroska->packets,同时matroska->num_packets 加1
    //经过以上操作,才得到matroska->num_packets > 0,这样最开始的那个while循环,才能拿到一个
    //AVPacket,退出循环
    dynarray_add(&matroska->packets, &matroska->num_packets, pkt);
    matroska->prev_pkt = pkt;

    return 0;
    ...
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值