/* * Copyright (C) 2020 Amlogic Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "audio_hw_decoder_spdif" //#define LOG_NDEBUG 0 #include "aml_audio_log.h" #include "audio_hw.h" #include "tv_patch_format_parser.h" #include "aml_audio_spdifdec.h" #define IEC61937_HEADER_PA_LITTLE 0xF872 #define IEC61937_HEADER_PB_LITTLE 0x4E1F #define IEC61937_HEADER_PA_BIG 0x72F8 #define IEC61937_HEADER_PB_BIG 0x1F4E #define IEC61937_DEFAULT_SIZE (6144) #define IEC61937_HEADER_SIZE (8) #define IEC61937_HEADER_COPY_SIZE (3) /*the header is 4 bytes, if sync failed, we need at least copy 3 bytes*/ #define IEC61937_PA_OFFSET (0) #define IEC61937_PB_OFFSET (2) #define IEC61937_PC_OFFSET (4) #define IEC61937_PD_OFFSET (6) #define IEC61937_HEADER_SYNC_PERIOD (8) /*in this period there is no IEC frame, increase this can accelerate the sync speed*/ #define IEC61937_DTSHD_HEAD_SIZE (12) #define IEC61937_QUICK_SYNC enum SPDIF_DEC_STATE { SPDIF_DEC_SYNCING, SPDIF_DEC_SYNCED, SPDIF_DEC_LACK_DATA, }; struct aml_spdif_decoder { audio_format_t format; void * buf; int32_t buf_size; int32_t buf_remain; uint32_t status; int32_t payload_size; }; int aml_spdif_decoder_open(void **spdifdec_handle) { struct aml_spdif_decoder *spdif_dec_handle = NULL; spdif_dec_handle = (struct aml_spdif_decoder *)aml_audio_calloc(1, sizeof(struct aml_spdif_decoder)); if (spdif_dec_handle == NULL) { ALOGE("%s handle error", __func__); goto ERROR; } spdif_dec_handle->buf_size = IEC61937_DEFAULT_SIZE; spdif_dec_handle->buf = aml_audio_calloc(1, IEC61937_DEFAULT_SIZE); if (spdif_dec_handle->buf == NULL) { ALOGE("%s data buffer error", __func__); goto ERROR; } spdif_dec_handle->format = AUDIO_FORMAT_INVALID; spdif_dec_handle->status = SPDIF_DEC_SYNCING; spdif_dec_handle->buf_remain = 0; spdif_dec_handle->payload_size = 0; *spdifdec_handle = spdif_dec_handle; ALOGI("%s exit =%p", __func__, spdif_dec_handle); return 0; ERROR: if (spdif_dec_handle) { if (spdif_dec_handle->buf) { aml_audio_free(spdif_dec_handle->buf); spdif_dec_handle->buf = NULL; } aml_audio_free(spdif_dec_handle); spdif_dec_handle = NULL; } *spdifdec_handle = NULL; ALOGE("%s error", __func__); return -1; } int aml_spdif_decoder_close(void *phandle) { struct aml_spdif_decoder *spdif_dec_handle = (struct aml_spdif_decoder *)phandle; if (spdif_dec_handle) { if (spdif_dec_handle->buf) { aml_audio_free(spdif_dec_handle->buf); spdif_dec_handle->buf = NULL; } aml_audio_free(spdif_dec_handle); spdif_dec_handle = NULL; } ALOGE("%s exit", __func__); return 0; } int aml_spdif_decoder_reset(void *phandle) { struct aml_spdif_decoder *spdif_dec_handle = (struct aml_spdif_decoder *)phandle; if (spdif_dec_handle) { spdif_dec_handle->status = SPDIF_DEC_SYNCING; spdif_dec_handle->buf_remain = 0; spdif_dec_handle->payload_size = 0; } ALOGE("%s exit", __func__); return 0; } /* *Find the position of 61937 sync word in the buffer, need PA/PB/PC/PD, 4*sizeof(short) */ static int seek_61937_sync_word(char *buffer, int size) { int i = -1; if (size < 8) { return i; } for (i = 0; i < (size - 3); i++) { if (buffer[i + 0] == 0x72 && buffer[i + 1] == 0xf8 && buffer[i + 2] == 0x1f && buffer[i + 3] == 0x4e) { return i; } if (buffer[i + 0] == 0xf8 && buffer[i + 1] == 0x72 && buffer[i + 2] == 0x4e && buffer[i + 3] == 0x1f) { return i; } } return -1; } static int16_t swap_int16(int16_t value) { return ((value & 0x00FF) << 8) | ((value & 0xFF00) >> 8) ; } static int get_iec61937_info(void *phandle, void * buf, int32_t size, int32_t *package_size, int32_t *payload_size) { uint16_t pa = 0; uint16_t pb = 0; uint16_t pc = 0; uint16_t pd = 0; uint32_t big_endian = 0; uint8_t data_type = 0; uint32_t tmp = 0; struct aml_spdif_decoder *spdif_dec_handle = (struct aml_spdif_decoder *)phandle; if (size < IEC61937_HEADER_SIZE) { return -1; } pa = *(uint16_t*)((uint8_t*)buf + IEC61937_PA_OFFSET); pb = *(uint16_t*)((uint8_t*)buf + IEC61937_PB_OFFSET); pc = *(uint16_t*)((uint8_t*)buf + IEC61937_PC_OFFSET); pd = *(uint16_t*)((uint8_t*)buf + IEC61937_PD_OFFSET); if (pa == IEC61937_HEADER_PA_LITTLE && pb == IEC61937_HEADER_PB_LITTLE) { big_endian = 0; } else if (pa == IEC61937_HEADER_PA_BIG && pb == IEC61937_HEADER_PB_BIG) { big_endian = 1; pc = swap_int16(pc); pd = swap_int16(pd); } else { ALOGE("It is not IEC Sync PA=0x%x PB=0x%x", pa, pb); return -1; } /*Data type defined in PC bits 0-6 in IEC 61937-1*/ data_type = pc & 0x3f; switch (data_type) { case IEC61937_AC3: { *package_size = AC3_PERIOD_SIZE; /*length code is in bits*/ *payload_size = pd >> 3; spdif_dec_handle->format = AUDIO_FORMAT_AC3; break; } case IEC61937_EAC3: { *package_size = EAC3_PERIOD_SIZE; /*length code is in bytes*/ *payload_size = pd; spdif_dec_handle->format = AUDIO_FORMAT_E_AC3; break; } case IEC61937_DTS1: { *package_size = DTS1_PERIOD_SIZE; /*length code is in bits*/ *payload_size = pd >> 3; spdif_dec_handle->format = AUDIO_FORMAT_DTS; break; } case IEC61937_DTS2: { *package_size = DTS2_PERIOD_SIZE; /*length code is in bits*/ *payload_size = pd >> 3; spdif_dec_handle->format = AUDIO_FORMAT_DTS; break; } case IEC61937_DTS3: { *package_size = DTS3_PERIOD_SIZE; /*length code is in bits*/ *payload_size = pd >> 3; spdif_dec_handle->format = AUDIO_FORMAT_DTS; break; } case IEC61937_DTSHD: { /*Value of 8-12bit is framesize*/ tmp = (pc & 0x7ff) >> 8; /*refer to IEC 61937-5 pdf, table 6*/ *package_size = DTSHD_PERIOD_SIZE << tmp ; spdif_dec_handle->format = AUDIO_FORMAT_DTS_HD; break; } case IEC61937_MAT: { *package_size = MAT_PERIOD_SIZE; /*length code is in bytes*/ *payload_size = pd; spdif_dec_handle->format = AUDIO_FORMAT_MAT; break; } default: { *package_size = 0; spdif_dec_handle->format = AUDIO_FORMAT_INVALID; ALOGE("unsupport iec61937 PC =0x%x PD=0x%x", pc, pd); return -1; } } return 0; } /*refer kodi how to add 12 bytes header for DTS HD 01 00 00 00 00 00 00 00 fe fe ** **, last 2 bytes for data size */ static int get_dtshd_info(void * buf, int32_t size, int32_t *payload_size, int32_t *dts_type4_subtype) { char *read_pointer = (char*)buf; if (size < (IEC61937_HEADER_SIZE + IEC61937_DTSHD_HEAD_SIZE)) { *payload_size = 0; return -1; } *dts_type4_subtype = read_pointer[5] & 0x18; /* Pc[11]~Pc[12], according to IEC61937-5. */ read_pointer += IEC61937_HEADER_SIZE; /* Structure of the IEC Data Burst for DTS Type 4 ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————— | Filed name |Pa |Pb |Pc |Pd |Chunk Index 1|Chunk Index 2|Reserved|Status Register|Chunk ID|Chunk Size| audio data | ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————— |Size in bytes| 2 | 2 | 2 | 2 | 1 | 1 | 5 | 1 | 2 | 2 | Chunk Size| ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————— Chunk Index and Chunk ID Values ——————————————————————————————————————————————————————— |Chunk Index Value|Chunk ID| DESCRIPTION | ——————————————————————————————————————————————————————— | 0 | 0x0000 | No chunk index entry | ——————————————————————————————————————————————————————— | 1 | 0xFEFE |DTS Presentation audio chunk| ——————————————————————————————————————————————————————— | 5 | 0xFAFA | DTS Command chunk | ——————————————————————————————————————————————————————— |all other values | | Reserved | ——————————————————————————————————————————————————————— PS:Chunk Size is the audio data size */ if (DTS_TYPE_IV_SUB_TYPE_DTS_HD == *dts_type4_subtype) { if (read_pointer[0] == 0x00 && read_pointer[1] == 0x01 && read_pointer[8] == 0xfe && read_pointer[9] == 0xfe) { *payload_size = (read_pointer[10] | read_pointer[11] << 8); } else if ((read_pointer[0] == 0x01 && read_pointer[1] == 0x00 && read_pointer[8] == 0xfe && read_pointer[9] == 0xfe)) { *payload_size = (read_pointer[11] | read_pointer[10] << 8); } else { ALOGE("DTS HD error data\n"); *payload_size = 0; return -1; } } else if (DTS_TYPE_IV_SUB_TYPE_DTS_UHD == *dts_type4_subtype) { if ((read_pointer[0] == 0x01 || read_pointer[0] == 0x02) && read_pointer[8] == 0xfe && read_pointer[9] == 0xfe) { *payload_size = (read_pointer[10] | read_pointer[11] << 8); } else if (((read_pointer[1] == 0x01 || read_pointer[1] == 0x02) && read_pointer[9] == 0xfe && read_pointer[8] == 0xfe)) { *payload_size = (read_pointer[11] | read_pointer[10] << 8); } else { // For DTS P2 stream, valid frames and empty frames appear alternately, we will drop the empty frame. //empty frame like this:72 f8 1f 4e 11 0a 08 00 25 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 //For empty frame, we should not print error msg if ((read_pointer[0] != 0x00 && read_pointer[0] != 0x00) || read_pointer[8] != 0x00 || read_pointer[9] != 0x00) { ALOGE("DTS UHD error data\n"); } *payload_size = 0; return -1; } } return 0; } static int aml_spdif_decoder_do_quick_sync (void *phandle , const void *inbuf , int32_t n_bytes_inbuf , int32_t *sync_word_offset , int32_t *buf_left , int32_t *buf_offset) { struct aml_spdif_decoder *spdif_dec_handle = (struct aml_spdif_decoder *)phandle; uint8_t *spdifdec_buf = NULL; bool is_quick_sync_suitable = false; uint8_t *buffer = (uint8_t *)inbuf; if (!spdif_dec_handle || !inbuf || !sync_word_offset || !buf_left || !buf_offset) { ALOGE("%s line %d spdif_dec_handle %p inbuf %p sync_word_offset %p buf_left %p buf_offset %p\n", __func__, __LINE__, spdif_dec_handle, inbuf, sync_word_offset, buf_left, buf_offset); return -1; } spdifdec_buf = spdif_dec_handle->buf; *buf_left = n_bytes_inbuf; /*if we have enough data and we are doing syncing, we can sync the header quickly in original buf*/ is_quick_sync_suitable = ((spdif_dec_handle->buf_remain == 0) && (spdif_dec_handle->status == SPDIF_DEC_SYNCING) && (n_bytes_inbuf >= IEC61937_HEADER_SIZE)); if (is_quick_sync_suitable) { *sync_word_offset = seek_61937_sync_word((char*)buffer, n_bytes_inbuf); /*to avoid the case the sync word accross the input buf, we need copy the last 3 bytes*/ if (*sync_word_offset < 0) { memcpy( spdifdec_buf, buffer + n_bytes_inbuf - IEC61937_HEADER_COPY_SIZE, IEC61937_HEADER_COPY_SIZE); spdif_dec_handle->buf_remain += IEC61937_HEADER_COPY_SIZE; return -1; } /*we have find the sync word, just copy the papb part*/ memcpy(spdifdec_buf , buffer + *sync_word_offset, IEC61937_HEADER_SIZE / 2); spdif_dec_handle->buf_remain += IEC61937_HEADER_SIZE / 2; *buf_offset += *sync_word_offset + IEC61937_HEADER_SIZE / 2; *buf_left = n_bytes_inbuf - *buf_offset; *sync_word_offset = 0; } return 0; } static int aml_spdif_decoder_find_syncword(void *phandle , const void *inbuf , int32_t n_bytes_inbuf , int32_t *sync_word_offset , int32_t *buf_left , int32_t *buf_offset , uint8_t **spdifdec_buf) { struct aml_spdif_decoder *spdif_dec_handle = (struct aml_spdif_decoder *)phandle; int32_t loop_cnt = 0; int32_t data_valid = 0; int32_t need_size = 0; uint8_t *buffer = (uint8_t *)inbuf; if (!spdif_dec_handle || !inbuf || !sync_word_offset || !buf_left || !buf_offset) { ALOGE("%s line %d spdif_dec_handle %p inbuf %p sync_word_offset %p buf_left %p buf_offset %p\n", __func__, __LINE__, spdif_dec_handle, inbuf, sync_word_offset, buf_left, buf_offset); return -1; } /*we need at least period bytes*/ if (spdif_dec_handle->buf_remain < IEC61937_HEADER_SYNC_PERIOD) { need_size = IEC61937_HEADER_SYNC_PERIOD - spdif_dec_handle->buf_remain; /*input data is not enough, just copy to internal buf*/ if (*buf_left < need_size) { memcpy(*spdifdec_buf + spdif_dec_handle->buf_remain, buffer + *buf_offset, *buf_left); spdif_dec_handle->buf_remain += *buf_left; goto ERROR; } /*make sure the remain buf has period bytes*/ memcpy(*spdifdec_buf + spdif_dec_handle->buf_remain, buffer + *buf_offset, need_size); spdif_dec_handle->buf_remain += need_size; *buf_offset += need_size; *buf_left = n_bytes_inbuf - *buf_offset; } if (spdif_dec_handle->status == SPDIF_DEC_SYNCING) { *sync_word_offset = -1; while (*sync_word_offset < 0) { /*sync the header, we have at least period bytes*/ if (spdif_dec_handle->buf_remain < IEC61937_HEADER_SYNC_PERIOD) { ALOGE("we should not get there"); goto DO_SYNC; } *sync_word_offset = seek_61937_sync_word((char*)*spdifdec_buf, spdif_dec_handle->buf_remain); /*if we don't find the header in period bytes, move the last 3 bytes to header*/ if (*sync_word_offset < 0) { memmove(*spdifdec_buf, *spdifdec_buf + spdif_dec_handle->buf_remain - IEC61937_HEADER_COPY_SIZE, IEC61937_HEADER_COPY_SIZE); spdif_dec_handle->buf_remain = IEC61937_HEADER_COPY_SIZE; need_size = IEC61937_HEADER_SYNC_PERIOD - spdif_dec_handle->buf_remain; /*input data is not enough, just copy to internal buf*/ if (*buf_left < need_size) { memcpy(*spdifdec_buf + spdif_dec_handle->buf_remain, buffer + *buf_offset, *buf_left); spdif_dec_handle->buf_remain += *buf_left; /*don't find the header, and there is no enough data*/ goto ERROR; } /*make the spdif dec buf has period bytes*/ memcpy(*spdifdec_buf + spdif_dec_handle->buf_remain, buffer + *buf_offset, need_size); spdif_dec_handle->buf_remain += need_size; *buf_offset += need_size; *buf_left = n_bytes_inbuf - *buf_offset; } loop_cnt++; } /*got here means we find the sync word*/ spdif_dec_handle->status = SPDIF_DEC_SYNCED; data_valid = spdif_dec_handle->buf_remain - *sync_word_offset; /*move the header to the beginning of buf*/ if (*sync_word_offset != 0) { memmove(*spdifdec_buf, *spdifdec_buf + *sync_word_offset, data_valid); } spdif_dec_handle->buf_remain = data_valid; need_size = IEC61937_HEADER_SYNC_PERIOD - data_valid; /*get some bytes to make sure it is at least period bytes*/ if (need_size > 0) { /*check if input has enough data*/ if (*buf_left < need_size) { memcpy(*spdifdec_buf + spdif_dec_handle->buf_remain, buffer + *buf_offset, *buf_left); spdif_dec_handle->buf_remain += *buf_left; goto ERROR; } /*make sure the remain buf has period bytes*/ memcpy(*spdifdec_buf + spdif_dec_handle->buf_remain, buffer + *buf_offset , need_size); spdif_dec_handle->buf_remain += need_size; *buf_offset += need_size; *buf_left = n_bytes_inbuf - *buf_offset; } } /*double check here*/ /*coverity[INTEGER_OVERFLOW]: buf_remain will not overflow, so it's ok.*/ *sync_word_offset = seek_61937_sync_word((char*)*spdifdec_buf, spdif_dec_handle->buf_remain); if (*sync_word_offset != 0) { ALOGE("we can't get here remain=%d,resync iec61937 header", spdif_dec_handle->buf_remain); goto DO_SYNC; } return 0; DO_SYNC: spdif_dec_handle->buf_remain = 0; spdif_dec_handle->status = SPDIF_DEC_SYNCING; ERROR: return -1; } static int aml_spdif_decoder_addbytes (void *phandle , const void *inbuf , int32_t n_bytes_inbuf , uint8_t *spdifdec_buf , int32_t *buf_left , int32_t *buf_offset , int32_t *used_size , const void **output_buf , int32_t *out_size) { struct aml_spdif_decoder *spdif_dec_handle = (struct aml_spdif_decoder *)phandle; int32_t need_size = 0; uint8_t *buffer = (uint8_t *)inbuf; int32_t package_size = 0; int32_t payload_size = 0; int32_t new_buf_size = 0; int32_t dtshd_header_len = 0; int32_t dts_type4_subtype = 0; int32_t dts_frame_size_is_odd = 0; int ret = 0; if (!spdif_dec_handle || !inbuf || !spdifdec_buf || !buf_left || !buf_offset || !used_size || !out_size) { ALOGE("%s line %d spdif_dec_handle %p inbuf %p spdifdec_buf %p buf_left %p buf_offset %p used_size %p out_size %p\n", __func__, __LINE__, spdif_dec_handle, inbuf, spdifdec_buf, buf_left, buf_offset, used_size, out_size); return -1; } /* we got here means we find the IEC header and * it is at the beginning of spedif dec buf and * it has at least period bytes, we can get the pc/pd */ ret = get_iec61937_info(phandle, spdifdec_buf, IEC61937_HEADER_SIZE, &package_size, &payload_size); if (ret != 0) { goto DO_SYNC; } /*if it is DTS HD, we need more 12 bytes to calculate the payload size*/ if (spdif_dec_handle->format == AUDIO_FORMAT_DTS_HD) { dtshd_header_len = IEC61937_DTSHD_HEAD_SIZE; need_size = (IEC61937_HEADER_SIZE + IEC61937_DTSHD_HEAD_SIZE) - spdif_dec_handle->buf_remain; if (need_size > 0) { /*if there is no enough data, try to get more*/ if (*buf_left < need_size) { memcpy(spdifdec_buf + spdif_dec_handle->buf_remain, buffer + *buf_offset, *buf_left); spdif_dec_handle->buf_remain += *buf_left; spdif_dec_handle->status = SPDIF_DEC_LACK_DATA; goto ERROR; } memcpy(spdifdec_buf + spdif_dec_handle->buf_remain, buffer + *buf_offset, need_size); spdif_dec_handle->buf_remain += need_size; *buf_offset += need_size; *buf_left = n_bytes_inbuf - *buf_offset; } ret = get_dtshd_info(spdifdec_buf, (IEC61937_HEADER_SIZE + IEC61937_DTSHD_HEAD_SIZE), &payload_size, &dts_type4_subtype); if (ret != 0) { goto DO_SYNC; } } /*check whether the input data has a complete payload*/ if (payload_size == 0) { ALOGE("%s wrong format=%d package size =%d payload =%d", __func__, spdif_dec_handle->format, package_size, payload_size); goto DO_SYNC; } //ALOGI("payload_size:%d odd:%d format:%x", payload_size, payload_size%2, spdif_dec_handle->format); if ((payload_size%2) && (spdif_dec_handle->format == AUDIO_FORMAT_DTS_HD || AUDIO_FORMAT_DTS == spdif_dec_handle->format)) { dts_frame_size_is_odd = 1; payload_size += 1;//for odd frame, the last audio byte comes from high address //ALOGI("1.payload_size:%d dts_frame_size_is_odd:%d", payload_size, dts_frame_size_is_odd); } /*we have a complete payload*/ if ((spdif_dec_handle->buf_remain - IEC61937_HEADER_SIZE - dtshd_header_len + *buf_left) >= payload_size) { need_size = payload_size - (spdif_dec_handle->buf_remain - IEC61937_HEADER_SIZE - dtshd_header_len); if (need_size >= 0) { new_buf_size = spdif_dec_handle->buf_remain + need_size; if (new_buf_size > spdif_dec_handle->buf_size) { spdif_dec_handle->buf = aml_audio_realloc(spdif_dec_handle->buf, new_buf_size); if (spdif_dec_handle->buf == NULL) { ALOGE("%s realloc buf failed =%d", __func__, new_buf_size); goto DO_SYNC; } ALOGI("%s realloc buf =%d", __func__, new_buf_size); spdifdec_buf = spdif_dec_handle->buf; spdif_dec_handle->buf_size = new_buf_size; } memcpy(spdifdec_buf + spdif_dec_handle->buf_remain, buffer + *buf_offset, need_size); *buf_offset += need_size; *buf_left = n_bytes_inbuf - *buf_offset; /*we may have some stuffing data, we can skip it*/ if (*buf_left > 0) { int32_t stuff_size = package_size - IEC61937_HEADER_SIZE - payload_size - dtshd_header_len; if (stuff_size < 0) { ALOGE("%s we can't get here suff size =%d", __func__, stuff_size); goto DO_SYNC; } if (*buf_left >= stuff_size) { *buf_offset += stuff_size; } else { *buf_offset += *buf_left; } } *output_buf = (void*)(spdifdec_buf + IEC61937_HEADER_SIZE + dtshd_header_len); if (dts_frame_size_is_odd) { payload_size -= 1; unsigned char *p = (unsigned char*)*output_buf; /*ALOGI("2.payload_size:%d dts_frame_size_is_odd:%d (%x,%x,%x,%x)", payload_size, dts_frame_size_is_odd, p[payload_size-3], p[payload_size-2], p[payload_size-1], p[payload_size]);*/ p[payload_size - 1] = p[payload_size];//for odd frame, the last audio byte comes from high address } *out_size = payload_size; *used_size = *buf_offset; ALOGV("OK type=0x%x payload size=%d used size=%d\n", spdif_dec_handle->format, payload_size, *buf_offset); /*one frame has complete, need find next one*/ spdif_dec_handle->buf_remain = 0; spdif_dec_handle->status = SPDIF_DEC_SYNCING; }else { /*internal buf has more data than payload, we only need part of it*/ *output_buf = (void*)(spdifdec_buf + IEC61937_HEADER_SIZE + dtshd_header_len); if (dts_frame_size_is_odd) { payload_size -= 1; unsigned char *p = (unsigned char*)*output_buf; /*ALOGI("3.payload_size:%d dts_frame_size_is_odd:%d (%x,%x,%x,%x)", payload_size, dts_frame_size_is_odd, p[payload_size-3], p[payload_size-2], p[payload_size-1], p[payload_size]);*/ p[payload_size - 1] = p[payload_size];//for odd frame, the last audio byte comes from high address } *out_size = payload_size; /*move need_size bytes back to original buf*/ *used_size = *buf_offset + need_size; ALOGV("wrap data type=0x%x payload size=%d used size=%d back size =%d\n", spdif_dec_handle->format, payload_size, *buf_offset, need_size); if (*used_size <= 0) { ALOGE("%s wrong used size =%d", __func__, *used_size); goto DO_SYNC; } /*one frame has complete, need find next one*/ spdif_dec_handle->buf_remain = 0; spdif_dec_handle->status = SPDIF_DEC_SYNCING; } } else { /*check whether the input buf size is big enough*/ new_buf_size = spdif_dec_handle->buf_remain + *buf_left; if (new_buf_size > spdif_dec_handle->buf_size) { spdif_dec_handle->buf = aml_audio_realloc(spdif_dec_handle->buf, new_buf_size); if (spdif_dec_handle->buf == NULL) { ALOGE("%s realloc buf failed =%d", __func__, new_buf_size); goto DO_SYNC; } ALOGI("%s realloc buf =%d", __func__, new_buf_size); spdifdec_buf = spdif_dec_handle->buf; spdif_dec_handle->buf_size = new_buf_size; } memcpy(spdifdec_buf + spdif_dec_handle->buf_remain, buffer + *buf_offset, *buf_left); spdif_dec_handle->buf_remain += *buf_left; spdif_dec_handle->status = SPDIF_DEC_LACK_DATA; goto ERROR; } if (spdif_dec_handle->payload_size != payload_size) { spdif_dec_handle->payload_size = payload_size; ALOGV("IEC61937 format =0x%x package size=%d payload_size=%d", spdif_dec_handle->format, package_size, payload_size); } return 0; DO_SYNC: spdif_dec_handle->buf_remain = 0; spdif_dec_handle->status = SPDIF_DEC_SYNCING; ERROR: return -1; } int aml_spdif_decoder_process(void *phandle, const void *inbuf, int32_t n_bytes_inbuf, int32_t *used_size, const void **output_buf, int32_t *out_size) { struct aml_spdif_decoder *spdif_dec_handle = (struct aml_spdif_decoder *)phandle; uint8_t *spdifdec_buf = NULL; int32_t sync_word_offset = -1; int32_t buf_left = 0; int32_t buf_offset = 0; int32_t ret = 0; if (!spdif_dec_handle || !inbuf) { goto ERROR; } spdifdec_buf = spdif_dec_handle->buf; buf_left = n_bytes_inbuf; ALOGV("%s input buf size=%d status=%d", __func__, n_bytes_inbuf, spdif_dec_handle->status); if (aml_spdif_decoder_do_quick_sync(phandle, inbuf, n_bytes_inbuf, &sync_word_offset, &buf_left, &buf_offset)) { ALOGV("%s aml_spdif_decoder_do_quick_sync error return status=%d", __func__, spdif_dec_handle->status); goto ERROR; } ret = aml_spdif_decoder_find_syncword(phandle, inbuf, n_bytes_inbuf, &sync_word_offset, &buf_left, &buf_offset, &spdifdec_buf); if (ret) { ALOGV("%s aml_spdif_decoder_find_syncword return %d status=%d", __func__, ret, spdif_dec_handle->status); goto ERROR; } ret = aml_spdif_decoder_addbytes(phandle, inbuf, n_bytes_inbuf, spdifdec_buf, &buf_left, &buf_offset, used_size, output_buf, out_size); ALOGV("%s aml_spdif_decoder_addbytes return %d status=%d", __func__, ret, spdif_dec_handle->status); if (ret == 0) { return 0; } ERROR: *output_buf = NULL; *out_size = 0; *used_size = n_bytes_inbuf; return 0; } int aml_spdif_decoder_getformat(void *phandle) { struct aml_spdif_decoder *spdif_dec_handle = (struct aml_spdif_decoder *)phandle; if (spdif_dec_handle == NULL) { return -1; } return (int)spdif_dec_handle->format; }