解决faplayer在android4.1上只有图像没有声音的问题

时间:2024-03-06 12:58:15

  研究过twilove的faplayer代码的人应该都知道,faplayer代码中使用了两个播放器程序,一个是android自带的播放器作为默认的播放器,另外一个就是使用了vlc代码的播放器。之前写过一篇相关的文章:采用faplayer播放EPUB书中的mp4视频
  这次要讲的问题就是在使用faplayer中的vlc代码的时候,之前在2.3系统上正常,后来升级的4.04的时候发现只有声音没有图像,这个问题后来解决了,解决的过程下篇日志再说,这次要说的是系统升级的4.1之后,发现只有图像又没有声音了!!!(尼玛能靠点谱不?)由于faplayer早已停止更新了,所以这个问题只能自己想办法搞定。最终在我的“不懈努力下”,问题终于搞定了,在解决问题的过程中我觉得有些东西是比较有意思也值得记录下来的,因此写了这篇文章.

遇到问题第一件事情当然是查看日志,vlc的日志是非常详细的,查看后我发现这两条日志非常可疑:
01-15 14:31:50.960: E/faplayer(1622): [0x67389ef8]audiotrack_android audio output: Could not initialize libmedia.so!
01-15 14:31:50.960: D/faplayer(1622): [0x67389ef8]main audio output: using audio output module "dummy"
 
上面这条日志是报了个错说无法初始化libmedia.so这个库,下面的日志说的是使用虚拟的音频输出模块,是不是使用了虚拟的音频模块,才导致了没有声音呢?
在faplayer的jni代码中查找这条日志的输出位置:在faplayer/jni/vlc/modules/audio_output/android_AudioTrack.c中:
1     p_library = InitLibrary(p_this);
2     if (!p_library) {
3         msg_Err(VLC_OBJECT(p_this), "Could not initialize libmedia.so!");
4         return VLC_EGENERIC;
5     }

看来是InitLibrary函数出了问题,我们来看看这个函数的内容:

 1 void *InitLibrary() {
 2     void *p_library;
 3 
 4     p_library = dlopen("libmedia.so", RTLD_NOW);
 5     if (!p_library)
 6         return NULL;
 7     as_getOutputFrameCount = (AudioSystem_getOutputFrameCount)(dlsym(p_library, "_ZN7android11AudioSystem19getOutputFrameCountEPii"));
 8     as_getOutputLatency = (AudioSystem_getOutputLatency)(dlsym(p_library, "_ZN7android11AudioSystem16getOutputLatencyEPji"));
 9     as_getOutputSamplingRate = (AudioSystem_getOutputSamplingRate)(dlsym(p_library, "_ZN7android11AudioSystem21getOutputSamplingRateEPii"));
10     at_getMinFrameCount = (AudioTrack_getMinFrameCount)(dlsym(p_library, "_ZN7android10AudioTrack16getMinFrameCountEPiij"));
11     at_ctor = (AudioTrack_ctor)(dlsym(p_library, "_ZN7android10AudioTrackC1EijiiijPFviPvS1_ES1_ii"));
12     at_ctor_legacy = (AudioTrack_ctor_legacy)(dlsym(p_library, "_ZN7android10AudioTrackC1EijiiijPFviPvS1_ES1_i"));
13     at_dtor = (AudioTrack_dtor)(dlsym(p_library, "_ZN7android10AudioTrackD1Ev"));
14     at_initCheck = (AudioTrack_initCheck)(dlsym(p_library, "_ZNK7android10AudioTrack9initCheckEv"));
15     at_start = (AudioTrack_start)(dlsym(p_library, "_ZN7android10AudioTrack5startEv"));
16     at_stop = (AudioTrack_stop)(dlsym(p_library, "_ZN7android10AudioTrack4stopEv"));
17     at_write = (AudioTrack_write)(dlsym(p_library, "_ZN7android10AudioTrack5writeEPKvj"));
18     at_flush = (AudioTrack_flush)(dlsym(p_library, "_ZN7android10AudioTrack5flushEv"));
19     // need the first 3 or the last 1
20     if (!((as_getOutputFrameCount && as_getOutputLatency && as_getOutputSamplingRate) || at_getMinFrameCount)) {
21         dlclose(p_library);
22         return NULL;
23     }
24     // need all in the list
25     if (!((at_ctor || at_ctor_legacy) && at_dtor && at_initCheck && at_start && at_stop && at_write && at_flush)) {
26         dlclose(p_library);
27         return NULL;
28     }
29     return p_library;
30 }

嗯,看来这个函数的内容是从so库中查找相应的函数地址,然后把地址赋值给对应的函数指针,那么类似“_ZN7android11AudioSystem19getOutputFrameCountEPii”这样的字符串就是函数在so库中的签名了。我们看看这个字符串所代表的函数的签名:

1 // _ZN7android11AudioSystem19getOutputFrameCountEPii
2 typedef int (*AudioSystem_getOutputFrameCount)(int *, int);

为什么这样的函数在so中会有这样奇怪的代号呢?这方面的知识有一篇文章讲的很好:C++的函数重载

了解了这个后我就在猜想:应该是某个或是某几个函数的签名在4.1中发生了改变,导致找不到才出的错,于是我这样修改程序:

 1 void *InitLibrary() {
 2     void *p_library;
 3 
 4     p_library = dlopen("libmedia.so", RTLD_NOW);
 5     if (!p_library)
 6         return NULL;
 7     as_getOutputFrameCount = (AudioSystem_getOutputFrameCount)(dlsym(p_library, "_ZN7android11AudioSystem19getOutputFrameCountEPii"));
 8     as_getOutputLatency = (AudioSystem_getOutputLatency)(dlsym(p_library, "_ZN7android11AudioSystem16getOutputLatencyEPji"));
 9     as_getOutputSamplingRate = (AudioSystem_getOutputSamplingRate)(dlsym(p_library, "_ZN7android11AudioSystem21getOutputSamplingRateEPii"));
10     at_getMinFrameCount = (AudioTrack_getMinFrameCount)(dlsym(p_library, "_ZN7android10AudioTrack16getMinFrameCountEPiij"));
11     at_ctor = (AudioTrack_ctor)(dlsym(p_library, "_ZN7android10AudioTrackC1EijiiijPFviPvS1_ES1_ii"));
12     at_ctor_legacy = (AudioTrack_ctor_legacy)(dlsym(p_library, "_ZN7android10AudioTrackC1EijiiijPFviPvS1_ES1_i"));
13     at_dtor = (AudioTrack_dtor)(dlsym(p_library, "_ZN7android10AudioTrackD1Ev"));
14     at_initCheck = (AudioTrack_initCheck)(dlsym(p_library, "_ZNK7android10AudioTrack9initCheckEv"));
15     at_start = (AudioTrack_start)(dlsym(p_library, "_ZN7android10AudioTrack5startEv"));
16     at_stop = (AudioTrack_stop)(dlsym(p_library, "_ZN7android10AudioTrack4stopEv"));
17     at_write = (AudioTrack_write)(dlsym(p_library, "_ZN7android10AudioTrack5writeEPKvj"));
18     at_flush = (AudioTrack_flush)(dlsym(p_library, "_ZN7android10AudioTrack5flushEv"));
19     // need the first 3 or the last 1
20     if (!((as_getOutputFrameCount && as_getOutputLatency && as_getOutputSamplingRate) || at_getMinFrameCount)) {
21         msg_Err(VLC_OBJECT(p_this), "interface error 1");
22         if (!as_getOutputFrameCount) {
23             msg_Err(VLC_OBJECT(p_this), "error1");
24         }
25         if (!as_getOutputLatency) {
26             msg_Err(VLC_OBJECT(p_this), "error2");
27         }
28         if (!as_getOutputSamplingRate) {
29             msg_Err(VLC_OBJECT(p_this), "error3");
30         }
31         if (!at_getMinFrameCount)
32         {
33             msg_Err(VLC_OBJECT(p_this), "error4");
34         }
35         dlclose(p_library);
36         return NULL;
37     }
38     // need all in the list
39     if (!((at_ctor || at_ctor_legacy) && at_dtor && at_initCheck && at_start && at_stop && at_write && at_flush)) {
40         msg_Err(VLC_OBJECT(p_this), "interface error 2");
41         dlclose(p_library);
42         return NULL;
43     }
44     return p_library;
45 }

查看日志后,发现是“error2” 也就是as_getOutputLatency为空,那说明“_ZN7android11AudioSystem16getOutputLatencyEPji”这个签名现在在libmedia.so中找不到了,那么现在这个函数的签名是什么呢?要想弄清楚这个,我们需要弄清楚怎么查看libmedia.so中函数的签名。

在网上查询方法后,在终端上使用readelf -s libmedia.so,结果是一长串符号列表,类似下面的内容:

 1 root@ubuntu:/mnt/hgfs/share/4.1.2# readelf -s libmedia.so
 2 
 3 Symbol table \'.dynsym\' contains 1918 entries:
 4    Num:    Value  Size Type    Bind   Vis      Ndx Name
 5      0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
 6      1: 00037069     4 FUNC    GLOBAL DEFAULT    7 _ZN7android10AudioTrack16
 7      2: 00000000     0 FUNC    GLOBAL DEFAULT  UND __aeabi_unwind_cpp_pr0
 8      3: 0003706d     2 FUNC    GLOBAL DEFAULT    7 _ZTv0_n16_N7android10Audi
 9      4: 0003706d     2 FUNC    GLOBAL DEFAULT    7 _ZN7android10AudioTrack16
10      5: 0003706f    12 FUNC    GLOBAL DEFAULT    7 _ZTv0_n12_N7android10Audi
11      6: 0003707d    68 FUNC    GLOBAL DEFAULT    7 _ZN7android10AudioTrack16
12      7: 00000000     0 FUNC    GLOBAL DEFAULT  UND pthread_cond_destroy
13      8: 00000000     0 FUNC    GLOBAL DEFAULT  UND pthread_mutex_destroy
14      9: 00000000     0 FUNC    GLOBAL DEFAULT  UND _ZN7android6ThreadD2Ev
15     10: 00000000     0 FUNC    GLOBAL DEFAULT  UND _ZN7android7RefBaseD2Ev
16     11: 000370c1    12 FUNC    GLOBAL DEFAULT    7 _ZTv0_n12_N7android10Audi
17     12: 000370cd    18 FUNC    GLOBAL DEFAULT    7 _ZN7android10AudioTrack16
18     13: 00000000     0 FUNC    GLOBAL DEFAULT  UND _ZdlPv
19     14: 00000000     0 FUNC    GLOBAL DEFAULT  UND pthread_mutex_lock
20     15: 00000000     0 FUNC    GLOBAL DEFAULT  UND __aeabi_unwind_cpp_pr1
21     16: 00000000     0 FUNC    GLOBAL DEFAULT  UND pthread_mutex_unlock
22     17: 00000000     0 FUNC    GLOBAL DEFAULT  UND __aeabi_idiv
23     18: 00000000     0 FUNC    GLOBAL DEFAULT  UND __aeabi_uidiv
24     19: 000370ed    98 FUNC    GLOBAL DEFAULT    7 _ZN7android10AudioTrack16
25     20: 0003f015    52 FUNC    GLOBAL DEFAULT    7 _ZN7android11AudioSystem2
26     21: 0003efdd    52 FUNC    GLOBAL DEFAULT    7 _ZN7android11AudioSystem1
27     22: 0003efa9    52 FUNC    GLOBAL DEFAULT    7 _ZN7android11AudioSystem1
28     23: 0003714f    62 FUNC    GLOBAL DEFAULT    7 _ZN7android10AudioTrackC2
29     24: 00000000     0 FUNC    GLOBAL DEFAULT  UND pthread_mutex_init
30     25: 0003718d    80 FUNC    GLOBAL DEFAULT    7 _ZN7android10AudioTrackC1
31     26: 00000000     0 FUNC    GLOBAL DEFAULT  UND _ZN7android7RefBaseC2Ev
32     27: 000371dd     4 FUNC    GLOBAL DEFAULT    7 _ZNK7android10AudioTrack9
33     28: 000371e1     4 FUNC    GLOBAL DEFAULT    7 _ZNK7android10AudioTrack7
34     29: 000371e5     4 FUNC    GLOBAL DEFAULT    7 _ZNK7android10AudioTrack1
35     30: 000371e9     4 FUNC    GLOBAL DEFAULT    7 _ZNK7android10AudioTrack6
36     31: 000371ed     6 FUNC    GLOBAL DEFAULT    7 _ZNK7android10AudioTrack1
37     32: 000371f3     6 FUNC    GLOBAL DEFAULT    7 _ZNK7android10AudioTrack1
38     33: 000371f9    44 FUNC    GLOBAL DEFAULT    7 _ZNK7android10AudioTrack9
39     34: 00037225     4 FUNC    GLOBAL DEFAULT    7 _ZN7android10AudioTrack12
40     35: 00037229    32 FUNC    GLOBAL DEFAULT    7 _ZNK7android10AudioTrack7
41     36: 00037249    48 FUNC    GLOBAL DEFAULT    7 _ZN7android10AudioTrack7f
42     37: 00000000     0 FUNC    GLOBAL DEFAULT  UND pthread_cond_signal
43     38: 00037279    30 FUNC    GLOBAL DEFAULT    7 _ZN7android10AudioTrack5f
44     39: 00037297    52 FUNC    GLOBAL DEFAULT    7 _ZN7android10AudioTrack5p
45     40: 000372cb    22 FUNC    GLOBAL DEFAULT    7 _ZN7android10AudioTrack4m
46     41: 000372e1    12 FUNC    GLOBAL DEFAULT    7 _ZNK7android10AudioTrack5
47     42: 000372ed   144 FUNC    GLOBAL DEFAULT    7 _ZN7android10AudioTrack9s
48     43: 0003737d    14 FUNC    GLOBAL DEFAULT    7 _ZNK7android10AudioTrack9
49     44: 0003738d    96 FUNC    GLOBAL DEFAULT    7 _ZN7android10AudioTrack21
50     45: 000373ed     8 FUNC    GLOBAL DEFAULT    7 _ZNK7android10AudioTrack2
51     46: 000373f5    74 FUNC    GLOBAL DEFAULT    7 _ZN7android10AudioTrack13
52     47: 0003743f    40 FUNC    GLOBAL DEFAULT    7 _ZNK7android10AudioTrack1
53     48: 00037469   188 FUNC    GLOBAL DEFAULT    7 _ZN7android10AudioTrack9s
54     49: 00000000     0 FUNC    GLOBAL DEFAULT  UND __android_log_print
55     50: 00037525    48 FUNC    GLOBAL DEFAULT    7 _ZN7android10AudioTrack7s
56     51: 00037555    22 FUNC    GLOBAL DEFAULT    7 _ZN7android10AudioTrack17
57     52: 0003756b    16 FUNC    GLOBAL DEFAULT    7 _ZNK7android10AudioTrack1
58     53: 0003757b    16 FUNC    GLOBAL DEFAULT    7 _ZNK7android10AudioTrack2
59     54: 0003758b    94 FUNC    GLOBAL DEFAULT    7 _ZN7android10AudioTrack11
60     55: 00000000     0 FUNC    GLOBAL DEFAULT  UND android_atomic_or
61     56: 000375e9    50 FUNC    GLOBAL DEFAULT    7 _ZN7android10AudioTrack11
62 ...

看上去挺像那么回事的是吧?其实在仔细查找其中的内容后,没有发现任何跟“_ZN7android11AudioSystem16getOutputLatencyEPji”相关的代码,别说这个空函数了,连已经证明加载成功的函数的签名也没有找到,这是为什么呢?

这时候我就想到,android系统中的库文件都是在arm-linux环境下编译的,属于交叉编译,而我们使用的命令都是在x86架构下的指令,他解析的符号类型会不会也是x86的指令呢?为了弄清楚这个问题,我需要安装arm-linux的开发工具,在参考了这几篇文章后,我成功的安装了arm-linux工具链。

在 Linux 下安装 GNU ARM 工具链

Android 开发环境建立-ARM编译器安装

编译mini2440工具链

使用arm-2008q3-72-arm-none-linux-gnueabi-i686-pc-linux-gnu交叉编译成功在板子上运行

然后使用命令:arm-none-linux-gnueabi-objdump -d libmedia.so:

 1 root@ubuntu:/mnt/hgfs/share/4.1.2# arm-none-linux-gnueabi-objdump -d libmedia.so 
 2 
 3 libmedia.so:     file format elf32-littlearm
 4 
 5 Disassembly of section .plt:
 6 
 7 00036358 <.plt>:
 8    36358:    e52de004     push    {lr}        ; (str lr, [sp, #-4]!)
 9    3635c:    e59fe004     ldr    lr, [pc, #4]    ; 36368 <_ZN7android10AudioTrack16AudioTrackThread10readyToRunEv-0xd00>
10    36360:    e08fe00e     add    lr, pc, lr
11    36364:    e5bef008     ldr    pc, [lr, #8]!
12 ... ...
13    37058:    e5bcffa0     ldr    pc, [ip, #4000]!
14    3705c:    e28fc600     add    ip, pc, #0    ; 0x0
15    37060:    e28cca38     add    ip, ip, #229376    ; 0x38000
16    37064:    e5bcff98     ldr    pc, [ip, #3992]!
17 Disassembly of section .text:
18 
19 00037068 <_ZN7android10AudioTrack16AudioTrackThread10readyToRunEv>:
20    37068:    2000          movs    r0, #0
21    3706a:    4770          bx    lr
22 
23 0003706c <_ZN7android10AudioTrack16AudioTrackThread10onFirstRefEv>:
24    3706c:    4770          bx    lr
25 
26 0003706e <_ZTv0_n12_N7android10AudioTrack16AudioTrackThreadD1Ev>:
27    3706e:    6801          ldr    r1, [r0, #0]
28    37070:    f851 3c0c     ldr.w    r3, [r1, #-12]
29    37074:    18c0          adds    r0, r0, r3
30    37076:    f000 b801     b.w    3707c <_ZN7android10AudioTrack16AudioTrackThreadD1Ev>
31     ...

结果是上面这样的代码。把结果输出到文件中,进行查找:

1 root@ubuntu:/mnt/hgfs/share/4.1.2# arm-none-linux-gnueabi-objdump -d libmedia.so > libmedia.txt
2 root@ubuntu:/mnt/hgfs/share/4.1.2# ls
3 4.0.4  4.0.4.txt  4.1.2.txt  a.txt  lib  libmedia_jni.so  libmedia_native.so  libmediaplayerservice.so  libmedia.so  libmedia.txt
4 root@ubuntu:/mnt/hgfs/share/4.1.2# gedit libmedia.txt 
5 root@ubuntu:/mnt/hgfs/share/4.1.2# grep getOutputLatency libmedia.txt
6    3710c:    f007 ff4c     bl    3efa8 <_ZN7android11AudioSystem16getOutputLatencyEPj19audio_stream_type_t>
7 0003efa8 <_ZN7android11AudioSystem16getOutputLatencyEPj19audio_stream_type_t>:
8    3efc4:    b130          cbz    r0, 3efd4 <_ZN7android11AudioSystem16getOutputLatencyEPj19audio_stream_type_t+0x2c>

可知getOutputLatency函数的符号由“_ZN7android11AudioSystem16getOutputLatencyEPji”变为“_ZN7android11AudioSystem16getOutputLatencyEPj19audio_stream_type_t”,于是我们这样修改代码:

1 as_getOutputLatency = (AudioSystem_getOutputLatency)(dlsym(p_library, "_ZN7android11AudioSystem16getOutputLatencyEPji"));
2 
3     // edit by yueang
4     if (!as_getOutputLatency) {
5         as_getOutputLatency = (AudioSystem_getOutputLatency)(dlsym(p_library, "_ZN7android11AudioSystem16getOutputLatencyEPj19audio_stream_type_t"));
6     }
7     // edit by yueang end

然后编译运行,问题解决!