You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python通过ctypes传字节流至C转uint8_t数组结果不符问题

问题排查:Python WebSocket视频字节流转C uint8_t数组不一致问题

问题背景

  • Python通过WebSocket获取视频原始二进制字节流,执行两个操作:
    • 截取前14字节后写入video.h264文件
    • 通过ctypes将字节流传递给C库decode_video.so的conversion_test函数,目标是转为uint8_t数组供FFmpeg解码
  • 当前C函数使用strtol将每两个字节转为十六进制值存入数组,但转换后的vals数组与C直接读取文件得到的inbuf数组内容完全不符

相关代码示例

Python代码

import ctypes
import websocket

# 加载C动态库
lib = ctypes.CDLL('./decode_video.so')

# 声明C函数参数与返回值类型
lib.conversion_test.argtypes = [ctypes.c_char_p, ctypes.c_int]
lib.conversion_test.restype = None

def on_message(ws, message):
    # 跳过前14字节的头数据
    data = message[14:]
    # 追加写入本地文件
    with open('video.h264', 'ab') as f:
        f.write(data)
    # 将字节流传递给C函数处理
    lib.conversion_test(data, len(data))

# WebSocket连接逻辑(省略初始化代码)
ws = websocket.WebSocketApp("ws://your_ws_endpoint", on_message=on_message)
ws.run_forever()

C代码(decode_video.c)

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

void conversion_test(char *data, int len) {
    // 错误:按每两个字节转一个元素分配空间
    uint8_t *vals = malloc(len / 2 * sizeof(uint8_t));
    int idx = 0;
    for (int i = 0; i < len; i += 2) {
        // 错误:将二进制字节当作十六进制字符串解析
        char hex[3] = {data[i], data[i+1], '\0'};
        vals[idx++] = (uint8_t)strtol(hex, NULL, 16);
    }

    // 打印转换结果前10个元素
    printf("转换后的vals数组前10个值:");
    for (int i = 0; i < 10; i++) {
        printf("%02x ", vals[i]);
    }
    printf("\n");

    // 直接读取本地文件对比
    FILE *fp = fopen("video.h264", "rb");
    uint8_t inbuf[10];
    fread(inbuf, 1, 10, fp);
    printf("直接读文件的inbuf数组前10个值:");
    for (int i = 0; i < 10; i++) {
        printf("%02x ", inbuf[i]);
    }
    printf("\n");

    free(vals);
    fclose(fp);
}

输出对比示例

转换后的vals数组前10个值:41 e3 18 05 00 00 00 01 67 42
直接读文件的inbuf数组前10个值:00 00 00 01 67 42 c0 1e 9a 60

问题分析与修正

核心错误

你混淆了二进制字节流和十六进制字符串的概念:

  • Python传递给C的data是原始二进制字节,比如文件中的0x00字节,在C的char*中就是值为0的字节,而非字符串"00"
  • 用strtol解析两个二进制字节为十六进制值的逻辑完全错误,相当于把随机的二进制值当作ASCII字符解析,自然和文件内容不符

正确实现

直接将char*中的字节逐位复制到uint8_t数组即可,因为char本质就是单字节类型,强转uint8_t可避免符号位问题:

修改后的C函数:

void conversion_test(char *data, int len) {
    // 正确:按字节数分配空间
    uint8_t *vals = malloc(len * sizeof(uint8_t));
    // 直接逐字节复制,无需转换
    for (int i = 0; i < len; i++) {
        vals[i] = (uint8_t)data[i];
    }

    // 打印对比
    printf("转换后的vals数组前10个值:");
    for (int i = 0; i < 10; i++) {
        printf("%02x ", vals[i]);
    }
    printf("\n");

    FILE *fp = fopen("video.h264", "rb");
    uint8_t inbuf[10];
    fread(inbuf, 1, 10, fp);
    printf("直接读文件的inbuf数组前10个值:");
    for (int i = 0; i < 10; i++) {
        printf("%02x ", inbuf[i]);
    }
    printf("\n");

    free(vals);
    fclose(fp);
}

额外说明

  • 若Python传递的是十六进制字符串(如将二进制转为"0000000167..."格式),原strtol逻辑才适用,但此处是原始二进制流,无需额外转换
  • 强转uint8_t是为了避免char作为有符号类型时的符号扩展问题,确保字节值正确
  • 内存分配需对应实际字节数,原代码的len/2会导致内存不足或数据截断

内容的提问来源于stack exchange,提问作者Arbaaz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 14:20:25