免费插画素材网站推广软文代写
概述
项目中涉及到一些向国标平台推送视频流的逻辑,因之前没有接触过该方面的知识,所以开始走了很多错误的路线,本文主要总结H265 视频中解析出NALU方法
代码实现
输出
[tcp @ 0x55842b7e60] No default whitelist set
[tcp @ 0x55842b7e60] Original list of addresses:
[tcp @ 0x55842b7e60] Address 192.168.1.181 port 554
[tcp @ 0x55842b7e60] Interleaved list of addresses:
[tcp @ 0x55842b7e60] Address 192.168.1.181 port 554
[tcp @ 0x55842b7e60] Starting connection attempt to 192.168.1.181 port 554
[tcp @ 0x55842b7e60] Successfully connected to 192.168.1.181 port 554
[rtsp @ 0x55842ed950] SDP:
v=0
o=- 1741789310577832 1741789310577832 IN IP4 192.168.1.181
s=Media Presentation
e=NONE
b=AS:5050
t=0 0
a=control:rtsp://192.168.1.181:554/Streaming/Channels/101/
m=video 0 RTP/AVP 96
c=IN IP4 0.0.0.0
b=AS:5000
a=recvonly
a=x-dimensions:1920,1080
a=control:rtsp://192.168.1.181:554/Streaming/Channels/101/trackID=1
a=rtpmap:96 H265/90000
a=Media_header:MEDIAINFO=494D4B48010300000400050000000000000000000000000000000000000000000000000000000000;
a=appversion:1.0[rtsp @ 0x55842ed950] video codec set to: hevc
[rtp @ 0x55842b7cc0] No default whitelist set
[udp @ 0x55842bb400] No default whitelist set
[udp @ 0x55842bb400] end receive buffer size reported is 131072
[udp @ 0x55843010e0] No default whitelist set
[udp @ 0x55843010e0] end receive buffer size reported is 131072
[rtsp @ 0x55842ed950] setting jitter buffer size to 500
[rtsp @ 0x55842ed950] hello state=0
[hevc @ 0x55842f07c0] nal_unit_type: 32(VPS), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 33(SPS), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 34(PPS), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 39(SEI_PREFIX), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 19(IDR_W_RADL), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] Decoding VPS
[hevc @ 0x55842f07c0] Main profile bitstream
[hevc @ 0x55842f07c0] Decoding SPS
[hevc @ 0x55842f07c0] Main profile bitstream
[hevc @ 0x55842f07c0] Decoding VUI
[hevc @ 0x55842f07c0] Decoding PPS
[hevc @ 0x55842f07c0] Decoding SEI
[hevc @ 0x55842f07c0] Skipped PREFIX SEI 229
[AVBSFContext @ 0x55842b7280] nal_unit_type: 32(VPS), nuh_layer_id: 0, temporal_id: 0
[AVBSFContext @ 0x55842b7280] nal_unit_type: 33(SPS), nuh_layer_id: 0, temporal_id: 0
[AVBSFContext @ 0x55842b7280] nal_unit_type: 34(PPS), nuh_layer_id: 0, temporal_id: 0
[AVBSFContext @ 0x55842b7280] nal_unit_type: 39(SEI_PREFIX), nuh_layer_id: 0, temporal_id: 0
[AVBSFContext @ 0x55842b7280] nal_unit_type: 19(IDR_W_RADL), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 32(VPS), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 33(SPS), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 34(PPS), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 39(SEI_PREFIX), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 19(IDR_W_RADL), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] Decoding VPS
[hevc @ 0x55842f07c0] Main profile bitstream
[hevc @ 0x55842f07c0] Decoding SPS
[hevc @ 0x55842f07c0] Main profile bitstream
[hevc @ 0x55842f07c0] Decoding VUI
[hevc @ 0x55842f07c0] Decoding PPS
[hevc @ 0x55842f07c0] Decoding SEI
[hevc @ 0x55842f07c0] Skipped PREFIX SEI 229
[hevc @ 0x55842f07c0] Format yuvj420p chosen by get_format().
[hevc @ 0x55842f07c0] Output frame with POC 0.
[hevc @ 0x55842f07c0] Decoded frame with POC 0.
[hevc @ 0x55842f07c0] nal_unit_type: 32(VPS), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 33(SPS), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 34(PPS), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] Decoding VPS
[hevc @ 0x55842f07c0] Main profile bitstream
[hevc @ 0x55842f07c0] Decoding SPS
[hevc @ 0x55842f07c0] Main profile bitstream
[hevc @ 0x55842f07c0] Decoding VUI
[hevc @ 0x55842f07c0] Decoding PPS
[hevc @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[rtsp @ 0x55842ed950] All info found
[rtsp @ 0x55842ed950] Setting avg frame rate based on r frame rate
NALU 类型: 32 (32), 大小: 23, PTS: -9223372036854775808, DTS: -9223372036854775808
NALU 类型: 33 (33), 大小: 34, PTS: -9223372036854775808, DTS: -9223372036854775808
NALU 类型: 34 (34), 大小: 7, PTS: -9223372036854775808, DTS: -9223372036854775808
NALU 类型: 39 (39), 大小: 9, PTS: -9223372036854775808, DTS: -9223372036854775808
NALU 类型: 19 (19), 大小: 263700, PTS: -9223372036854775808, DTS: -9223372036854775808
NALU 类型: 1 (1), 大小: 788, PTS: 3600, DTS: 3600
NALU 类型: 1 (1), 大小: 2978, PTS: 7200, DTS: 7200
NALU 类型: 1 (1), 大小: 2220, PTS: 10800, DTS: 10800
NALU 类型: 1 (1), 大小: 2947, PTS: 14400, DTS: 14400
NALU 类型: 1 (1), 大小: 3518, PTS: 18000, DTS: 18000
NALU 类型: 1 (1), 大小: 5597, PTS: 21600, DTS: 21600
NALU 类型: 1 (1), 大小: 8614, PTS: 25200, DTS: 25200
NALU 类型: 1 (1), 大小: 6374, PTS: 28800, DTS: 28800
NALU 类型: 1 (1), 大小: 3811, PTS: 32400, DTS: 32400
NALU 类型: 1 (1), 大小: 7767, PTS: 36000, DTS: 36000
NALU 类型: 1 (1), 大小: 9875, PTS: 39600, DTS: 39600
NALU 类型: 1 (1), 大小: 10074, PTS: 43200, DTS: 43200
NALU 类型: 1 (1), 大小: 10542, PTS: 46800, DTS: 46800
NALU 类型: 1 (1), 大小: 10142, PTS: 50400, DTS: 50400
NALU 类型: 1 (1), 大小: 10576, PTS: 54000, DTS: 54000
NALU 类型: 1 (1), 大小: 10192, PTS: 57600, DTS: 57600
NALU 类型: 1 (1), 大小: 9648, PTS: 61200, DTS: 61200
NALU 类型: 1 (1), 大小: 9878, PTS: 64800, DTS: 64800
NALU 类型: 1 (1), 大小: 9835, PTS: 68400, DTS: 68400
NALU 类型: 1 (1), 大小: 10402, PTS: 72000, DTS: 72000
NALU 类型: 1 (1), 大小: 9714, PTS: 75600, DTS: 75600
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 8508, PTS: 79200, DTS: 79200
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 8509, PTS: 82800, DTS: 82800
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 12812, PTS: 86400, DTS: 86400
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 12787, PTS: 90000, DTS: 90000
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 17511, PTS: 93600, DTS: 93600
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 12669, PTS: 97200, DTS: 97200
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 9989, PTS: 100800, DTS: 100800
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 12735, PTS: 104400, DTS: 104400
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 13694, PTS: 108000, DTS: 108000
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 14115, PTS: 111600, DTS: 111600
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 13653, PTS: 115200, DTS: 115200
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 13454, PTS: 118800, DTS: 118800
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 13525, PTS: 122400, DTS: 122400
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 16936, PTS: 126000, DTS: 126000
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 14288, PTS: 129600, DTS: 129600
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 15038, PTS: 133200, DTS: 133200
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 14235, PTS: 136800, DTS: 136800
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 14089, PTS: 140400, DTS: 140400
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 13728, PTS: 144000, DTS: 144000
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 19235, PTS: 147600, DTS: 147600
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 6320, PTS: 151200, DTS: 151200
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 13692, PTS: 154800, DTS: 154800
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 17981, PTS: 158400, DTS: 158400
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 19105, PTS: 162000, DTS: 162000
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 16396, PTS: 165600, DTS: 165600
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 18006, PTS: 169200, DTS: 169200
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 19030, PTS: 172800, DTS: 172800
[NULL @ 0x55842f07c0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
NALU 类型: 1 (1), 大小: 17141, PTS: 176400, DTS: 176400
[NULL @ 0x55842f07c0] nal_unit_type: 32(VPS), nuh_layer_id: 0, temporal_id: 0
[NULL @ 0x55842f07c0] nal_unit_type: 33(SPS), nuh_layer_id: 0, temporal_id: 0
[NULL @ 0x55842f07c0] nal_unit_type: 34(PPS), nuh_layer_id: 0, temporal_id: 0
[NULL @ 0x55842f07c0] nal_unit_type: 39(SEI_PREFIX), nuh_layer_id: 0, temporal_id: 0
[NULL @ 0x55842f07c0] nal_unit_type: 19(IDR_W_RADL), nuh_layer_id: 0, temporal_id: 0
[NULL @ 0x55842f07c0] Decoding VPS
[NULL @ 0x55842f07c0] Main profile bitstream
[NULL @ 0x55842f07c0] Decoding SPS
[NULL @ 0x55842f07c0] Main profile bitstream
[NULL @ 0x55842f07c0] Decoding VUI
[NULL @ 0x55842f07c0] Decoding PPS
[NULL @ 0x55842f07c0] Decoding SEI
[NULL @ 0x55842f07c0] Skipped PREFIX SEI 229
NALU 类型: 32 (32), 大小: 23, PTS: 180000, DTS: 180000
NALU 类型: 33 (33), 大小: 34, PTS: 180000, DTS: 180000
NALU 类型: 34 (34), 大小: 7, PTS: 180000, DTS: 180000
NALU 类型: 39 (39), 大小: 9, PTS: 180000, DTS: 180000
NALU 类型: 19 (19), 大小: 236733, PTS: 180000, DTS: 180000
源码
// g++ -o test test.cpp -lavformat -lavcodec -lavutil
// (测试成功)代码已经成功测试使用ffmpeg拉流AVPacket解析出NALU,H265视频格式专用
extern "C"{#include <libavformat/avformat.h>#include <libavcodec/avcodec.h>#include <libavutil/avutil.h>#include <libavutil/opt.h>
}
#include <stdio.h>
#include <stdint.h>// H265的NALU类型
typedef enum {NALU_TYPE_UNDEFINED = -1,NALU_TYPE_TRAIL_N = 0, NALU_TYPE_TRAIL_R = 1, NALU_TYPE_TSA_N = 2, NALU_TYPE_TSA_R = 3, NALU_TYPE_STSA_N = 4, NALU_TYPE_STSA_R = 5, NALU_TYPE_RADL_N = 6, NALU_TYPE_RADL_R = 7, NALU_TYPE_RASL_N = 8, NALU_TYPE_RASL_R = 9, NALU_TYPE_BLA_W_LP = 16, NALU_TYPE_BLA_W_RADL = 17, NALU_TYPE_BLA_N_LP = 18, NALU_TYPE_IDR_W_RADL = 19, NALU_TYPE_IDR_N_LP = 20, NALU_TYPE_CRA_NUT = 21, NALU_TYPE_RSV_VCL_N10= 22, NALU_TYPE_RSV_VCL_H11= 23, NALU_TYPE_RSV_VCL_V12= 24, NALU_TYPE_RSV_VCL_H13= 25, NALU_TYPE_RSV_VCL_N14= 26, NALU_TYPE_RSV_VCL_R15= 27, NALU_TYPE_VPS = 32, NALU_TYPE_SPS = 33, NALU_TYPE_PPS = 34, NALU_TYPE_AUD = 35, NALU_TYPE_EOS_NUT = 36, NALU_TYPE_EOB_NUT = 37, NALU_TYPE_FD_NUT = 38, NALU_TYPE_SEI_PREFIX = 39, NALU_TYPE_SEI_SUFFIX = 40, NALU_TYPE_RSV_NVCL41 = 41, NALU_TYPE_RSV_NVCL42 = 42, NALU_TYPE_RSV_NVCL43 = 43, NALU_TYPE_RSV_NVCL44 = 44, NALU_TYPE_RSV_NVCL45 = 45, NALU_TYPE_RSV_NVCL46 = 46, NALU_TYPE_RSV_NVCL47 = 47, NALU_TYPE_UNSPEC48 = 48, NALU_TYPE_FRAGMENT_UNIT = 49
} NaluType;// 解析出来H265的NALU类型
NaluType parse_nalu_type(uint8_t *nalu_data) {if (nalu_data == NULL) {fprintf(stderr, "错误: nalu_data 为 nullptr\n");return NALU_TYPE_UNDEFINED;}// H.265 NALU type is in the first byte of NALU data, bits 1-6 (0-indexed)return static_cast<NaluType>((nalu_data[0] >> 1) & 0x3F); // Directly parse NALU type from the first byte
}// 打印NALU类型
void handle_nalu(uint8_t *nalu_data, int nalu_size, NaluType nalu_type, int64_t pts, int64_t dts) {printf("NALU 类型: %d (%d), 大小: %d, PTS: %ld, DTS: %ld\n", nalu_type, (int)nalu_type, nalu_size, pts, dts);
}// 处理AVPacket
void process_packet(AVPacket *pkt) {uint8_t *data = pkt->data;int size = pkt->size;int startcode_len = 0;// Logging (optional, for debugging)// printf("AVPacket->data (前 64 字节): ..."); // ...while (size > 0) {startcode_len = 0; if (size >= 4 && data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x00 && data[3] == 0x01) {startcode_len = 4;// Logging (optional, for debugging)// printf("找到 4 字节起始码,位置偏移: ...");} else if (size >= 3 && data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x01) {startcode_len = 3;// Logging (optional, for debugging)// printf("找到 3 字节起始码,位置偏移: ...");} else {data++;size--;continue;}uint8_t *next_startcode = NULL;for (int i = startcode_len; i < size - 3; i++) {if (data[i] == 0x00 && data[i+1] == 0x00 && data[i+2] == 0x01) {next_startcode = data + i;break; }if (data[i] == 0x00 && data[i+1] == 0x00 && data[i+2] == 0x00 && data[i+3] == 0x01) {next_startcode = data + i;break; }}int nalu_size = (next_startcode != NULL) ?(next_startcode - (data + startcode_len)) :(size - startcode_len);uint8_t *nalu_data = data + startcode_len; // Logging (optional, for debugging)// printf("parse_nalu_type 接收到的数据 (前 8 字节): ...");// Corrected call: Pass nalu_data directlyNaluType nalu_type = parse_nalu_type(nalu_data); handle_nalu(nalu_data, nalu_size, nalu_type, pkt->pts, pkt->dts);data += startcode_len + nalu_size;size -= startcode_len + nalu_size;}
}void set_ffmpeg_log_level() {av_log_set_level(AV_LOG_DEBUG);
}int test_rtsp_stream() {avformat_network_init();set_ffmpeg_log_level();AVFormatContext *fmt_ctx = NULL;AVPacket *pkt = av_packet_alloc();if (!pkt) {fprintf(stderr, "无法分配 AVPacket\n");return -1;}const char *rtsp_url = "rtsp://admin:jhx12345@192.168.1.181:554/Streaming/Channels/101"; if (avformat_open_input(&fmt_ctx, rtsp_url, NULL, NULL) < 0) {fprintf(stderr, "无法打开输入流: %s\n", rtsp_url);av_packet_free(&pkt);return -1;}if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {fprintf(stderr, "无法获取流信息\n");avformat_close_input(&fmt_ctx);av_packet_free(&pkt);return -1;}int video_stream_idx = -1;for (int i = 0; i < fmt_ctx->nb_streams; i++) {if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {video_stream_idx = i;break;}}if (video_stream_idx == -1) {fprintf(stderr, "未找到视频流\n");avformat_close_input(&fmt_ctx);av_packet_free(&pkt);return -1;}while (av_read_frame(fmt_ctx, pkt) >= 0) {if (pkt->stream_index == video_stream_idx) {process_packet(pkt); }av_packet_unref(pkt); }if (feof(stdin)) {printf("到达流末尾\n");} else if (ferror(stdin)) {fprintf(stderr, "读取流时发生错误\n");}av_packet_free(&pkt);avformat_close_input(&fmt_ctx);return 0;
}// main function - Same as before
int main() {if (test_rtsp_stream() < 0) {fprintf(stderr, "RTSP 流测试失败\n");return -1;}printf("RTSP 流测试成功\n");return 0;
}
分析
avpacket
该结构体中主要用于存储音视频数据,其中的data字段存储着多个NALU数据,下面只说明其重要的字段
typedef struct AVPacket {uint8_t *data; // 数据缓冲区指针,指向编码后的音视频数据int size; // 数据大小int64_t pts; // 该数据包的显示时间戳 (Presentation Time Stamp)int64_t dts; // 解码时间戳 (Decoding Time Stamp)...
} AVPacket;
- data: 这是指向数据缓冲区的指针,它包含了实际的编码数据(例如,H.265 视频的 NALU 数据)。这个缓冲区可能包含一个完整的 NALU,或者包含多个 NALU 数据。
- size: 这是
data
中存储的字节数,即数据的大小。它告诉我们这个数据包的总大小。
data字段存储NALU
一个标准的NALU主要是由起始码进行标识,一般是三个或者四个字节的0x000001 0x00000001,通过这些起始码来分割NALU
解析过程分析
核心过程分析
- 查找起始码,循环寻找001、0001开头的,只要找到则代表找到了一个新的NALU
- 提取NALU,找到起始码后,提取起始码后面的数据,直到下一个起始码出现
- 解析NALU,H265中的NALU的规定是其类型存储在第一个自己的高六位
具体解析代码
void process_packet(AVPacket *pkt) {uint8_t *data = pkt->data;int size = pkt->size;int startcode_len = 0;while (size > 0) {startcode_len = 0; if (size >= 4 && data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x00 && data[3] == 0x01) {startcode_len = 4;} else if (size >= 3 && data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x01) {startcode_len = 3;} else {data++;size--;continue;}uint8_t *next_startcode = NULL;for (int i = startcode_len; i < size - 3; i++) {if (data[i] == 0x00 && data[i+1] == 0x00 && data[i+2] == 0x01) {next_startcode = data + i;break;}if (data[i] == 0x00 && data[i+1] == 0x00 && data[i+2] == 0x00 && data[i+3] == 0x01) {next_startcode = data + i;break;}}int nalu_size = (next_startcode != NULL) ? (next_startcode - (data + startcode_len)) : (size - startcode_len);uint8_t *nalu_data = data + startcode_len;NaluType nalu_type = parse_nalu_type(nalu_data); handle_nalu(nalu_data, nalu_size, nalu_type, pkt->pts, pkt->dts);data += startcode_len + nalu_size;size -= startcode_len + nalu_size;}
}