声明:
本文是我在对player debug时碰到问题时的思路,希望可以对你有所帮助,不过我们很多时候其实就是遇到问题,思考问题,解决问题。这里只是我自己的一点点总结。
我们都知道在播放器中一个特定格式的文件被播放出来要经过下面的步骤:
file
|
|
demux
| |
| |
audio video -------------read
//
///
//
\\\ --------------write
用户态
------------------------------------------------------------------------------------
| | 内核态
| |
stream abuffer vbuffer
| |
| |
audio decoder video decoder
很多时候我们碰到一个错误很可能会无从下手,而这个时候我们就要看看他有没有进过上面的几个步骤,或者说在上面的步骤中有没有碰到什么错误。同时我们注意到上面的处理过程分为了两个态,其中一个是用户态,在用户态中可以对文件进行解协议以及封装的步骤,也就是说在用户态我们要实现的是将一个特定格式的音视频文件转化为一个个的数据包的形式(packet或者frame)。而这中间又经历了:从file---》 stream -----》 packet的步骤。而在内核态主要是对write如的frame或者packet进行codec的过程。
1. 查看内核信息:
因此我们在查看一个文件是否可以播放的时候,我们要看一下他的内核信息,来看一下在内核中codec是否已经初始化,同时一些相关的信息是否已经设置好了。而这个时候如果可以有一个用于对比的就再好不过了。例如对于同一种文件格式,如果在好的播放器中可以播放,而在debug的播放器中不可以播放,那么我们就可以观察一下好的播放器中打印的内核log信息与debug的播放器中打印的内核log信息有什么不一样的地方。同时让内核显示更多的log信息可以使用命令:
echo 7 > /proc/sys/kernel/printk
通过对比可以知道debug的播放器播放器在内核中有哪些是没有完成的。
2. dump数据流
由于我们是要将从用户态读到的信息写入到内核中,所以如果可以有一个对比的player我们可以使用dump数据来对比一下他们在read和write时的数据是否相同。如果read和write到的数据都是一样的,那么很有可能是在后面codec中出了错误。而对于dump数据有两种可能:
a:第一种是在程序中已经写好了dump数据的open,write,close函数,我们只需要设置一些数据值就可以打开这些功能。
b: 第二种是自己写dump函数,也就是自己写对应的open,write,close函数。而当自己写这些东西的时候就要注意一些了,如我提到的fopen失败的各种原因:http://note.youdao.com/noteshare?id=0564f9ed70df8e2915638140830468d0&sub=3BC402CF22FA4288AD58660F12400129
这里有一些小的技巧可以分享一下,很多时候我们不管是读数据或者是写数据都是会有返回值的,而利用返回值就可以很好的实现数据的dump,如在好的播放器中使用的dump数据的方法:
当返回值为小于0时表示读取数据错误或者已经读到packet的末尾-->这个时候可以使用close函数来结束dump
而当返回值为0时表示读到了数据,---->可以在这个时候使用write函数将read到的packet的数据dump出来。
其实dump数据对比很重要,因为通过对比我们可以发现:
a: 如果在read到的数据就出现了错误,那么很有可能是在前面对文件解析的时候就出现了错误,
1).这个时候我们可以向前排查看有没有实现av的分离。如果没有继续向前排查,如果有分别对比一下是所有的数据都出错了,还是只有几个字节的数据出错。
2).我前面碰到的错误就是read到的数据比好的播放器 read到的数据多几个字节。然后详细阅读程序找到了多出来的几个字节的出处。
b: 对比一下从read到的数据到write出去的数据是不是是否相同,同时与好的播放器对比一下数据是否有什么不同的地方。对于我碰到的WMV的格式文件,从read到数据到write数据之前要添加一个header的信息。而debug的播放器中没有添加信息所以不能播放视频流。
c: 如果write到的数据是一样的,那么很有可能是在后面codec的设置或者其他的地方出现了错误。或者内核层中出现了错误(这个应该也是有可能的)。
3. 对比codec中参数
这些参数是要送入到内核中去的。在我调试的过程中发现内核中有些驱动是没有启动的。所以可能是有些参数没有传下去。