多媒体框架

支持的芯片:[RTL8735C]

概述

SDK 提供轻量化的 多媒体框架 (MMF),用于让音频与视频 pipeline 的开发更模块化、更直观。每个功能组件,包括 video capture、audio capture、H.264/HEVC encoding、AAC encoding/decoding、RTSP streaming、USB UVC output、MP4 recording 以及 neural network inference,都会以独立 module 的形式实现。开发者可通过打开所需 module、配置参数,并使用 linker 将 module 连接起来,建立完整 pipeline。

这种模块化设计具备以下优点:

  • 每个 module 都可以独立开发、测试与替换。

  • 不同复杂度的 pipeline 都使用相同的 API pattern 建立。

  • 若要替换输出目标(例如从 RTSP 改为 UVC,或从 RTSP 改为 MP4),通常只需要改变 module 之间的连接方式。

  • 若要将 NN inference 加入既有 pipeline,只需打开 VIPNN module,并将其插入数据路径。

MMF 运行在 FreeRTOS 上,并采用 producer-consumer model:module 会将处理后的 frame 放入 output queue,linker task 再从 queue 中取出 frame,并推送到下一个 module 的 input。因此,module 之间的数据传递是异步且 thread-safe 的。

视频管线架构

在 video 应用中,平台内部会使用两个 core。AP core (CA32) 运行用户侧 media application,例如 RTSP、UVC、MP4 recording 或 NN 示例。VP core (KM4) 运行 Realtek 提供的 video firmware,负责 camera、ISP、encoder 与 video frame export path。

从应用开发者的角度来看,AP 侧的 video_module 是主要接口。开发者在 AP 侧配置 stream 参数、打开 MMF module,并使用 linker 将 module 连接起来。底层 ISP 与 encoder driver 流程则由 VP firmware 处理。

AP 内部会将 video control command 发送到 VP,VP 再将产生的 frame 推回 AP 侧 MMF pipeline。多数应用不需要直接调用 IPC API。

../../_images/multimedia_pro_mmf_video_pipeline_ap_vp.drawio.svg

备注

应用开发者只需要专注于 AP 侧应用开发。IPC 机制与 VP 侧 firmware 由 Realtek 提供。本图仅用于帮助用户理解整体 video 架构。

框架架构

下图说明典型 pipeline 中的数据流向:

┌─────────────┐   mm_queue_item_t   ┌──────────────┐   mm_queue_item_t   ┌──────────────┐
│   Module A  │ ──────────────────> │    Linker    │ ──────────────────> │   Module B   │
│  (Producer) │                     │  (SISO/MIMO) │                     │  (Consumer)  │
└─────────────┘                     └──────────────┘                     └──────────────┘

每个 module 都维护自己的 internal output queue。当 module 完成一帧数据处理后,会将对应的 mm_queue_item_t 放入 output queue。linker task 会持续从 queue 中取出 item,并转发到 pipeline 中的下一个 module。Frame buffer 会由 framework 内部回收,因此应用程序不需要自行管理 buffer lifetime。

关键概念

模块 (``mm_module_t``)

模块由 mm_module_t 结构定义,是独立的处理单元。它提供标准接口:create、destroy、control 与 handle。可用模块 章节列出所有 module 及其用途。

模块上下文 (``mm_context_t``)

调用 mm_module_open() 会分配并返回 mm_context_t handle。该 opaque handle 会保存 module 的内部状态、queue pair,以及指向 private instance data 的指针。后续所有配置与连接操作都会使用这个 handle。

mm_context_t *ctx = mm_module_open(&video_module);

队列项 (``mm_queue_item_t``)

模块之间会以 mm_queue_item_t item 的形式传递数据。对应用开发者最重要的字段如下:

字段

说明

data_addr

指向 frame payload 的指针(encoded bitstream、 raw PCM 等)

size

Payload size,单位为 byte

type

Codec 或数据类型(AV_CODEC_ID_H264AV_CODEC_ID_RGB888 等)

timestamp

Frame timestamp,单位为 ms

flag

Allocation mode:MMQI_FLAG_STATICMMQI_FLAG_DYNAMIC

STATIC 与 DYNAMIC 分配模式

初始化 module queue(MM_CMD_INIT_QUEUE_ITEMS)时,需要在两种 allocation mode 中选择一种:

  • MMQI_FLAG_STATIC:所有 queue item buffer 会在启动时一次性预分配。Buffer size 固定。适合 audio(frame size 固定,latency 可预测)。

  • MMQI_FLAG_DYNAMIC:buffer 会依照需求从 heap 动态分配。适合 frame size 会逐帧变化的 video stream(例如压缩后的 H.264)。弹性较高,但会使用 heap memory。

一般建议:audio module 使用 MMQI_FLAG_STATIC,video module 使用 MMQI_FLAG_DYNAMIC

链接器 (Linker)

Linker 是一个 FreeRTOS task,会持续从一个 module 的 output queue 读取 item,并推送到下一个 module 的 input。可用的 linker topology 有四种:

类型

Topology

典型用途

SISO

1 input -> 1 output

单一 stream 片段

MIMO

最多 4 inputs -> 最多 4 outputs (可为每个 output 指定 dependency mask)

从共用 source 同时进行 A/V recording 与 streaming

MISO

Multiple inputs -> 1 output

Audio mixing

SIMO

1 input -> multiple outputs

将一个 stream 复制给多个 consumer

模块生命周期

所有 module 都遵循相同的初始化顺序:

// 1. Open the module — returns a context handle
mm_context_t *ctx = mm_module_open(&xxx_module);
if (!ctx) goto error;

// 2. Configure parameters
mm_module_ctrl(ctx, CMD_XXX_GET_PARAMS, (int)&params);  // read defaults (optional)
params.field = value;
mm_module_ctrl(ctx, CMD_XXX_SET_PARAMS, (int)&params);

// 3. Set queue depth and allocate queue items
mm_module_ctrl(ctx, MM_CMD_SET_QUEUE_LEN, 6);
mm_module_ctrl(ctx, MM_CMD_INIT_QUEUE_ITEMS, MMQI_FLAG_STATIC);  // or MMQI_FLAG_DYNAMIC

// 4. Apply (start the module)
mm_module_ctrl(ctx, CMD_XXX_APPLY, 0);

标准 control command (所有 module 都可接受):

Command

说明

MM_CMD_SET_QUEUE_LEN

设置 queue depth(item 数量)

MM_CMD_INIT_QUEUE_ITEMS

分配 queue item(arg: MMQI_FLAG_STATICMMQI_FLAG_DYNAMIC

MM_CMD_CLEAR_QUEUE_ITEMS

清除 queued item

Queue depth 建议

  • Video module(encoded output):60 个 item,搭配 MMQI_FLAG_DYNAMIC

  • Audio module:6 个 item,搭配 MMQI_FLAG_STATIC

  • NN / post-processing:6 个 item,搭配 MMQI_FLAG_DYNAMIC

较深的 video queue 可吸收 encoder 的 burst output,并在 downstream module 短时间忙碌时避免 frame drop。

Teardown 顺序

请务必先拆除 linker,再关闭 module:

// 1. Stop and delete linkers first
siso_stop(siso);
siso_delete(siso);

// 2. Then close modules
mm_module_close(ctx);

如果 module 已关闭但 linker 仍在运行,linker task 会访问已释放的 memory。

Linker API

SISO

SISO 用于连接一个 module output 到一个 module input。每个 SISO instance 会建立一个 FreeRTOS task。

mm_siso_t *siso = siso_create();

siso_ctrl(siso, MMIC_CMD_ADD_INPUT,  (uint32_t)src_ctx,  0);
siso_ctrl(siso, MMIC_CMD_ADD_OUTPUT, (uint32_t)dst_ctx,  0);

// Optional tuning
siso_ctrl(siso, MMIC_CMD_SET_STACKSIZE,    32 * 1024, 0);  // stack size in bytes
siso_ctrl(siso, MMIC_CMD_SET_TASKPRIORITY, 3,         0);  // FreeRTOS priority

siso_start(siso);

其他 SISO 操作:

siso_pause(siso);    // temporarily halt data flow
siso_resume(siso);   // resume
siso_stop(siso);     // stop the task
siso_delete(siso);   // free all resources

MIMO

MIMO 用于连接多个 input 到多个 output。每个 output 会建立自己的 FreeRTOS task,output_dep bitmask 用于控制某个 output task 在转发数据前,需要等待哪些 input 已就绪。单一 MIMO instance 因此可同时处理来自三个共用 input source 的 MP4 recording(V1 + audio)与 RTSP streaming(V2 + audio)。

mm_mimo_t *mimo = mimo_create();

mimo_ctrl(mimo, MMIC_CMD_ADD_INPUT0, (uint32_t)video_v1_ctx, 0);  // input 0: V1 stream
mimo_ctrl(mimo, MMIC_CMD_ADD_INPUT1, (uint32_t)video_v2_ctx, 0);  // input 1: V2 stream
mimo_ctrl(mimo, MMIC_CMD_ADD_INPUT2, (uint32_t)aac_ctx,      0);  // input 2: audio

// Output 0 (MP4): waits for V1 and audio to both be ready
mimo_ctrl(mimo, MMIC_CMD_ADD_OUTPUT0, (uint32_t)mp4_ctx,
          MMIC_DEP_INPUT0 | MMIC_DEP_INPUT2);

// Output 1 (RTSP): waits for V2 and audio to both be ready
mimo_ctrl(mimo, MMIC_CMD_ADD_OUTPUT1, (uint32_t)rtsp_ctx,
          MMIC_DEP_INPUT1 | MMIC_DEP_INPUT2);

mimo_start(mimo);

Dependency bitmask 常量:

常量

Bit

MMIC_DEP_INPUT0

0x01

MMIC_DEP_INPUT1

0x02

MMIC_DEP_INPUT2

0x04

MMIC_DEP_INPUT3

0x08

MIMO 支持选择性 pause 与 resume:

mimo_pause(mimo, pause_mask);  // pause specific inputs or outputs
mimo_resume(mimo);             // resume all outputs

MISO

MISO (Multiple Input, Single Output) 会从多个 source 收集 frame,并送入一个 downstream module。典型用途是 audio mixing,也就是在编码前混合多个 PCM source。

mm_miso_t *miso = miso_create();
miso_ctrl(miso, MMIC_CMD_ADD_INPUT0, (uint32_t)audio_ctx_a, 0);
miso_ctrl(miso, MMIC_CMD_ADD_INPUT1, (uint32_t)audio_ctx_b, 0);
miso_ctrl(miso, MMIC_CMD_ADD_OUTPUT, (uint32_t)aac_ctx,     0);
miso_start(miso);

SIMO

SIMO (Single Input, Multiple Output) 会将一个 module 的输出送给多个 downstream consumer。Framework 会自动处理 buffer sharing 与 recycling;应用程序只需要照常连接 module 并启动 linker。

mm_simo_t *simo = simo_create();
simo_ctrl(simo, MMIC_CMD_ADD_INPUT,   (uint32_t)video_v1_ctx, 0);
simo_ctrl(simo, MMIC_CMD_ADD_OUTPUT0, (uint32_t)rtsp_ctx,     0);
simo_ctrl(simo, MMIC_CMD_ADD_OUTPUT1, (uint32_t)uvcd_ctx,     0);
simo_start(simo);

常用 linker control command

Command

说明

MMIC_CMD_ADD_INPUT[0-3]

连接 port N 上的 input module

MMIC_CMD_ADD_OUTPUT[0-3]

连接 port N 上的 output module

MMIC_CMD_SET_STACKSIZE

FreeRTOS task stack size(byte)

MMIC_CMD_SET_TASKPRIORITY

FreeRTOS task priority

MMIC_CMD_SET_CTRL_TIMEOUT

Control command timeout(ms)

Stack size 参考值

Linker task 的 stack 必须足以容纳 downstream module 的 handler。如果 stack 太小,FreeRTOS 会发生 stack-overflow 并复位系统。

场景

建议大小

Simple pass-through(mux/demux)

8 - 16 KB

Video encoding(H.264 / HEVC)

32 KB

Audio encoding(AAC)

44 KB

NN inference(VIPNN)

32 - 64 KB

任务优先级建议

Linker task 的默认 priority 为 1``(``tskIDLE_PRIORITY + 1)。可依照系统调度需求调整 priority。请勿将 linker task priority 提高到 5 以上,因为过高的 priority 可能会阻塞 ISP 与 encoder driver task,造成 frame drop。

可用模块

AP 侧 multimedia framework 提供以下 module:

模块

头文件

说明

video_module

module_video.h

Video capture 与 encoding(H.264 / HEVC / JPEG / RGB)

audio_module

module_audio.h

通过 AMIC / DMIC / DAC 进行 audio capture 与 playback

aac_module

module_aac.h

AAC audio encoder

aad_module

module_aad.h

AAC audio decoder(用于 playback)

rtp_module

module_rtp.h

RTP audio receiver(用于 two-way audio)

rtsp2_module

module_rtsp2.h

通过网络进行 live audio/video streaming 的 RTSP server

uvcd_module

module_uvcd.h

USB UVC device,将 video stream 输出到 USB host

mp4_module

module_mp4.h

用于 SD card recording 的 MP4 file muxer

vipnn_module

module_vipnn.h

VIP neural network inference(object / face detection)

facerecog_module

module_facerecog.h

Face recognition:比较 MobileFaceNet embedding 与已保存的 identity database

array_module

module_array.h

用于 offline testing 的 synthetic data source(不需要 ISP)

filesaver_module

module_filesaver.h

通用 file saver

关键 module 参数会在各自的使用指南中说明。以下章节概述最重要的配置点。

video_module

video_module 封装 ISP 与 hardware encoder。依照 format 字段设置,它可输出 raw(RGB / NV12)或 compressed(H.264 / HEVC / JPEG)数据。

ISP 最多支持 5 个同时输出的 channel。每个 video_module instance 会占用一个 channel,并由 stream_id 参数选择:

Channel

典型格式

典型用途

V1

H.264 或 HEVC,高分辨率

Recording (MP4) 或主要 RTSP stream

V2

H.264,中分辨率

第二路 RTSP stream 或 UVC

V3

H.264 或 JPEG,低分辨率

Thumbnail、snapshot

V4

JPEG

Still capture

V5

RGB888 或 NV12

Neural network inference input

V5 较特殊:hardware encoder 会被 bypass,raw RGB 或 NV12 frame 会直接传给 downstream module,通常是 vipnn_module

video_params_t video_params = {
    .stream_id = V1_STREAM_ID,       // 0–4, selects the ISP output channel
    .format    = VIDEO_H264,         // VIDEO_HEVC, VIDEO_JPEG, VIDEO_RGB, VIDEO_NV12
    .width     = 1920,
    .height    = 1080,
    .fps       = 30,
    .gop       = 30,                 // keyframe interval (frames)
    .bps       = 2000000,            // target bitrate in bps
    .rc_mode   = ENC_VBR,            // ENC_VBR, ENC_CBR, ENC_ABR
};
mm_module_ctrl(video_ctx, CMD_VIDEO_SET_PARAMS, (int)&video_params);
mm_module_ctrl(video_ctx, MM_CMD_SET_QUEUE_LEN, 60);
mm_module_ctrl(video_ctx, MM_CMD_INIT_QUEUE_ITEMS, MMQI_FLAG_DYNAMIC);
mm_module_ctrl(video_ctx, CMD_VIDEO_APPLY, 0);

Runtime 调整:module 运行后,可在不重启 pipeline 的情况下动态修改 bitrate 与 frame rate:

mm_module_ctrl(video_ctx, CMD_VIDEO_BITRATE, 1500000);  // change target bitrate (bps)
mm_module_ctrl(video_ctx, CMD_VIDEO_FPS,     20);       // change frame rate

强制 keyframe:当新的 RTSP client 连接时,可调用此 command,让 client 不必等待下一次自然产生的 keyframe 即可开始解码:

mm_module_ctrl(video_ctx, CMD_VIDEO_FORCE_IFRAME, 0);

audio_module

audio_module 在同一个 module instance 中同时处理 capture(microphone)与 playback(DAC)路径。

audio_params_t audio_params;
mm_module_ctrl(audio_ctx, CMD_AUDIO_GET_PARAMS, (int)&audio_params);  // read defaults
audio_params.sample_rate    = ASR_16KHZ;    // ASR_8KHZ, ASR_16KHZ, ASR_48KHZ
audio_params.channel        = 1;
audio_params.use_mic_type   = USE_AUDIO_AMIC;  // or DMIC_LEFT, DMIC_RIGHT
audio_params.mic_gain       = MIC_20DB;
audio_params.enable_record  = 1;
audio_params.avsync_en      = 1;            // enable A/V sync timestamps (required for MP4)
mm_module_ctrl(audio_ctx, CMD_AUDIO_SET_PARAMS, (int)&audio_params);
mm_module_ctrl(audio_ctx, MM_CMD_SET_QUEUE_LEN, 6);
mm_module_ctrl(audio_ctx, MM_CMD_INIT_QUEUE_ITEMS, MMQI_FLAG_STATIC);
mm_module_ctrl(audio_ctx, CMD_AUDIO_APPLY, 0);

备注

当 audio 会与 video 在 MIMO pipeline 中组合时(MP4 recording、A/V RTSP),请设置 avsync_en = 1。此设置会为每个 audio frame 启用硬件对齐的 timestamp,使 muxer 能正确同步 audio 与 video。若未启用,MP4 文件可能出现 audio/video drift。

aac_module

aac_module 会将 PCM audio 编码为 AAC。设置参数后必须显式初始化 memory pool。

aac_params_t aac_params = {
    .trans_type  = AAC_TYPE_ADTS,   // AAC_TYPE_RAW or AAC_TYPE_ADTS
    .object_type = AAC_AOT_LC,
    .sample_rate = 16000,
    .channel     = 1,
    .bitrate     = 32000,
};
mm_module_ctrl(aac_ctx, CMD_AAC_SET_PARAMS, (int)&aac_params);
mm_module_ctrl(aac_ctx, CMD_AAC_INIT_MEM_POOL, 0);  // must call after SET_PARAMS
mm_module_ctrl(aac_ctx, MM_CMD_SET_QUEUE_LEN, 6);
mm_module_ctrl(aac_ctx, MM_CMD_INIT_QUEUE_ITEMS, MMQI_FLAG_DYNAMIC);
mm_module_ctrl(aac_ctx, CMD_AAC_APPLY, 0);

备注

连接 audio_module -> aac_module 的 SISO linker 必须设置较大的 stack size(44 KB),因为 AAC encoder 会在 linker task context 中运行。

siso_ctrl(siso_audio_aac, MMIC_CMD_SET_STACKSIZE, 44 * 1024, 0);

rtsp2_module

rtsp2_module 通过 RTSP 输出 video 与 audio。Video stream 与 audio stream 会使用 CMD_RTSP2_SELECT_STREAM 分别配置。

// Configure video stream (stream 0)
rtsp2_params_t rtsp2_v = {
    .type = AVMEDIA_TYPE_VIDEO,
    .u.v  = { .codec_id = AV_CODEC_ID_H264, .fps = 30 },
};
mm_module_ctrl(rtsp_ctx, CMD_RTSP2_SELECT_STREAM, 0);
mm_module_ctrl(rtsp_ctx, CMD_RTSP2_SET_PARAMS, (int)&rtsp2_v);
mm_module_ctrl(rtsp_ctx, CMD_RTSP2_SET_APPLY, 0);

// Configure audio stream (stream 1)
rtsp2_params_t rtsp2_a = {
    .type = AVMEDIA_TYPE_AUDIO,
    .u.a  = { .codec_id = AV_CODEC_ID_MP4A_LATM, .channel = 1, .samplerate = 16000 },
};
mm_module_ctrl(rtsp_ctx, CMD_RTSP2_SELECT_STREAM, 1);
mm_module_ctrl(rtsp_ctx, CMD_RTSP2_SET_PARAMS, (int)&rtsp2_a);
mm_module_ctrl(rtsp_ctx, CMD_RTSP2_SET_APPLY, 0);

mm_module_ctrl(rtsp_ctx, CMD_RTSP2_SET_STREAMMING, ON);

mp4_module

mp4_module 会将 video 与 audio mux 成 MP4 文件并写入 SD card。发出 CMD_MP4_START 后开始 recording。

mp4_params_t mp4_params = {
    .fps              = 30,
    .gop              = 30,
    .width            = 1920,
    .height           = 1080,
    .sample_rate      = 16000,
    .channel          = 1,
    .record_length    = 60,         // seconds per file
    .record_file_num  = 5,
    .record_type      = STORAGE_ALL,  // video + audio
    .record_file_name = "mmc:/test",
    .fatfs_buf_size   = 32 * 1024,
};
mm_module_ctrl(mp4_ctx, CMD_MP4_SET_PARAMS, (int)&mp4_params);
mm_module_ctrl(mp4_ctx, CMD_MP4_LOOP_MODE, 0);
mm_module_ctrl(mp4_ctx, CMD_MP4_START, mp4_params.record_file_num);

vipnn_module

vipnn_module 会在 NPU 上执行 neural network inference。完整说明请参考 NN 使用指南。与 multimedia pipeline 整合时,关键是通过 CMD_VIPNN_SET_DISPPOST 注册 result callback:

static nn_data_param_t nn_input_params = {
    .img = {
        .width  = NN_WIDTH,   // incoming RGB/NV12 frame width
        .height = NN_HEIGHT,  // incoming RGB/NV12 frame height
    },
    .codec_type = AV_CODEC_ID_RGB888,
};

mm_module_ctrl(vipnn_ctx, CMD_VIPNN_SET_MODEL,           (int)&NN_MODEL_OBJ);
mm_module_ctrl(vipnn_ctx, CMD_VIPNN_SET_MODEL_FILE_NAME, (int)"vfs:/model.nb");
mm_module_ctrl(vipnn_ctx, CMD_VIPNN_SET_IN_PARAMS,       (int)&nn_input_params);
mm_module_ctrl(vipnn_ctx, CMD_VIPNN_SET_DISPPOST,        (int)nn_display_cb);
mm_module_ctrl(vipnn_ctx, CMD_VIPNN_SET_RES_SIZE,        sizeof(objdetect_res_t));
mm_module_ctrl(vipnn_ctx, CMD_VIPNN_SET_RES_MAX_zhT,     32);
mm_module_ctrl(vipnn_ctx, CMD_VIPNN_APPLY, 0);

nn_data_param_t.img.widthheight 描述 VIPNN 实际收到的 frame。近期 SDK 示例使用完整 frame 作为 NN input;此结构中不再配置 per-frame ROI。

array_module

array_module 会将预先加载的 binary buffer 当作 video 或 audio source 重放。此 module 适合在没有 camera 或 microphone 的情况下做 offline testing。Buffer 是编译时加载到 memory 中的 raw encoded stream(例如 H.264 或 RGB frame)。

array_params_t array_params = {
    .type     = AVMEDIA_TYPE_VIDEO,
    .codec_id = AV_CODEC_ID_RGB888,
    .fps      = 15,
    .loop_en  = 1,
    .u        = { .v = { .width = 416, .height = 416 } },
};
mm_module_ctrl(array_ctx, CMD_ARRAY_SET_PARAMS, (int)&array_params);
mm_module_ctrl(array_ctx, MM_CMD_SET_QUEUE_LEN, 6);
mm_module_ctrl(array_ctx, MM_CMD_INIT_QUEUE_ITEMS, MMQI_FLAG_DYNAMIC);
mm_module_ctrl(array_ctx, CMD_ARRAY_APPLY, 0);
mm_module_ctrl(array_ctx, CMD_ARRAY_STREAMING, 1);  // start playback

Pipeline 示例

以下图示说明常见的 pipeline topology。各示例的完整 source code、build 说明与 compile-time option,请参考 视频使用指南

示例 1:单一 stream — V1 -> RTSP

这是最小且实用的 pipeline:单一路 H.264 channel 通过 RTSP live streaming 输出。若刚开始使用 MMF,建议从此示例开始。

[video_module V1: H.264 1920×1080 @ 30fps] ──SISO──> [rtsp2_module]

示例 2:NN inference — array -> VIPNN

不使用 camera 的 offline model verification。Synthetic image buffer 会通过 SISO linker 将 test frame 送入 NPU。此方式适合在连接 live ISP channel 前验证 model integration。

[array_module (RGB test image)] ──SISO──> [vipnn_module]
                                                |
                                         nn_display_cb()

示例 3:双 stream — V1 RTSP + V5 face detection

两个独立的 SISO pipeline 同时共享 ISP。V1 编码 H.264 并用于 RTSP streaming;V5 输出 raw RGB frame 到 face detection model。两个 pipeline 可使用不同 frame rate,且彼此不会互相干扰。

[video_module V1: H.264 1920×1080 @ 30fps] ──SISO──> [rtsp2_module]
[video_module V5: RGB   576×320  @ 15fps ] ──SISO──> [vipnn_module]
                                                           |
                                                    nn_display_cb()

示例 4:完整 A/V — MP4 recording + RTSP + NN

三个 video channel、AAC-encoded audio、MP4 file recording、RTSP live streaming 与 YOLO object detection 可通过 MIMO linker 同时运行。

                                       ┌──MIMO──> [mp4_module]   (V1 + AAC)
[video_module V1: HEVC 1920×1080] ──┐  │
[video_module V2: H264  1280×720] ──┼──┤
[audio_module] ─SISO─> [aac_module]─┘  └──MIMO──> [rtsp2_module] (V2 + AAC)

[video_module V5: RGB 416×416] ──SISO──> [vipnn_module]
                                               |
                                        nn_display_cb()

MIMO linker 有 3 个 input 与 2 个 output。每个 output 都会通过 bitmask 指定其依赖的 input(请参考 Linker API -> MIMO):

  • Output 0 (MP4):MMIC_DEP_INPUT0 | MMIC_DEP_INPUT2 — V1 + AAC

  • Output 1 (RTSP):MMIC_DEP_INPUT1 | MMIC_DEP_INPUT2 — V2 + AAC

V5 NN chain 完全独立运行,不会影响 recording 或 streaming 的 throughput。

错误处理模式

所有 module open 与 linker create 操作都可能失败。各示例中使用的标准写法会检查 return value,并在失败时跳转到 cleanup label:

mm_context_t *video_ctx = mm_module_open(&video_module);
if (!video_ctx) {
    RTK_LOGE(TAG, "video open fail\n\r");
    goto error;
}
mm_module_ctrl(video_ctx, CMD_VIDEO_SET_PARAMS,    (int)&video_params);
mm_module_ctrl(video_ctx, MM_CMD_SET_QUEUE_LEN,    60);
mm_module_ctrl(video_ctx, MM_CMD_INIT_QUEUE_ITEMS, MMQI_FLAG_DYNAMIC);
mm_module_ctrl(video_ctx, CMD_VIDEO_APPLY,         0);

mm_siso_t *siso = siso_create();
if (!siso) {
    RTK_LOGE(TAG, "siso create fail\n\r");
    goto error;
}
siso_ctrl(siso, MMIC_CMD_ADD_INPUT,  (uint32_t)video_ctx, 0);
siso_ctrl(siso, MMIC_CMD_ADD_OUTPUT, (uint32_t)rtsp_ctx,  0);
siso_start(siso);
return;

error:
if (siso)      { siso_stop(siso);   siso_delete(siso); }
if (video_ctx) { mm_module_close(video_ctx); }
return;

Debug 输出

MMF 提供可在 runtime 控制的 per-subsystem debug logging。可使用 mmf2_dbg.h 中的 macro 启用或关闭特定类别:

DBG_MMF_DEBUG_MSG_ON(_MMF_DBG_NN_);      // enable NN module debug
DBG_MMF_DEBUG_MSG_ON(_MMF_DBG_LINKER_);  // enable linker debug
DBG_MMF_INFO_MSG_OFF(0xFFFFFFFF);        // suppress all INFO messages

常用 flag:

Flag

Module

_MMF_DBG_VIDEO_

video_module

_MMF_DBG_AUDIO_

audio_module

_MMF_DBG_RTSP_

rtsp2_module

_MMF_DBG_NN_

vipnn_module

_MMF_DBG_MODULE_

Core module framework

_MMF_DBG_LINKER_

所有 linker type(SISO、MIMO 等)

_MMF_DBG_ISP_

ISP driver

_MMF_DBG_ENCODER_

Hardware encoder