2015-09-11 69 views
2

我有一個需求,我需要多次寫入wav(與pcma數據)文件。Wav文件寫入和播放多重時間

說我有一個文件audio-g711a.wav。我想寫它到一個新的文件說audio-g711a-out.wav 2次。當我播放audio-g711a-out.wav時,它應該播放比原始文件長兩倍的播放時間。

我用下面的代碼寫了。但是它的播放時間與原始文件的播放時間完全相同(我期待它能播放兩倍的時間)。

代碼如下。

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

#include <signal.h> 
#include <pthread.h> 
#include <unistd.h> 
#include <sys/uio.h> 
#include <sys/ipc.h> 
#include <sys/shm.h> 
#include <sys/stat.h> 
#include <errno.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 

int g_count = 0; 

void init_config(int argc,char **argv); 
void rewrite_file(int count); 

int main(int argc, char **argv) 
{ 
    init_config(argc, argv); 
    printf("Count = %d\n", g_count); 
    rewrite_file(g_count); 
    return 0; 
} 

void rewrite_file(int count) 
{ 
    int index; 
    char arr[101]; 
    FILE *fd_in; 
    FILE *fd_out; 
    size_t len; 
    unsigned long chunk_size; 

    index = 0; 
    fd_in = fopen("./audio-g711a.wav", "r"); 
    fd_out = fopen("./audio-g711a-out.wav", "w+"); 

rw_again:  
    index++; 
    len = fread(arr, 1, 100, fd_in); 
    while(len == 100) 
    { 
     fwrite(arr, 1, 100, fd_out); 
     len = fread(arr, 1, 100, fd_in); 
    } 
    fwrite(arr, 1, len, fd_out); 
    if(count > index) 
    { 
     printf("Completed %d round of operation of %d total rounds.\n", index, count); 
     fclose(fd_in); 
     fd_in = fopen("./audio-g711a.wav", "r"); 
     goto rw_again; 
    } 

    return; 
} 

void init_config(int argc,char **argv) 
{ 
    int ch; 

    while ((ch = getopt(argc, argv, "v:n:N:X")) != -1) 
    { 
     switch (ch) 
     { 
      case 'n': 
      case 'N': 
      { 
       g_count = atoi(optarg); 
      } 
      break; 

      default: 
      break; 

     } 
    } 

    return; 
} 

要執行此操作,一個可以執行像./a.out -n 2

一些ř& d後,我意識到wav文件有某種報頭。當我第二次寫作時,我再次寫頭。這可能會導致文件無法進一步播放。在第二次寫入時,我停止寫頭部分(44字節)。這並沒有解決問題。

有人可以請指導我怎樣才能實現至少2次寫入wav文件。

更新
工作代碼如下。

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

#include <signal.h> 
#include <pthread.h> 
#include <unistd.h> 
#include <sys/uio.h> 
#include <sys/ipc.h> 
#include <sys/shm.h> 
#include <sys/stat.h> 
#include <errno.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 

int g_count = 0; 

void init_config(int argc,char **argv); 
void rewrite_file(int count); 

int main(int argc, char **argv) 
{ 
    init_config(argc, argv); 
    printf("Count = %d\n", g_count); 
    rewrite_file(g_count); 
    return 0; 
} 

void rewrite_file(int count) 
{ 
    int index; 
    char arr[101]; 
    FILE *fd_in; 
    FILE *fd_out; 
    size_t len; 
    unsigned short data_index = 0; 
    index = 0; 
    fd_in = fopen("./audio-g711a.wav", "r"); 
    fd_out = fopen("./audio-g711a-out.wav", "w+"); 

    // copy header 
    len = fread(arr, 1, 40, fd_in); 
    fwrite(arr, 1, len, fd_out); 

    if(strncmp("data", (arr+36), 4) == 0) 
    { 
     data_index = 40; 
    } 
    else 
    { 
     len = fread(arr, 1, 14, fd_in); 
     fwrite(arr, 1, len, fd_out); 

     if(strncmp("data", (arr+10), 4) == 0) 
     { 
      data_index = 54; 
     } 
    } 


    // update header 
    uint32_t dl; 
    fseek(fd_in, data_index, SEEK_SET); 
    fseek(fd_out, data_index, SEEK_SET); 
    fread(&dl, sizeof(dl), 1, fd_in); 
    dl *= count; 
    fwrite(&dl, sizeof(dl), 1, fd_out); 

    // copy data 
rw_again: 
    index++; 
    fseek(fd_in, (4 + data_index), SEEK_SET); 
    len = fread(arr, 1, 100, fd_in); 
    while(len > 0) 
    { 
     fwrite(arr, 1, len, fd_out); 
     len = fread(arr, 1, 100, fd_in); 
    } 
    fwrite(arr, 1, len, fd_out); 
    if(count > index) 
    { 
     printf("Completed %d round of operation of %d total rounds.\n", index, count); 
     fclose(fd_in); 
     fd_in = fopen("./audio-g711a.wav", "r"); 
     goto rw_again; 
    } 

    fclose(fd_in); 
    fclose(fd_out); 

    return; 
} 
void init_config(int argc,char **argv) 
{ 
    int ch; 

    while ((ch = getopt(argc, argv, "v:n:N:X")) != -1) 
    { 
     switch (ch) 
     { 
      case 'n': 
      case 'N': 
      { 
       g_count = atoi(optarg); 
      } 
      break; 

      default: 
      break; 

     } 
    } 

    return; 
} 
+1

查找標題的格式。您需要更改標題的某些部分。 – immibis

+0

我看到了這裏的格式http://www.codeproject.com/Articles/29676/CWave-A-Simple-C-Class-to-Manipulate-WAV-Files。但不明白我需要做什麼... – Kamal

+1

標題只有36個字節。以下8個字節屬於第一個數據塊。 –

回答

1

WAV文件有一個標題和一個數據段:

[HEADER][DATA] 

簡單的複製,因爲你這樣做,會產生以下文件格式:

[HEADER][DATA][HEADER][DATA] 

你需要的是:

[HEADER][DATADATA] 
    ^
    | 
    +--- chunksize at offset 40 updated 

這是一個quic ķ劈:

void rewrite_file(int count) 
{ 
    int index; 
    char arr[101]; 
    FILE *fd_in; 
    FILE *fd_out; 
    size_t len; 
    unsigned long chunk_size; 

    index = 0; 
    fd_in = fopen("./audio-g711a.wav", "r"); 
    fd_out = fopen("./audio-g711a-out.wav", "w+"); 

    // copy header 
    len = fread(arr, 1, 40, fd_in); 
    fwrite(arr, 1, len, fd_out); 

    // update header 
    uint32_t dl; 
    fseek(fd_in, 40, SEEK_SET); 
    fseek(fd_out, 40, SEEK_SET); 
    fread(&dl, sizeof(dl), 1, fd_in); 
    dl *= count; 
    fwrite(&dl, sizeof(dl), 1, fd_out); 

    // copy data 
rw_again: 
    index++; 
    fseek(fd_in, 44, SEEK_SET); 
    len = fread(arr, 1, 100, fd_in); 
    while(len > 0) 
    { 
     fwrite(arr, 1, len, fd_out); 
     len = fread(arr, 1, 100, fd_in); 
    } 
    fwrite(arr, 1, len, fd_out); 
    if(count > index) 
    { 
     printf("Completed %d round of operation of %d total rounds.\n", index, count); 
     fclose(fd_in); 
     fd_in = fopen("./audio-g711a.wav", "r");   
     goto rw_again; 
    } 

    fclose(fd_in); 
    fclose(fd_out); 

    return; 
} 

更新:

如果wav文件包含一個 '事實' 塊(非PCM格式),那麼數據塊大小偏移不是40,而是54例如。因此,最好搜索「data」標籤來計算數據塊偏移量,而不是使用40作爲幻數。

+0

嘗試此代碼,因爲它。如果我使用avplay玩,我會得到錯誤。 [wav @ 0x7f1b00004f80]找不到'data'標記 audio-g711a-out.wav:處理輸入時發現無效數據 – Kamal

+0

@ user1861447 Hm,與我的測試文件配合使用。你能提供你的文件嗎? – sergej

+0

請分享您的電子郵件ID。或者有什麼辦法可以通過堆棧溢出發送文件。 – Kamal

1

您需要加倍「數據」子塊的「數據」部分。

讀取總塊大小(偏移量4)。

讀取數據子塊大小(偏移量40)。

這兩個值應該由子塊大小增加(如果大小的4個字節包含在子塊大小值中,則可能爲-4)。

數據子塊的數據部分(從偏移量44開始)應加倍(寫入兩次)。