diff --git a/.github/workflows/eeasy-sv82x.yml b/.github/workflows/eeasy-sv82x.yml new file mode 100644 index 0000000..0a7887b --- /dev/null +++ b/.github/workflows/eeasy-sv82x.yml @@ -0,0 +1,69 @@ +name: eeasy-sv82x + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + workflow_dispatch: + branches: [ main ] + +env: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Release + BOARD: SV82x + +jobs: + ecr-prepare: + runs-on: ubuntu-latest + + steps: + - name: Configure AWS credentials + id: configure-aws-credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Login to Amazon ECR + id: login-ecr + uses: codingspirit/amazon-ecr-login@master + + - name: Set ECR credentials + id: set-ecr-credentials + run: | + gh auth login --with-token <<< ${{ secrets.PA_TOKEN }} + gh secret set --env ECR ECR_REGISTRY --body ${{ steps.login-ecr.outputs.registry }} --repo ${{ github.repository }} + gh secret set --env ECR ECR_USERNAME --body ${{ steps.login-ecr.outputs.docker_username }} --repo ${{ github.repository }} + gh secret set --env ECR ECR_PASSWORD --body ${{ steps.login-ecr.outputs.docker_password }} --repo ${{ github.repository }} + + eeasy: + environment: ECR + needs: ecr-prepare + runs-on: ubuntu-latest + strategy: + matrix: + container: [ "482862934379.dkr.ecr.us-east-1.amazonaws.com/eeasy:7.5.0" ] + container: + image: ${{ matrix.container }} + credentials: + username: ${{ secrets.ECR_USERNAME }} + password: ${{ secrets.ECR_PASSWORD }} + + steps: + - name: Git checkout + uses: actions/checkout@v2 + + - name: Prepare board SDK + run: | + cp -r /SV82x/* ${GITHUB_WORKSPACE}/3rdparty/SV82x/ + + - name: Configure CMake + run: cmake -B ${{ github.workspace }}/build -DBOARD=${{ env.BOARD }} -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} -DBUILD_WEBRTC_SAMPLES=ON -DBUILD_KVS_SAMPLES=ON -DBUILD_SAVE_FRAME_SAMPLES=ON + + - name: Build + run: cmake --build ${{ github.workspace }}/build --config ${{ env.BUILD_TYPE }} --parallel 4 + + - name: Test + run: ctest -C ${{ env.BUILD_TYPE }} diff --git a/.github/workflows/file.yml b/.github/workflows/file.yml index 14bbd00..69e7daa 100644 --- a/.github/workflows/file.yml +++ b/.github/workflows/file.yml @@ -1,12 +1,6 @@ name: file -on: - push: - branches: [ develop, main ] - pull_request: - branches: [ develop, main ] - workflow_dispatch: - branches: [ develop, main ] +on: [push, pull_request, workflow_dispatch] env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) diff --git a/.github/workflows/v4l2.yml b/.github/workflows/v4l2.yml index db3dd05..0dc4054 100644 --- a/.github/workflows/v4l2.yml +++ b/.github/workflows/v4l2.yml @@ -1,12 +1,6 @@ name: v4l2 -on: - push: - branches: [ develop, main ] - pull_request: - branches: [ develop, main ] - workflow_dispatch: - branches: [ develop, main ] +on: [push, pull_request, workflow_dispatch] env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) diff --git a/3rdparty/README.md b/3rdparty/README.md index 7a35bb5..532f9bb 100644 --- a/3rdparty/README.md +++ b/3rdparty/README.md @@ -9,6 +9,7 @@ This documents provides guidelines to install board SDK required by this library - [FH8626V100](#fh8626v100) - [AK3918](#ak3918) - [C302](#c302) + - [SV82x](#sv82x) ## FILE @@ -112,3 +113,15 @@ C302/ ``` > Other related dependent libraries and header files need to obtain the cross-compiled toolchain of C302. + +## SV82x + +User need to put SV82x board SDK under [3rdparty/SV82x/](SV82x/): + +``` +SV82x/ +├── common +├── include +├── lib +└── sample +``` diff --git a/3rdparty/SV82x/.gitkeep b/3rdparty/SV82x/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/CMake/SV82x.cmake b/CMake/SV82x.cmake new file mode 100755 index 0000000..91e791a --- /dev/null +++ b/CMake/SV82x.cmake @@ -0,0 +1,177 @@ +if(BOARD STREQUAL "SV82x") + set(BOARD_SDK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/${BOARD}) + set(BOARD_SRCS + ${BOARD_SDK_DIR}/common/sample_comm_audio.c + ${BOARD_SDK_DIR}/common/sample_comm_doss.c + ${BOARD_SDK_DIR}/common/sample_comm_ippu.c + ${BOARD_SDK_DIR}/common/sample_comm_isp.c + ${BOARD_SDK_DIR}/common/sample_comm_sys.c + ${BOARD_SDK_DIR}/common/sample_comm_vdec.c + ${BOARD_SDK_DIR}/common/sample_comm_venc.c + ${BOARD_SDK_DIR}/common/sample_comm_video.c + ${BOARD_SDK_DIR}/common/sample_comm_viss.c + ) + set(BOARD_INCS_DIR + ${BOARD_SDK_DIR}/include/ + ${BOARD_SDK_DIR}/common/ + ) + + if(USE_MUCLIBC) + set(BOARD_LIBS_DIR + ${BOARD_SDK_DIR}/lib/uclibc + ) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -muclibc") + set(BOARD_DESTINATION_PLATFORM arm-unknown-linux-uclibc) + else() + set(BOARD_LIBS_DIR + ${BOARD_SDK_DIR}/lib/glibc + ) + set(BOARD_DESTINATION_PLATFORM arm-unknown-linux-gnu) + endif() + + set(BOARD_LIBS_SHARED + i2cops + cam_gc4653_mipi + ext_drv_ms41929 + extops + audioin + cam_sc2335_mipi + ext_drv_a6208 + ei_AGC + customer_af + audiocommon + cam_imx327_mipi + cam_ar0230_dvp + ax + cam_ov9732_mipi + ei_hpf + panel_spcs92048_prgb + cam_ov5640_mipi + ae + awb + audioout + cam_gc4663_mipi + threadpool + ei_eq + panel_wks43178_cpu + cam_tp9950_mipi + mbase + ei_drc + cam_sc4210_mipi + cam_cr286_dvp + panel_ili9488_mipi + cam_sc200ai_mipi + ctest + cam_tp2850_mipi + viss + af + panel_eos_default + cam_imx415_mipi + cam_tp2815_mipi + isp + mfake + cam_sc4238_mipi + doss + audioenc + vgss + audiodec + cam_imx307_mipi + cam_os05a20_mipi + cam_imx335_mipi + cam_gc2145_mipi + cam_tp9930_dvp + cam_ov2710_dvp + cam_ov5640_dvp + mlink + cam_tp9950_dvp + ext_drv_ap1511b + region + vc + dnvqe + vbuf + cam_ov2735_mipi + panel_wks70002_lvds + sam + ei_RES + cam_ov8858_mipi + ei_common + panel_otm1289a_mipi + upvqe + cam_clb + panel_lt8912b_mipi + m pthread dl + ) + set(BOARD_LIBS_STATIC + cam_gc4653_mipi.a + ext_drv_ms41929.a + extops.a + audioin.a + cam_sc2335_mipi.a + ext_drv_a6208.a + ei_AGC + customer_af.a + audiocommon.a + cam_imx327_mipi.a + cam_ar0230_dvp.a + ax.a + cam_ov9732_mipi.a + ei_hpf + panel_spcs92048_prgb.a + cam_ov5640_mipi.a + ae.a + awb.a + audioout.a + cam_gc4663_mipi.a + threadpool.a + ei_eq + panel_wks43178_cpu.a + cam_tp9950_mipi.a + mbase.a + ei_drc + cam_sc4210_mipi.a + cam_cr286_dvp.a + panel_ili9488_mipi.a + cam_sc200ai_mipi.a + ctest.a + cam_tp2850_mipi.a + viss.a + af.a + panel_eos_default.a + cam_imx415_mipi.a + cam_tp2815_mipi.a + isp.a + mfake.a + cam_sc4238_mipi.a + doss.a + audioenc.a + vgss.a + audiodec.a + cam_imx307_mipi.a + cam_os05a20_mipi.a + cam_imx335_mipi.a + cam_gc2145_mipi.a + cam_tp9930_dvp.a + cam_ov2710_dvp.a + cam_ov5640_dvp.a + mlink.a + cam_tp9950_dvp.a + ext_drv_ap1511b.a + region.a + vc.a + dnvqe.a + vbuf.a + cam_ov2735_mipi.a + log.a + panel_wks70002_lvds.a + sam.a + ei_RES + cam_ov8858_mipi.a + ei_common + i2cops.a + panel_otm1289a_mipi.a + upvqe.a + cam_clb.a + panel_lt8912b_mipi.a + libm.a pthread dl + ) +endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index 0695ece..af00d8b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,8 @@ elseif(BOARD STREQUAL "AK3918") message(STATUS "Selected board AK3918") elseif(BOARD STREQUAL "C302") message(STATUS "Selected board C302") +elseif(BOARD STREQUAL "SV82x") + message(STATUS "Selected board SV82x") else() message(FATAL_ERROR "${BOARD} is not implemented yet.") endif() diff --git a/README.md b/README.md index 1f54aa6..7b2ba69 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ [![fullhan-fh8626v100](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/fullhan-fh8626v100.yml/badge.svg)](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/fullhan-fh8626v100.yml) [![anyka-ak3918](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/anyka-ak3918.yml/badge.svg)](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/anyka-ak3918.yml) [![amlogic-c302](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/amlogic-c302.yml/badge.svg)](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/amlogic-c302.yml) +[![eeasy-sv82x](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/eeasy-sv82x.yml/badge.svg)](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/eeasy-sv82x.yml) - [Amazon Kinesis Video Streams Media Interface](#amazon-kinesis-video-streams-media-interface) - [Introduction](#introduction) @@ -25,15 +26,16 @@ ## Supported Boards -| Name | Description | CMake Parameter | Status | -| ------------------ | --------------------------------------------------------------------- | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| FILE | Dummy boards that can capture from [sample frames](resources/frames/) | `-DBOARD=FILE` | [![file](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/file.yml/badge.svg)](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/file.yml) | -| x86/x64 | Capture from V4L2 device or capture from dummy frames | `-DBOARD=V4L2`
or `-DBOARD=FILE` | [![v4l2](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/v4l2.yml/badge.svg)](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/v4l2.yml)[![file](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/file.yml/badge.svg)](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/file.yml) | -| Raspberry Pi | Capture from V4L2 device or capture from dummy frames | `-DBOARD=V4L2`
or `-DBOARD=FILE` | [![v4l2](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/v4l2.yml/badge.svg)](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/v4l2.yml)[![file](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/file.yml/badge.svg)](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/file.yml) | -| Ingenic T31 | IPC SoC designed by Ingenic | `-DBOARD=T31` | [![ingenic-t31](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/ingenic-t31.yml/badge.svg)](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/ingenic-t31.yml) | -| Fullhan FH8626V100 | IPC SoC designed by Fullhan | `-DBOARD=FH8626V100` | [![fullhan-fh8626v100](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/fullhan-fh8626v100.yml/badge.svg)](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/fullhan-fh8626v100.yml) | -| Anyka AK3918 | IPC SoC designed by Anyka | `-DBOARD=AK3918` | [![anyka-ak3918](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/anyka-ak3918.yml/badge.svg)](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/anyka-ak3918.yml) | -| Amlogic C302 | IPC SoC designed by Amlogic | `-DBOARD=C302` | [![amlogic-c302](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/amlogic-c302.yml/badge.svg)](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/amlogic-c302.yml) | +| Name | Description | CMake Parameter | Status | +| ------------------ | --------------------------------------------------------------------------- | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| FILE | Dummy boards that can capture from [sample frames](resources/frames/) | `-DBOARD=FILE` | [![file](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/file.yml/badge.svg)](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/file.yml) | +| x86/x64 | Capture from V4L2 device or capture from [sample frames](resources/frames/) | `-DBOARD=V4L2`
or `-DBOARD=FILE` | [![v4l2](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/v4l2.yml/badge.svg)](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/v4l2.yml)[![file](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/file.yml/badge.svg)](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/file.yml) | +| Raspberry Pi | Capture from V4L2 device or capture from [sample frames](resources/frames/) | `-DBOARD=V4L2`
or `-DBOARD=FILE` | [![v4l2](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/v4l2.yml/badge.svg)](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/v4l2.yml)[![file](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/file.yml/badge.svg)](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/file.yml) | +| Ingenic T31 | IPC SoC designed by Ingenic | `-DBOARD=T31` | [![ingenic-t31](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/ingenic-t31.yml/badge.svg)](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/ingenic-t31.yml) | +| Fullhan FH8626V100 | IPC SoC designed by Fullhan | `-DBOARD=FH8626V100` | [![fullhan-fh8626v100](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/fullhan-fh8626v100.yml/badge.svg)](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/fullhan-fh8626v100.yml) | +| Anyka AK3918 | IPC SoC designed by Anyka | `-DBOARD=AK3918` | [![anyka-ak3918](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/anyka-ak3918.yml/badge.svg)](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/anyka-ak3918.yml) | +| Amlogic C302 | IPC SoC designed by Amlogic | `-DBOARD=C302` | [![amlogic-c302](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/amlogic-c302.yml/badge.svg)](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/amlogic-c302.yml) | +| Eeasy SV82x | IPC SoC designed by Eeasy | `-DBOARD=SV82x` | [![eeasy-sv82x](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/eeasy-sv82x.yml/badge.svg)](https://github.com/aws-samples/amazon-kinesis-video-streams-media-interface/actions/workflows/eeasy-sv82x.yml) | ## Getting started with out-of-box KVS WebRTC sample diff --git a/source/SV82x/SV82xAudioCapturer.c b/source/SV82x/SV82xAudioCapturer.c new file mode 100644 index 0000000..37024c4 --- /dev/null +++ b/source/SV82x/SV82xAudioCapturer.c @@ -0,0 +1,406 @@ +/* + * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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. + */ + +#include +#include + +#include "com/amazonaws/kinesis/video/capturer/AudioCapturer.h" + +#include "SV82xCommon.h" + +#define SV82X_HANDLE_GET(x) SV82XAudioCapturer* sv82xHandle = (SV82XAudioCapturer*) ((x)) +#define AAC_HEADER_SIZE (7) + +typedef struct { + AudioCapturerStatus status; + AudioCapability capability; + AudioFormat format; + AudioChannel channel; + AudioBitDepth bitDepth; + AudioSampleRate sampleRate; +} SV82XAudioCapturer; + +sv82x_audio_stream_info_t g_audio_capture = { + .AiDev = 0, + .AencChn = 0, + .paramEncode.payload_type = PT_LPCM, + .paramEncode.samplerate = AUDIO_SAMPLE_RATE_48000, + .paramEncode.num_per_frm = 160, + .paramEncode.fps = 25, + .paramEncode.sound_mode = AUDIO_SOUND_MODE_MONO, + .paramEncode.bitwidth = AUDIO_BIT_WIDTH_8, + .paramEncode.volume = 50, + .paramEncode.u32ChnCnt = 1, + .bAioReSample = EI_FALSE, + .enInSampleRate = AUDIO_SAMPLE_RATE_BUTT, + .enOutSampleRate = AUDIO_SAMPLE_RATE_BUTT, + .enVqe = EI_TRUE, + .audio_vqe.open_mask = AI_VQE_MASK_AEC, + .enAudioCreate = EI_FALSE, + .enAencCreate = EI_FALSE, +}; + +static int setStatus(AudioCapturerHandle handle, const AudioCapturerStatus newStatus) +{ + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + + if (newStatus != sv82xHandle->status) { + sv82xHandle->status = newStatus; + LOG("AudioCapturer new status[%d]", newStatus); + } + + return 0; +} + +AudioCapturerHandle audioCapturerCreate(void) +{ + SV82XAudioCapturer* sv82xHandle = (SV82XAudioCapturer*) malloc(sizeof(SV82XAudioCapturer)); + + if (!sv82xHandle) { + LOG("%s OOM", __func__); + return NULL; + } + + memset(sv82xHandle, 0, sizeof(SV82XAudioCapturer)); + + // Now implementation supports raw PCM, G.711 ALAW and ULAW, MONO, 8k/16k, 16 bits + sv82xHandle->capability.formats = (1 << (AUD_FMT_G711A - 1)) | (1 << (AUD_FMT_G711U - 1)) | (1 << (AUD_FMT_PCM - 1)) | (1 << (AUD_FMT_AAC - 1)); + sv82xHandle->capability.channels = (1 << (AUD_CHN_MONO - 1)); + sv82xHandle->capability.sampleRates = (1 << (AUD_SAM_8K - 1)) | (1 << (AUD_SAM_16K - 1)); + sv82xHandle->capability.bitDepths = (1 << (AUD_BIT_16 - 1)); + + setStatus((AudioCapturerHandle) sv82xHandle, AUD_CAP_STATUS_STREAM_OFF); + return (AudioCapturerHandle) sv82xHandle; +} + +AudioCapturerStatus audioCapturerGetStatus(const AudioCapturerHandle handle) +{ + if (!handle) { + return AUD_CAP_STATUS_NOT_READY; + } + + SV82X_HANDLE_GET(handle); + return sv82xHandle->status; +} + +int audioCapturerGetCapability(const AudioCapturerHandle handle, AudioCapability* pCapability) +{ + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + + if (!pCapability) { + return -EINVAL; + } + + *pCapability = sv82xHandle->capability; + + return 0; +} + +// START AENC +int audioCapturerSetFormat(AudioCapturerHandle handle, const AudioFormat format, const AudioChannel channel, const AudioSampleRate sampleRate, + const AudioBitDepth bitDepth) +{ + EI_S32 s32Ret = EI_SUCCESS; + EI_S32 s32AencChnCnt; + AIO_ATTR_S stAioAttr; + PAYLOAD_TYPE_E payType; + + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + SV82X_HANDLE_STATUS_CHECK(sv82xHandle, AUD_CAP_STATUS_STREAM_OFF); + + switch (format) { + case AUD_FMT_AAC: + payType = PT_AAC; + break; + case AUD_FMT_PCM: + payType = PT_LPCM; + break; + case AUD_FMT_G711A: + payType = PT_G711A; + break; + case AUD_FMT_G711U: + payType = PT_G711U; + break; + case AUD_FMT_OPUS: + default: + LOG("Unsupported format %d", format); + return -EINVAL; + } + + if (channel == AUD_CHN_MONO) { + g_audio_capture.paramEncode.sound_mode == AUDIO_SOUND_MODE_MONO; + g_audio_capture.paramEncode.u32ChnCnt = 1; + } else { + g_audio_capture.paramEncode.sound_mode == AUDIO_SOUND_MODE_STEREO; + g_audio_capture.paramEncode.u32ChnCnt = 2; + } + + switch (sampleRate) { + case AUD_SAM_8K: + g_audio_capture.paramEncode.samplerate = AUDIO_SAMPLE_RATE_8000; + break; + case AUD_SAM_16K: + g_audio_capture.paramEncode.samplerate = AUDIO_SAMPLE_RATE_16000; + break; + case AUD_SAM_24K: + g_audio_capture.paramEncode.samplerate = AUDIO_SAMPLE_RATE_24000; + break; + case AUD_SAM_32K: + g_audio_capture.paramEncode.samplerate = AUDIO_SAMPLE_RATE_32000; + break; + case AUD_SAM_44_1K: + g_audio_capture.paramEncode.samplerate = AUDIO_SAMPLE_RATE_44100; + break; + case AUD_SAM_48K: + g_audio_capture.paramEncode.samplerate = AUDIO_SAMPLE_RATE_48000; + break; + default: + LOG("Unsupported sampleRate %d", sampleRate); + return -EINVAL; + } + + switch (bitDepth) { + case AUD_BIT_8: + g_audio_capture.paramEncode.bitwidth = AUDIO_BIT_WIDTH_8; + break; + case AUD_BIT_16: + g_audio_capture.paramEncode.bitwidth = AUDIO_BIT_WIDTH_16; + break; + case AUD_BIT_32: + g_audio_capture.paramEncode.bitwidth = AUDIO_BIT_WIDTH_24; + break; + default: + LOG("Unsupported bitDepth %d", bitDepth); + return -EINVAL; + } + + g_audio_capture.paramEncode.payload_type = payType; + stAioAttr.enSamplerate = g_audio_capture.paramEncode.samplerate; + stAioAttr.enBitwidth = g_audio_capture.paramEncode.bitwidth; + stAioAttr.enSoundmode = g_audio_capture.paramEncode.sound_mode; + stAioAttr.u32EXFlag = 0; + stAioAttr.u32FrmNum = 30; + stAioAttr.u32PtNumPerFrm = g_audio_capture.paramEncode.num_per_frm; + stAioAttr.u32ChnCnt = g_audio_capture.paramEncode.u32ChnCnt; + + s32AencChnCnt = stAioAttr.u32ChnCnt >> stAioAttr.enSoundmode; + s32Ret = SAMPLE_COMM_AUDIO_StartAenc(s32AencChnCnt, &stAioAttr, g_audio_capture.paramEncode.payload_type); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_AUDIO_StartAenc failed, s32Ret=%d\n", s32Ret); + s32Ret = SAMPLE_COMM_AUDIO_StopAenc(s32AencChnCnt); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_AUDIO_StopAenc failed, s32Ret=%d\n", s32Ret); + } + return -EAGAIN; + } + + sv82xHandle->format = format; + sv82xHandle->channel = channel; + sv82xHandle->sampleRate = sampleRate; + sv82xHandle->bitDepth = bitDepth; + + return 0; +} + +int audioCapturerGetFormat(const AudioCapturerHandle handle, AudioFormat* pFormat, AudioChannel* pChannel, AudioSampleRate* pSampleRate, + AudioBitDepth* pBitDepth) +{ + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + + *pFormat = sv82xHandle->format; + *pChannel = sv82xHandle->channel; + *pSampleRate = sv82xHandle->sampleRate; + *pBitDepth = sv82xHandle->bitDepth; + + return 0; +} + +// START AI +int audioCapturerAcquireStream(AudioCapturerHandle handle) +{ + EI_S32 s32Ret = EI_SUCCESS; + AI_CHN AiChn = 0; + EI_S32 s32AiChnCnt; + AENC_CHN AeChn = 0; + AIO_ATTR_S stAioAttr; + AI_VQE_CONFIG_S stAiVqeAttr; + EI_VOID* pAiVqeAttr = NULL; + + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + + AUDIO_DEV AiDev = g_audio_capture.AiDev; + + stAioAttr.enSamplerate = g_audio_capture.paramEncode.samplerate; + stAioAttr.enBitwidth = g_audio_capture.paramEncode.bitwidth; + stAioAttr.enSoundmode = g_audio_capture.paramEncode.sound_mode; + stAioAttr.u32EXFlag = 0; + stAioAttr.u32FrmNum = 30; + stAioAttr.u32PtNumPerFrm = g_audio_capture.paramEncode.num_per_frm; + stAioAttr.u32ChnCnt = g_audio_capture.paramEncode.u32ChnCnt; + + s32AiChnCnt = stAioAttr.u32ChnCnt; + if (g_audio_capture.enVqe == EI_TRUE) { + memset(&stAiVqeAttr, 0, sizeof(AI_VQE_CONFIG_S)); + g_audio_capture.audio_vqe.sample_rate = g_audio_capture.paramEncode.samplerate; + stAiVqeAttr.s32WorkSampleRate = g_audio_capture.audio_vqe.sample_rate; + stAiVqeAttr.s32FrameSample = g_audio_capture.paramEncode.num_per_frm; + stAiVqeAttr.enWorkstate = VQE_WORKSTATE_COMMON; + stAiVqeAttr.u32OpenMask = g_audio_capture.audio_vqe.open_mask; + pAiVqeAttr = (EI_VOID*) &stAiVqeAttr; + } + + s32Ret = SAMPLE_COMM_AUDIO_StartAi(AiDev, s32AiChnCnt, &stAioAttr, g_audio_capture.enOutSampleRate, g_audio_capture.bAioReSample, pAiVqeAttr); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_AUDIO_StartAi failed, s32Ret=%d\n", s32Ret); + return -EAGAIN; + } + + s32Ret = SAMPLE_COMM_AUDIO_CreatTrdAiAenc(AiDev, AiChn, AeChn); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_AUDIO_OpenSaveFile failed, s32Ret=%d\n", s32Ret); + s32AiChnCnt = stAioAttr.u32ChnCnt >> stAioAttr.enSoundmode; + s32Ret |= SAMPLE_COMM_AUDIO_StopAi(AiDev, s32AiChnCnt, g_audio_capture.bAioReSample, g_audio_capture.enVqe); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_AUDIO_StopAi failed, s32Ret=%d\n", s32Ret); + } + return -EAGAIN; + } + + LOG("SAMPLE_COMM_AUDIO_StartAi OK,AI(%d,%d),AencChn:%d\n", AiDev, AiChn, AeChn); + + return setStatus(handle, AUD_CAP_STATUS_STREAM_ON); +} + +int audioCapturerGetFrame(AudioCapturerHandle handle, void* pFrameDataBuffer, const size_t frameDataBufferSize, uint64_t* pTimestamp, + size_t* pFrameSize) +{ + EI_S32 s32Ret = EI_SUCCESS; + AUDIO_STREAM_S stStream; + int AeChn = g_audio_capture.AencChn; + + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + SV82X_HANDLE_STATUS_CHECK(sv82xHandle, AUD_CAP_STATUS_STREAM_ON); + + if (!pFrameDataBuffer || !pTimestamp || !pFrameSize) + return -EINVAL; + + while (handle) { + s32Ret = EI_MI_AENC_GetStream(AeChn, &stStream, -1); + if (s32Ret != EI_SUCCESS) { + LOG("EI_MI_AENC_GetStream failed. s32Ret=%x\n", s32Ret); + continue; + } + if (PT_AAC == g_audio_capture.paramEncode.payload_type) { + if (stStream.u32Len > 0 && stStream.u32Len <= frameDataBufferSize) { + memcpy(pFrameDataBuffer, stStream.pStream + AAC_HEADER_SIZE, stStream.u32Len - AAC_HEADER_SIZE); + *pFrameSize = stStream.u32Len - AAC_HEADER_SIZE; + *pTimestamp = stStream.u64TimeStamp; + EI_MI_AENC_ReleaseStream(AeChn, &stStream); + return 0; + } + } else { + if (stStream.u32Len > 0 && stStream.u32Len <= frameDataBufferSize) { + memcpy(pFrameDataBuffer, stStream.pStream, stStream.u32Len); + *pFrameSize = stStream.u32Len; + *pTimestamp = stStream.u64TimeStamp; + EI_MI_AENC_ReleaseStream(AeChn, &stStream); + return 0; + } + } + + s32Ret = EI_MI_AENC_ReleaseStream(AeChn, &stStream); + if (s32Ret != EI_SUCCESS) { + LOG("EI_MI_AENC_ReleaseStream(%d), failed with %#x!\n", AeChn, s32Ret); + } + return -EAGAIN; + } + + return -EAGAIN; +} + +int audioCapturerReleaseStream(AudioCapturerHandle handle) +{ + int s32Ret = EI_SUCCESS; + int bAioReSample = 0; + EI_BOOL bVqeEn = g_audio_capture.enVqe; + int s32AiChncnt = 1; + AUDIO_DEV AiDev = g_audio_capture.AiDev; + AUDIO_DEV AdChn = g_audio_capture.AdecChn; + AI_CHN AiChn; + int i = 0; + int s32AencChnCnt; + int u32ChnCnt = 2; + + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + + SV82X_HANDLE_STATUS_CHECK(sv82xHandle, AUD_CAP_STATUS_STREAM_ON); + + if (g_audio_capture.enAencCreate == EI_FALSE) + return -EINVAL; + + g_audio_capture.enAencCreate = EI_FALSE; + + s32AencChnCnt = u32ChnCnt >> g_audio_capture.paramEncode.sound_mode; + + for (i = 0; i < s32AencChnCnt; i++) { + AiChn = i; + s32Ret = SAMPLE_COMM_AUDIO_DestroyTrdAi(AiDev, AiChn); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_AUDIO_DestroyTrdAi failed, s32Ret=%d\n", s32Ret); + } + + s32Ret = SAMPLE_COMM_AUDIO_DestroyTrdAencAdec(AdChn); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_AUDIO_DestroyTrdAencAdec failed, s32Ret=%d\n", s32Ret); + } + } + + s32Ret = SAMPLE_COMM_AUDIO_StopAenc(s32AencChnCnt); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_AUDIO_StopAenc failed %x\n", s32Ret); + return -EAGAIN; + } + + s32Ret = SAMPLE_COMM_AUDIO_StopAi(AiDev, s32AiChncnt, bAioReSample, bVqeEn); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_AUDIO_StopAi failed %x\n", s32Ret); + return -EAGAIN; + } + + return setStatus(handle, AUD_CAP_STATUS_STREAM_OFF); +} + +void audioCapturerDestory(AudioCapturerHandle handle) +{ + if (!handle) + return; + + SV82X_HANDLE_GET(handle); + + if (sv82xHandle->status == AUD_CAP_STATUS_STREAM_ON) { + audioCapturerReleaseStream(handle); + } + + setStatus(handle, AUD_CAP_STATUS_NOT_READY); + + free(handle); +} diff --git a/source/SV82x/SV82xAudioPlayer.c b/source/SV82x/SV82xAudioPlayer.c new file mode 100644 index 0000000..885e6fa --- /dev/null +++ b/source/SV82x/SV82xAudioPlayer.c @@ -0,0 +1,357 @@ +/* + * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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. + */ + +#include +#include + +#include "com/amazonaws/kinesis/video/player/AudioPlayer.h" + +#include "SV82xCommon.h" + +#define SV82X_HANDLE_GET(x) SV82XAudioPlayer* sv82xHandle = (SV82XAudioPlayer*) ((x)) + +typedef struct { + AudioPlayerStatus status; + AudioCapability capability; + AudioFormat format; + AudioChannel channel; + AudioBitDepth bitDepth; + AudioSampleRate sampleRate; +} SV82XAudioPlayer; + +sv82x_audio_stream_info_t g_audio_player = { + .AdecChn = 0, + .AoChn = 0, + .AoDev = 0, + .paramDecode.payload_type = PT_MP3, + .paramDecode.samplerate = AUDIO_SAMPLE_RATE_48000, + .paramDecode.num_per_frm = 512, + .paramDecode.fps = 25, + .paramDecode.sound_mode = AUDIO_SOUND_MODE_MONO, + .paramDecode.bitwidth = AUDIO_BIT_WIDTH_16, + .paramDecode.volume = 50, + .paramDecode.u32ChnCnt = 1, + .bAioReSample = EI_FALSE, + .enInSampleRate = AUDIO_SAMPLE_RATE_BUTT, + .enOutSampleRate = AUDIO_SAMPLE_RATE_BUTT, + .enVqe = EI_FALSE, + .enAudioCreate = EI_FALSE, + .enUserGetMode = EI_FALSE, +}; + +static int setStatus(AudioPlayerHandle handle, const AudioPlayerStatus newStatus) +{ + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + + if (newStatus != sv82xHandle->status) { + sv82xHandle->status = newStatus; + LOG("AudioPlayer new status[%d]", newStatus); + } + + return 0; +} + +AudioPlayerHandle audioPlayerCreate(void) +{ + SV82XAudioPlayer* sv82xHandle = (SV82XAudioPlayer*) malloc(sizeof(SV82XAudioPlayer)); + + if (!sv82xHandle) { + LOG("%s OOM", __func__); + return NULL; + } + + memset(sv82xHandle, 0, sizeof(SV82XAudioPlayer)); + + sv82xHandle->capability.formats = (1 << (AUD_FMT_G711A - 1)) | (1 << (AUD_FMT_G711U - 1)) | (1 << (AUD_FMT_PCM - 1)) | (1 << (AUD_FMT_AAC - 1)); + sv82xHandle->capability.channels = (1 << (AUD_CHN_MONO - 1)); + sv82xHandle->capability.sampleRates = (1 << (AUD_SAM_8K - 1)); + sv82xHandle->capability.bitDepths = (1 << (AUD_BIT_16 - 1)); + + setStatus((AudioPlayerHandle) sv82xHandle, AUD_PLY_STATUS_STREAM_OFF); + + return (AudioPlayerHandle) sv82xHandle; +} + +int audioPlayerGetCapability(const AudioPlayerHandle handle, AudioCapability* pCapability) +{ + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + + if (!pCapability) { + return -EINVAL; + } + + *pCapability = sv82xHandle->capability; + + return 0; +} + +int audioPlayerSetFormat(AudioPlayerHandle handle, const AudioFormat format, const AudioChannel channel, const AudioSampleRate sampleRate, + const AudioBitDepth bitDepth) +{ + EI_S32 s32Ret; + ADEC_CHN AdChn = 0; + AIO_ATTR_S stAioAttr; + + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + SV82X_HANDLE_STATUS_CHECK(sv82xHandle, AUD_PLY_STATUS_STREAM_OFF); + + switch (format) { + case AUD_FMT_AAC: + g_audio_player.paramDecode.payload_type = PT_AAC; + break; + case AUD_FMT_PCM: + g_audio_player.paramDecode.payload_type = PT_LPCM; + break; + case AUD_FMT_G711A: + g_audio_player.paramDecode.payload_type = PT_G711A; + break; + case AUD_FMT_G711U: + g_audio_player.paramDecode.payload_type = PT_G711U; + break; + case AUD_FMT_OPUS: + default: + LOG("Unsupported format %d", format); + return -EINVAL; + } + + if (channel == AUD_CHN_MONO) { + g_audio_player.paramDecode.sound_mode = AUDIO_SOUND_MODE_MONO; + g_audio_player.paramDecode.u32ChnCnt = 1; + } else { + g_audio_player.paramDecode.sound_mode = AUDIO_SOUND_MODE_STEREO; + g_audio_player.paramDecode.u32ChnCnt = 2; + } + + switch (sampleRate) { + case AUD_SAM_8K: + g_audio_player.paramDecode.samplerate = AUDIO_SAMPLE_RATE_8000; + break; + case AUD_SAM_16K: + g_audio_player.paramDecode.samplerate = AUDIO_SAMPLE_RATE_16000; + break; + case AUD_SAM_24K: + g_audio_player.paramDecode.samplerate = AUDIO_SAMPLE_RATE_24000; + break; + case AUD_SAM_32K: + g_audio_player.paramDecode.samplerate = AUDIO_SAMPLE_RATE_32000; + break; + case AUD_SAM_44_1K: + g_audio_player.paramDecode.samplerate = AUDIO_SAMPLE_RATE_44100; + break; + case AUD_SAM_48K: + g_audio_player.paramDecode.samplerate = AUDIO_SAMPLE_RATE_48000; + break; + default: + LOG("Unsupported sampleRate %d", sampleRate); + return -EINVAL; + } + + switch (bitDepth) { + case AUD_BIT_8: + g_audio_player.paramDecode.bitwidth = AUDIO_BIT_WIDTH_8; + break; + case AUD_BIT_16: + g_audio_player.paramDecode.bitwidth = AUDIO_BIT_WIDTH_16; + break; + case AUD_BIT_32: + g_audio_player.paramDecode.bitwidth = AUDIO_BIT_WIDTH_24; + break; + default: + LOG("Unsupported bitDepth %d", bitDepth); + return -EINVAL; + } + sv82xHandle->format = format; + sv82xHandle->channel = channel; + sv82xHandle->sampleRate = sampleRate; + sv82xHandle->bitDepth = bitDepth; + + return 0; +} + +int audioPlayerGetFormat(const AudioPlayerHandle handle, AudioFormat* pFormat, AudioChannel* pChannel, AudioSampleRate* pSampleRate, + AudioBitDepth* pBitDepth) +{ + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + + *pFormat = sv82xHandle->format; + *pChannel = sv82xHandle->channel; + *pSampleRate = sv82xHandle->sampleRate; + *pBitDepth = sv82xHandle->bitDepth; + + return 0; +} + +int audioPlayerAcquireStream(AudioPlayerHandle handle) +{ + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + EI_S32 s32Ret; + AO_CHN AoChn = 0; + ADEC_CHN AdChn = 0; + EI_S32 s32AoChnCnt; + AIO_ATTR_S stAioAttr; + AUDIO_DEV AoDev = g_audio_player.AoDev; + + stAioAttr.enSamplerate = g_audio_player.paramDecode.samplerate; + stAioAttr.enBitwidth = g_audio_player.paramDecode.bitwidth; + stAioAttr.enSoundmode = g_audio_player.paramDecode.sound_mode; + stAioAttr.u32EXFlag = 0; + stAioAttr.u32FrmNum = 30; + stAioAttr.u32PtNumPerFrm = g_audio_player.paramDecode.num_per_frm; + stAioAttr.u32ChnCnt = g_audio_player.paramDecode.u32ChnCnt; + + s32Ret = SAMPLE_COMM_AUDIO_StartAdec(AdChn, &stAioAttr, g_audio_player.paramDecode.payload_type); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_AUDIO_StartAdec failed, ret=%d\n", s32Ret); + return -EAGAIN; + } + + stAioAttr.enSamplerate = g_audio_player.paramDecode.samplerate; + stAioAttr.enBitwidth = g_audio_player.paramDecode.bitwidth; + stAioAttr.enSoundmode = g_audio_player.paramDecode.sound_mode; + stAioAttr.u32EXFlag = 0; + stAioAttr.u32FrmNum = 30; + stAioAttr.u32PtNumPerFrm = g_audio_player.paramDecode.num_per_frm; + stAioAttr.u32ChnCnt = g_audio_player.paramDecode.u32ChnCnt; + + s32AoChnCnt = stAioAttr.u32ChnCnt; + s32Ret = SAMPLE_COMM_AUDIO_StartAo(AoDev, s32AoChnCnt, &stAioAttr, g_audio_player.enInSampleRate, g_audio_player.bAioReSample); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_AUDIO_StartAo failed, ret=%d\n", s32Ret); + return -EAGAIN; + } + + if (g_audio_player.enUserGetMode == EI_TRUE) { + s32Ret = SAMPLE_COMM_AUDIO_CreatTrdAdeAo(AoDev, AoChn, AdChn, NULL); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_AUDIO_CreatTrdAdeAo failed, ret=%d\n", s32Ret); + s32AoChnCnt = stAioAttr.u32ChnCnt >> stAioAttr.enSoundmode; + s32Ret |= SAMPLE_COMM_AUDIO_StopAo(AoDev, s32AoChnCnt, g_audio_player.bAioReSample); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_AUDIO_StopAo failed, ret=%d\n", s32Ret); + } + return -EAGAIN; + } + } else { + s32Ret = SAMPLE_COMM_AUDIO_AoLinkAdec(AoDev, AoChn, AdChn); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_AUDIO_AoLinkAdec failed, ret=%d\n", s32Ret); + s32AoChnCnt = stAioAttr.u32ChnCnt >> stAioAttr.enSoundmode; + s32Ret |= SAMPLE_COMM_AUDIO_StopAo(AoDev, s32AoChnCnt, g_audio_player.bAioReSample); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_AUDIO_StopAo failed, ret=%d\n", s32Ret); + } + return -EAGAIN; + } + } + + setStatus(handle, AUD_PLY_STATUS_STREAM_ON); + + return 0; +} + +int audioPlayerWriteFrame(AudioPlayerHandle handle, void* pData, const size_t size) +{ + EI_S32 s32Ret = EI_SUCCESS; + AUDIO_STREAM_S stStream; + int AdChn = g_audio_player.AdecChn; + + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + + SV82X_HANDLE_STATUS_CHECK(sv82xHandle, AUD_PLY_STATUS_STREAM_ON); + + if (!pData) + return -EINVAL; + + if (size <= 0) { + s32Ret = EI_MI_ADEC_SendEndOfStream(AdChn, EI_FALSE); + if (s32Ret != EI_SUCCESS) { + LOG("%s: EI_MI_ADEC_SendEndOfStream failed:%d!\n", __func__, size); + return -EAGAIN; + } + return 0; + } + + memset(&stStream, 0, sizeof(AUDIO_STREAM_S)); + stStream.pStream = (EI_U8 ATTRIBUTE*) pData; + stStream.u32Len = size; + s32Ret = EI_MI_ADEC_SendStream(AdChn, &stStream, EI_TRUE); + if (s32Ret != EI_SUCCESS) { + LOG("EI_MI_ADEC_SendStream(%d) failed with %#x!\n", AdChn, s32Ret); + return -EAGAIN; + } + + return 0; +} + +int audioPlayerReleaseStream(AudioPlayerHandle handle) +{ + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + + int s32Ret = EI_SUCCESS; + AO_CHN AoChn = g_audio_player.AoChn; + ADEC_CHN AdChn = g_audio_player.AdecChn; + AUDIO_DEV AoDev = g_audio_player.AoDev; + EI_S32 s32AoChnCnt; + EI_BOOL bResampleEn = EI_FALSE; + + if (g_audio_player.enUserGetMode == EI_TRUE) { + s32Ret = SAMPLE_COMM_AUDIO_DestroyTrdAdec(AdChn); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_AUDIO_DestroyTrdAdec failed %x\n", s32Ret); + return -EAGAIN; + } + } else { + s32Ret = SAMPLE_COMM_AUDIO_AoUnbindAdec(AoDev, AoChn, AdChn); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_AUDIO_AoUnbindAdec failed %x\n", s32Ret); + return -EAGAIN; + } + } + + s32AoChnCnt = g_audio_player.paramDecode.u32ChnCnt >> g_audio_player.paramDecode.sound_mode; + s32Ret = SAMPLE_COMM_AUDIO_StopAo(AoDev, s32AoChnCnt, bResampleEn); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_AUDIO_StopAo failed %x\n", s32Ret); + return -EAGAIN; + } + s32Ret = SAMPLE_COMM_AUDIO_StopAdec(AdChn); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_AUDIO_StopAdec failed %x\n", s32Ret); + return -EAGAIN; + } + return setStatus(handle, AUD_PLY_STATUS_STREAM_OFF); +} + +void audioPlayerDestory(AudioPlayerHandle handle) +{ + if (!handle) + return; + + SV82X_HANDLE_GET(handle); + + if (sv82xHandle->status == AUD_PLY_STATUS_STREAM_ON) + audioPlayerReleaseStream(handle); + + setStatus(handle, AUD_PLY_STATUS_NOT_READY); + + free(handle); +} diff --git a/source/SV82x/SV82xCommon.h b/source/SV82x/SV82xCommon.h new file mode 100644 index 0000000..e33e9c8 --- /dev/null +++ b/source/SV82x/SV82xCommon.h @@ -0,0 +1,87 @@ +/* + * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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. + */ + +#pragma once + +#include +#include +#include + +#include "sample_comm.h" + +#define LOG(msg, ...) printf(msg "\n", ##__VA_ARGS__) + +#define SV82X_HANDLE_NULL_CHECK(x) \ + if (!(x)) { \ + return -EINVAL; \ + } +#define EI_TRACE_AUDIO(level, fmt, args...) EI_TRACE(EI_ID_AUDIOIN, level, fmt, ##args) +#define SV82X_HANDLE_STATUS_CHECK(Handle, expectedStatus) \ + if ((Handle)->status != (expectedStatus)) { \ + return -EAGAIN; \ + } + +typedef enum { + ELF_AUDIO_FRAME_G711A, + ELF_AUDIO_FRAME_G711U, + ELF_AUDIO_FRAME_ADPCMA, + ELF_AUDIO_FRAME_G726, + ELF_AUDIO_FRAME_G729, + ELF_AUDIO_FRAME_LPCM, + ELF_AUDIO_FRAME_AAC, + ELF_AUDIO_FRAME_MP3, + ELF_AUDIO_FRAME_TYPE_MAX, +} sv82x_audio_frame_type_e; + +typedef enum { ELF_AUDIO_STREAM_CAPTURE, ELF_AUDIO_STREAM_PLAYBACK, ELF_AUDIO_STREAM_MAX } sv82x_audio_stream_e; + +typedef struct { + PAYLOAD_TYPE_E payload_type; /* payload type */ + AUDIO_SAMPLE_RATE_E samplerate; + unsigned int num_per_frm; /* sample per frame */ + unsigned int fps; /* frame rate ;default 25*/ + AUDIO_SOUND_MODE_E sound_mode; + AUDIO_BIT_WIDTH_E bitwidth; + int volume; + unsigned int u32ChnCnt; +} sv82x_audio_param_t; + +typedef struct { + int sample_rate; + int frame_rate; + EI_U32 open_mask; /*AEC | AGC | ANR | EQ | HPF */ +} sv82x_audio_vqe_t; + +typedef struct VIDEO_STREAM_CTX { + EI_U32 AiDev; + EI_U32 AencChn; + EI_U32 AdecChn; + EI_U32 AoChn; + EI_U32 AoDev; + EI_U32 u32ChnCnt; + sv82x_audio_param_t paramEncode; + sv82x_audio_param_t paramDecode; + EI_BOOL audio_adec_ao_flag; + PAYLOAD_TYPE_E enPayloadType; + EI_BOOL bAioReSample; + EI_BOOL enInSampleRate; + EI_BOOL enOutSampleRate; + EI_BOOL enVqe; + EI_BOOL enAudioCreate; + EI_BOOL enAencCreate; + EI_BOOL enUserGetMode; + sv82x_audio_vqe_t audio_vqe; + EI_CHAR playFileName[512]; +} sv82x_audio_stream_info_t; diff --git a/source/SV82x/SV82xVideoCapturer.c b/source/SV82x/SV82xVideoCapturer.c new file mode 100644 index 0000000..4a5b743 --- /dev/null +++ b/source/SV82x/SV82xVideoCapturer.c @@ -0,0 +1,699 @@ +/* + * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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. + */ + +#include +#include +#include +#include +#include +#include +#include "errno.h" +#include "com/amazonaws/kinesis/video/capturer/VideoCapturer.h" +#include "SV82xCommon.h" +#include "sample_comm.h" + +#define SV82X_VIDEO_STREAM_1080P_CHN (0) +#define SV82X_VIDEO_STREAM_720P_CHN (1) +#define SV82X_VIDEO_STREAM_LOW_RES_CHN (2) +#define SV82X_VIDEO_STREAM_CHN_NUM (3) + +#define SV82X_VIDEO_STREAM_FPS (30) +#define SV82X_VIDEO_STREAM_BITRATE (2 * 1024 * 1024) +#define SV82X_VIDEO_STREAM_GOP (30) +#define SV82X_VIDEO_RC_MODE (SAMPLE_RC_VBR) + +#define SV82X_IPPU_DEV (0) +#define SV82X_ISP_DEV (0) + +#define SV82X_HANDLE_NULL_CHECK_RET_VOID(x) \ + do { \ + if (x == EI_NULL) { \ + LOG("Null Pointer!\n"); \ + return; \ + } \ + } while (0) + +#define SV82X_HANDLE_GET(x) Sv82xVideoCapturer_t* Sv82xHandle = (Sv82xVideoCapturer_t*) ((x)) + +typedef struct { + VideoCapturerStatus status; + VideoCapability capability; + VideoFormat format; + VideoResolution resolution; + uint8_t channel; + VBUF_POOL Pool; + uint8_t VideoCreatFlag; + uint8_t enable; +} Sv82xVideoCapturer_t; + +typedef struct { + SAMPLE_VISS_CONFIG_S stVissConfig; + int VideoCreatHandleCnt; + int IppuEnableCnt; +} Sv82xVideoInfo_t; +static Sv82xVideoInfo_t VideoAttrs = {0}; +static int SystemInitFlag = 0; + +static int SystemInit(void) +{ + EI_S32 s32Ret = EI_FAILURE; + + SNS_TYPE_E enSnsType; + VISS_PIC_TYPE_E stPicType = {0}; + IPPU_DEV_ATTR_S stDevAttr = {0}; + SAMPLE_VISS_CONFIG_S stVissConfig; + + EI_MI_MBASE_Init(); + EI_MI_VBUF_Init(); + EI_MI_MLINK_Init(); + + enSnsType = GC4663_MIPI_2560_1440_30FPS_RAW10; + memset(&VideoAttrs.stVissConfig, 0, sizeof(SAMPLE_VISS_CONFIG_S)); + stVissConfig = VideoAttrs.stVissConfig; + stVissConfig.astVissInfo[0].stDevInfo.VissDev = (enSnsType < 200000) ? 0 : 1; + stVissConfig.astVissInfo[0].stDevInfo.aBindPhyChn[0] = 0; + stVissConfig.astVissInfo[0].stDevInfo.enOutPath = VISS_OUT_PATH_PIXEL; + stVissConfig.astVissInfo[0].stChnInfo.aVissChn[0] = 0; + stVissConfig.astVissInfo[0].stChnInfo.enWorkMode = VISS_WORK_MODE_1Chn; + stVissConfig.astVissInfo[0].stIspInfo.IspDev = SV82X_ISP_DEV; + stVissConfig.astVissInfo[0].stIspInfo.enRunningMode = ISP_MODE_RUNNING_ONLINE; + stVissConfig.astVissInfo[0].stSnsInfo.enSnsType = enSnsType; + stVissConfig.s32WorkingVissNum = 1; + + s32Ret = SAMPLE_COMM_ISP_Start(&stVissConfig.astVissInfo[0]); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_ISP_Start failed with %#x\n", s32Ret); + return -EAGAIN; + } + + s32Ret = SAMPLE_COMM_VISS_StartViss(&stVissConfig); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_VISS_StartViss failed with %#x\n", s32Ret); + return -EAGAIN; + } + + s32Ret = SAMPLE_COMM_VISS_GetPicTypeBySensor(enSnsType, &stPicType); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_VISS_GetPicTypeBySensor failed with %#x\n", s32Ret); + return -EAGAIN; + } + + stDevAttr.s32IppuDev = SV82X_IPPU_DEV; + stDevAttr.u32DataSrc = (enSnsType < 200000) ? 0 : 1; + stDevAttr.u32InputWidth = stPicType.stSize.u32Width; + stDevAttr.u32InputHeight = stPicType.stSize.u32Height; + stDevAttr.enRunningMode = IPPU_MODE_RUNNING_ONLINE; + s32Ret = EI_MI_IPPU_Create(SV82X_IPPU_DEV, &stDevAttr); + if (s32Ret != EI_SUCCESS) { + LOG("EI_MI_IPPU_Create failed with %#x\n", s32Ret); + return -EAGAIN; + } + s32Ret = EI_MI_IPPU_Start(SV82X_IPPU_DEV); + if (s32Ret != EI_SUCCESS) { + LOG("EI_MI_IPPU_Start failed with %#x\n", s32Ret); + return -EAGAIN; + } + + return 0; +} + +static int SystemDeinit(void) +{ + EI_S32 s32Ret = EI_FAILURE; + SAMPLE_VISS_CONFIG_S stVissConfig; + + s32Ret = EI_MI_IPPU_Stop(SV82X_IPPU_DEV); + if (s32Ret != EI_SUCCESS) { + LOG("EI_MI_IPPU_Stop failed with %#x\n", s32Ret); + return -EAGAIN; + } + + s32Ret = EI_MI_IPPU_Destroy(SV82X_IPPU_DEV); + if (s32Ret != EI_SUCCESS) { + LOG("EI_MI_IPPU_Destroy failed with %#x\n", s32Ret); + return -EAGAIN; + } + + stVissConfig = VideoAttrs.stVissConfig; + s32Ret = SAMPLE_COMM_VISS_StopViss(&stVissConfig); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_VISS_StopViss failed with %#x\n", s32Ret); + return -EAGAIN; + } + + s32Ret = SAMPLE_COMM_ISP_Stop(SV82X_IPPU_DEV); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_ISP_Stop failed with %#x\n", s32Ret); + return -EAGAIN; + } + + EI_MI_MLINK_Exit(); + EI_MI_VBUF_Exit(); + EI_MI_MBASE_Exit(); + + return 0; +} + +static int setStatus(VideoCapturerHandle handle, const VideoCapturerStatus newStatus) +{ + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + + if (newStatus != Sv82xHandle->status) { + Sv82xHandle->status = newStatus; + LOG("VideoCapturer new status[%d]", newStatus); + } + + return 0; +} + +static int _Sv82xVideoBufPoolCreat(VideoCapturerHandle handle, VIDEO_FRAME_INFO_S* pstVideoFrameInfo) +{ + EI_S32 s32Ret = EI_FAILURE; + VBUF_POOL_CONFIG_S stPoolCfg = {0}; + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + + stPoolCfg.u32BufSize = EI_MI_VBUF_GetPicBufferSize(pstVideoFrameInfo); + stPoolCfg.u32BufCnt = 4; + stPoolCfg.enRemapMode = VBUF_REMAP_MODE_NOCACHE; + stPoolCfg.enVbufUid = VBUF_UID_COMMON; + /* create buffer pool */ + Sv82xHandle->Pool = EI_MI_VBUF_CreatePool(&stPoolCfg); + /* set buffer pool info */ + s32Ret = EI_MI_VBUF_SetFrameInfo(Sv82xHandle->Pool, pstVideoFrameInfo); + if (s32Ret != EI_SUCCESS) { + LOG("EI_MI_VBUF_SetFrameInfo failed with %#x\n", s32Ret); + return -EAGAIN; + } + + return 0; +} + +static int _Sv82xVideoBufPoolDestory(VideoCapturerHandle handle) +{ + EI_S32 s32Ret = EI_FAILURE; + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + + s32Ret = EI_MI_VBUF_DestroyPool(Sv82xHandle->Pool); + if (s32Ret) { + LOG("EI_MI_VBUF_DestroyPool error s32Ret:%d\n", s32Ret); + return -EAGAIN; + } + return 0; +} + +static int _Sv82xIppuStart(VideoCapturerHandle handle, const IPPU_CHN_ATTR_S* pstChnAttr) +{ + EI_S32 s32Ret = EI_FAILURE; + IPPU_DEV dev = 0; + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + + s32Ret = EI_MI_IPPU_SetChnAttr(dev, Sv82xHandle->channel, pstChnAttr); + if (s32Ret != EI_SUCCESS) { + LOG("%s:%d EI_MI_IPPU_SetChnAttr failed\n", __func__, __LINE__); + EI_MI_IPPU_Destroy(dev); + return -EAGAIN; + } + s32Ret = EI_MI_IPPU_EnableChn(dev, Sv82xHandle->channel); + if (s32Ret != EI_SUCCESS) { + LOG("%s:%d EI_MI_IPPU_EnableChn failed\n", __func__, __LINE__); + EI_MI_IPPU_Destroy(dev); + return -EAGAIN; + } + Sv82xHandle->enable = 1; + VideoAttrs.IppuEnableCnt++; + + return 0; +} + +static int _Sv82xIppuStop(VideoCapturerHandle handle) +{ + EI_S32 s32Ret = EI_SUCCESS; + IPPU_DEV dev = 0; + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + + LOG("%s chn is :%d\n", __func__, Sv82xHandle->channel); + if (!Sv82xHandle->enable) { + LOG("ippu channel:%d is disable\n", Sv82xHandle->channel); + return -EINVAL; + } + + if (Sv82xHandle->channel >= IPPU_PHY_CHN_MAX_NUM || Sv82xHandle->channel < 0) { + LOG("channel:%d is illegal\n", Sv82xHandle->channel); + return -EINVAL; + } + + s32Ret = EI_MI_IPPU_DisableChn(dev, Sv82xHandle->channel); + if (s32Ret != EI_SUCCESS) { + LOG("IPPU_DisableChn failed with %d!\n", s32Ret); + return -EAGAIN; + } + Sv82xHandle->enable = 0; + VideoAttrs.IppuEnableCnt--; + + return 0; +} + +static int _Sv82xVideoCreat(VideoCapturerHandle handle, const VideoFormat format, SAMPLE_VENC_CONFIG_S* pstSamplVenc) +{ + EI_S32 s32Ret = 0, RcMode = 0, GopMode = 0, PayloadType = 0; + + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + RcMode = SV82X_VIDEO_RC_MODE; + GopMode = VENC_GOPMODE_NORMAL_P; + switch (format) { + case VID_FMT_H264: + PayloadType = PT_H264; + break; + case VID_FMT_H265: + PayloadType = PT_H265; + break; + default: + LOG("Unsupported format %d", format); + return -EINVAL; + } + + if (PayloadType == PT_H264 || PayloadType == PT_H265) { + s32Ret = SAMPLE_COMM_VENC_Creat(Sv82xHandle->channel, PayloadType, RcMode, pstSamplVenc, COMPRESS_MODE_NONE, GopMode); + if (EI_SUCCESS != s32Ret) { + LOG("SAMPLE_COMM_VENC_Creat faild with%#x! \n", s32Ret); + return -EAGAIN; + } + + s32Ret = SAMPLE_COMM_IPPU_Link_VPU(0, Sv82xHandle->channel, Sv82xHandle->channel); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_IPPU_Link_VPU failed with %#x\n", s32Ret); + EI_MI_VENC_DestroyChn(Sv82xHandle->channel); + return -EAGAIN; + } + } + Sv82xHandle->VideoCreatFlag = 1; + return 0; +} + +static int _Sv82xVideoDestory(VideoCapturerHandle handle) +{ + EI_S32 s32Ret = 0; + + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + + s32Ret = SAMPLE_COMM_IPPU_UnLink_VPU(0, Sv82xHandle->channel, Sv82xHandle->channel); + if (s32Ret != EI_SUCCESS) { + LOG("SAMPLE_COMM_IPPU_UnLink_VPU failed with %#x\n", s32Ret); + return -EAGAIN; + } + s32Ret = EI_MI_VENC_DestroyChn(Sv82xHandle->channel); + if (s32Ret != EI_SUCCESS) { + LOG("EI_MI_VENC_DestroyChn failed with %#x\n", s32Ret); + return -EAGAIN; + } + Sv82xHandle->VideoCreatFlag = 0; + + return 0; +} + +static int _Sv82xVideoStart(VideoCapturerHandle handle) +{ + EI_S32 s32Ret = 0; + VENC_RECV_PIC_PARAM_S stRecvParam = {0}; + + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + + stRecvParam.s32RecvPicNum = -1; + s32Ret = EI_MI_VENC_StartRecvFrame(Sv82xHandle->channel, &stRecvParam); + if (s32Ret != EI_SUCCESS) { + LOG("EI_MI_VENC_StartRecvFrame failed with %#x\n", s32Ret); + return -EAGAIN; + } + setStatus(handle, VID_CAP_STATUS_STREAM_ON); + + return 0; +} + +static int _Sv82xVideoStop(VideoCapturerHandle handle) +{ + EI_S32 s32Ret = 0; + + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + + s32Ret = EI_MI_VENC_StopRecvFrame(Sv82xHandle->channel); + if (s32Ret != EI_SUCCESS) { + LOG("EI_MI_VENC_StopRecvFrame failed with %#x\n", s32Ret); + return -EAGAIN; + } + + setStatus(handle, VID_CAP_STATUS_STREAM_OFF); + + return 0; +} + +VideoCapturerHandle videoCapturerCreate(void) +{ + EI_S32 s32Ret = EI_SUCCESS; + Sv82xVideoCapturer_t* Handle = NULL; + if (VideoAttrs.VideoCreatHandleCnt >= SV82X_VIDEO_STREAM_CHN_NUM) + return NULL; + if (!(Handle = (Sv82xVideoCapturer_t*) malloc(sizeof(Sv82xVideoCapturer_t)))) { + LOG("%s:%d oom\n", __func__, __LINE__); + return NULL; + } + memset(Handle, 0, sizeof(Sv82xVideoCapturer_t)); + + if (!SystemInitFlag) { + s32Ret = SystemInit(); + if (s32Ret) { + LOG("%s:%d SystemInit\n", __func__, __LINE__); + free(Handle); + return NULL; + } + } + SystemInitFlag = 1; + Handle->capability.formats = (1 << (VID_FMT_H264 - 1)) | (1 << (VID_FMT_H265 - 1)) | (1 << (VID_FMT_RAW - 1)); + Handle->capability.resolutions = + (1 << (VID_RES_1080P - 1)) | (1 << (VID_RES_720P - 1)) | (1 << (VID_RES_480P - 1)) | (1 << (VID_RES_360P - 1)) | (1 << (VID_RES_320P - 1)); + + setStatus((VideoCapturerHandle) Handle, VID_CAP_STATUS_STREAM_OFF); + + VideoAttrs.VideoCreatHandleCnt++; + + return (VideoCapturerHandle) Handle; +} + +VideoCapturerStatus videoCapturerGetStatus(const VideoCapturerHandle const handle) +{ + if (!handle) { + return VID_CAP_STATUS_NOT_READY; + } + + SV82X_HANDLE_GET(handle); + return Sv82xHandle->status; +} + +int videoCapturerGetCapability(const VideoCapturerHandle const handle, VideoCapability* pCapability) +{ + EI_S32 s32Ret = EI_SUCCESS; + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + + if (!pCapability) + return -EINVAL; + + *pCapability = Sv82xHandle->capability; + + return 0; +} + +int videoCapturerSetFormat(VideoCapturerHandle const handle, const VideoFormat format, const VideoResolution resolution) +{ + EI_S32 s32Ret = EI_FAILURE; + EI_S32 width = 0, height = 0; + VIDEO_FRAME_INFO_S stVideoFrameInfo = {0}; + IPPU_CHN_ATTR_S ippu_chn_attr = {0}; + SAMPLE_VENC_CONFIG_S stSamplVenc = {0}; + + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + SV82X_HANDLE_STATUS_CHECK(Sv82xHandle, VID_CAP_STATUS_STREAM_OFF); + + switch (resolution) { + case VID_RES_1080P: + Sv82xHandle->channel = SV82X_VIDEO_STREAM_1080P_CHN; + width = 1920; + height = 1080; + break; + case VID_RES_720P: + Sv82xHandle->channel = SV82X_VIDEO_STREAM_720P_CHN; + width = 1280; + height = 720; + break; + case VID_RES_480P: + Sv82xHandle->channel = SV82X_VIDEO_STREAM_LOW_RES_CHN; + width = 640; + height = 480; + break; + case VID_RES_360P: + Sv82xHandle->channel = SV82X_VIDEO_STREAM_LOW_RES_CHN; + width = 480; + height = 360; + break; + case VID_RES_320P: + Sv82xHandle->channel = SV82X_VIDEO_STREAM_LOW_RES_CHN; + width = 416; + height = 320; + break; + default: + LOG("Unsupported resolution %d", resolution); + return -EINVAL; + } + // creat buf pool + stVideoFrameInfo.enFrameType = MDP_FRAME_TYPE_COMMON; + stVideoFrameInfo.stCommFrameInfo.u32Align = 32; + stVideoFrameInfo.stCommFrameInfo.u32Width = width; + stVideoFrameInfo.stCommFrameInfo.u32Height = height; + stVideoFrameInfo.stCommFrameInfo.enPixelFormat = PIX_FMT_YUV_SEMIPLANAR_420; + s32Ret = _Sv82xVideoBufPoolCreat(handle, &stVideoFrameInfo); + if (s32Ret != EI_SUCCESS) { + LOG("%s:%d _sv82x_video_init failed\n", __func__, __LINE__); + return -EAGAIN; + } + + // set ippu chn attrs and enable ippu chn + ippu_chn_attr.s32Chn = Sv82xHandle->channel; + ippu_chn_attr.u32Width = width; + ippu_chn_attr.u32Height = height; + ippu_chn_attr.enPixelFormat = PIX_FMT_YUV_SEMIPLANAR_420; + ippu_chn_attr.u32Align = 32; + ippu_chn_attr.stFrameRate.s32DstFrameRate = SV82X_VIDEO_STREAM_FPS; + ippu_chn_attr.stFrameRate.s32SrcFrameRate = SV82X_VIDEO_STREAM_FPS; + if (format == VID_FMT_RAW) + ippu_chn_attr.u32Depth = 1; + else + ippu_chn_attr.u32Depth = 0; + ippu_chn_attr.enCompressMode = COMPRESS_MODE_NONE; + + s32Ret = _Sv82xIppuStart(handle, &ippu_chn_attr); + if (s32Ret != EI_SUCCESS) { + LOG("%s:%d _Sv82xIppuStart failed\n", __func__, __LINE__); + return -EAGAIN; + } + if (format != VID_FMT_RAW) { + // vpu chn creat + stSamplVenc.enInputFormat = PIX_FMT_YUV_SEMIPLANAR_420; + stSamplVenc.u32width = width; + stSamplVenc.u32height = height; + stSamplVenc.u32bitrate = SV82X_VIDEO_STREAM_BITRATE; + stSamplVenc.u32srcframerate = SV82X_VIDEO_STREAM_FPS; + stSamplVenc.u32dstframerate = SV82X_VIDEO_STREAM_FPS; + s32Ret = _Sv82xVideoCreat(handle, format, &stSamplVenc); + if (s32Ret != EI_SUCCESS) { + LOG("%s:%d _Sv82xVideoCreat failed\n", __func__, __LINE__); + return -EAGAIN; + } + } + + Sv82xHandle->format = format; + Sv82xHandle->resolution = resolution; + + return 0; +} + +int videoCapturerGetFormat(const VideoCapturerHandle const handle, VideoFormat* pFormat, VideoResolution* pResolution) +{ + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + + *pFormat = Sv82xHandle->format; + *pResolution = Sv82xHandle->resolution; + return 0; +} + +int videoCapturerAcquireStream(VideoCapturerHandle handle) +{ + EI_S32 s32Ret = EI_FAILURE; + + s32Ret = _Sv82xVideoStart(handle); + if (s32Ret != EI_SUCCESS) { + LOG("_Sv82xVideoStart failed with %#x\n", s32Ret); + return -EAGAIN; + } + + return 0; +} + +int videoCapturerGetFrame(VideoCapturerHandle handle, void* pFrameDataBuffer, const size_t frameDataBufferSize, uint64_t* pTimestamp, + size_t* pFrameSize) +{ + EI_S32 s32Ret = -1; + VENC_CHN_STATUS_S stStatus = {0}; + VENC_STREAM_S stStream = {0}; + VENC_STREAM_S VencStream = {0}; + VIDEO_FRAME_INFO_S stVFrameInfo = {0}; + VC_CHN channel; + EI_U32 data_len = 0; + + SV82X_HANDLE_NULL_CHECK(handle); + SV82X_HANDLE_GET(handle); + channel = Sv82xHandle->channel; + if (Sv82xHandle->format == VID_FMT_RAW) { + s32Ret = EI_MI_IPPU_GetChnFrame(0, channel, &stVFrameInfo, 2000); + if (s32Ret != EI_SUCCESS) { + LOG("%s:%d EI_MI_IPPU_GetChnFrame chn-%d error : %d\n", __func__, __LINE__, channel, s32Ret); + return -EAGAIN; + } + + EI_MI_VBUF_FrameMmap(&stVFrameInfo, VBUF_REMAP_MODE_CACHED); + if (((char*) stVFrameInfo.stVFrame.ulPlaneVirAddr[0] != NULL) && (stVFrameInfo.stVFrame.u32PlaneSize[0] != 0) && + ((char*) stVFrameInfo.stVFrame.ulPlaneVirAddr[1] != NULL) && (stVFrameInfo.stVFrame.u32PlaneSize[1] != 0)) { + *pFrameSize = stVFrameInfo.stCommFrameInfo.u32Width * stVFrameInfo.stCommFrameInfo.u32Height * 1.5; + } + memset(pFrameDataBuffer, 0, frameDataBufferSize); + if (*pFrameSize <= frameDataBufferSize) { + if (((char*) stVFrameInfo.stVFrame.ulPlaneVirAddr[0] != NULL) && (stVFrameInfo.stVFrame.u32PlaneSize[0] != 0)) { + memcpy(pFrameDataBuffer, (char*) stVFrameInfo.stVFrame.ulPlaneVirAddr[0], + stVFrameInfo.stCommFrameInfo.u32Width * stVFrameInfo.stCommFrameInfo.u32Height); + if (((char*) stVFrameInfo.stVFrame.ulPlaneVirAddr[1] != NULL) && (stVFrameInfo.stVFrame.u32PlaneSize[1] != 0)) { + memcpy(pFrameDataBuffer + stVFrameInfo.stCommFrameInfo.u32Width * stVFrameInfo.stCommFrameInfo.u32Height, + (char*) stVFrameInfo.stVFrame.ulPlaneVirAddr[1], + stVFrameInfo.stCommFrameInfo.u32Width * stVFrameInfo.stCommFrameInfo.u32Height * 0.5); + } + } + } else + LOG("ch:%d data len is to big datalen:%d buflen:%d\n", channel, *pFrameSize, frameDataBufferSize); + *pTimestamp = stVFrameInfo.stVFrame.u64PTS; + EI_MI_IPPU_ReleaseChnFrame(0, channel, &stVFrameInfo); + } else if (Sv82xHandle->format == VID_FMT_H264 || Sv82xHandle->format == VID_FMT_H265) { + s32Ret = EI_MI_VENC_QueryStatus(channel, &stStatus); + if (s32Ret != EI_SUCCESS) { + LOG("%s:%d query status chn-%d error : %d\n", __func__, __LINE__, channel, s32Ret); + return -EAGAIN; + } + + s32Ret = EI_MI_VENC_GetStream(channel, &stStream, 1000); + if (s32Ret == EI_ERR_VENC_NOBUF) { + LOG("No buffer\n"); + return -EAGAIN; + } else if (s32Ret != EI_SUCCESS) { + LOG("get stream chn-%d error : %d\n", channel, s32Ret); + return -EAGAIN; + } + + memset(&VencStream, 0, sizeof(VENC_STREAM_S)); + memcpy(&VencStream, &stStream, sizeof(VENC_STREAM_S)); + + if ((VencStream.pstPack.pu8Addr[0] != EI_NULL) && (VencStream.pstPack.u32Len[0] != 0)) { + data_len = VencStream.pstPack.u32Len[0]; + if ((VencStream.pstPack.pu8Addr[1] != EI_NULL) && (VencStream.pstPack.u32Len[1] != 0)) + data_len += VencStream.pstPack.u32Len[1]; + } + + if (pFrameDataBuffer == NULL) { + LOG("pFrameDataBuffer is null\n"); + EI_MI_VENC_ReleaseStream(channel, &stStream); + return -EAGAIN; + } + + *pFrameSize = data_len; + memset(pFrameDataBuffer, 0, frameDataBufferSize); + if (frameDataBufferSize < *pFrameSize) { + LOG("ch:%d data len is to big datalen:%d buflen:%d\n", channel, *pFrameSize, frameDataBufferSize); + EI_MI_VENC_ReleaseStream(channel, &stStream); + return -EAGAIN; + } + + if ((VencStream.pstPack.pu8Addr[0] != EI_NULL) && (VencStream.pstPack.u32Len[0] != 0)) { + memcpy(pFrameDataBuffer, VencStream.pstPack.pu8Addr[0], VencStream.pstPack.u32Len[0]); + if ((VencStream.pstPack.pu8Addr[1] != EI_NULL) && (VencStream.pstPack.u32Len[1] != 0)) + memcpy(pFrameDataBuffer + VencStream.pstPack.u32Len[0], VencStream.pstPack.pu8Addr[1], VencStream.pstPack.u32Len[1]); + } + *pTimestamp = stStream.pstPack.u64PTS; + s32Ret = EI_MI_VENC_ReleaseStream(channel, &stStream); + if (s32Ret != EI_SUCCESS) { + LOG("release stream chn-%d error s32Ret: %d\n", channel, s32Ret); + return -EAGAIN; + } + } + + return 0; +} + +int videoCapturerReleaseStream(VideoCapturerHandle handle) +{ + EI_S32 s32Ret = EI_FAILURE; + + s32Ret = _Sv82xVideoStop(handle); + if (s32Ret != EI_SUCCESS) { + LOG("_Sv82xVideoStop failed with %#x\n", s32Ret); + return -EAGAIN; + } + + return 0; +} + +void videoCapturerDestory(VideoCapturerHandle handle) +{ + EI_S32 s32Ret = EI_FAILURE; + + SV82X_HANDLE_NULL_CHECK_RET_VOID(handle); + SV82X_HANDLE_GET(handle); + + if (Sv82xHandle->status == VID_CAP_STATUS_STREAM_ON) { + s32Ret = videoCapturerReleaseStream(handle); + if (s32Ret != EI_SUCCESS) { + LOG("videoCapturerReleaseStream failed with %#x\n", s32Ret); + return; + } + } + + if (Sv82xHandle->VideoCreatFlag) { + s32Ret = _Sv82xVideoDestory(handle); + if (s32Ret != EI_SUCCESS) { + LOG("_Sv82xVideoDestory failed with %#x\n", s32Ret); + return; + } + } + if (Sv82xHandle->enable) { + s32Ret = _Sv82xIppuStop(handle); + if (s32Ret != EI_SUCCESS) { + LOG("_Sv82xIppuStop failed with %#x\n", s32Ret); + return; + } + } + + s32Ret = _Sv82xVideoBufPoolDestory(handle); + if (s32Ret != EI_SUCCESS) { + LOG("_Sv82xVideoBufPoolDestory failed with %#x\n", s32Ret); + return; + } + VideoAttrs.VideoCreatHandleCnt--; + if (VideoAttrs.IppuEnableCnt == 0) { + s32Ret = SystemDeinit(); + if (s32Ret != EI_SUCCESS) { + LOG("SystemDeinit failed with %#x\n", s32Ret); + return; + } + } + + SystemInitFlag = 0; + + return; +}