瑞芯微rv1126 rtsp+mpp+rga取流

本文详细介绍了在瑞芯微芯片上使用RTSP协议配合MPP解码和RGB转换技术,实现1920*1080分辨率视频的高效取流,每帧耗时约60ms,适合实时应用需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

瑞芯微rv1126 rtsp+mpp+rga取流


经过测试,使用rtsp+mpp+rga取流1920*1080图像一帧耗时60ms左右,基本可满足要求

一、mpp解码

void decoder_routine(QImage &img,bool &bOK)
{
    int ret;
    RK_U32 pkt_done = 0;
    // write data to packet
    mpp_packet_write(packet, 0, packet_buffer, packet_wpos);
    // reset pos and set valid length
    mpp_packet_set_pos(packet, packet_buffer);
    mpp_packet_set_length(packet, packet_wpos);
//    printf("packet_wpos = :%d\n",packet_wpos);
    packet_wpos = 0;
    // setup eos flag
    if (pkt_eos)
        mpp_packet_set_eos(packet);

    do {

        RK_S32 times = 5;
        // send the packet first if packet is not done
        if (!pkt_done)
        {
            ret = mpi->decode_put_packet(ctx, packet);
            if (MPP_OK == ret)
                pkt_done = 1;
        }

        // then get all available frame and release
        do {
            RK_S32 get_frm = 0;
            RK_U32 frm_eos = 0;

        try_again:
            ret = mpi->decode_get_frame(ctx, &frame);
            if (MPP_ERR_TIMEOUT == ret) {
                if (times > 0) {
                    times--;
                    msleep(MPP_H264_DECODE_TIMEOUT);
                    goto try_again;
                }
                mpp_err("decode_get_frame failed too much time\n");
            }
            if (MPP_OK != ret) {
                mpp_err("decode_get_frame failed ret %d\n", ret);
                break;
            }

            if (frame) {
                if (mpp_frame_get_info_change(frame))
                {
                    RK_U32 width = mpp_frame_get_width(frame);
                    RK_U32 height = mpp_frame_get_height(frame);
                    RK_U32 hor_stride = mpp_frame_get_hor_stride(frame);
                    RK_U32 ver_stride = mpp_frame_get_ver_stride(frame);

                    mpp_log("decode_get_frame get info changed found\n");
                    mpp_log("decoder require buffer w:h [%d:%d] stride [%d:%d]\n",
                            width, height, hor_stride, ver_stride);

                    ret = mpp_buffer_group_get_internal(&frm_grp,MPP_BUFFER_TYPE_DRM);
                    if (ret) {
                        mpp_err("get mpp buffer group  failed ret %d\n", ret);
                        break;
                    }
                    mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, frm_grp);
                    mpi->control(ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL);

                } else {
                    RK_U32 err_info = mpp_frame_get_errinfo(frame) | mpp_frame_get_discard(frame);
                    if (err_info) {
                        frame_err++;
                        mpp_log("decoder_get_frame get err info:%d discard:%d.\n",
                                mpp_frame_get_errinfo(frame), mpp_frame_get_discard(frame));
                    }
                    else
                    {
                        /** Got a frame */
                        timeval start,end;
                        gettimeofday(&start,NULL);
                        frame_out(img);
                        bOK = true;
                        gettimeofday(&end,NULL);
                        float use_time = 1000*(end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec)/1000;
                        qDebug() << "rgacvt use time ="<< use_time;

                        static timeval last,now;
                        gettimeofday(&now,NULL);
                        float t = 1000*(now.tv_sec - last.tv_sec) + (now.tv_usec - last.tv_usec)/1000;
                        printf("*******time******:%f\n",t);
                        last = now;

                    }
                }
                frm_eos = mpp_frame_get_eos(frame);
                mpp_frame_deinit(&frame);
                frame = NULL;
                get_frm = 1;
            }

            // if last packet is send but last frame is not found continue
            if (pkt_eos && pkt_done && !frm_eos) {
                msleep(MPP_H264_DECODE_TIMEOUT);
                qDebug() << "continue";
                continue;
            }

            if (frm_eos) {
                mpp_log("found last frame\n");
                break;
            }

            if (!get_frm)
                break;
        } while (1);

        if (pkt_done)
            break;

        /*
         * why sleep here:
         * mpi->decode_put_packet will failed when packet in internal queue is
         * full,waiting the package is consumed .
         */
        msleep(MPP_H264_DECODE_TIMEOUT);

    } while (1);
}

void frame_out()
{
//    MppFrameFormat fmt  = mpp_frame_get_fmt(frame);
    MppBuffer buff = mpp_frame_get_buffer(frame);
//    size_t size = mpp_frame_get_buf_size(frame);
    RK_U32 h = mpp_frame_get_height(frame);
    RK_U32 w = mpp_frame_get_width(frame);

    FrameData *framedata = convertdata((char*)mpp_buffer_get_ptr(buff),w,h);

    if(framedata->data == nullptr)
    {
        qDebug() << "frame->data = null";
        return;
    }
}

二、rga转换

char *dst_buf = nullptr;
char *dst_output_buf = nullptr;
char *dst_resize_output_buf = nullptr;

// read frame
struct FrameData *convertdata(char *srcdata,int width, int height)
{

    FrameData * data = new FrameData();

    // rga
    rga_buffer_t 	src;
    rga_buffer_t 	dst;
    rga_buffer_t  dst_output;
    rga_buffer_t  dst_resize_output;


    try {
        // h264 16bit 1920 * 1080 == 1920 * 1088
        int size = 1920 * 1088* 1.5;
        printf("size = %d",size);
        if (size == 3133440 || size == 4177920 )
        {
            src = wrapbuffer_virtualaddr(srcdata, 1920, 1088, RK_FORMAT_YCrCb_420_SP);
            if (dst_buf == NULL)
            {
                dst_buf = (char*)malloc(1920*1088*get_bpp_from_format(DST_FORMAT));
            }
            dst = wrapbuffer_virtualaddr(dst_buf, 1920, 1088, DST_FORMAT);
            if (dst_output_buf == NULL)
            {
                dst_output_buf = (char*)malloc(1920*1080*get_bpp_from_format(DST_FORMAT));
            }
            dst_output = wrapbuffer_virtualaddr(dst_output_buf, 1920, 1080, DST_FORMAT);
            if (dst_resize_output_buf == NULL)
            {
                dst_resize_output_buf = (char*)malloc(width*height*get_bpp_from_format(DST_FORMAT));
            }
            dst_resize_output = wrapbuffer_virtualaddr(dst_resize_output_buf, width, height, DST_FORMAT);

            if(src.width == 0 || dst.width == 0 || dst_output.width == 0)
            {
                printf("%s, %s\n", __FUNCTION__, imStrError());
                // return data;
            }
            else
            {
                imcvtcolor(src, dst, src.format, dst.format);
                im_rect src_rect = {0, 0, 1920, 1080};
                imcrop(dst,dst_output,src_rect);
                imresize(dst_output,dst_resize_output);
                data->width = width;
                data->height = height;
                data->data = dst_resize_output_buf;
                data->size = width*height*get_bpp_from_format(DST_FORMAT);
            }
        }
    }

    catch (...)
    {
        data->isRun = STATUS_DISCONNECT;
        data->size = 0;
        return data;
    }

    return data;

}

### RV1126 RGA RGB通道顺序颠倒解决方案 对于RK1126设备上遇到的RGB颜色通道顺序错误问题,可以采以下措施来修正这一现象。通常情况下,这种问题是由于在处理图像数据时未正确指定或转换色彩空间所引起的。 #### 修改RGA属性配置 当创建RGA通道并设置其属性时,确保指定了正确的像素格式以及相应的字节序。如果当前使用的默认配置导致了RGB通道顺序异常,则应调整`stRgaAttr_01`结构体中的成员变量以匹配实际需求[^3]: ```c // 初始化RGA属性结构体 memset(&stRgaAttr_01, 0, sizeof(RGA_ATTR_S)); /* 设置源图层 */ stSrcRect.enPixelFormat = RK_FMT_RGB888; // 假设原始图片为RGB888格式 ... /* 设置目标图层 */ stDstRect.enPixelFormat = RK_FMT_YUV420SP; // 如果最终目的是NV12则采用此格式 ... ret = RK_MPI_RGA_CreateChn(0, &stRgaAttr_01); if (ret != RK_SUCCESS) { printf("Failed to create RGA channel\n"); } ``` 注意,在上述代码片段中,通过设定`enPixelFormat`字段可控制输入输出端口的颜色编码方式。这里假设原图为标准BGR排列(即OpenCV库常用的形式),而目的则是将其转化为适合后续处理程所需的YUV/YCbCr形式之一——具体来说就是NV12格式。 #### 调整RGB到NV12转换逻辑 考虑到可能存在从RGB至其他格式间的变换过程,应当仔细审查这部分实现细节。依据先前提到的一个在线资源提供了关于如何执行此类操作的具体指导[^1]。下面给出了一种可能的方法用于完成这个任务,并且特别关注于保持正确的颜色分量次序: ```cpp void rgb_to_nv12(const unsigned char* srcRgbData, int width, int height, unsigned char*& dstNv12Data) { const size_t frameSize = width * height; const size_t yStride = ALIGN(width, 16); // 对齐宽度以满足硬件要求 const size_t uvStride = ALIGN(width / 2, 16); // 分配足够的内存存储转换后的结果 dstNv12Data = new unsigned char[frameSize + (frameSize >> 2)]; // 预留空间给Y平面 memset(dstNv12Data, 0, frameSize); // 计算U/V平面对应位置 auto pYPlane = reinterpret_cast<uint8_t*>(dstNv12Data); auto pUVPlane = pYPlane + frameSize; for(int i=0;i<height;++i){ for(int j=0;j<width;++j){ uint8_t r = *(srcRgbData++); uint8_t g = *(srcRgbData++); uint8_t b = *(srcRgbData++); // 将RGB值映射成对应的Y/U/V亮度/色度分量 float Y = .299f*r + .587f*g + .114f*b; float U = -.1687f*r - .3313f*g + .5f*b + 128.f; float V = .5f*r - .4187f*g - .0813f*b + 128.f; // 存储计算得到的结果 pYPlane[i*yStride+j]=(uint8_t)(std::min(std::max(Y,0.),255.)); if((i%2==0)&&(j%2==0)){ pUVPlane[(i>>1)*uvStride+(j>>1)]=(uint8_t)((int(U)&0xFF)|(int(V)<<8)); } } } } ``` 该函数接收指向连续RGB三元组数组的指针作为输入参数,并返回一个新分配的缓冲区地址,其中包含了按照NV12布局组织的数据。值得注意的是,为了提高效率和兼容性,这段程序还考虑到了某些特定平台上的缓存线对齐约束条件。
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值