研究過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
然后編譯運行,問題解決!
