解決faplayer在android4.1上只有圖像沒有聲音的問題


  研究過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

然后編譯運行,問題解決!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM