天天看點

SDL2_code_play_pcm

/**
 * 
 * ffmpeg -i file_name.mp3 -acodec pcm_s16le -f s16le -ac 2 -ar 44100 file_name.pcm
 * ffmpeg -i xiongmao.flv -vn -c:a pcm_s16le -f s16le -ac 2 -ar 44100 xiongmao.pcm
 * 
 */

#include <SDL2/SDL.h>

#define PATH_PCM "1.pcm"
#define PCM_BUF_SIZE 4096000

FILE *pcm_fp = NULL;
int isRun = 1;
int pcm_read_len;
char pcm_buf[PCM_BUF_SIZE];

// 回調函數
// 需要len位元組資料寫到指針stream處
// userdata 傳遞過來的參數
void user_feed_pcm(void *userdata, Uint8 *stream, int len)
{

  if (!isRun)
  { // 如果程式要退出
    return;
  }

  if (!pcm_fp) // 如果未打開檔案
  {
    pcm_fp = fopen(PATH_PCM, "r");
    if (!pcm_fp) // 如果打開檔案失敗
    {
      SDL_Log("Failed to open pcm file %s!\n", PATH_PCM);
      isRun = 0;
      return;
    }
  }

  SDL_memset(stream, 0, len); // 一定要清空!!!!

  if ((pcm_read_len = fread(pcm_buf, 1, len, pcm_fp)) < 0) // 如果讀取錯誤
  {
    SDL_Log("Failed to read pcm file %s!\n", PATH_PCM);
    isRun = 0;
    return;
  }

  if (pcm_read_len == 0) // 讀取完畢~
  {
    isRun = 0;
    return;
  }

  // 将PCM資料拷貝到聲霸卡的緩存區裡
  SDL_MixAudio(stream, pcm_buf, pcm_read_len, SDL_MIX_MAXVOLUME / 32); // 破音就除個數
}

int main(int argc, char *argv[])
{

  SDL_Init(SDL_INIT_AUDIO);

  SDL_AudioSpec spec;
  spec.freq = 44100;
  spec.channels = 2;
  spec.format = AUDIO_S16SYS;
  spec.silence = 0;
  spec.samples = 1024;
  spec.callback = user_feed_pcm; // NULL 就使用 SDL_QueueAudio()來主動填充資料
  spec.userdata = NULL;

  if (SDL_OpenAudio(&spec, NULL) < 0)
  {
    SDL_Log("Failed to open audio device!\n");
    goto __EXIT;
  }

  SDL_PauseAudio(0);

  while (isRun)
  {
    SDL_Delay(20);
  }

  if (pcm_fp)
  {
    fclose(pcm_fp);
  }

  SDL_CloseAudio();

__EXIT:
  SDL_Quit();
  return 0;
}