Guest User

serverRTP

a guest
Nov 18th, 2020
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.07 KB | None | 0 0
  1. #include <iostream>
  2. #include <gst/gst.h>
  3.  
  4. #include <gst/rtp/rtp.h>
  5. #include <time.h>
  6. using namespace std;
  7.  
  8. /*
  9.  * Sender example setup
  10.  * sends the output of v4l2src as h264 encoded RTP on port 5000, RTCP is sent on
  11.  * port 5001. The destination is 127.0.0.1.
  12.  * the video receiver RTCP reports are received on port 5005
  13.  *
  14.  * .-------.    .-------.    .-------.      .----------.     .-------.
  15.  * |v4l2   |    |x264enc|    |h264pay|      | rtpbin   |     |udpsink|  RTP
  16.  * |      src->sink    src->sink    src->send_rtp send_rtp->sink     | port=5000
  17.  * '-------'    '-------'    '-------'      |          |     '-------'
  18.  *                                          |          |
  19.  *                                          |          |     .-------.
  20.  *                                          |          |     |udpsink|  RTCP
  21.  *                                          |    send_rtcp->sink     | port=5001
  22.  *              .-------.    .--------.     |          |     '-------' sync=false
  23.  *    RTCP      |udpsrc |    |identity|     |          |               async=false
  24.  *    port=5005 |      src->sink     src->recv_rtcp    |
  25.  *              '-------'    '--------'     '----------'
  26.  */
  27.  
  28.  
  29. void OnPadAdded(GstElement *element, GstPad *pad, gpointer data) {
  30.     GstPad *sinkpad;
  31.     //узнаю навания элементов котоыре передаются.
  32.     gchar *name = gst_element_get_name(element);
  33.     g_print("Element name is %s\n",name);
  34.     gchar *pad_name = GST_PAD_NAME(pad);
  35.     g_print("Element pad is %s\n",pad_name);
  36.     //узнаю навания элементов котоыре передаются.
  37.     GstElement *udpsink = (GstElement *) data;
  38.     gchar *name_decoder = gst_element_get_name(udpsink);
  39.     g_print("Element name is %s\n",name_decoder);
  40.  
  41.  
  42.     sinkpad = gst_element_get_static_pad(udpsink, "sink");
  43.  
  44.     GstPadLinkReturn ret = gst_pad_link(pad, sinkpad);
  45.  
  46.     gst_object_unref(sinkpad);
  47. }
  48.  
  49. static gboolean bus_call (GstBus     *bus,
  50.                          GstMessage *msg,
  51.                          gpointer    data)
  52. {
  53.     GMainLoop *loop = (GMainLoop *)data;
  54.  
  55.     switch (GST_MESSAGE_TYPE (msg)) {
  56.     case GST_MESSAGE_EOS:
  57.         g_print ("End-of-stream\n");
  58.         g_main_loop_quit (loop);
  59.         break;
  60.     case GST_MESSAGE_ERROR: {
  61.         gchar *debug = NULL;
  62.         GError *err = NULL;
  63.  
  64.         gst_message_parse_error (msg, &err, &debug);
  65.  
  66.         g_print ("Error: %s\n", err->message);
  67.         g_error_free (err);
  68.  
  69.         if (debug) {
  70.             g_print ("Debug details: %s\n", debug);
  71.             g_free (debug);
  72.         }
  73.  
  74.         g_main_loop_quit (loop);
  75.         break;
  76.     }
  77.     default:
  78.         break;
  79.     }
  80.  
  81.     return TRUE;
  82. }
  83.  
  84.  
  85. static gboolean
  86. process_rtcp_packet(GstRTCPPacket *packet){
  87.     guint32 ssrc, rtptime, packet_count, octet_count;
  88.     guint64 ntptime;
  89.     guint count, i;
  90.  
  91.     count = gst_rtcp_packet_get_rb_count(packet);
  92.     cerr << "    count " << count;
  93.     for (i=0; i<count; i++) {
  94.         guint32 exthighestseq, jitter, lsr, dlsr;
  95.         guint8 fractionlost;
  96.         gint32 packetslost;
  97.  
  98.         gst_rtcp_packet_get_rb(packet, i, &ssrc, &fractionlost,
  99.                                &packetslost, &exthighestseq, &jitter, &lsr, &dlsr);
  100.  
  101.         cerr << "    block " << i;
  102.         cerr << "    ssrc " << ssrc;
  103.         cerr << "    highest seq " << exthighestseq;
  104.         cerr << "    jitter " << jitter;
  105.         cerr << "    fraction lost " << fractionlost;
  106.         cerr << "    packet lost " << packetslost;
  107.         cerr << "    lsr " << lsr;
  108.         cerr << "    dlsr " << dlsr;
  109.  
  110.         //        rtcp_pkt->fractionlost = fractionlost;
  111.         //        rtcp_pkt->jitter = jitter;
  112.         //        rtcp_pkt->packetslost = packetslost;
  113.     }
  114.  
  115.     //cerr << "Received rtcp packet");
  116.  
  117.     return TRUE;
  118. }
  119.  
  120.  
  121. static gboolean cb_receive_rtcp(GstElement *rtpsession, GstBuffer *buf, gpointer data){
  122.  
  123.     GstRTCPBuffer rtcpBuffer = GST_RTCP_BUFFER_INIT;
  124.     //    GstRTCPBuffer *rtcpBuffer = (GstRTCPBuffer*)malloc(sizeof(GstRTCPBuffer));
  125.     //    rtcpBuffer->buffer = nullptr;
  126.     GstRTCPPacket *rtcpPacket = (GstRTCPPacket*)malloc(sizeof(GstRTCPPacket));
  127.  
  128.  
  129.     if (!gst_rtcp_buffer_validate(buf))
  130.     {
  131.         cerr << "Received invalid RTCP packet" << endl;
  132.     }
  133.  
  134.     cerr << "Received rtcp packet" << "\n";
  135.  
  136.  
  137.     gst_rtcp_buffer_map (buf,(GstMapFlags)(GST_MAP_READ),&rtcpBuffer);
  138.     gboolean more = gst_rtcp_buffer_get_first_packet(&rtcpBuffer,rtcpPacket);
  139.     while (more) {
  140.         GstRTCPType type;
  141.  
  142.         type = gst_rtcp_packet_get_type(rtcpPacket);
  143.         switch (type) {
  144.         case GST_RTCP_TYPE_RR:
  145.             process_rtcp_packet(rtcpPacket);
  146.             //   gst_rtcp_buffer_unmap (&rtcpBuffer);
  147.             //g_debug("RR");
  148.             //send_event_to_encoder(venc, &rtcp_pkt);
  149.             break;
  150.         default:
  151.             cerr << "Other types" << endl;
  152.             break;
  153.         }
  154.         more = gst_rtcp_packet_move_to_next(rtcpPacket);
  155.     }
  156.  
  157.     free(rtcpPacket);
  158.     return TRUE;
  159. }
  160. bool linkStaticAndRequestPad(GstElement *sourse,GstElement *sink,gchar *nameSrcPad,gchar *nameSinkPad)
  161. {
  162.  
  163.     GstPad *srcPad = gst_element_get_static_pad(sourse,nameSrcPad);
  164.     GstPad *sinkPad = gst_element_get_request_pad(sink,nameSinkPad);
  165.     GstPadLinkReturn ret_link = gst_pad_link(srcPad,sinkPad);
  166.     if (ret_link != GST_PAD_LINK_OK)
  167.     {
  168.         cerr << "Error create link, beetwen recvRtpSinkPad and udpSrcRtpPad\n";
  169.         return false;
  170.     }
  171.     gst_object_unref(GST_OBJECT(srcPad));
  172.     gst_object_unref(GST_OBJECT(sinkPad));
  173.     return true;
  174. }
  175. bool linkRequestAndStatic(GstElement *sourse,GstElement *sink,gchar *nameSrcPad,gchar *nameSinkPad)
  176. {
  177.  
  178.  
  179.     GstPad *srcPad = gst_element_get_request_pad(sourse,nameSrcPad);
  180.     GstPad *sinkPad = gst_element_get_static_pad(sink,nameSinkPad);
  181.     GstPadLinkReturn ret_link = gst_pad_link(srcPad,sinkPad);
  182.     if (ret_link != GST_PAD_LINK_OK)
  183.     {
  184.         cerr << "Error create link, beetwen recvRtpSinkPad and udpSrcRtpPad\n";
  185.         return false;
  186.     }
  187.     gst_object_unref(GST_OBJECT(srcPad));
  188.     gst_object_unref(GST_OBJECT(sinkPad));
  189.     return true;
  190. }
  191.  
  192. static GstPadProbeReturn load_time_send_to_rtp(GstPad *pad, GstPadProbeInfo *info, gpointer *data) {
  193.  
  194.     GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
  195.     GstRTPBuffer rtp_buffer;
  196.     memset(&rtp_buffer, 0, sizeof(GstRTPBuffer));
  197.  
  198.     if (buffer != NULL) {
  199.         struct timespec ts;
  200.         timespec_get(&ts, TIME_UTC);
  201.         gconstpointer nsec = &ts.tv_nsec;
  202.         gconstpointer sec = &ts.tv_sec;
  203.         if (gst_rtp_buffer_map(buffer, (GstMapFlags)GST_MAP_READWRITE, &rtp_buffer)) {
  204.             //gst_rtp_buffer_add_extension_onebyte_header()
  205.  
  206.             gst_rtp_buffer_add_extension_twobytes_header(&rtp_buffer, 0, 1, nsec, sizeof(ts.tv_nsec));
  207.             gst_rtp_buffer_add_extension_twobytes_header(&rtp_buffer, 0, 2, sec, sizeof(ts.tv_sec));
  208.             std::cout << "sec: " << ts.tv_sec << " " << "nanosec: " << ts.tv_nsec <<  std::endl;
  209.         }
  210.         else {
  211.             cerr << "RTP buffer not mapped\n";
  212.         }
  213.     }
  214.     else {
  215.         cerr << "Gst buffer is NULL\n";
  216.     }
  217.     gst_rtp_buffer_unmap(&rtp_buffer);
  218. }
  219.  
  220. GstElement *create_pipeline(){
  221.     GstElement *pipeline,*source,*videconverter,
  222.         *x264encoder,*rtph264pay,
  223.         *rtpbin,*udpSinkRtp;
  224.     GstElement *udpSrcRtcp,*udpSinkRtcp;
  225.  
  226.     pipeline = gst_pipeline_new("rtpStreamer");
  227.  
  228.     // Создаю элемент захвата видео с камеры.
  229.     source = gst_element_factory_make("v4l2src","source");
  230.     // Создаю элелмент который преобразует данные с камеры, к данным которые поддерживает кодировщик.
  231.     videconverter = gst_element_factory_make("videoconvert","converter");
  232.     // Создаю кодек
  233.     x264encoder = gst_element_factory_make("x264enc","encoder");
  234.     // Создаю элемент который упакуют донные от кодера, в rtp пакеты
  235.     rtph264pay = gst_element_factory_make("rtph264pay","rtppay");
  236.     // Создаю элемент управющий rtp сесией
  237.     rtpbin = gst_element_factory_make("rtpbin","rtpbin");
  238.     // Создаю udp сток для отпраки rtp пакетов
  239.     udpSinkRtp = gst_element_factory_make("udpsink","udpSinkRtp");
  240.     // Создаю upd сток для отпраки rtcp пакетов
  241.     udpSinkRtcp = gst_element_factory_make("udpsink","udpSinkRtcp");
  242.     // Создаю udp источник для принятия rtcp пакетов.
  243.     udpSrcRtcp = gst_element_factory_make("udpsrc","udpSrcRtcp");
  244.  
  245.     if (!pipeline || !source || !videconverter || !x264encoder || !rtph264pay || !rtpbin || !udpSinkRtp || !udpSinkRtcp || !udpSrcRtcp)
  246.     {
  247.         cerr << "Not all elements could be created.\n";
  248.         return NULL;
  249.     }
  250.     // Задаю устройство с которог захватывать видео
  251.     g_object_set(G_OBJECT(source),"device","/dev/video0",NULL);
  252.     // Устанавливаю параметры кодека.
  253.     g_object_set(G_OBJECT(x264encoder),"tune",0x00000004,NULL);
  254.     g_object_set(G_OBJECT(x264encoder),"bitrate",500,NULL);
  255.     //   g_object_set(G_OBJECT(x264encoder),"threads",2,NULL);
  256.  
  257.     // Устанавливаю параметры для upd сойденений.
  258.     g_object_set(G_OBJECT(udpSinkRtp),"host","127.0.0.1",NULL);
  259.     g_object_set(G_OBJECT(udpSinkRtp),"port",5000,NULL);
  260.  
  261.     g_object_set(G_OBJECT(udpSinkRtcp),"host","127.0.0.1",NULL);
  262.     g_object_set(G_OBJECT(udpSinkRtcp),"port",5001,NULL);
  263.     g_object_set(G_OBJECT(udpSinkRtcp),"sync",FALSE,NULL);
  264.     g_object_set(G_OBJECT(udpSinkRtcp),"async",FALSE,NULL);
  265.  
  266.     g_object_set(G_OBJECT(udpSrcRtcp),"address","127.0.0.1",NULL);
  267.     g_object_set(G_OBJECT(udpSrcRtcp),"port",5005,NULL);
  268.     g_object_set(G_OBJECT (udpSrcRtcp), "caps", gst_caps_from_string("application/x-rtcp"), NULL);
  269.  
  270.  
  271.     // Добавляю элементы в контейнер
  272.     gst_bin_add_many(GST_BIN(pipeline),source,videconverter,
  273.                      x264encoder,rtph264pay,rtpbin,
  274.                      udpSinkRtp,udpSinkRtcp,udpSrcRtcp,NULL);
  275.  
  276.  
  277.     // Создаю caps для того, чтобы согласовать параметры захвата видео с камеры и кодировщика.
  278.     GstCaps *capV4l2VideoConverter;
  279.     capV4l2VideoConverter = gst_caps_new_simple ("video/x-raw",
  280.                                                 "format",G_TYPE_STRING,"YUY2",
  281.                                                 "framerate", GST_TYPE_FRACTION, 30, 1,
  282.                                                 NULL);
  283.     if (!capV4l2VideoConverter){
  284.         cerr << "Error create caps\n";
  285.         return NULL;
  286.     }
  287.     GstCaps *capVideoConverterEncoder;
  288.     capVideoConverterEncoder  = gst_caps_new_simple ("video/x-raw",
  289.                                                    "format",G_TYPE_STRING,"I420",
  290.                                                    "framerate", GST_TYPE_FRACTION, 30, 1,
  291.                                                    NULL);
  292.     if (!capVideoConverterEncoder){
  293.         cerr << "Error create caps\n";
  294.         return NULL;
  295.     }
  296.  
  297.  
  298.     // Связваю все элементы.
  299.     if (!gst_element_link_filtered(source,videconverter,capV4l2VideoConverter))
  300.     {
  301.         cerr << "Elements could not be linked source and videoconv.\n";
  302.         return NULL;
  303.     }
  304.  
  305.     if (!gst_element_link_filtered(videconverter,x264encoder,capVideoConverterEncoder))
  306.     {
  307.         cerr << "Elements could not be linked videoconv and x264.\n";
  308.         return NULL;
  309.     }
  310.  
  311.  
  312.  
  313.     if (!gst_element_link_many(x264encoder,rtph264pay,NULL))
  314.     {
  315.         cerr << "Elements could not be linked other.\n";
  316.         return NULL;
  317.  
  318.     }
  319.  
  320.     if (!linkStaticAndRequestPad(rtph264pay,rtpbin,"src","send_rtp_sink_%u"))
  321.     {
  322.         cerr << "Error create link, beetwen rtph264pay and rtpbin\n";
  323.         return NULL;
  324.     }
  325.  
  326.     if (!gst_element_link(rtpbin,udpSinkRtp))
  327.     {
  328.         cerr << "Elements could not be linked rtpbin and udpSinkRtp.\n";
  329.     }
  330.  
  331.     if (!linkRequestAndStatic(rtpbin,udpSinkRtcp,"send_rtcp_src_%u","sink"))
  332.     {
  333.         cerr << "Error create link, beetwen rtpbin and udpSinkRtcp\n";
  334.         return NULL;
  335.     }
  336.  
  337.  
  338.     if (!linkStaticAndRequestPad(udpSrcRtcp,rtpbin,"src","recv_rtcp_sink_%u"))
  339.     {
  340.         cerr << "Error create link, beetwen udpSrcRtcp and rtpbin\n";
  341.         return NULL;
  342.     }
  343.     //Пад для расширения заголовка RTP, не успел проверить работает код или нет.
  344.  /*   GstPad *rtpPaySrcPad = gst_element_get_static_pad(rtph264pay, "src");
  345.     gst_pad_add_probe(rtpPaySrcPad, GST_PAD_PROBE_TYPE_BUFFER, (GstPadProbeCallback)load_time_send_to_rtp, NULL, NULL);
  346.     gst_object_unref(GST_OBJECT(rtpPaySrcPad));
  347.  
  348.     // Подключаю сигнал по обработке принятых rtcp пакетов.
  349.     GObject *session;
  350.     g_signal_emit_by_name (rtpbin, "get-internal-session", 0, &session);
  351.     g_signal_connect_after (session, "on-receiving-rtcp",
  352.                            G_CALLBACK (cb_receive_rtcp), NULL);
  353.     // g_object_unref(session);
  354.     */
  355.     return pipeline;
  356.  
  357. }
  358.  
  359.  
  360. int main(int argc, char *argv[])
  361. {
  362.  
  363.  
  364.  
  365.     gst_init(0,0);
  366.  
  367.  
  368.  
  369.     GMainLoop *loop;
  370.     loop = g_main_loop_new(NULL,FALSE);
  371.     GstBus *bus;
  372.  
  373.     GstElement *pipeline = create_pipeline();
  374.     if (pipeline == NULL)
  375.     {
  376.         cerr << "Error create pipeline!" << endl;
  377.         return -1;
  378.     }
  379.  
  380.     guint watch_id;
  381.     bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
  382.     watch_id = gst_bus_add_watch (bus, bus_call, loop);
  383.     gst_object_unref (bus);
  384.  
  385.  
  386.     GstStateChangeReturn ret;
  387.     ret = gst_element_set_state(pipeline, GST_STATE_PLAYING);
  388.  
  389.     g_main_loop_run (loop);
  390.  
  391.  
  392.  
  393.     /* clean up */
  394.     gst_element_set_state (pipeline, GST_STATE_NULL);
  395.     gst_object_unref (pipeline);
  396.     g_source_remove (watch_id);
  397.     g_main_loop_unref (loop);
  398.  
  399.  
  400.     return 0;
  401. }
  402.  
Add Comment
Please, Sign In to add comment