多slice码流

现象

在iOS平台的硬解的实践中,我们可能会遇到如下图的这种情况(上面一部分有画面,下面部分是绿屏):

原因

有的推流端出于编码性能的考虑,会选择通过切片的方式来编码,这样一个frame的数据就可能被切片分散于多个nalu中(哥伦布编码),但是videotoolbox解码又必须是整个frame合并到一个nalu中解码,暂时不知道合并算法,但是通过ffmpeg打开得到的流是合并过的(据说的熵编码)。

例子

下面是一个切片的裸流数据(PES包后的裸数据)

  00 00 00 01 67 64...
  00 00 00 01 68 ea...
  00 00 01 06 05 ff...
  00 00 01 65 88 84...
  00 00 01 65 00 60...
  00 00 01 65 00 30...
  00 00 01 65 00 12...

  00 00 00 01 41 9a 3b 1b ff 00 00 03 00 02 92
     00 00 01 41 00 60 26 8e c6 ff 00 00 03 00 02
     00 00 01 41 00 30 09 a3 b1 bf 00 00 03 00 02
     00 00 01 41 00 12 02 68 ec 6f 00 00 03 00 02
  00 00 00 01 41 9a 46 0d ff 00 00 03 00 02 93
     00 00 01 41 00 60 26 91 83 7f 00 00 03 00 02
     00 00 01 41 00 30 09 a4 60 df 00 00 03 00 02
     00 00 01 41 00 12 02 69 18 37 ff 00 00 03 00 02
获取H.264码流中的slice type,需要先解析码流中的NALU(Network Abstraction Layer Unit),然后从NALU中获取slice header,从slice header中读取slice type。以下是一个简单的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define NALU_TYPE_SLICE 1 typedef struct { unsigned char *data; int size; } NALU; int find_start_code(unsigned char *buf, int buflen) { if (buflen < 3) { return -1; } if (buf[0] != 0 || buf[1] != 0) { return -1; } if (buf[2] == 1) { return 3; } if (buflen < 4) { return -1; } if (buf[2] == 0 && buf[3] == 1) { return 4; } return -1; } NALU *read_nalu(FILE *fp) { NALU *nalu = NULL; int startcode_len = 0; int pos = 0; int readlen = 0; unsigned char *buf = (unsigned char*)malloc(1024 * 1024); while (1) { int ch = fgetc(fp); if (ch == EOF) { break; } buf[pos++] = ch; if (pos >= 4) { startcode_len = find_start_code(buf, pos); if (startcode_len != -1) { break; } } if (pos >= 1024 * 1024) { fprintf(stderr, "NALU too large\n"); exit(1); } } if (pos == 0) { free(buf); return NULL; } nalu = (NALU*)malloc(sizeof(NALU)); nalu->size = pos - startcode_len; nalu->data = (unsigned char*)malloc(nalu->size); memcpy(nalu->data, buf + startcode_len, nalu->size); free(buf); return nalu; } int get_slice_type(NALU *nalu) { int slice_type = -1; unsigned char *data = nalu->data; int size = nalu->size; int pos = 0; if (size < 4) { return slice_type; } if ((data[pos] & 0x1f) == NALU_TYPE_SLICE) { pos += 1; slice_type = (data[pos] >> 1) & 0x7; } return slice_type; } int main(int argc, char **argv) { FILE *fp = fopen(argv[1], "rb"); NALU *nalu = NULL; while ((nalu = read_nalu(fp)) != NULL) { int slice_type = get_slice_type(nalu); printf("slice_type=%d\n", slice_type); free(nalu->data); free(nalu); } fclose(fp); return 0; } ``` 该示例代码实现了从H.264码流中读取NALU,并从NALU中获取slice type。具体步骤如下: 1. 定义NALU结构体,存储NALU的数据和大小。 2. 实现find_start_code函数,用于在码流中查找start code(0x000001或0x00000001)。 3. 实现read_nalu函数,用于从文件中读取NALU。 4. 实现get_slice_type函数,用于从NALU中读取slice type。 5. 在main函数中循环读取NALU,并输出slice type。 注意,该示例代码只能读取单个NALU,如果码流中包含多个NALU,则需要在read_nalu函数中做相应的修改。此外,该示例代码没有处理码流的完整性和正确性,实际使用时需要进行相应的检查和处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值