rtmp视频流提取h264裸流
2017-11-27 本文已影响434人
爱吃花栗鼠的猫
流媒体服务器在判断出消息类型为video之后,进行h264参数集和nalu的提取,并加入分隔符,代码如下
文中用读取文件的方式代替rtmp msg里面的payload
rtmp视频消息示例:
。。。。
image.png
#include <string>
#include <sstream>
FILE *f264 = NULL;
uint16_t ReadU16BE(uint8_t data[2]) {
uint16_t v = 0;
uint16_t v1 = uint16_t(data[0]);
v1 <<= 16;
uint16_t v2 = uint16_t(data[1]);
v |= v1;
v |= v2;
return v;
}
uint32_t ReadU32BE(uint8_t data[4]) {
uint32_t v = 0;
uint32_t v1 = uint32_t(data[0]);
v1 <<= 24;
uint32_t v2 = uint32_t(data[1]);
v2 <<= 16;
uint32_t v3 = uint32_t(data[2]);
v3 <<= 8;
uint32_t v4 = uint32_t(data[3]);
v |= v1;
v |= v2;
v |= v3;
v |= v4;
return v;
}
void write_h264nalu_to_disk(char *nalu, int nalu_len) {
char separator[4] = {0x00, 0x00, 0x00, 0x01};
fwrite(separator, 1, 4, f264);
fwrite(nalu, 1, nalu_len, f264);
}
void parse_one_frame(char *payload, int payload_size) {
char frame_type = payload[0];
frame_type = (frame_type >> 4) & 0x0F;
char avc_packet_type = payload[1];
if (1 == frame_type && 0 == avc_packet_type)// spspps. 17 00
{
//sps
int offset = 0;
offset += 11;
int sps_len = payload[offset] * 16 + payload[offset + 1];
offset += 2;
write_h264nalu_to_disk(&payload[offset], sps_len);
offset += sps_len;
//pps
offset += 1; //pps num.
char nalu_len_data[2] = {payload[offset], payload[offset + 1]};
int pps_len = ReadU16BE((uint8_t *) nalu_len_data);
offset += 2;
offset + pps_len;
write_h264nalu_to_disk(&payload[offset], pps_len);
} else if (1 == avc_packet_type) // nalu
{
int offset = 0;
offset += 5;
while (offset < payload_size) {
char nalu_len_data[4] = {payload[offset], payload[offset + 1], payload[offset + 2], payload[offset + 3]};
int nalu_len = ReadU32BE((uint8_t *) nalu_len_data);
offset += 4;
write_h264nalu_to_disk(&payload[offset], nalu_len);
offset += nalu_len;
}
}
}
int main() {
std::string path = "/home/yangkai/CLionProjects/jvsrs/trunk/cmake-build-debug/origin/";
enum {
READ_EVERY_TIME = 128
};
char *payload = new char[1 * 1024 * 1024];
int payload_size = 0;
f264 = fopen("end.264", "wb+");
for (int i = 0; i < 1956; ++i) {
std::stringstream ss;
ss << path << "origin-" << i << ".h264";
FILE *f = fopen(ss.str().c_str(), "rb");
while (1) {
int readsize = fread(payload + payload_size, 1, READ_EVERY_TIME, f);
payload_size += readsize;
if (readsize != READ_EVERY_TIME) {
break;
}
}
fclose(f);
parse_one_frame(payload, payload_size);
payload_size = 0;
}
delete[] payload;
fclose(f264);
return 0;
}