rtph264depay插件分析笔记

news2024/12/23 9:24:36

1、rtp协议头

2、rtp可以基于TCP或者UDP

其中基于TCP需要加4个字节的RTP标志

3、rtph264depay定义解析函数gst_rtp_h264_depay_process,通过RFC 3984文档实现。

static void
gst_rtp_h264_depay_class_init (GstRtpH264DepayClass * klass)
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;
  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
  gobject_class = (GObjectClass *) klass;
  gstelement_class = (GstElementClass *) klass;
  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
  gobject_class->finalize = gst_rtp_h264_depay_finalize;
  gobject_class->set_property = gst_rtp_h264_depay_set_property;
  gobject_class->get_property = gst_rtp_h264_depay_get_property;

  /**
   * GstRtpH264Depay:wait-for-keyframe:
   *
   * Wait for the next keyframe after packet loss,
   * meaningful only when outputting access units
   *
   * Since: 1.20
   */
  g_object_class_install_property (gobject_class, PROP_WAIT_FOR_KEYFRAME,
      g_param_spec_boolean ("wait-for-keyframe", "Wait for Keyframe",
          "Wait for the next keyframe after packet loss, meaningful only when "
          "outputting access units",
          DEFAULT_WAIT_FOR_KEYFRAME,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

  /**
   * GstRtpH264Depay:request-keyframe:
   *
   * Request new keyframe when packet loss is detected
   *
   * Since: 1.20
   */
  g_object_class_install_property (gobject_class, PROP_REQUEST_KEYFRAME,
      g_param_spec_boolean ("request-keyframe", "Request Keyframe",
          "Request new keyframe when packet loss is detected",
          DEFAULT_REQUEST_KEYFRAME,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  gst_element_class_add_static_pad_template (gstelement_class,
      &gst_rtp_h264_depay_src_template);
  gst_element_class_add_static_pad_template (gstelement_class,
      &gst_rtp_h264_depay_sink_template);
  gst_element_class_set_static_metadata (gstelement_class,
      "RTP H264 depayloader", "Codec/Depayloader/Network/RTP",
      "Extracts H264 video from RTP packets (RFC 3984)",
      "Wim Taymans <wim.taymans@gmail.com>");
  gstelement_class->change_state = gst_rtp_h264_depay_change_state;
  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_h264_depay_process;
  gstrtpbasedepayload_class->set_caps = gst_rtp_h264_depay_setcaps;
  gstrtpbasedepayload_class->handle_event = gst_rtp_h264_depay_handle_event;
}

4、gst_rtp_h264_depay_process的具体实现

static GstBuffer *
gst_rtp_h264_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
{
    GstRtpH264Depay *rtph264depay;
    GstBuffer *outbuf = NULL;
    guint8 nal_unit_type;
    rtph264depay = GST_RTP_H264_DEPAY (depayload);
    if (!rtph264depay->merge)
        rtph264depay->waiting_for_keyframe = FALSE;

    /* 是否是弃用数据 */
    if (GST_BUFFER_IS_DISCONT (rtp->buffer)) {
        gst_adapter_clear (rtph264depay->adapter);
        rtph264depay->wait_start = TRUE;
        rtph264depay->current_fu_type = 0;
        rtph264depay->last_fu_seqnum = 0;
        if (rtph264depay->merge && rtph264depay->wait_for_keyframe) {
            rtph264depay->waiting_for_keyframe = TRUE;
        }
        if (rtph264depay->request_keyframe)
        gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depayload),gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE,TRUE, 0));
    }

    {
    gint payload_len;
    guint8 *payload;
    guint header_len;
    guint8 nal_ref_idc;
    GstMapInfo map;
    guint outsize, nalu_size;
    GstClockTime timestamp;
    gboolean marker;

    timestamp = GST_BUFFER_PTS (rtp->buffer);
    payload_len = gst_rtp_buffer_get_payload_len (rtp);
    payload = gst_rtp_buffer_get_payload (rtp);
    marker = gst_rtp_buffer_get_marker (rtp);
    GST_DEBUG_OBJECT (rtph264depay, "receiving %d bytes", payload_len);

    if (payload_len == 0)
        goto empty_packet;

    /* +---------------+
     * |0|1|2|3|4|5|6|7|
     * +-+-+-+-+-+-+-+-+
     * |F|NRI|  Type   |
     * +---------------+
     *
     * F must be 0.
     */
    nal_ref_idc = (payload[0] & 0x60) >> 5;
    nal_unit_type = payload[0] & 0x1f;

    /* at least one byte header with type */
    header_len = 1;
    GST_DEBUG_OBJECT (rtph264depay, "NRI %d, Type %d %s", nal_ref_idc, nal_unit_type, marker ? "marker" : "");

    /* If FU unit was being processed, but the current nal is of a different
     * type.  Assume that the remote payloader is buggy (didn't set the end bit
     * when the FU ended) and send out what we gathered thusfar */
    if (G_UNLIKELY (rtph264depay->current_fu_type != 0 && nal_unit_type != rtph264depay->current_fu_type))
        gst_rtp_h264_finish_fragmentation_unit (rtph264depay);

    switch (nal_unit_type) {
      case 0:
      case 30:
      case 31:
        /* undefined */
        goto undefined_type;
      case 25:
        /* STAP-B    Single-time aggregation packet     5.7.1 */
        /* 2 byte extra header for DON */
        header_len += 2;
        /* fallthrough */
      case 24:
      {
        /* strip headers */
        payload += header_len;
        payload_len -= header_len;
        rtph264depay->wait_start = FALSE;

        /* STAP-A    Single-time aggregation packet     5.7.1 */
        while (payload_len > 2) {
            gboolean last = FALSE;
          /*                      1
           *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
           * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           * |         NALU Size             |
           * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           */
          nalu_size = (payload[0] << 8) | payload[1];

          /* don't include nalu_size */
          if (nalu_size > (payload_len - 2))
            nalu_size = payload_len - 2;

          outsize = nalu_size + sizeof (sync_bytes);
          outbuf = gst_buffer_new_and_alloc (outsize);
          gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
          if (rtph264depay->byte_stream) {
            memcpy (map.data, sync_bytes, sizeof (sync_bytes));
          } else {
            map.data[0] = map.data[1] = 0;
            map.data[2] = payload[0];
            map.data[3] = payload[1];
          }

          /* strip NALU size */
          payload += 2;
          payload_len -= 2;
          memcpy (map.data + sizeof (sync_bytes), payload, nalu_size);
          gst_buffer_unmap (outbuf, &map);
          gst_rtp_copy_video_meta (rtph264depay, outbuf, rtp->buffer);
          if (payload_len - nalu_size <= 2)
            last = TRUE;
          gst_rtp_h264_depay_handle_nal (rtph264depay, outbuf, timestamp,
              marker && last);
          payload += nalu_size;
          payload_len -= nalu_size;
        }
        break;
      }
      case 26:
        /* MTAP16    Multi-time aggregation packet      5.7.2 */
        // header_len = 5;
        /* fallthrough, not implemented */
      case 27:
        /* MTAP24    Multi-time aggregation packet      5.7.2 */
        // header_len = 6;
        goto not_implemented;
        break;
      case 28:
      case 29:
      {
        /* FU-A      Fragmentation unit                 5.8 */
        /* FU-B      Fragmentation unit                 5.8 */
        gboolean S, E;
        /* +---------------+
         * |0|1|2|3|4|5|6|7|
         * +-+-+-+-+-+-+-+-+
         * |S|E|R|  Type   |
         * +---------------+
         *
         * R is reserved and always 0
         */
        S = (payload[1] & 0x80) == 0x80;
        E = (payload[1] & 0x40) == 0x40;
        GST_DEBUG_OBJECT (rtph264depay, "S %d, E %d", S, E);

        if (rtph264depay->wait_start && !S)
          goto waiting_start;

        if (S) {
          /* NAL unit starts here */
          guint8 nal_header;

          /* If a new FU unit started, while still processing an older one.
           * Assume that the remote payloader is buggy (doesn't set the end
           * bit) and send out what we've gathered thusfar */
          if (G_UNLIKELY (rtph264depay->current_fu_type != 0))
            gst_rtp_h264_finish_fragmentation_unit (rtph264depay);
          rtph264depay->current_fu_type = nal_unit_type;
          rtph264depay->fu_timestamp = timestamp;
          rtph264depay->last_fu_seqnum = gst_rtp_buffer_get_seq (rtp);
          rtph264depay->wait_start = FALSE;
          /* reconstruct NAL header */
          nal_header = (payload[0] & 0xe0) | (payload[1] & 0x1f);

          /* strip type header, keep FU header, we'll reuse it to reconstruct
           * the NAL header. */
          payload += 1;
          payload_len -= 1;

          nalu_size = payload_len;
          outsize = nalu_size + sizeof (sync_bytes);
          outbuf = gst_buffer_new_and_alloc (outsize);

          gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
          memcpy (map.data + sizeof (sync_bytes), payload, nalu_size);
          map.data[sizeof (sync_bytes)] = nal_header;
          gst_buffer_unmap (outbuf, &map);

          gst_rtp_copy_video_meta (rtph264depay, outbuf, rtp->buffer);
          GST_DEBUG_OBJECT (rtph264depay, "queueing %d bytes", outsize);

          /* and assemble in the adapter */
          gst_adapter_push (rtph264depay->adapter, outbuf);
        } else {
          if (rtph264depay->current_fu_type == 0) {
            /* previous FU packet missing start bit? */
            GST_WARNING_OBJECT (rtph264depay, "missing FU start bit on an "
                "earlier packet. Dropping.");
            gst_adapter_clear (rtph264depay->adapter);
            return NULL;
          }
          if (gst_rtp_buffer_compare_seqnum (rtph264depay->last_fu_seqnum,
                  gst_rtp_buffer_get_seq (rtp)) != 1) {
            /* jump in sequence numbers within an FU is cause for discarding */
            GST_WARNING_OBJECT (rtph264depay, "Jump in sequence numbers from "
                "%u to %u within Fragmentation Unit. Data was lost, dropping "
                "stored.", rtph264depay->last_fu_seqnum,
                gst_rtp_buffer_get_seq (rtp));
            gst_adapter_clear (rtph264depay->adapter);
            return NULL;
          }
          rtph264depay->last_fu_seqnum = gst_rtp_buffer_get_seq (rtp);

          /* strip off FU indicator and FU header bytes */
          payload += 2;
          payload_len -= 2;
          outsize = payload_len;
          outbuf = gst_buffer_new_and_alloc (outsize);
          gst_buffer_fill (outbuf, 0, payload, outsize);
          gst_rtp_copy_video_meta (rtph264depay, outbuf, rtp->buffer);
          GST_DEBUG_OBJECT (rtph264depay, "queueing %d bytes", outsize);

          /* and assemble in the adapter */
          gst_adapter_push (rtph264depay->adapter, outbuf);
        }
        outbuf = NULL;
        rtph264depay->fu_marker = marker;

        /* if NAL unit ends, flush the adapter */
        if (E)
          gst_rtp_h264_finish_fragmentation_unit (rtph264depay);
        break;
      }
      default:
      {
        rtph264depay->wait_start = FALSE;

        /* 1-23   NAL unit  Single NAL unit packet per H.264   5.6 */
        /* the entire payload is the output buffer */
        nalu_size = payload_len;
        outsize = nalu_size + sizeof (sync_bytes);
        outbuf = gst_buffer_new_and_alloc (outsize);

        gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
        if (rtph264depay->byte_stream) {
          memcpy (map.data, sync_bytes, sizeof (sync_bytes));
        } else {
          map.data[0] = map.data[1] = 0;
          map.data[2] = nalu_size >> 8;
          map.data[3] = nalu_size & 0xff;
        }
        memcpy (map.data + sizeof (sync_bytes), payload, nalu_size);
        gst_buffer_unmap (outbuf, &map);
        gst_rtp_copy_video_meta (rtph264depay, outbuf, rtp->buffer);
        gst_rtp_h264_depay_handle_nal (rtph264depay, outbuf, timestamp, marker);
        break;
      }
    }
  }
  return NULL;

  /* ERRORS */
empty_packet:
  {
    GST_DEBUG_OBJECT (rtph264depay, "empty packet");
    return NULL;
  }
undefined_type:
  {
    GST_ELEMENT_WARNING (rtph264depay, STREAM, DECODE,
        (NULL), ("Undefined packet type"));
    return NULL;
  }
waiting_start:
  {
    GST_DEBUG_OBJECT (rtph264depay, "waiting for start");
    return NULL;
  }
not_implemented:
  {
    GST_ELEMENT_ERROR (rtph264depay, STREAM, FORMAT,
        (NULL), ("NAL unit type %d not supported yet", nal_unit_type));
    return NULL;
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1551298.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++初阶:2_类与对象(下)

类与对象(下) 一.再谈构造函数 1. 构造函数体赋值 在创建对象时&#xff0c;编译器通过调用构造函数&#xff0c;给对象中各个成员变量一个合适的初始值。 class Date { public:Date(int year, int month, int day){_year year;_month month;_day day;} private:int _ye…

Kubernetes容器平台下的 GPU 集群算力管控

引言 随着最近一两年生成式大模型的迭代出新&#xff0c;尤其是以 ChartGPT 为代表的大语言模型&#xff0c;几乎一夜间让所有人都看到了人工智能改变世界的潜力。而作为持续发力 GPU 通用计算&#xff08;CUDA&#xff09;的 AI 专业显卡提供商&#xff0c;Nvidia 公司成为了…

人大金仓数据库介绍与使用指南

人大金仓数据库是一款强大的关系型数据库管理系统&#xff0c;具有简单易用、高性能和稳定可靠的特点。本文将介绍人大金仓数据库的安装方法、常用的SQL语法以及相关工具的使用。 一、安装方法&#xff1a; 1、下载人大金仓数据库安装程序&#xff1b; 2、运行安装程序&#…

事件穿透效果

讲述一下事件穿透的需求&#xff0c;大家可以根据实际情况来考虑是否采用这种方式来制作页面&#xff0c;&#xff08;项目中遇到了底部是地图&#xff0c;两侧面板&#xff0c;但是UI在设计的时候为了好看&#xff0c;会有很大的遮罩阴影部分&#xff0c;如果按照时间制作会导…

pip永久修改镜像地址

修改命令&#xff1a; pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple/ 效果&#xff1a; 会在C:\Users\PC(用户名)\AppData\Roaming\pip目录下新增或修改文件pip.ini 文件内容&#xff1a; [global] index-url https://pypi.tuna.tsinghua.e…

关于柔性阵列(/三维阵列)波束形成的仿真实践以及稳健波束形成的思考(1)

说明 关于波束形成&#xff0c;我之前写过几篇相关的博文&#xff0c;如参考资料[1]、[2]、[3]。除去在博文[2]中有讨论过阵元相对位置关系对波束形成的影响&#xff1a;“如何基于遗传算法优化阵元相对位置关系以压低旁瓣峰值”以外&#xff0c;似乎我认知里的天线阵列&#x…

PS从入门到精通视频各类教程整理全集,包含素材、作业等

PS从入门到精通视频各类教程整理全集&#xff0c;包含素材、作业等 最新PS以及插件合集&#xff0c;可在我以往文章中找到 由于阿里云盘有分享次受限制和文件大小限制&#xff0c;今天先分享到这里&#xff0c;后续持续更新 【Photoshop 教程】史上最容易听懂的PS...在最后四…

k8s入门到实战(十四)—— Helm详细介绍及使用

Helm 使用 Helm 是一个 k8s 应用的包管理工具&#xff0c;类似于 Ubuntu 的 APT 和 CentOS 中的 YUM。 Helm 使用 chart 来封装 k8s 应用的 yaml 文件&#xff0c;我们只需要设置自己的参数&#xff0c;就可以实现自动化的快速部署应用。 Helm 通过打包的方式&#xff0c;支…

谭浩强第五版C语言课后习题(编程题)+答案

谭浩强第五版作为初学C语言必读的一本教材&#xff0c;课后习题具有非常大的参考价值&#xff0c;也是很多高校期末考试或者考研的重要参考。在这里我整理了一部分个人认为比较重要的编程题&#xff0c;供大家作参考 1.输入两个数&#xff0c;求他们的最大公约数和最小公倍数&…

Cesium.js综合实验

Cesium.js综合实验 1 概述 Cesium是一个跨平台、跨浏览器的展示三维地球和地图的开源 JavaScript 库&#xff0c;是AGI公司计算机图形开发小组与2011年研发的三维地球和地图可视化开源JavaScript库&#xff0c;Cesium一词来源于化学元素铯&#xff0c;铯是制造原子钟的关键元…

VUE+ elementUI 表头动态渲染的两种方法

效果&#xff1a; <template><div><el-alert title"比较麻烦的写法" type"error"></el-alert><el-table border style"width:300px;" :data"tabelData"><el-table-columnv-for"column in colum…

如何在群晖NAS搭建bitwarden密码管理软件并实现无公网IP远程访问

前言 作者简介&#xff1a; 懒大王敲代码&#xff0c;计算机专业应届生 今天给大家聊聊如何在群晖NAS搭建bitwarden密码管理软件并实现无公网IP远程访问&#xff0c;希望大家能觉得实用&#xff01; 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&am…

访问学者如何申请国外信用卡?

作为一名访问学者&#xff0c;如果你计划在国外长期居住或短期停留&#xff0c;并希望申请国外信用卡&#xff0c;这可能是一个相当实用的工具。国外信用卡不仅可以帮助你在海外购物和旅行时更加便利&#xff0c;还能建立起你在国际金融体系中的信用记录&#xff0c;为未来的金…

鼠标不动了怎么办?鼠标不能移动解决方法

鼠标不能移动有可能是鼠标坏了&#xff0c;或者是电脑的软件和硬件有冲突等原因造成。最近有小伙伴就咨询了有关鼠标的问题&#xff0c;昨天鼠标还能使用&#xff0c;不知道为什么今天就突然不能用了。那么我们在排除鼠标坏掉了的情况下&#xff0c;试试对鼠标进行修复吧。下面…

请你记住这3款国产软件,免费又实用,它们值得收藏

闲话不多说&#xff0c;直上干货。 1、坚果云 坚果云是一款极具良心的网盘软件&#xff0c;其免费版本同样无广告干扰&#xff0c;界面设计简约大气&#xff0c;在文件上传与下载速度上&#xff0c;坚果云完全不限速&#xff0c;这一点远超其他同类产品。 用户可以在手机、电…

粗略总结AI大模型学习需要了解的要点

目录 一、概念简介 二、兴起原因 三、相关要点 四、不足之处 五、总结 一、概念简介 AI大模型学习是指利用大规模数据集和强大计算能力进行深度学习模型的训练。随着数据的爆炸式增长和计算资源的提升&#xff0c;AI大模型学习成为了现代人工智能研究的重要方向。 二、兴起…

徽宇阀门现已加入2024第13届生物发酵展会

参展企业介绍 温州徽宇阀门有限公司是专业生产高精度不锈钢过滤器设备及卫生级阀门、管道、管件及泵等系列产品。秉承严谨、实用的作风,所有产品均选用高品质的原材料。公司对产品品质的要求没有止境,生产全部采用CNC等国际一流的数控加工中心设备&#xff0c;所有产品均按照IS…

Linux系统使用Docker部署Portainer结合内网穿透实现远程管理容器和镜像

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

VR全景赋能智慧农业,打造沉浸式种植体验平台

随着人口的增长&#xff0c;传统农业也正在面临着不一样的挑战&#xff0c;加上很多人对农业的固有印象&#xff0c;很少有年轻人愿意下到农田里&#xff0c;那么该如何提高产量、降低成本以及引导年轻人深刻感受现代农业成为了急需解决的问题。 随着城市化脚步的推进&#xff…

代码随想录笔记|C++数据结构与算法学习笔记-栈和队列(〇)|stack、queue、单调队列和优先队列(priority_queue)、大顶堆和小顶堆

文章目录 stack容器stack 基本概念常用接口构造函数赋值操作数据存取大小操作 queue容器queue常用接口构造函数&#xff1a;赋值操作数据存取大小操作 单调队列优先队列大顶堆小顶堆 stack容器 stack 基本概念 栈中只有顶端的元素才可以被外界使用&#xff0c;因此栈不允许有遍…