# myffplay **Repository Path**: hejinjing/myffplay ## Basic Information - **Project Name**: myffplay - **Description**: 将ffmpeg 中的ffplay 分割为若干个文件,以方便分析,调试和理解. - **Primary Language**: C - **License**: GPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-03-09 - **Last Updated**: 2025-04-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README 1. 首先自己建一个目录,编译通过ffplay.c 2. 拆分ffplay.c 先提出一个main() 函数, 3. 继续拆分, 把main 中用到了函数挪到main, 例如opt类操作的函数, 从而提出opt选项表及opt 函数 4. 拆分过程. 3.1 拆分当然离不开copy,粘贴. 3个5个以内可以手工操作. 多了就要上点手段了. vim的宏操作可以帮到你. 3.2: 函数拆出后,尤其是函数拆到新文件中时,要在对应的头文件上 添加函数头声明, 方便从其它文件中调用该函数. 3.3: 新文件中的函数往往要调用别的函数,所以一般是编译不过了. 它需要做3件事. 1. 缺少了数据类型,必须包含上必要的头文件. 否则不知道类型名.编译错误. unknow type name 'xxxxx' 数据类型你不告诉它是如何进行内存分配的,计算机就没法工作,所以算错误. 要告诉它类型是什么样子的. 2. 把它访问的变量挪到自己的文件中,或者声明为外部引用. 否则编译错误, ‘xxxxx’ undeclared 声明为外部的方法是: extern xxxxx, 是需要你找的,添加到你文件的开头. TYPE 找不到算错误,计算机没法继续进行. 要告诉它变量是什么类型. 一种偷懒的办法是把全局变量集中在一起作为global.c, 再对所有的变量声明为extern ....作为global.h 然后对每个新添的文件包含上这个头文件. 则省却了对外部变量引用的烦恼. 不过最好用extern ... 加在新生成的文件头部,一个是为了精简,一个是为了你熟悉这些变量. 3. 把它调用的函数挪到自己的文件中,或者包含上调用函数声明的头文件. 否则c文件会有警告信息说函数未声明. 简单变通. 如果仅有1,2个函数未声明,不想包含太大的头文件,可以直接再重写一次函数声明. 通过了1,2项就消除了错误, 编译就能通过, 但可能还有连接的错误. 对 'xxxxx' 未定义的引用. 说明它想调用一个函数, 但找不到在哪里. 这就要查看该函数是否书写,及该函数是否声明为static 了, static 不能被其它文件引用. 当处理连接错误时,你可能需要去掉statcic 声明, 再包含上函数声明就可以了. 但问题没有那么简单, 也许你发现就只有一处调用它,把它挪到新文件岂不更好?,然后你把它copy了进来, 这时发现,嗯!... 又要重复1,2步, 是个递归的过程. 是的,就是这样的,看起来容易做起来难. 不过后面的原则上比前面要容易些了, 只能加油! 兄弟们, 万事开头难,头都已经开了,就只有往前走了. 注意, 当你发现牵扯的函数太复杂时,不要一味的挪挪挪,要及时停止,用再次声明函数声明而停止,就像 庖丁解牛,后面又要带一大堆时,该切割就要切割了,不能越拖越大,没头没了. 关于第3项的warning, 虽然重要性不太高,可以第2步处理, 当太多的警告也让人眼花. 有一些不重要警告可以用#pragma 把它关闭. 例如: #pragma GCC diagnostic ignored "-Wsign-compare" #pragma GCC diagnostic ignored "-Wunused-parameter" 对于 warning: implicit declaration of function 'xxxxx' 你要是知道函数声明在哪个头文件中,包含上它就闭嘴了. 当没有错误了,只剩下warning 时,处理也就方便,快捷多了. 只需要添加几个头文件就可以了. 其中2,3项工作构成拆分主要工作量.面对成百上千的错误和警告,就要一步步把它消除. 当然为了工作效率还是要上点手段. 那就是批量书写代码. 这就是vim, emacs的高级编辑功能了. 其中vim更精准,emacs更灵活. 关键是要得心应手. 改多了对变量和函数也就熟悉了. 3.4: 拆分的原则是2点,一是空间分割,一是时间分割. 所谓空间分割就是以一个结构变量为中心,把它按类的方式拆分出来. 例如这里的packet_queue,frame_queue. 将来他们的功能也很容易写测试代码测试. 所谓时间分割就是按照主流程的架构,分割过程到不同的文件,这样对流程更好的把控. 例如这里的event_loop 每一步都把所有的error 和 warning 都删除干净,岂不妙哉! warning 看不见了, make clean, 再make 即可看见了. 分割代码重新编译连接通过,也是一个再创造的过程.想搞懂它,也是一个基本的起点. 对于那些陌生的单词,符号,到底什么意思,就从编译,连接开始吧. 编译通过,还需要阅读,调试,理解和继续重构代码, 灵活掌握,为我所用. 搞定它,也有驯服烈马的感觉. 里面有很多东西可以学! 目前分割: main->option stream-open->threads->subs decoder frame_queue packet_queue clock video audio event-loop