k230边录视频边显示,无法获取编码数据

Viewed 82

问题描述


使用01Studio K230mini, 我有一个很简单的需求,边录视频边显示,请问应该用什么方法来实现呢?

已经尝试的方法:

  1. 直接使用 MP4Container 来采集,好像没办法实时显示吧,还是我的使用方式不对?

  2. 使用 VENC 例程2 https://www.kendryte.com/k230_canmv/zh/main/zh/api/mpp/K230_CanMV_VENC%E6%A8%A1%E5%9D%97API%E6%89%8B%E5%86%8C.html#stream-type

遇到的问题有:

1) 把 yuv420sp_img 复制一份并转换成显示需要的 RGB565 格式, 但是使用转换图片格式转换方法

	img2 = yuv420sp_img.to_rgb565(copy=True)

	一直失败,经过查看得知支持的图像格式 没有YUV420SP, 难道是这个原因?
	
	
2) 把采集和编码的数据格式都改成  RGB565 , 碰到的问题 

	encoder.GetStream(venc_chn, streamData)   无法获取到编码数据, 可能是输入的数据有问题,请问应该如何改?

===============================================================================================================

def stream_venc_test(file_name,width=1280, height=720):
print("venc_test start")
venc_chn = VENC_CHN_ID_0
width = ALIGN_UP(width, 16)
venc_payload_type = K_PT_H264

# 判断文件类型
suffix = file_name.split('.')[-1]
if suffix == '264':
    venc_payload_type = K_PT_H264
elif suffix == '265':
    venc_payload_type = K_PT_H265
else:
    print("Unknown file extension")
    return

# 初始化sensor
sensor = Sensor(id=0)
sensor.reset()
# 设置camera 输出buffer
# set chn0 output size
sensor.set_framesize(width = width, height = height, alignment=12)
# set chn0 output format
sensor.set_pixformat(Sensor.RGB565)

Display.init(Display.ST7701, width=g_display_width, height=g_display_height, osd_num=2, to_ide=False)  # 启用IDE显示功能 / Enable IDE display function


# 实例化video encoder
encoder = Encoder()
# 设置video encoder 输出buffer
encoder.SetOutBufs(venc_chn, 8, width, height)

# init media manager
MediaManager.init()

if (venc_payload_type == K_PT_H264):
    chnAttr = ChnAttrStr(encoder.PAYLOAD_TYPE_H264, encoder.H264_PROFILE_MAIN, width, height)
elif (venc_payload_type == K_PT_H265):
    chnAttr = ChnAttrStr(encoder.PAYLOAD_TYPE_H265, encoder.H265_PROFILE_MAIN, width, height)

streamData = StreamData()

# 创建编码器
encoder.Create(venc_chn, chnAttr)

# 开始编码
encoder.Start(venc_chn)
# 启动camera
sensor.run()

frame_count = 0
print("save stream to file: ", file_name)

yuv420sp_img = None
frame_info = k_video_frame_info()
with open(file_name, "wb") as fo:
    try:
        while True:
            os.exitpoint()
            yuv420sp_img = sensor.snapshot(chn=CAM_CHN_ID_0)
            if (yuv420sp_img == -1):
                print("yuv420sp_img error")
                continue


            show_img = image.Image(g_display_width, g_display_height, image.RGB565)
            #print("create show_image success")
            #img2 = image.Image(g_image_width, g_image_height, image.RGB565)
            #print("create img2 success")
            #img2 = yuv420sp_img.to_rgb565(copy=True)
            #print("convert show_image success")
            show_img.draw_image(yuv420sp_img, 0, 0, g_display_width / g_image_width, g_display_height / g_image_height)
            print("draw show_image success")
            Display.show_image(show_img, 0, 0, Display.LAYER_OSD1, 150)
            print("display show_image success")

            frame_info.v_frame.width = yuv420sp_img.width()
            frame_info.v_frame.height = yuv420sp_img.height()
            frame_info.v_frame.pixel_format = Sensor.RGB565
            frame_info.pool_id = yuv420sp_img.poolid()
            frame_info.v_frame.phys_addr[0] = yuv420sp_img.phyaddr()
            #frame_info.v_frame.phys_addr[1] = yuv420sp_img.phyaddr(1)
            if (yuv420sp_img.width() == 800 and yuv420sp_img.height() == 480):
                frame_info.v_frame.phys_addr[1] = frame_info.v_frame.phys_addr[0] + frame_info.v_frame.width*frame_info.v_frame.height + 1024
            elif (yuv420sp_img.width() == 1920 and yuv420sp_img.height() == 1080):
                frame_info.v_frame.phys_addr[1] = frame_info.v_frame.phys_addr[0] + frame_info.v_frame.width*frame_info.v_frame.height + 3072
            elif (yuv420sp_img.width() == 640 and yuv420sp_img.height() == 360):
                frame_info.v_frame.phys_addr[1] = frame_info.v_frame.phys_addr[0] + frame_info.v_frame.width*frame_info.v_frame.height + 3072
            else:
                frame_info.v_frame.phys_addr[1] = frame_info.v_frame.phys_addr[0] + frame_info.v_frame.width*frame_info.v_frame.height


            encoder.SendFrame(venc_chn,frame_info)
            print("encoder sendframe success")
            encoder.GetStream(venc_chn, streamData) # 无法获取编码数据
            print("encoder getStream success")

            for pack_idx in range(0, streamData.pack_cnt):
                stream_data = uctypes.bytearray_at(streamData.data[pack_idx], streamData.data_size[pack_idx])
                fo.write(stream_data) # 码流写文件
                print("stream size: ", streamData.data_size[pack_idx], "stream type: ", streamData.stream_type[pack_idx])

            encoder.ReleaseStream(venc_chn, streamData) # 释放一帧码流

            frame_count += 1
            print("frame_count = ", frame_count)
            if frame_count >= 200:
                break
    except KeyboardInterrupt as e:
        print("user stop: ", e)
    except BaseException as e:
        import sys
        sys.print_exception(e)

gc.collect()
# 停止camera
sensor.stop()
# 停止编码
encoder.Stop(venc_chn)
# 销毁编码器
encoder.Destroy(venc_chn)

Display.deinit()
# 清理buffer
MediaManager.deinit()
print("venc_test stop")

硬件板卡


01Studio K230mini

软件版本


CanMV_K230_01Studio_micropython_v1.4-16-g3a2aed8_nncase_v2.9.0.img

硬件板卡


01Studio K230mini

软件版本


CanMV_K230_01Studio_micropython_v1.4-16-g3a2aed8_nncase_v2.9.0.img

1 Answers

获取摄像头两路通道数据流,一路用于画面显示,一路送入编码器编码,两路均采用绑定模式;图像格式支持按通道独立配置,可根据需求为不同通道设置不同格式。