-
Notifications
You must be signed in to change notification settings - Fork 4
/
h264_frame_parser.c
116 lines (95 loc) · 2.99 KB
/
h264_frame_parser.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include "h264_frame_parser.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "rtmp_server_base/amf_byte_stream.h"
const char* AVCFindStartCodeInternal(const char *p, const char *end)
{
const char *a = p + 4 - ((ptrdiff_t)p & 3);
for (end -= 3; p < a && p < end; p++) {
if (p[0] == 0 && p[1] == 0 && p[2] == 1)
return p;
}
for (end -= 3; p < end; p += 4) {
unsigned int x = *(const unsigned int*)p;
// if ((x - 0x01000100) & (~x) & 0x80008000) // little endian
// if ((x - 0x00010001) & (~x) & 0x00800080) // big endian
if ((x - 0x01010101) & (~x) & 0x80808080) { // generic
if (p[1] == 0) {
if (p[0] == 0 && p[2] == 1)
return p;
if (p[2] == 0 && p[3] == 1)
return p+1;
}
if (p[3] == 0) {
if (p[2] == 0 && p[4] == 1)
return p+2;
if (p[4] == 0 && p[5] == 1)
return p+3;
}
}
}
for (end += 3; p < end; p++) {
if (p[0] == 0 && p[1] == 0 && p[2] == 1)
return p;
}
return end + 3;
}
const char* AVCFindStartCode(const char *p, const char *end)
{
const char *out= AVCFindStartCodeInternal(p, end);
if(p<out && out<end && !out[-1]) out--;
return out;
}
void AVCParseNalUnits(const char *bufIn, int inSize, char* bufOut, int* outSize)
{
const char *p = bufIn;
const char *end = p + inSize;
const char *nal_start, *nal_end;
char* pbuf = bufOut;
*outSize = 0;
nal_start = AVCFindStartCode(p, end);
while (nal_start < end)
{
unsigned int nal_size = 0;
while(!*(nal_start++));
nal_end = AVCFindStartCode(nal_start, end);
nal_size = nal_end - nal_start;
pbuf = UI32ToBytes(pbuf, nal_size);
memcpy(pbuf, nal_start, nal_size);
pbuf += nal_size;
nal_start = nal_end;
}
*outSize = (pbuf - bufOut);
}
void ParseH264Frame(const char* nalsbuf, int size, char* outBuf, int* outLen,
char* spsBuf, int* spsSize, char* ppsBuf, int* ppsSize,
int* isKeyframe)
{
char* start = 0;
char* end = 0;
AVCParseNalUnits(nalsbuf, size, (char*)outBuf, outLen);
start = outBuf;
end = outBuf + *outLen;
/* look for sps and pps */
while (start < end)
{
unsigned int size = BytesToUI32(start);
unsigned char nal_type = start[4] & 0x1f;
if (nal_type == 7 && spsBuf) /* SPS */
{
*spsSize = size;
memcpy(spsBuf, start + 4, *spsSize);
}
else if (nal_type == 8 && ppsBuf) /* PPS */
{
*ppsSize = size;
memcpy(ppsBuf, start + 4, *ppsSize);
}
else if (nal_type == 5)
{
*isKeyframe = 1;
}
start += size + 4;
}
}