基于RTP的H264视频数据打包解包类

      最近考虑使用RTP替换原有的高清视频传输协议,遂上网查找有关H264视频RTP打包、解包的文档和代码。功夫不负有心人,找到不少有价值的文档和代码。参考这些资料,写了H264 RTP打包类、解包类,实现了单个NAL单元包和FU_A分片单元包。对于丢包处理,采用简单的策略:丢弃随后的所有数据包,直到收到关键帧。测试效果还不错,代码贴上来,若能为同道中人借鉴一二,足矣。两个类的使用说明如下(省略了错误处理过程):

 DWORD H264SSRC ;
 CH264_RTP_PACK pack ( H264SSRC ) ;
 BYTE *pVideoData ;
 DWORD Size, ts ;
 bool IsEndOfFrame ;
 WORD wLen ;
 pack.Set ( pVideoData, Size, ts, IsEndOfFrame ) ;
 BYTE *pPacket ;
 while ( pPacket = pack.Get ( &wLen ) )
 {
  // rtp packet process
  // ...
 }


 HRESULT hr ;
 CH264_RTP_UNPACK unpack ( hr ) ;
 BYTE *pRtpData ;
 WORD inSize;
 int outSize ;
 BYTE *pFrame = unpack.Parse_RTP_Packet ( pRtpData, inSize, &outSize ) ;
 if ( pFrame != NULL )
 {
  // frame process
  // ...
 }

 

 

 

  • 3
    点赞
  • 97
    收藏
    觉得还不错? 一键收藏
  • 49
    评论
解包 RTP H.264 数据需要进行以下步骤: 1. 从 RTP 报文中提取出 H.264 数据包。 2. 解析 H.264 数据包,提取出 NAL 单元。 3. 将 NAL 单元按照 H.264 规范进行拼接,形成完整的 H.264 帧。 4. 对 H.264 帧进行解码,获取视频帧。 下面是一个基于 C++ 和 FFmpeg 库的简单示例代码: ```cpp #include <stdio.h> #include <stdlib.h> #include <string.h> extern "C" { #include <libavformat/avformat.h> #include <libavcodec/avcodec.h> } #define MAX_RTP_PKT_LENGTH 1360 int main(int argc, char* argv[]) { AVFormatContext* fmt_ctx = NULL; AVCodecContext* codec_ctx = NULL; AVCodec* codec = NULL; AVPacket pkt; AVFrame* frame = NULL; uint8_t* frame_buf = NULL; int frame_size = 0; int got_frame = 0; int ret = 0; int i; av_register_all(); // 打开 RTP 输入文件 if (avformat_open_input(&fmt_ctx, "rtp://127.0.0.1:1234", NULL, NULL) != 0) { printf("Could not open input file.\n"); return -1; } // 查找视频流 if (avformat_find_stream_info(fmt_ctx, NULL) < 0) { printf("Could not find stream information.\n"); return -1; } int video_stream_index = -1; AVStream* video_stream = NULL; for (i = 0; i < fmt_ctx->nb_streams; i++) { if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { video_stream_index = i; video_stream = fmt_ctx->streams[i]; break; } } if (video_stream_index == -1) { printf("Could not find video stream.\n"); return -1; } // 查找视频解码器 codec = avcodec_find_decoder(video_stream->codecpar->codec_id); if (codec == NULL) { printf("Could not find codec.\n"); return -1; } // 初始化视频解码器上下文 codec_ctx = avcodec_alloc_context3(codec); if (codec_ctx == NULL) { printf("Could not allocate codec context.\n"); return -1; } if (avcodec_parameters_to_context(codec_ctx, video_stream->codecpar) < 0) { printf("Could not copy codec parameters.\n"); return -1; } if (avcodec_open2(codec_ctx, codec, NULL) < 0) { printf("Could not open codec.\n"); return -1; } // 解码 RTP 数据包 av_init_packet(&pkt); pkt.data = (uint8_t*)malloc(MAX_RTP_PKT_LENGTH); while (1) { // 从 RTP 文件中读取数据包 ret = av_read_frame(fmt_ctx, &pkt); if (ret < 0) { break; } // 跳过 RTP 头 uint8_t* rtp_data = pkt.data + 12; // 提取 H.264 NAL 单元 while (pkt.size > 0) { int nal_start = 0, nal_end = 0; for (i = 0; i < pkt.size - 4; i++) { if (rtp_data[i] == 0x00 && rtp_data[i + 1] == 0x00 && rtp_data[i + 2] == 0x00 && rtp_data[i + 3] == 0x01) { if (nal_start != 0) { nal_end = i - 1; break; } else { nal_start = i + 4; } } } if (nal_end == 0) { nal_end = pkt.size - 1; } // 拼接 NAL 单元 int nal_size = nal_end - nal_start + 1; if (frame_buf == NULL) { frame_buf = (uint8_t*)malloc(nal_size); } else { frame_buf = (uint8_t*)realloc(frame_buf, frame_size + nal_size); } memcpy(frame_buf + frame_size, rtp_data + nal_start, nal_size); frame_size += nal_size; // 解码 H.264 帧 while (frame_size > 0) { ret = avcodec_decode_video2(codec_ctx, frame, &got_frame, &pkt); if (ret < 0) { printf("Error decoding frame.\n"); break; } if (got_frame) { // 处理解码后的视频帧 printf("Decoded frame: %dx%d\n", codec_ctx->width, codec_ctx->height); } // 移动指针 int consumed = av_parser_parse2(codec_ctx->parser, codec_ctx, &pkt.data, &pkt.size, rtp_data + nal_end + 1, pkt.size - nal_size - (rtp_data + nal_end + 1 - pkt.data), pkt.pts, pkt.dts, pkt.pos); frame_size -= nal_size + consumed; rtp_data += nal_size + consumed; } // 移动指针 pkt.size -= nal_size; } av_packet_unref(&pkt); } // 释放资源 if (codec_ctx != NULL) { avcodec_close(codec_ctx); avcodec_free_context(&codec_ctx); } if (fmt_ctx != NULL) { avformat_close_input(&fmt_ctx); } if (frame_buf != NULL) { free(frame_buf); } return 0; } ``` 这里使用了 FFmpeg 库中的函数进行 RTP 数据包的解析和 H.264 数据的解码,具体流程请参考代码注释。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 49
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值