LCOV - code coverage report
Current view: top level - filters - in_rtp.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 208 340 61.2 %
Date: 2021-04-29 23:48:07 Functions: 11 13 84.6 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2021
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / RTP/RTSP input filter
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : #include "in_rtp.h"
      27             : 
      28             : #ifndef GPAC_DISABLE_STREAMING
      29             : 
      30             : 
      31          20 : static void rtpin_reset(GF_RTPIn *ctx, Bool is_finalized)
      32             : {
      33          60 :         while (gf_list_count(ctx->streams)) {
      34          20 :                 GF_RTPInStream *st = (GF_RTPInStream *)gf_list_get(ctx->streams, 0);
      35          20 :                 gf_list_rem(ctx->streams, 0);
      36          20 :                 if (!is_finalized && st->opid) gf_filter_pid_remove(st->opid);
      37          20 :                 rtpin_stream_del(st);
      38             :         }
      39             : 
      40          20 :         rtpin_rtsp_del(ctx->session);
      41          20 :         ctx->session = NULL;
      42             : 
      43          20 :         if (ctx->iod_desc) gf_odf_desc_del(ctx->iod_desc);
      44          20 :         ctx->iod_desc = NULL;
      45          20 : }
      46             : 
      47        2939 : static GF_FilterProbeScore rtpin_probe_url(const char *url, const char *mime)
      48             : {
      49             :         /*embedded data - TO TEST*/
      50        2939 :         if (strstr(url, "data:application/mpeg4-od-au;base64")
      51        2939 :                 || strstr(url, "data:application/mpeg4-bifs-au;base64")
      52        2939 :                 || strstr(url, "data:application/mpeg4-es-au;base64"))
      53             :         {
      54             :                 return GF_FPROBE_SUPPORTED;
      55             :         }
      56             : 
      57             :         /*we need rtsp/tcp , rtsp/udp or direct RTP sender (no control)*/
      58        2939 :         if (!strnicmp(url, "rtsp://", 7)
      59        2934 :                 || !strnicmp(url, "rtspu://", 8)
      60        2934 :                 || !strnicmp(url, "rtp://", 6)
      61        2933 :                 || !strnicmp(url, "satip://", 6))
      62             :         {
      63             :                 return GF_FPROBE_SUPPORTED;
      64             :         }
      65             : 
      66        2933 :         return GF_FPROBE_NOT_SUPPORTED;
      67             : }
      68             : 
      69             : //simplified version of RTSP_UnpackURL for SAT>IP
      70           0 : static void rtpin_satip_get_server_ip(const char *sURL, char *Server)
      71             : {
      72             :         char schema[10], *test, text[1024], *retest;
      73             :         u32 i, len;
      74             :         Bool is_ipv6;
      75             : 
      76             :         strcpy(Server, "");
      77             : 
      78             :         //extract the schema
      79             :         i = 0;
      80           0 :         while (i <= strlen(sURL)) {
      81           0 :                 if (sURL[i] == ':')
      82             :                         goto found;
      83           0 :                 schema[i] = sURL[i];
      84           0 :                 i += 1;
      85             :         }
      86           0 :         return;
      87             : 
      88           0 : found:
      89           0 :         schema[i] = 0;
      90           0 :         if (stricmp(schema, "satip")) {
      91           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP] Wrong SATIP schema %s - not setting up\n", schema));
      92             :                 return;
      93             :         }
      94           0 :         test = strstr(sURL, "://");
      95           0 :         test += 3;
      96             : 
      97             :         //check for port
      98           0 :         retest = strrchr(test, ':');
      99             :         /*IPV6 address*/
     100           0 :         if (retest && strchr(retest, ']')) retest = NULL;
     101             : 
     102           0 :         if (retest && strstr(retest, "/")) {
     103           0 :                 retest += 1;
     104             :                 i = 0;
     105           0 :                 while (i<strlen(retest)) {
     106           0 :                         if (retest[i] == '/') break;
     107           0 :                         text[i] = retest[i];
     108           0 :                         i += 1;
     109             :                 }
     110           0 :                 text[i] = 0;
     111             :         }
     112             :         //get the server name
     113             :         is_ipv6 = GF_FALSE;
     114           0 :         len = (u32)strlen(test);
     115             :         i = 0;
     116           0 :         while (i<len) {
     117           0 :                 if (test[i] == '[') is_ipv6 = GF_TRUE;
     118           0 :                 else if (test[i] == ']') is_ipv6 = GF_FALSE;
     119           0 :                 if ((test[i] == '/') || (!is_ipv6 && (test[i] == ':'))) break;
     120           0 :                 text[i] = test[i];
     121           0 :                 i += 1;
     122             :         }
     123           0 :         text[i] = 0;
     124             :         strcpy(Server, text);
     125             : }
     126             : 
     127             : 
     128          14 : static GF_Err rtpin_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
     129             : {
     130             :         const GF_PropertyValue *prop;
     131             :         const char *src = NULL;
     132             :         u32 crc;
     133          14 :         GF_RTPIn *ctx = gf_filter_get_udta(filter);
     134             : 
     135          14 :         if (ctx->src) {
     136           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[RTPIn] Configure pid called on filter instanciated with SRC %s\n", ctx->src));
     137             :                 return GF_BAD_PARAM;
     138             :         }
     139             : 
     140          14 :         if (is_remove) {
     141           0 :                 ctx->ipid = NULL;
     142             :                 //reset session, remove pids
     143           0 :                 rtpin_reset(ctx, GF_FALSE);
     144           0 :                 return GF_OK;
     145             :         }
     146             : 
     147          14 :         if (! gf_filter_pid_check_caps(pid))
     148             :                 return GF_NOT_SUPPORTED;
     149             : 
     150             :         //we must have a file path
     151          14 :         prop = gf_filter_pid_get_property(pid, GF_PROP_PID_FILEPATH);
     152          14 :         if (prop && prop->value.string) src = prop->value.string;
     153             :         if (!src)
     154             :                 return GF_NOT_SUPPORTED;
     155             : 
     156          14 :         crc = gf_crc_32(src, (u32) strlen(src) );
     157             : 
     158          14 :         if (!ctx->ipid) {
     159          14 :                 ctx->ipid = pid;
     160             :         } else {
     161           0 :                 if (pid != ctx->ipid) {
     162             :                         return GF_REQUIRES_NEW_INSTANCE;
     163             :                 }
     164           0 :                 if (ctx->sdp_url_crc == crc) return GF_OK;
     165             : 
     166             :                 //reset session, remove pids for now
     167           0 :                 rtpin_reset(ctx, GF_FALSE);
     168             :         }
     169          14 :         gf_filter_pid_set_framing_mode(pid, GF_TRUE);
     170          14 :         ctx->sdp_url_crc = crc;
     171          14 :         ctx->sdp_loaded = GF_FALSE;
     172          14 :         return GF_OK;
     173             : }
     174             : 
     175             : 
     176           0 : static void gf_rtp_switch_quality(GF_RTPIn *rtp, Bool switch_up)
     177             : {
     178             :         u32 i,count;
     179             :         GF_RTPInStream *stream, *cur_stream;
     180             : 
     181           0 :         count = gf_list_count(rtp->streams);
     182             :         /*find the current stream*/
     183             :         stream = cur_stream = NULL;
     184           0 :         for (i = 0; i < count; i++) {
     185           0 :                 cur_stream = (GF_RTPInStream *) gf_list_get(rtp->streams, i);
     186           0 :                 if (cur_stream->mid != rtp->cur_mid) {
     187             :                         cur_stream = NULL;
     188           0 :                         continue;
     189             :                 }
     190             :                 break;
     191             :         }
     192           0 :         if (!cur_stream) return;
     193             : 
     194           0 :         if (switch_up) {
     195             :                 /*this is the highest stream*/
     196           0 :                 if (!cur_stream->next_stream) {
     197           0 :                         cur_stream->status = RTP_Running;
     198             :                         return;
     199             :                 } else {
     200           0 :                         for (i = 0; i < count; i++) {
     201           0 :                                 stream = (GF_RTPInStream *) gf_list_get(rtp->streams, i);
     202           0 :                                 if (stream->mid == cur_stream->next_stream) {
     203             :                                         /*resume streaming next channel*/
     204           0 :                                         rtpin_stream_init(stream, GF_FALSE);
     205           0 :                                         stream->status = RTP_Running;
     206           0 :                                         rtp->cur_mid = stream->mid;
     207             :                                         break;
     208             :                                 }
     209             : 
     210             :                         }
     211             :                 }
     212             :         } else {
     213             :                 /*this is the lowest stream i.e base layer*/
     214           0 :                 if (!cur_stream->prev_stream) {
     215           0 :                         cur_stream->status = RTP_Running;
     216             :                         return;
     217             :                 } else {
     218           0 :                         for (i = 0; i < count; i++) {
     219           0 :                                 stream = (GF_RTPInStream *) gf_list_get(rtp->streams, i);
     220           0 :                                 if (stream->mid == cur_stream->prev_stream) {
     221             :                                         /*stop streaming current channel*/
     222           0 :                                         gf_rtp_stop(cur_stream->rtp_ch);
     223           0 :                                         cur_stream->status = RTP_Connected;
     224           0 :                                         rtp->cur_mid = stream->mid;
     225             :                                         break;
     226             :                                 }
     227             :                         }
     228             :                 }
     229             :         }
     230           0 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("Switch from ES%d to ES %d\n", cur_stream->mid, stream->mid));
     231             :         return;
     232             : }
     233             : 
     234             : 
     235             : #ifdef FILTER_FIXME
     236             : static void rtpin_send_data_base64(GF_RTPInStream *stream)
     237             : {
     238             :         u32 size;
     239             :         char *pck_data;
     240             :         GF_FilterPacket *pck;
     241             :         char *data;
     242             : 
     243             :         if (stream->current_start<0) return;
     244             : 
     245             :         data = strstr(stream->control, ";base64");
     246             :         if (!data) return;
     247             : 
     248             :         /*decode data*/
     249             :         data = strstr(data, ",");
     250             :         data += 1;
     251             :         size = gf_base64_decode(data, (u32) strlen(data), stream->buffer, stream->rtpin->block_size);
     252             : 
     253             :         pck = gf_filter_pck_new_alloc(stream->opid, size, &pck_data);
     254             :         if (!pck) return;
     255             :         memcpy(pck_data, stream->buffer, size);
     256             :         gf_filter_pck_set_cts(pck, (u64) (stream->current_start * stream->ts_res));
     257             :         gf_filter_pck_set_sap(pck, GF_FILTER_SAP_1);
     258             :         gf_filter_pck_send(pck);
     259             : 
     260             :         stream->flags &= ~GF_RTP_NEW_AU;
     261             :         stream->current_start = -1;
     262             : }
     263             : #endif
     264             : 
     265           6 : static void rtpin_check_setup(GF_RTPInStream *stream)
     266             : {
     267             :         RTPIn_StreamDescribe ch_desc;
     268           6 :         switch (stream->status) {
     269           0 :         case RTP_Connected:
     270             :         case RTP_Running:
     271           0 :                 rtpin_stream_ack_connect(stream, GF_OK);
     272           0 :                 return;
     273             :         default:
     274             :                 break;
     275             :         }
     276             :         memset(&ch_desc, 0, sizeof(RTPIn_StreamDescribe));
     277           6 :         ch_desc.opid = stream->opid;
     278           6 :         rtpin_stream_setup(stream, &ch_desc);
     279             : }
     280             : 
     281          86 : static Bool rtpin_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
     282             : {
     283             :         GF_RTPInStream *stream;
     284          86 :         GF_RTPIn *ctx = (GF_RTPIn *) gf_filter_get_udta(filter);
     285             :         Bool reset_stream = GF_FALSE;
     286             :         Bool skip_rtsp_teardown = GF_FALSE;
     287             : 
     288          86 :         if (evt->base.type == GF_FEVT_QUALITY_SWITCH) {
     289           0 :                 gf_rtp_switch_quality(ctx, evt->quality_switch.up);
     290           0 :                 return GF_TRUE;
     291             :         }
     292             : 
     293             :         /*ignore commands other than channels one*/
     294          86 :         if (!evt->base.on_pid) {
     295             :                 return GF_TRUE;
     296             :         }
     297             : 
     298          86 :         stream = rtpin_find_stream(ctx, evt->base.on_pid, 0, NULL, GF_FALSE);
     299          86 :         if (!stream) return GF_TRUE;
     300             : 
     301          72 :         switch (evt->base.type) {
     302          19 :         case GF_FEVT_PLAY:
     303             : 
     304          19 :                 ctx->is_eos = GF_FALSE;
     305             : 
     306          19 :                 if ((stream->status==RTP_Running) && ((ctx->last_start_range >= 0) && (ctx->last_start_range==evt->play.start_range)))
     307             :                         return GF_TRUE;
     308             : 
     309          19 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP] Processing play on channel @%08x - %s\n", stream, stream->rtsp ? "RTSP control" : "No control (RTP)" ));
     310             :                 /*is this RTSP or direct RTP?*/
     311          19 :                 stream->flags &= ~RTP_EOS;
     312          19 :                 stream->flags &= ~RTP_EOS_FLUSHED;
     313             : 
     314          19 :                 if (!(stream->flags & RTP_INTERLEAVED)) {
     315          19 :                         if (stream->rtp_ch->rtp)
     316           0 :                                 gf_sk_group_register(ctx->sockgroup, stream->rtp_ch->rtp);
     317          19 :                         if (stream->rtp_ch->rtcp)
     318           0 :                                 gf_sk_group_register(ctx->sockgroup, stream->rtp_ch->rtcp);
     319             :                 }
     320             : 
     321          19 :                 if (stream->rtsp) {
     322             :                         //send a setup if needed
     323           6 :                         rtpin_check_setup(stream);
     324             : 
     325             :                         //if not aggregated control or no more queued events send a play
     326           6 :                         if (! (stream->rtsp->flags & RTSP_AGG_CONTROL) )  {
     327           6 :                                 rtpin_rtsp_usercom_send(stream->rtsp, stream, evt);
     328           6 :                                 ctx->last_start_range = evt->play.start_range;
     329             :                         } else {
     330             :                         //tricky point here: the play events may get at different times depending on the length
     331             :                         //of each filter chain connected to our output pids.
     332             :                         //we store the event and wait for no more pending events
     333           0 :                                 if (!ctx->postponed_play_stream) {
     334           0 :                                         ctx->postponed_play = evt->play;
     335           0 :                                         ctx->postponed_play_stream = stream;
     336           0 :                                         ctx->last_start_range = evt->play.start_range;
     337             :                                 }
     338             :                                 return GF_TRUE;
     339             :                         }
     340             :                 } else {
     341          13 :                         ctx->last_start_range = evt->play.start_range;
     342          13 :                         stream->status = RTP_Running;
     343          13 :                         if (!stream->next_stream)
     344          13 :                                 ctx->cur_mid = stream->mid;
     345             : 
     346          13 :                         if (stream->rtp_ch) {
     347             :                                 //wait for RTCP to perform stream sync
     348          13 :                                 stream->rtcp_init = GF_FALSE;
     349          13 :                                 rtpin_stream_init(stream, (stream->flags & RTP_CONNECTED) ? GF_TRUE : GF_FALSE);
     350          13 :                                 gf_rtp_set_info_rtp(stream->rtp_ch, 0, 0, 0);
     351             :                         } else {
     352             :                                 /*direct channel, store current start*/
     353           0 :                                 stream->current_start = evt->play.start_range;
     354           0 :                                 stream->flags |= GF_RTP_NEW_AU;
     355           0 :                                 gf_rtp_depacketizer_reset(stream->depacketizer, GF_FALSE);
     356             :                         }
     357             :                 }
     358             :                 break;
     359          39 :         case GF_FEVT_STOP:
     360             : 
     361          19 :                 while (1) {
     362          39 :                         u32 size = gf_rtp_read_flush(stream->rtp_ch, stream->buffer, stream->rtpin->block_size);
     363          39 :                         if (!size) break;
     364          19 :                         rtpin_stream_on_rtp_pck(stream, stream->buffer, size);
     365             :                 }
     366             : 
     367             :                 /*is this RTSP or direct RTP?*/
     368          20 :                 if (stream->rtsp) {
     369           6 :                         if (!ctx->is_eos)
     370           6 :                                 rtpin_rtsp_usercom_send(stream->rtsp, stream, evt);
     371             :                         else
     372             :                                 skip_rtsp_teardown=GF_TRUE;
     373             :                 } else {
     374          14 :                         stream->status = RTP_Connected;
     375          14 :                         stream->rtpin->last_ntp = 0;
     376          14 :                         stream->flags |= RTP_EOS;
     377             :                 }
     378          20 :                 ctx->last_start_range = -1.0;
     379          20 :                 stream->rtcp_init = GF_FALSE;
     380          20 :                 reset_stream = stream->pck_queue ? GF_TRUE : GF_FALSE;
     381             : 
     382          20 :                 if (!(stream->flags & RTP_INTERLEAVED)) {
     383          19 :                         if (stream->rtp_ch->rtp)
     384          19 :                                 gf_sk_group_unregister(ctx->sockgroup, stream->rtp_ch->rtp);
     385          19 :                         if (stream->rtp_ch->rtcp)
     386          19 :                                 gf_sk_group_unregister(ctx->sockgroup, stream->rtp_ch->rtcp);
     387             :                 }
     388          20 :                 if (reset_stream) {
     389          40 :                         while (gf_list_count(stream->pck_queue)) {
     390          33 :                                 GF_FilterPacket *pck = gf_list_pop_front(stream->pck_queue);
     391          33 :                                 gf_filter_pck_send(pck);
     392             :                         }
     393             :                 }
     394             :                 break;
     395           0 :         case GF_FEVT_SET_SPEED:
     396             :         case GF_FEVT_PAUSE:
     397             :         case GF_FEVT_RESUME:
     398             :                 assert(stream->rtsp);
     399           0 :                 rtpin_rtsp_usercom_send(stream->rtsp, stream, evt);
     400           0 :                 break;
     401             :         default:
     402             :                 break;
     403             :         }
     404             : 
     405             :         //flush rtsp commands
     406          72 :         if (ctx->session && !skip_rtsp_teardown) {
     407          12 :                 rtpin_rtsp_process_commands(ctx->session);
     408             :         }
     409             : 
     410          72 :         if (reset_stream) rtpin_stream_reset_queue(stream);
     411             :         //cancel event
     412             :         return GF_TRUE;
     413             : }
     414             : 
     415          10 : static void rtpin_rtsp_flush(GF_RTPInRTSP *session)
     416             : {
     417             :         /*process teardown on all sessions*/
     418         226 :         while (!session->connect_error) {
     419         216 :                 if (!gf_list_count(session->rtsp_commands))
     420             :                         break;
     421         206 :                 rtpin_rtsp_process_commands(session);
     422             :         }
     423          10 : }
     424             : 
     425     6237963 : static GF_Err rtpin_process(GF_Filter *filter)
     426             : {
     427             :         u32 i;
     428             :         GF_RTPInStream *stream;
     429     6237963 :         GF_RTPIn *ctx = gf_filter_get_udta(filter);
     430             : 
     431     6237963 :         if (ctx->is_eos) return GF_EOS;
     432             : 
     433     6237868 :         if (ctx->ipid) {
     434     5145299 :                 GF_FilterPacket *pck = gf_filter_pid_get_packet(ctx->ipid);
     435             : 
     436     5145299 :                 if (!ctx->sdp_loaded && pck) {
     437             :                         Bool start, end;
     438             :                         u32 sdp_len;
     439             :                         const char *sdp_data;
     440          14 :                         gf_filter_pck_get_framing(pck, &start, &end);
     441             :                         assert(end);
     442             :                 
     443          14 :                         sdp_data = gf_filter_pck_get_data(pck, &sdp_len);
     444          14 :                         rtpin_load_sdp(ctx, (char *)sdp_data, sdp_len, NULL);
     445          14 :                         gf_filter_pid_drop_packet(ctx->ipid);
     446          14 :                         ctx->sdp_loaded = GF_TRUE;
     447             :                 }
     448             :                 //we act as a source filter, request process task
     449     5145299 :                 gf_filter_post_process_task(filter);
     450             :         }
     451             : 
     452     6237868 :         if (ctx->postponed_play_stream) {
     453             :                 GF_FilterEvent evt;
     454           0 :                 if (gf_filter_get_num_events_queued(filter))
     455           0 :                         return GF_OK;
     456           0 :                 stream = ctx->postponed_play_stream;
     457           0 :                 ctx->postponed_play_stream = NULL;
     458           0 :                 evt.play = ctx->postponed_play;
     459           0 :                 rtpin_rtsp_usercom_send(stream->rtsp, stream, &evt);
     460             :         }
     461             : 
     462             : 
     463     6237868 :         if (ctx->retry_tcp && ctx->session) {
     464             :                 GF_FilterEvent evt;
     465             :                 Bool send_agg_play = GF_TRUE;
     466           0 :                 GF_List *streams = gf_list_new();
     467           0 :                 ctx->retry_tcp = GF_FALSE;
     468           0 :                 ctx->interleave = 1;
     469           0 :                 i=0;
     470           0 :                 while ((stream = (GF_RTPInStream *)gf_list_enum(ctx->streams, &i))) {
     471             :                         if (stream->status >= RTP_Setup) {
     472           0 :                                 gf_list_add(streams, stream);
     473             :                         }
     474             :                 }
     475           0 :                 rtpin_rtsp_flush(ctx->session);
     476             :                 /*send teardown*/
     477           0 :                 rtpin_rtsp_teardown(ctx->session, NULL);
     478           0 :                 rtpin_rtsp_flush(ctx->session);
     479             :                 //for safety reset the session, some servers don't handle teardown that well
     480           0 :                 gf_rtsp_session_reset(ctx->session->session, GF_TRUE);
     481             : 
     482           0 :                 ctx->session->flags |= RTSP_FORCE_INTER;
     483           0 :                 evt.play = ctx->postponed_play;
     484           0 :                 if (!evt.base.type) evt.base.type = GF_FEVT_PLAY;
     485           0 :                 gf_rtsp_set_buffer_size(ctx->session->session, ctx->block_size);
     486             : 
     487             :                 stream = NULL;
     488           0 :                 for (i=0; i<gf_list_count(streams); i++) {
     489           0 :                         stream = (GF_RTPInStream *)gf_list_get(streams, i);
     490             :                         //reset status
     491           0 :                         stream->status = RTP_Disconnected;
     492             :                         //reset all dynamic flags
     493           0 :                         stream->flags &= ~(RTP_EOS | RTP_EOS_FLUSHED | RTP_SKIP_NEXT_COM | RTP_CONNECTED);
     494             :                         //mark as interleaved
     495           0 :                         stream->flags |= RTP_INTERLEAVED;
     496             :                         //reset SSRC since some servers don't include it in interleave response
     497           0 :                         gf_rtp_reset_ssrc(stream->rtp_ch);
     498             : 
     499             :                         //send setup
     500           0 :                         rtpin_check_setup(stream);
     501           0 :                         rtpin_rtsp_flush(ctx->session);
     502             : 
     503             :                         //if not aggregated control or no more queued events send a play
     504           0 :                         if (! (stream->rtsp->flags & RTSP_AGG_CONTROL) )  {
     505           0 :                                 evt.base.on_pid = stream->opid;
     506           0 :                                 rtpin_rtsp_usercom_send(stream->rtsp, stream, &evt);
     507             :                                 send_agg_play = GF_FALSE;
     508             :                         }
     509           0 :                         rtpin_rtsp_flush(ctx->session);
     510             :                 }
     511           0 :                 if (stream && send_agg_play) {
     512           0 :                         evt.base.on_pid = stream->opid;
     513           0 :                         rtpin_rtsp_usercom_send(ctx->session, stream, &evt);
     514             :                 }
     515             : 
     516           0 :                 gf_list_del(streams);
     517             :         }
     518             : 
     519             : 
     520             :         /*fetch data on udp*/
     521             :         u32 tot_read=0;
     522             :         while (1) {
     523             :                 u32 read=0;
     524             :                 //select both read and write
     525     6238607 :                 GF_Err e = gf_sk_group_select(ctx->sockgroup, 10, GF_SK_SELECT_BOTH);
     526     6238607 :                 if (e) {
     527      506511 :                         if ((e==GF_IP_NETWORK_EMPTY) && !ctx->eos_probe_start)
     528          27 :                                 ctx->eos_probe_start = gf_sys_clock();
     529             :                         break;
     530             :                 }
     531             : 
     532     5732096 :                 ctx->eos_probe_start = 0;
     533             : 
     534     5732096 :                 i=0;
     535    17259182 :                 while ((stream = (GF_RTPInStream *)gf_list_enum(ctx->streams, &i))) {
     536     5794990 :                         if (stream->status==RTP_Running) {
     537             :                                 /*for interleaved channels don't read too fast, query the buffer occupancy*/
     538     5794080 :                                 read += rtpin_stream_read(stream);
     539             :                         }
     540             : 
     541     5794990 :                         if (stream->flags & RTP_EOS) {
     542      169577 :                                 ctx->eos_probe_start = gf_sys_clock();
     543             :                         }
     544             :                 }
     545             : 
     546     5732096 :                 if (!read) {
     547             :                         break;
     548             :                 }
     549             :                 tot_read+=read;
     550             :         }
     551             : 
     552             :         //we wait max 300ms to detect eos
     553     6237868 :         if (ctx->eos_probe_start && (gf_sys_clock() - ctx->eos_probe_start > 300) ) {
     554             :                 u32 nb_eos=0;
     555          11 :                 i=0;
     556          29 :                 while ((stream = (GF_RTPInStream *)gf_list_enum(ctx->streams, &i))) {
     557          11 :                         if (! (stream->flags & RTP_EOS)) break;
     558           7 :                         if (stream->flags & RTP_EOS_FLUSHED) {
     559           0 :                                 nb_eos++;
     560           0 :                                 continue;
     561             :                         }
     562           0 :                         while (1) {
     563           7 :                                 u32 size = gf_rtp_flush_rtp(stream->rtp_ch, stream->buffer, stream->rtpin->block_size);
     564           7 :                                 if (!size) break;
     565           0 :                                 rtpin_stream_on_rtp_pck(stream, stream->buffer, size);
     566             :                         }
     567             : 
     568           7 :                         stream->stat_stop_time = gf_sys_clock();
     569           7 :                         if (stream->pck_queue) {
     570          10 :                                 while (gf_list_count(stream->pck_queue)) {
     571           5 :                                         GF_FilterPacket *pck = gf_list_pop_front(stream->pck_queue);
     572           5 :                                         gf_filter_pck_send(pck);
     573             :                                 }
     574             :                         }
     575           7 :                         gf_filter_pid_set_eos(stream->opid);
     576           7 :                         stream->flags |= RTP_EOS_FLUSHED;
     577           7 :                         nb_eos++;
     578             :                 }
     579          11 :                 if (nb_eos==gf_list_count(ctx->streams)) {
     580           7 :                         if (!ctx->is_eos) {
     581           7 :                                 ctx->is_eos = GF_TRUE;
     582           7 :                                 if (ctx->session) {
     583             :                                         /*send teardown*/
     584           5 :                                         rtpin_rtsp_teardown(ctx->session, NULL);
     585           5 :                                         rtpin_rtsp_flush(ctx->session);
     586             :                                 }
     587             :                         }
     588             :                         return GF_EOS;
     589             :                 }
     590           4 :                 ctx->eos_probe_start = 0;
     591             :         }
     592             : 
     593             :         /*and process commands / flush TCP*/
     594     6237861 :         if (ctx->session) {
     595      811140 :                 rtpin_rtsp_process_commands(ctx->session);
     596             : 
     597      811140 :                 if (ctx->session->connect_error) {
     598           0 :                         gf_filter_setup_failure(filter, ctx->session->connect_error);
     599           0 :                         ctx->session->connect_error = GF_OK;
     600             :                 }
     601             :         }
     602     6237861 :         if (ctx->max_sleep<0)
     603           0 :                 gf_filter_ask_rt_reschedule(filter, (u32) ((-ctx->max_sleep) *1000) );
     604             :         else {
     605             :                 assert(ctx->min_frame_dur_ms <= (u32) ctx->max_sleep);
     606     6237861 :                 gf_filter_ask_rt_reschedule(filter, ctx->min_frame_dur_ms*1000);
     607             :         }
     608             :         return GF_OK;
     609             : }
     610             : 
     611             : 
     612          20 : static GF_Err rtpin_initialize(GF_Filter *filter)
     613             : {
     614          20 :         GF_RTPIn *ctx = gf_filter_get_udta(filter);
     615             :         char *the_ext;
     616             : 
     617          20 :         ctx->streams = gf_list_new();
     618          20 :         ctx->filter = filter;
     619             :         //turn on interleave on http port
     620          20 :         if ((ctx->default_port == 80) || (ctx->default_port == 8080))
     621           0 :                 ctx->interleave = 1;
     622             : 
     623          20 :         ctx->last_start_range = -1.0;
     624             : 
     625          20 :         ctx->sockgroup = gf_sk_group_new();
     626             : 
     627             :         //sdp mode, we will have a configure_pid
     628          20 :         if (!ctx->src) return GF_OK;
     629             : 
     630             :         /*rtsp and rtsp over udp*/
     631             : 
     632           6 :         the_ext = strrchr(ctx->src, '#');
     633           6 :         if (the_ext) {
     634           0 :                 if (!stricmp(the_ext, "#audio")) ctx->stream_type = GF_STREAM_AUDIO;
     635           0 :                 else if (!stricmp(the_ext, "#video")) ctx->stream_type = GF_STREAM_VISUAL;
     636           0 :                 the_ext[0] = 0;
     637             :         }
     638           6 :         gf_filter_disable_inputs(filter);
     639             : 
     640           6 :         if (!strnicmp(ctx->src, "rtp://", 6)) {
     641             :                 GF_RTPInStream *stream;
     642             :                 GF_Err e = GF_OK;
     643             :                 u32 port = 1234;
     644           1 :                 char *ip = ctx->src + 6;
     645           1 :                 char *sep = strchr(ip, ':');
     646           1 :                 if (sep) {
     647           2 :                         port = atoi(sep+1);
     648           1 :                         sep[0] = 0;
     649           1 :                         ip = gf_strdup(ip);
     650           1 :                         sep[0] = ':';
     651             :                 } else {
     652           0 :                         ip = gf_strdup(ip);
     653             :                 }
     654           1 :                 stream = rtpin_stream_new_standalone(ctx, ip, port);
     655           1 :                 gf_free(ip);
     656           1 :                 if (!stream)
     657             :                         e = GF_OUT_OF_MEM;
     658             : 
     659             :                 if (!e)
     660           1 :                         e = rtpin_add_stream(ctx, stream, NULL);
     661             : 
     662           1 :                 if (!e)
     663           1 :                         e = rtpin_stream_init(stream, GF_FALSE);
     664             : 
     665           1 :                 if (e) {
     666           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTPIn]] Couldn't setup RTP stream: %s\n", gf_error_to_string(e) ));
     667             :                         return e;
     668             :                 }
     669           1 :                 stream->status = RTP_Running;
     670           1 :                 return GF_OK;
     671             :         }
     672           5 :         ctx->session = rtpin_rtsp_new(ctx, (char *) ctx->src);
     673           5 :         if (!strnicmp(ctx->src, "satip://", 8)) {
     674           0 :                 ctx->session->satip = GF_TRUE;
     675           0 :                 ctx->session->satip_server = gf_malloc(GF_MAX_PATH);
     676           0 :                 rtpin_satip_get_server_ip(ctx->src, ctx->session->satip_server);
     677             :         }
     678             : 
     679           5 :         if (!ctx->session) {
     680             :                 return GF_NOT_SUPPORTED;
     681             :         } else {
     682           5 :                 rtpin_rtsp_describe_send(ctx->session, 0, NULL);
     683             :         }
     684           5 :         return GF_OK;
     685             : }
     686             : 
     687             : 
     688          20 : static void rtpin_finalize(GF_Filter *filter)
     689             : {
     690          20 :         GF_RTPIn *ctx = gf_filter_get_udta(filter);
     691          20 :         ctx->done = GF_TRUE;
     692          20 :         if (ctx->session) {
     693           5 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP] Closing RTSP service\n"));
     694           5 :                 rtpin_rtsp_flush(ctx->session);
     695           5 :                 if (!ctx->is_eos) {
     696             :                         /*send teardown*/
     697           0 :                         rtpin_rtsp_teardown(ctx->session, NULL);
     698           0 :                         rtpin_rtsp_flush(ctx->session);
     699             :                 }
     700             :         }
     701             : 
     702          20 :         rtpin_reset(ctx, GF_TRUE);
     703          20 :         gf_list_del(ctx->streams);
     704             : 
     705          20 :         gf_sk_group_del(ctx->sockgroup);
     706          20 : }
     707             : 
     708        3065 : static const char *rtpin_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
     709             : {
     710             :         Bool is_sdp = GF_TRUE;
     711             :         char *pdata = (char *)data;
     712        3065 :         char cend = pdata[size-1];
     713        3065 :         pdata[size-1] = 0;
     714        3065 :         if (!strstr(pdata, "\n")) is_sdp = GF_FALSE;
     715        1089 :         else if (!strstr(pdata, "v=0")) is_sdp = GF_FALSE;
     716          14 :         else if (!strstr(pdata, "o=")) is_sdp = GF_FALSE;
     717          14 :         else if (!strstr(pdata, "c=")) is_sdp = GF_FALSE;
     718        3065 :         pdata[size-1] = cend;
     719        3065 :         if (is_sdp) {
     720          14 :                 *score = GF_FPROBE_SUPPORTED;
     721          14 :                 return "application/sdp";
     722             :         }
     723             :         return NULL;
     724             : }
     725             : 
     726             : static const GF_FilterCapability RTPInCaps[] =
     727             : {
     728             :         CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
     729             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "sdp"),
     730             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "application/sdp"),
     731             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
     732             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
     733             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_SCENE),
     734             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_OD),
     735             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_TEXT),
     736             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_METADATA),
     737             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_ENCRYPTED),
     738             :         {0},
     739             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
     740             :         CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "ts|m2t|mts|dmb|trp"),
     741             :         CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "video/mpeg-2|video/mp2t|video/mpeg"),
     742             : };
     743             : 
     744             : #define OFFS(_n)        #_n, offsetof(GF_RTPIn, _n)
     745             : static const GF_FilterArgs RTPInArgs[] =
     746             : {
     747             :         { OFFS(src), "location of source content (SDP, RTP or RTSP URL)", GF_PROP_NAME, NULL, NULL, 0},
     748             :         { OFFS(firstport), "default first port number to use. 0 lets the filter decide", GF_PROP_UINT, "0", NULL, GF_FS_ARG_HINT_ADVANCED},
     749             :         { OFFS(ifce), "default interface IP to use for multicast. If NULL, the default system interface will be used", GF_PROP_STRING, NULL, NULL, GF_FS_ARG_HINT_ADVANCED},
     750             :         { OFFS(ttl), "multicast TTL", GF_PROP_UINT, "127", "0-127", GF_FS_ARG_HINT_ADVANCED},
     751             :         { OFFS(reorder_len), "reorder length in packets", GF_PROP_UINT, "1000", NULL, GF_FS_ARG_HINT_ADVANCED},
     752             :         { OFFS(reorder_delay), "max delay in RTP reorderer, packets will be dispatched after that", GF_PROP_UINT, "50", NULL, GF_FS_ARG_HINT_ADVANCED},
     753             :         { OFFS(block_size), "buffer size fur RTP/UDP or RTSP when interleaved", GF_PROP_UINT, "0x200000", NULL, GF_FS_ARG_HINT_ADVANCED},
     754             :         { OFFS(disable_rtcp), "disable RTCP reporting", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
     755             :         { OFFS(nat_keepalive), "delay in ms of NAT keepalive, disabled by default (except for SatIP, set to 30s by default)", GF_PROP_UINT, "0", NULL, GF_FS_ARG_HINT_ADVANCED},
     756             :         { OFFS(force_mcast), "force multicast on indicated IP in RTSP setup", GF_PROP_STRING, NULL, NULL, GF_FS_ARG_HINT_ADVANCED},
     757             :         { OFFS(use_client_ports), "force using client ports  (hack for some RTSP servers overriding client ports)", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
     758             :         { OFFS(bandwidth), "set bandwidth param for RTSP requests", GF_PROP_UINT, "0", NULL, GF_FS_ARG_HINT_ADVANCED},
     759             :         { OFFS(default_port), "set default RTSP port", GF_PROP_UINT, "554", "0-65535", 0},
     760             :         { OFFS(satip_port), "set default port for SATIP", GF_PROP_UINT, "1400", "0-65535", 0},
     761             :         { OFFS(interleave), "set RTP over RTSP", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_EXPERT},
     762             :         { OFFS(udp_timeout), "default timeout before considering UDP is down", GF_PROP_UINT, "10000", NULL, 0},
     763             :         { OFFS(rtsp_timeout), "default timeout before considering RTSP is down", GF_PROP_UINT, "3000", NULL, 0},
     764             :         { OFFS(rtcp_timeout), "default timeout for RTCP traffic in ms. After this timeout, playback will start unsync. If 0 always wait for RTCP", GF_PROP_UINT, "5000", NULL, GF_FS_ARG_HINT_ADVANCED},
     765             :         { OFFS(autortsp), "automatically reconfig RTSP interleaving if UDP timeout", GF_PROP_BOOL, "true", NULL, GF_FS_ARG_HINT_ADVANCED},
     766             :         { OFFS(first_packet_drop), "set number of first RTP packet to drop - 0 if no drop", GF_PROP_UINT, "0", NULL, GF_FS_ARG_HINT_EXPERT},
     767             :         { OFFS(frequency_drop), "drop 1 out of N packet - 0 disable dropping", GF_PROP_UINT, "0", NULL, GF_FS_ARG_HINT_EXPERT},
     768             :         { OFFS(user_agent), "user agent string, by default solved from GPAC preferences", GF_PROP_STRING, "$GUA", NULL, 0},
     769             :         { OFFS(languages), "user languages, by default solved from GPAC preferences", GF_PROP_STRING, "$GLANG", NULL, 0},
     770             :         { OFFS(stats), "update statistics to the user every given MS, 0 disables reporting", GF_PROP_UINT, "500", NULL, GF_FS_ARG_HINT_ADVANCED},
     771             :         { OFFS(max_sleep), "set max sleep in milliseconds. A negative value -N means to always sleep for N ms, a positive value N means to sleep at most N ms but will sleep less if frame duration is shorter", GF_PROP_SINT, "1000", NULL, GF_FS_ARG_HINT_EXPERT},
     772             :         { OFFS(rtcpsync), "use RTCP to adjust synchronization", GF_PROP_BOOL, "true", NULL, GF_FS_ARG_HINT_EXPERT},
     773             :         {0}
     774             : };
     775             : 
     776             : 
     777             : GF_FilterRegister RTPInRegister = {
     778             :         .name = "rtpin",
     779             :         GF_FS_SET_DESCRIPTION("RTP/RTSP/SDP input")
     780             :         GF_FS_SET_HELP("This filter handles SDP/RTSP/RTP input reading. It supports:\n"
     781             :         "- SDP file reading\n"
     782             :         "- RTP direct url through `rtp://` protocol scheme\n"
     783             :         "- RTSP session processing through `rtsp://` and `satip://` protocol schemes\n"
     784             :         " \n"
     785             :         "The filter produces either media PIDs and compressed media frames, or file PIDs and multiplex data (e.g., MPEG-2 TS).")
     786             :         .private_size = sizeof(GF_RTPIn),
     787             :         .args = RTPInArgs,
     788             :         .initialize = rtpin_initialize,
     789             :         .finalize = rtpin_finalize,
     790             :         SETCAPS(RTPInCaps),
     791             :         .configure_pid = rtpin_configure_pid,
     792             :         .process = rtpin_process,
     793             :         .process_event = rtpin_process_event,
     794             :         .probe_url = rtpin_probe_url,
     795             :         .probe_data = rtpin_probe_data
     796             : };
     797             : 
     798             : #endif
     799             : 
     800             : 
     801        2877 : const GF_FilterRegister *rtpin_register(GF_FilterSession *session)
     802             : {
     803             : #ifndef GPAC_DISABLE_STREAMING
     804        2877 :         return &RTPInRegister;
     805             : #else
     806             :         return NULL;
     807             : #endif
     808             : }
     809             : 

Generated by: LCOV version 1.13