2013-06-05 59 views
1

我想讀出SD卡wav文件的音頻採樣應用我使用NDK和100建設%本地代碼。我有一個方法遍歷包含樣本路徑和流的預定義數組,每個數據緩衝區稍後將由OpenSL播放。致命信號11 NDK使用fopen()函數,FREAD()打開文件時,但AAsset_read工作正常

當我加載的文件作爲資產,使用下面的方法:

int open_asset(AAssetManager* mgr, char* filename, int samp) 
{ 

    assert(NULL != mgr); 
    AAsset *asset = AAssetManager_open(mgr, filename, AASSET_MODE_BUFFER); 

    __android_log_write(ANDROID_LOG_DEBUG, "ASSET", "AAssetManager_open"); 

    if (NULL == asset) 
    { 
     __android_log_write(ANDROID_LOG_DEBUG, "ASSET", "Asset not found, loading aborted."); 
     return JNI_FALSE; 
    } 

    oneshot_samples[samp].buffer_header = (unsigned short*) malloc(HEADER_SIZE); 
    AAsset_read(asset, oneshot_samples[samp].buffer_header, HEADER_SIZE); 

    unsigned short* fmttype; 
    unsigned long* databytes; 

    fmttype = (oneshot_samples[samp].buffer_header + 10); 

    if (*fmttype != 0x1) 
    { 
     __android_log_write(ANDROID_LOG_DEBUG, "ASSET", "*fmttype not PCM, loading aborted."); 
     return JNI_FALSE; 
    } 

    databytes = (oneshot_samples[samp].buffer_header + 20); 

    oneshot_samples[samp].data_size = *databytes; 

    oneshot_samples[samp].buffer_data = (unsigned short*) malloc(*databytes); 
    AAsset_seek(asset, HEADER_SIZE, SEEK_SET); 
    AAsset_read(asset, oneshot_samples[samp].buffer_data, oneshot_samples[samp].data_size); 

    __android_log_print(ANDROID_LOG_DEBUG, "ASSET", "*fmttype: %x", *fmttype); 
    __android_log_print(ANDROID_LOG_DEBUG, "ASSET", "*databytes: %x", *databytes); 

    AAsset_close(asset); 

    __android_log_write(ANDROID_LOG_DEBUG, "ASSET", "AAsset_close(asset)"); 

    return JNI_TRUE; 
} 

他們加載沒有問題。但對於我的應用程序,我希望用戶能夠從SD卡讀取樣本。我改變了文件路徑上的SD卡(只用於測試)一個硬編碼的位置,並使用fopen()和FREAD()嘗試以下方法:

void open_external_file(char* filepath, int samp) 
{ 

    FILE* fp; 
    oneshot_samples[samp].buffer_header = (unsigned short*) malloc(HEADER_SIZE); 

    __android_log_print(ANDROID_LOG_DEBUG, "open_external_file", 
         "filepath: %s", filepath); 

    __android_log_print(ANDROID_LOG_DEBUG, "open_external_file", 
         "size of filepath: %d", sizeof filepath); 

    if ((fp = fopen(filepath, "r")) != NULL) 
    { 
     __android_log_write(ANDROID_LOG_DEBUG, "open_external_file", "fopen()"); 

     fread(oneshot_samples[samp].buffer_header, sizeof(unsigned short), HEADER_SIZE, fp); 
    } 

    unsigned short* fmttype; 
    unsigned long* databytes; 

    fmttype = (oneshot_samples[samp].buffer_header + 10); 

    if (*fmttype != 0x1) 
    { 
     __android_log_write(ANDROID_LOG_DEBUG, "open_external_file", "*fmttype not PCM, loading aborted."); 
    } 

    databytes = (oneshot_samples[samp].buffer_header + 20); 
    oneshot_samples[samp].data_size = *databytes; 
    oneshot_samples[samp].buffer_data = (unsigned short*) malloc(*databytes); 

    __android_log_print(ANDROID_LOG_DEBUG, "open_external_file", "*fmttype: %x", *fmttype); 
    __android_log_print(ANDROID_LOG_DEBUG, "open_external_file", "*databytes: %x", *databytes); 


    fseek(fp , HEADER_SIZE , SEEK_SET); 
    fread(oneshot_samples[samp].buffer_data, sizeof(unsigned short), oneshot_samples[samp].data_size, fp); 

    fclose(fp); 
    __android_log_write(ANDROID_LOG_DEBUG, "open_external_file", "fclose(fp);"); 
} 

這給了我可怕的ANR和不可避免的崩潰:

11月6日至6日:42:30.915:I/dalvikvm(7222):主題ID = 3:反應以信號3 11月6日至6日:42:30.915:A/libc的(7222):致命信號11(SIGSEGV)at 0x0000000c(code = 1)

但奇怪的是,它發生了非常隨機的 - 有36個奇數的樣本,有時錯誤出現在第4次之後,有時在20次左右之後。在閱讀thread之後,它看起來可能是一個分段錯誤,但我不知道它是如何引起的 - 或者兩種方法之間的區別是什麼。

從文件頭* fmttype和的值*數據字節被正確每次返回100%。

我很新的C所以它很可能我做得顯然是錯誤的 - 真的很感激,如果更有經驗的人可能會提供一些線索到什麼原因可能是。

更新:我切換回使用AAsset_read(),並且我仍然得到:

十二月6日至六日:33:50.393:I/dalvikvm(9755):主題ID = 3:反應以信號3 12月6日至六日:33:50.393:I/dalvikvm(9755):寫的堆棧跟蹤到 '/data/anr/traces.txt'

但文件仍然加載罰款,每次,和應用程序不崩潰。 512 MB測試平板的測試樣本總大小爲48.4 MB - 這是否會導致此問題?不過,如果這是我沒有看到如何使用AAsset_read()會有所作爲。

回答

1

你分配HEADER_SIZE字節:

(unsigned short*) malloc(HEADER_SIZE); 

,然後讀HEADER_SIZE * 2字節進去,溢出的緩衝區:

fread(oneshot_samples[samp].buffer_header, sizeof(unsigned short), HEADER_SIZE, fp); 

(由HEADER_SIZEfread()sizeof(unsigned short),加倍了。)

對再次進行同樣的重讀。它不會失敗的Android資產實施,因爲你正在閱讀正確的數據量。修改sizeof(unsigned short)1

不相關:如果fopen()返回NULL,則應該從該函數返回,而不是處理未初始化的數據。

「信號3」消息意味着系統正在從應用程序請求堆棧跟蹤,可能是因爲主線程繁忙併且未響應消息。

+0

非常感謝您的回答。我想知道的是:'buffer_data'是一個'unsigned short *',每個樣本必須有16位,即OpenSL ES需要這樣讀取。將sizeof(unsigned short)改爲1會影響數據在緩衝區中的排列方式嗎?波形文件中的數據也排列成小尾數。 –

+0

它不會改變數據在緩衝區中的放置方式。爲什麼'fread()'這樣宣佈是一個謎。其他人都想知道它... http://stackoverflow.com/questions/295994/what-is-the-rationale-for-fread-fwrite-taking-size-and-count-as-arguments – fadden

+0

有趣的閱讀。正如你所說,fread(oneshot_samples [samp] .buffer_data,sizeof(unsigned short),oneshot_samples [samp] .data_size/2,fp)和fread(oneshot_samples [samp] .buffer_data,1,oneshot_samples [samp]。 data_size,fp)給了我完全相同的結果。這很明顯,爲什麼'AAsset_read()'工作,'fread()'不工作。感謝您解決我的問題。 –