Page 1 of 1

luckfox pico ultra w 自己编译的使用ffmpeg的应用程序在librockit.so.0库中段错误

Posted: 2025-01-07 8:33
by lyphotoes
大家好,我打算在购买的luckfox pico ultra w 板子上使用rkmpi api 和ffmpeg api写一个简单的录制摄像头画面保存为mp4的测试程序。程序编译好后放到板上运行总是报段错误,使用gdb调试发现错误的地方在librockit.so.0这个库中,测试发现仅仅简单调用 ffmpeg api

Code: Select all

AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);
就会报错,如下是会报错误的main函数实现:

Code: Select all

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

    RK_S32  ret;
    RK_S32 viId = 0;
    RK_S32 channelId = 0;
    RK_S32 vencId = 0;
    RK_S32 width = 1920;
    RK_S32 height = 1080;
    RK_S32 maxWidth = 1920;
    RK_S32 maxHeight = 1080;
    RK_U32 gopSize = 60;
    RK_U32 dstCodec = 8;// 8:H264, 12:H265
    char * aEntityName = "/dev/video11";
    VI_DEV_ATTR_S stDevAttr;
    VI_DEV_STATUS_S stDevStatus;
    VI_CHN_ATTR_S stChnAttr;
    VI_DEV_BIND_PIPE_S stBindPipe;

    MPP_CHN_S stSrcChn, stDestChn;
    VENC_CHN_ATTR_S stEncAttr;
    VENC_CHN_PARAM_S stEncPara;
    RK_S32 loopCountSet = -1;
    FILE *fp = NULL;
    VENC_STREAM_S stFrame;
    void *pData = RK_NULL;

    memset(&stChnAttr, 0, sizeof stChnAttr);
    stChnAttr.stIspOpt.u32BufCount = 3;
    stChnAttr.stIspOpt.enMemoryType = VI_V4L2_MEMORY_TYPE_DMABUF;
    stChnAttr.stIspOpt.bNoUseLibV4L2 = RK_TRUE;
    stChnAttr.u32Depth = 0;
    stChnAttr.enPixelFormat = RK_FMT_YUV420SP;
    stChnAttr.stFrameRate.s32DstFrameRate = -1;
    stChnAttr.stFrameRate.s32SrcFrameRate = -1;

    stChnAttr.stSize.u32Width = width;
    stChnAttr.stSize.u32Height = height;
    stChnAttr.enCompressMode = COMPRESS_MODE_NONE;
    stChnAttr.stIspOpt.stMaxSize.u32Width = maxWidth;
    stChnAttr.stIspOpt.stMaxSize.u32Height = maxHeight;

    memcpy(stChnAttr.stIspOpt.aEntityName, aEntityName, MAX_VI_ENTITY_NAME_LEN);


    //初始化信号处理函数
    signal(SIGINT, signal_handler);
    signal(SIGPIPE, signal_handler);
    signal(SIGTERM, signal_handler);


    ret = RK_MPI_SYS_Init();
    if (RK_SUCCESS != ret) {
        RK_LOGE("rk mpi sys init failed!");
        goto __FAILED;
    }

    // vi init begin
    ret = RK_MPI_VI_QueryDevStatus(viId, &stDevStatus);
    if (RK_SUCCESS == ret) {
        if(!stDevStatus.bProbeOk){
            RK_LOGE("sensor probe failed!");
            goto __FAILED;
        }
    }

    ret = RK_MPI_VI_GetDevAttr(viId, &stDevAttr);
    if (RK_ERR_VI_NOT_CONFIG == ret) {
        ret = RK_MPI_VI_SetDevAttr(viId, &stDevAttr);

        if (RK_SUCCESS != ret) {
            RK_LOGE("rk mpi vi set dev attr failed 0x%x!",ret);
            goto __FAILED;
        }
    }else{
        RK_LOGE("rk mpi vi set dev attr already!");
    }


    ret = RK_MPI_VI_GetDevIsEnable(viId);
    if (RK_SUCCESS != ret) {
        ret = RK_MPI_VI_EnableDev(viId);
        if (RK_SUCCESS != ret) {
            RK_LOGE("rk mpi vi enable dev failed 0x%x!",ret);
            goto __FAILED;
        }

        stBindPipe.u32Num = 0;
        stBindPipe.PipeId[0] = 0;
        ret = RK_MPI_VI_SetDevBindPipe(viId, &stBindPipe);
        if (ret != RK_SUCCESS) {
            RK_LOGE("rk mpi vi set dev bind pipe failed 0x%x!",ret);
            goto __FAILED;
        }
    }else{
        RK_LOGE("rk mpi vi enable  dev  already!");
    }

    ret = RK_MPI_VI_SetChnAttr(0, channelId, &stChnAttr);

    if (RK_SUCCESS != ret) {
        RK_LOGE("rk mpi vi set chn attr failed 0x%x!",ret);
        goto __FAILED;
    }

    ret = RK_MPI_VI_EnableChn(0, channelId);
    if (RK_SUCCESS != ret) {
        RK_LOGE("rk mpi vi enable chn failed 0x%x!",ret);
        goto __FAILED;
    }

    // vi inited

    // bind
    stSrcChn.enModId = RK_ID_VI;
    stSrcChn.s32ChnId = viId;
    stSrcChn.s32ChnId = channelId;

    // venc chn attr init
    memset(&stEncAttr, 0, sizeof stEncAttr);
    stEncAttr.stVencAttr.enType = dstCodec;
    stEncAttr.stVencAttr.enPixelFormat = stChnAttr.enPixelFormat;
    stEncAttr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;
    stEncAttr.stRcAttr.stH264Cbr.u32BitRate = 3000;
    stEncAttr.stRcAttr.stH264Cbr.u32Gop = gopSize;
    stEncAttr.stVencAttr.u32Profile = 100;
    stEncAttr.stVencAttr.u32MaxPicWidth = maxWidth;
    stEncAttr.stVencAttr.u32MaxPicHeight = maxHeight;
    stEncAttr.stVencAttr.u32PicWidth = width;
    stEncAttr.stVencAttr.u32PicHeight = height;
    stEncAttr.stVencAttr.u32VirWidth = width;
    stEncAttr.stVencAttr.u32VirHeight = height;
    stEncAttr.stVencAttr.u32StreamBufCnt = 5;
    stEncAttr.stVencAttr.u32BufSize = width * height  / 2;
    stEncAttr.stGopAttr.u32MaxLtrCount = 1;

    // venc chn init
    {

        VENC_RECV_PIC_PARAM_S stRecvParam;
        stRecvParam.s32RecvPicNum = loopCountSet;
        printf("create venc\n");
        ret = RK_MPI_VENC_CreateChn(0, &stEncAttr);
        if (ret != RK_SUCCESS) {
            RK_LOGE("rk mpi venc create chn failed 0x%x!\n",ret);
            goto __FAILED;
        }
        ret = RK_MPI_VENC_StartRecvFrame(0, &stRecvParam);
        if (ret != RK_SUCCESS) {
            RK_LOGE("rk mpi venc start recv frame failed 0x%x!\n",ret);
            goto __FAILED;
        }
    }


    stDestChn.enModId = RK_ID_VENC;
    stDestChn.s32DevId = 0;
    stDestChn.s32ChnId = 0;
    ret = RK_MPI_SYS_Bind(&stSrcChn, &stDestChn);
    if (ret != RK_SUCCESS) {
        RK_LOGE("rk mpi sys bind failed 0x%x!\n",ret);
        goto __FAILED;
    }

    stFrame.pstPack = (VENC_PACK_S *) malloc(sizeof(VENC_PACK_S));

    fp = fopen("rockit_output.h264", "w+b");
    char *out_filename = "test.mp4";


    // init ffmpeg

    printf("ffmpeg init\n");

    AVFormatContext * ofmt_ctx = create_mp4_file(out_filename);
    if (!ofmt_ctx) {
        fprintf(stderr, "Could not create output context\n");
        goto __FAILED;
    }

    AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);//引发问题的代码
    if (!codec) {
        fprintf(stderr, "Codec not found.\n");
        avformat_free_context(ofmt_ctx);
        goto __FAILED;
    }

    AVPacket *pkt = av_packet_alloc();

    printf("begin loop\n");
    while (run_) {


        //printf("read ...\n");

        ret = RK_MPI_VENC_GetStream(0, &stFrame,2500);
        if (ret == RK_SUCCESS) {


            pData = RK_MPI_MB_Handle2VirAddr(stFrame.pstPack->pMbBlk);
            if (pData) {
                /* pkt->data = av_malloc(stFrame.pstPack->u32Len); */
                /* if (pkt->data) { */
                /*     int flag = 0; */
                /*     if (stFrame.pstPack->DataType.enH264EType == H264E_NALU_IDRSLICE || stFrame.pstPack->DataType.enH264EType == H264E_NALU_ISLICE || stFrame.pstPack->DataType.enH265EType == H265E_NALU_IDRSLICE || stFrame.pstPack->DataType.enH265EType == H265E_NALU_ISLICE) { */
                /*         flag |= AV_PKT_FLAG_KEY; */
                /*     } */
                /*     memcpy(pkt->data,pData,stFrame.pstPack->u32Len); */
                /*     pkt->size = stFrame.pstPack->u32Len; */
                /*     pkt->pts = stFrame.pstPack->u64PTS; */
                /*     pkt->dts = stFrame.pstPack->u64PTS; */
                /*     pkt->stream_index = 0; */
                /*     pkt->flags |= flag; */

                /*     ret = write_frame(ofmt_ctx, pkt); */
                /*     if (ret < 0) { */
                /*         printf("write frame err!\n"); */
                /*     } */
                /* }else{ */
                /*     fprintf(stderr, "av_malloc failed\n"); */
                /* } */
                fwrite(pData, 1, stFrame.pstPack->u32Len, fp);
                fflush(fp);


            }


            usleep(1 * 1000);
            /* if (pkt->data) { */
            /*     av_freep(&pkt->data); */
            /*     pkt->data = NULL; */
            /* } */

            ret = RK_MPI_VENC_ReleaseStream(0, &stFrame);
            if (ret != RK_SUCCESS) {
                RK_LOGE("RK_MPI_VENC_ReleaseStream fail 0x%x", ret);
            }

        } else {
            RK_LOGE("RK_MPI_VI_GetChnFrame fail 0x%x", ret);
        }
        usleep(10 * 1000);
    }

    //av_write_trailer(ofmt_ctx);

    if(fp)
        fclose(fp);

    if(pkt)
        av_packet_free(&pkt);

    //avcodec_free_context(&codec_ctx);
    //avformat_free_context(ofmt_ctx);


    RK_MPI_SYS_UnBind(&stSrcChn, &stDestChn);

    RK_MPI_VI_DisableChn(viId,channelId );


    RK_MPI_VENC_StopRecvFrame(0);
    RK_MPI_VENC_DestroyChn(0);

    RK_MPI_VI_DisableDev(viId);

    if (stFrame.pstPack) {
        free(stFrame.pstPack);
    }

     return 0;

 __FAILED:
    return -1;
}
补充信息:
[*] 注释掉

Code: Select all

AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);
,程序正常。
[*] 开发环境为官方SDK 编译的 buildroot
[*] FFmpeg库链接的是官方sdk buildroot 中编译好的
有没有人在这个板上做过FFmpeg api 开发,请问这个是问题怎么解决?

Re: luckfox pico ultra w 自己编译的使用ffmpeg的应用程序在librockit.so.0库中段错误

Posted: 2025-01-07 12:43
by Ryand
检查一下传递的参数是否有问题,看到最近一次调用的函数是strlen(),有可能是使用librockit.so 中相关的api时传递了空指针;当然,只是我的猜测,不一定对

Re: luckfox pico ultra w 自己编译的使用ffmpeg的应用程序在librockit.so.0库中段错误

Posted: 2025-01-17 7:48
by lyphotoes
结贴!问题已找到!

Code: Select all

memcpy(stChnAttr.stIspOpt.aEntityName, aEntityName, MAX_VI_ENTITY_NAME_LEN);
上面代码有问题,宏 MAX_VI_ENTITY_NAME_LEN超出了stChnAttr.stIspOpt.aEntityName数组范围,将代码改为:

Code: Select all

memcpy(stChnAttr.stIspOpt.aEntityName, DEV_NAME, strlen(DEV_NAME));
其实这段代码是从rockit 官方 Demo encode_test抄的,居然会因为这句影响整个rockit内部报随机性错误,可见rockit 库写得不够稳健,因此,为方便大家入门 rockit api开发,特将rockit Demo做了精简汇总放在如下gitee仓库https://gitee.com/lyphotoes2022/rockit_test