Hi3519A播放ACC理解

硬件相關內容

ACC編解碼器

海思平臺內置了ACC編解碼器。

音頻接口

音頻輸入輸出接口簡稱AIO(Audio Input/Output)接口,用於和Audio Codec對接,完成聲音的錄製和播放。AIO接口分爲兩種類型:只支持輸入或只支持輸出,當爲輸入類型時,又稱爲 AIP,當爲輸出類型時,又稱爲 AOP。

軟件中負責抽象音頻接口輸入功能的單元,稱之爲 AI 設備;負責抽象音頻接口輸出功能的單元,稱之爲 AO 設備。

對每個輸入輸出接口,軟件根據該接口支持的功能,分別與 AI 設備和 AO 設備建立映射關係。例如:AIP0 只支持音頻輸入,則 AIP0 映射爲 AiDev0;AOP0 只支持音頻輸出,則 AOP0 映射爲 AoDev0。

播放原理

芯片利用 DMA 將內存中的數據傳輸到 AO 設備。AO設備通過 I2S 時序或 PCM 時序向 Audio Codec 發送數據。Audio Codec 完成數字信號到模擬信號的轉換過程,並輸出模擬信號。示意圖如下所示。

音頻接口時序

支持標準 IIS 接口時序模式和 PCM 接口時序模式,並提供靈活的配置以支持與多種 Audio Codec 對接。詳細的時序支持情況請參考對應芯片的用戶指南。

AI、AO通道

API相關

音頻相關的API都在HiMPP中。

音頻 API 接口依賴 HI_MPI_SYS_Init 和 HI_MPI_SYS_Exit 的順序調用,不支持異步調用 HI_MPI_SYS_Init 和 HI_MPI_SYS_Exit。

基本流程

1、創建獨立線程。

2、先調用 HI_MPI_SYS_Init()。

3、調用音頻相關的接口初始化,如 HI_MPI_ADEC_AacInit()。

4、打開fopen()音頻文件。

5、讀取文件。

6、發送frame到AO接口

....

n、出初始化時,需要先調用音頻相關接口去初始化,如 HI_MPI_ADEC_AacDeInit(),再調用 HI_MPI_SYS_Exit()。

重點函數

和ACC解碼相關的 API 函數名稱基本爲 HI_MPI_ADEC_xxxx(),包括如下幾個。

HI_MPI_ADEC_CreateChn

創建音頻解碼通道。

HI_MPI_ADEC_DestoryChn

銷燬音頻解碼通道。

HI_MPI_ADEC_SendStream

發送音頻解碼流到音頻解碼通道。

  • 創建解碼通道時可以指定解碼方式爲 pack 方式或 stream 方式。
    • - pack 方式用於確定碼流包爲一幀的情況下,比如從 AENC 直接獲取的碼流,從文件讀取確切知道一幀邊界(語音編碼碼流長度固定,很容易確定邊界)的碼流,效率較高。
    • - stream 方式用於不確定碼流包爲一幀的情況下,效率較低,且可能會有延遲。
  • 支持阻塞或非阻塞方式發送碼流。
  • 當阻塞方式發送碼流時,如果用於緩存解碼後的音頻幀的 Buffer 滿,則此接口調用會被阻塞,直至解碼後的音頻幀數據被取走,或 ADEC 通道被銷燬。

【參數】

AdChn 通道號。
取值範圍:[0, ADEC_MAX_CHN_NUM)。
輸入
pstStream 音頻碼流。 輸入
bBlock 阻塞標識。
HI_TRUE:阻塞。
HI_FALSE:非阻塞。

HI_MPI_ADEC_ClearChnBuf

清除 ADEC 通道中當前的音頻數據緩存。

HI_MPI_ADEC_RegisterDecoder

註冊解碼器。

HI_MPI_ADEC_UnRegisterDecoder

註銷解碼器。

HI_MPI_ADEC_GetFrame

獲取音頻解碼幀數據。

HI_MPI_ADEC_ReleaseFrame

釋放音頻解碼幀數據。

HI_MPI_ADEC_SendEndOfStream

向解碼器發送碼流結束標誌符,並清除碼流Buffer。

數據結構

AIO_ATTR_S

定義音頻輸入輸出設備屬性結構體。

typedef struct hiAIO_ATTR_S {
    AUDIO_SAMPLE_RATE_E enSamplerate; /*sample rate*/
    AUDIO_BIT_WIDTH_E enBitwidth; /*bitwidth*/
    AIO_MODE_E enWorkmode; /*master or slave mode*/
    AUDIO_SOUND_MODE_E enSoundmode; /*momo or steror*/
    HI_U32 u32EXFlag; /*expand 8bit to 16bit */
    HI_U32 u32FrmNum; /*frame num in buffer*/
    HI_U32 u32PtNumPerFrm; /*number of samples*/
    HI_U32 u32ChnCnt;
    HI_U32 u32ClkSel;
    AIO_I2STYPE_E enI2sType;
}AIO_ATTR_S;
enSamplerate 音頻採樣率(從模式下,此參數不起作用)。
靜態屬性。
enBitwidth 音頻採樣精度(從模式下,此參數必須和音頻 AD/DA 的採樣精
度匹配)。
靜態屬性。
enWorkmode 音頻輸入輸出工作模式。
靜態屬性。
enSoundmode 音頻聲道模式。
靜態屬性。
u32EXFlag 取值範圍:{0, 1, 2}。
 0:不擴展。
 1:擴展成 16 位,8bit 到 16bit 擴展標誌(只對 AI 採樣精度爲
8bit 時有效)。
 2:24 位裁剪成 16 位,在外置 Codec 的場景下可能用到。
靜態屬性,保留參數,一般設置成 1 即可。
u32FrmNum 緩存幀數目。
取值範圍:[2, MAX_AUDIO_FRAME_NUM]。
靜態屬性。
u32PtNumPerFrm 每幀的採樣點個數。
取值範圍:G711、G726、ADPCM_DVI4 編碼時取值爲 80、
160、240、320、480;ADPCM_IMA 編碼時取值爲 81、161、
241、321、481。
AI 取值範圍爲:[80, 2048],AO 取值範圍爲:[80, 4096]。
靜態屬性。
u32ChnCnt 支持的通道數目。
取值:1、2、4、8、16。
(輸入最多支持 AIO_MAX_CHN_NUM 個通道,輸出最多支持 2
個通道)。
u32ClkSel 配置 AI 設備 0 是否複用 AO 設備 0 的幀同步時鐘及位流時鐘。
取值:0、1。
0:不復用;
1:複用。
enI2sType 配置設備 I2S 類型 (僅
Hi3559AV100/Hi3519AV100/Hi3516CV500/Hi3516EV200 支持該
參數)。
AI 取值:AIO_I2STYPE_INNERCODEC,
AIO_I2STYPE_EXTERN
AO 取值:AIO_I2STYPE_INNERCODEC,
AIO_I2STYPE_EXTERN,AIO_I2STYPE_INNERHDMI。
靜態屬性。

ADEC_CHN_ATTR_S

定義解碼通道屬性結構體。

typedef struct hiADEC_CH_ATTR_S {
    PAYLOAD_TYPE_E enType;
    HI_U32 u32BufSize;
    ADEC_MODE_E enMode;
    HI_VOID ATTRIBUTE *pValue;
} ADEC_CHN_ATTR_S;
enType 音頻解碼協議類型。
靜態屬性。
u32BufSize 音頻解碼緩存大小。
取值範圍:[2, MAX_AUDIO_FRAME_NUM],以幀爲單位。
靜態屬性。
enMode 解碼方式。
靜態屬性。
pValue 具體協議屬性指針。

簡單樣例

來自海思 SDK 的 Sample 。

/******************************************************************************
* function : get stream from file, and send it  to Adec
******************************************************************************/
void *SAMPLE_COMM_AUDIO_AdecProc(SAMPLE_ADEC_S *pstAdec)
{
    HI_S32 s32Ret;
    AUDIO_STREAM_S stAudioStream;
    HI_U32 u32Len = 2048;
    HI_U32 u32ReadLen;
    HI_S32 s32AdecChn;
    HI_U8 *pu8AudioStream = NULL;
    SAMPLE_ADEC_S *pstAdecCtl = (SAMPLE_ADEC_S *)pstAdec;
    AO_CHN_STATE_S pstStatus;
    FILE *pfd = pstAdecCtl->pfd;
    s32AdecChn = pstAdecCtl->AdChn;
 
    pu8AudioStream = (HI_U8*)malloc(sizeof(HI_U8)*MAX_AUDIO_STREAM_LEN);
 
    if (NULL == pu8AudioStream)
    {
        printf("%s: malloc failed!\n", __FUNCTION__);
        return NULL;
    }
 
    while (HI_TRUE == pstAdecCtl->bStart)
    {
        /* read from file */
        stAudioStream.pStream = pu8AudioStream;
        u32ReadLen = fread(stAudioStream.pStream, 1, u32Len, pfd);
        if (u32ReadLen <= 0)
        {
            /*
            s32Ret = HI_MPI_ADEC_SendEndOfStream(s32AdecChn, HI_FALSE);
            if (HI_SUCCESS != s32Ret)
            {
                printf("%s: HI_MPI_ADEC_SendEndOfStream failed!\n", __FUNCTION__);
            }
            fseek(pfd, 0, SEEK_SET);
            */
            printf("u32ReadLen <= 0 break! s32Ret:%d \n",s32Ret);
            break;
        }
 
        /* here only demo adec streaming sending mode, but pack sending mode is commended */
        stAudioStream.u32Len = u32ReadLen;
        s32Ret = HI_MPI_ADEC_SendStream(s32AdecChn, &stAudioStream, HI_TRUE);
        if(HI_SUCCESS != s32Ret)
        {
            printf("%s: HI_MPI_ADEC_SendStream(%d) failed with %#x!\n",\
                   __FUNCTION__, s32AdecChn, s32Ret);
            //break;
        }
        usleep(1000*10);
    }
 
    while (HI_TRUE == pstAdecCtl->bStart)
    {
        s32Ret = HI_MPI_AO_QueryChnStat(0, 0,&pstStatus);
        //printf("pstStatus.u32ChnBusyNum: %d\n",pstStatus.u32ChnBusyNum);
        if(pstStatus.u32ChnBusyNum < 1)
        {
            s32Ret = HI_MPI_ADEC_SendEndOfStream(s32AdecChn, HI_FALSE);
            if (HI_SUCCESS != s32Ret)
            {
                printf("%s: HI_MPI_ADEC_SendEndOfStream failed!\n", __FUNCTION__);
            }
            break;
        }
        sleep(1);
    }
 
 
    free(pu8AudioStream);
    pu8AudioStream = NULL;
    fclose(pfd);
    pstAdecCtl->bStart = HI_FALSE;
    return NULL;
}

/******************************************************************************
* function : Create the thread to get stream from file and send to adec
******************************************************************************/
HI_S32 SAMPLE_COMM_AUDIO_CreatTrdFileAdec(ADEC_CHN AdChn, FILE *pAdcFd) {
    SAMPLE_ADEC_S *pstAdec = NULL;
 
    if (NULL == pAdcFd)
    {
        return HI_FAILURE;
    }
 
    pstAdec = &gs_stSampleAdec[AdChn];
    pstAdec->AdChn = AdChn;
    pstAdec->pfd = pAdcFd;
    pstAdec->bStart = HI_TRUE;
    //pthread_create(&pstAdec->stAdPid, 0, SAMPLE_COMM_AUDIO_AdecProc, pstAdec);
    SAMPLE_COMM_AUDIO_AdecProc(pstAdec);
 
    return HI_SUCCESS;
}

HI_S32 main(int argc, char *argv[]) {
    char ch;
    HI_S32 s32Ret= HI_SUCCESS;
    AIO_ATTR_S stAioAttr;
 
    /* init stAio. all of cases will use it */
    memset(&stAioAttr, 0, sizeof(AIO_ATTR_S));
    stAioAttr.enBitwidth = AUDIO_BIT_WIDTH_16;
    stAioAttr.enWorkmode = AIO_WORK_MODE;
    stAioAttr.enSoundmode = AUDIO_SOUND_MODE_MONO;
    stAioAttr.u32EXFlag = 0;
    stAioAttr.u32FrmNum = 30;
    stAioAttr.u32ChnCnt = 1;
#ifdef HI_ACODEC_TYPE_TLV320AIC31
    stAioAttr.u32ClkSel = 1;
#else
    stAioAttr.u32ClkSel = 0;
#endif
 
    stAioAttr.enSamplerate = AUDIO_SAMPLE_RATE_8000;
    stAioAttr.u32PtNumPerFrm = (AAC_TYPE_AACLC == gs_enAacType) ? 1024 : 2048;
 
    //signal(SIGINT, SAMPLE_AUDIO_HandleSig);
    //signal(SIGTERM, SAMPLE_AUDIO_HandleSig);
 
    s32Ret = SAMPLE_COMM_SYS_Init();
    if (HI_SUCCESS != s32Ret) {
        printf("%s: system init failed with %d!\n", __FUNCTION__, s32Ret);
        return HI_FAILURE;
    }
 
    /* register aac encoder and decoder */
    HI_MPI_ADEC_AacInit();
 
    s32Ret = SAMPLE_AUDIO_AdecAo(argv[1],&stAioAttr);/* read audio stream from file,decode and send AO*/
 
    if (s32Ret != HI_SUCCESS) {
 
    }
 
    SAMPLE_COMM_SYS_Exit();
 
    return HI_SUCCESS;
}

 

發佈了164 篇原創文章 · 獲贊 11 · 訪問量 104萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章