解决faplayer在android4.1上只有图像没有声音的问题
研究过twilove的faplayer代码的人应该都知道,faplayer代码中使用了两个播放器程序,一个是android自带的播放器作为默认的播放器,另外一个就是使用了vlc代码的播放器。之前写过一篇相关的文章:采用faplayer播放EPUB书中的mp4视频
这次要讲的问题就是在使用faplayer中的vlc代码的时候,之前在2.3系统上正常,后来升级的4.04的时候发现只有声音没有图像,这个问题后来解决了,解决的过程下篇日志再说,这次要说的是系统升级的4.1之后,发现只有图像又没有声音了!!!(尼玛能靠点谱不?)由于faplayer早已停止更新了,所以这个问题只能自己想办法搞定。最终在我的“不懈努力下”,问题终于搞定了,在解决问题的过程中我觉得有些东西是比较有意思也值得记录下来的,因此写了这篇文章.
01-15 14:31:50.960: D/faplayer(1622): [0x67389ef8]main audio output: using audio output module "dummy"
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工具链。
使用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
然后编译运行,问题解决!