14.read_frame_internal

static int read_frame_internal(AVFormatContext *s, AVPacket *pkt)
{...//初始化packetav_init_packet(pkt);while (!got_packet && !s->parse_queue) {.../* read next packet *//*这个会调用format的read packet.例如mkv的,稍后再对这个API进行深入剖析,这个API每次读取一个block data<==>AVPacketAVInputFormat 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给pktstatic int matroska_deliver_packet(MatroskaDemuxContext *matroska,AVPacket *pkt){//第一次读,matroska->num_packets 为0,返回-1if (matroska->num_packets > 0) {//如果num_packets >0 说明有parse好的AVPacket,直接copymemcpy(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减1matroska->num_packets--;return 0;}return -1;}*/while (matroska_deliver_packet(matroska, pkt)) {//第一次读,while条件是-1,需要重新parse cluster,读取avpacket,//下面介绍 matroska_parse_clusterint64_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_blockfor (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 parsefor (n = 0; n < laces; n++) {//计算每个lace的durationint64_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_frameres = 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类型处理...//分配AVPacketpkt = 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;...
}

ffmpeg源码学习笔记五相关推荐

  1. 雷神FFMpeg源码学习笔记

    雷神FFMpeg源码学习笔记 文章目录 雷神FFMpeg源码学习笔记 读取编码并依据编码初始化内容结构 每一帧的视频解码处理 读取编码并依据编码初始化内容结构 在开始编解码视频的时候首先第一步需要注册 ...

  2. ffmpeg源码学习笔记三

    9. 关于如何parse mkv 前面为了不把战线拉太长,把如何parse mkv container 内容直接跳过了 接下来还是从read_header 开始讲解 static int matros ...

  3. Vuex 4源码学习笔记 - 通过dispatch一步步来掌握Vuex整个数据流(五)

    在上一篇笔记中:Vuex 4源码学习笔记 - Store 构造函数都干了什么(四) 我们通过查看Store 构造函数的源代码可以看到主要做了三件事情: 初始化一些内部变量以外 执行installMod ...

  4. Java多线程之JUC包:Semaphore源码学习笔记

    若有不正之处请多多谅解,并欢迎批评指正. 请尊重作者劳动成果,转载请标明原文链接: http://www.cnblogs.com/go2sea/p/5625536.html Semaphore是JUC ...

  5. jquery源码学习笔记三:jQuery工厂剖析

    jquery源码学习笔记二:jQuery工厂 jquery源码学习笔记一:总体结构 上两篇说过,query的核心是一个jQuery工厂.其代码如下 function( window, noGlobal ...

  6. RocketMQ 源码学习笔记 Producer 是怎么将消息发送至 Broker 的?

    RocketMQ 源码学习笔记 Producer 是怎么将消息发送至 Broker 的? 文章目录 RocketMQ 源码学习笔记 Producer 是怎么将消息发送至 Broker 的? 前言 项目 ...

  7. Vuex 4源码学习笔记 - 通过Vuex源码学习E2E测试(十一)

    在上一篇笔记中:Vuex 4源码学习笔记 - 做好changelog更新日志很重要(十) 我们学到了通过conventional-changelog来生成项目的Changelog更新日志,通过更新日志 ...

  8. Vuex 4源码学习笔记 - Vuex是怎么与Vue结合?(三)

    在上一篇笔记中:Vuex源码学习笔记 - Vuex开发运行流程(二) 我们通过运行npm run dev命令来启动webpack,来开发Vuex,并在Vuex的createStore函数中添加了第一个 ...

  9. Apache log4j-1.2.17源码学习笔记

    (1)Apache log4j-1.2.17源码学习笔记 http://blog.csdn.net/zilong_zilong/article/details/78715500 (2)Apache l ...

最新文章

  1. [android] 练习使用ListView(一)
  2. 【编译原理】递归下降的预测分析(真の能看懂~!)
  3. Java中的注解以及应用 @Deprecated @SupressWarning @Override
  4. 关于Netty的一些理解、实践与陷阱
  5. BIRT:基于 Eclipse 的报表
  6. 《配置管理最佳实践》——1.2 从哪里开始
  7. 力软敏捷开发框架真正源码_敏捷真正使谁受益?
  8. 【java笔记】java语言的跨平台性和运行环境
  9. 资源管理器和计算机的功能基本相同吗,“资源管理器”和“计算机”的功能基本相同...
  10. Logs Viewer
  11. GridView commandname
  12. PHP第一季视频教程.李炎恢.学习笔记(五)(第3章 操作符与控制结构(1)(2))
  13. 通过写《费用明细表》发现写sql的乐趣
  14. 爆款养成思路,教你利用砍价做出刷屏活动!
  15. 关闭“Chromium 未正确关闭”提示
  16. 首个“中国籍”曲妥珠单抗于欧盟获批上市
  17. liferay的控制条docbar消失解决方法
  18. DNS劫持,HTTP劫持、HTTPS劫持【流量劫持】
  19. HackerEarth, The Grass Type (dsu on tree)
  20. 使用xlsx.utils.js前端导出excel

热门文章

  1. 2021-05-26 2021年T电梯修理最新解析及T电梯修
  2. OpenCV SIFT源码详解——总体概览
  3. 用差分方程写三角形的重心
  4. 国内 IT 相关网站
  5. Jetson TX1 开发教程(6)--安卓手机控制TX1和Qt程序打包
  6. ACL最全详解:原理及作用、分类及特点、配置及需求
  7. 转行程序员日记---2020-11-10【忙里偷闲大法开启】
  8. 高并发大流量情况下带来的海量数据分库分表的正确姿势
  9. 生产者消费者的实现与思考
  10. visual studio 里面解决方案资源管理器界面不见了,应该如何显示出来?并且如何将其从右边更改到左边