UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
rtsp.c
Go to the documentation of this file.
1/*
2 * AUTHOR: Gerard Castillo <gerard.castillo@i2cat.net>,
3 * Martin German <martin.german@i2cat.net>
4 *
5 * Copyright (c) 2005-2010 Fundació i2CAT, Internet I Innovació Digital a Catalunya
6 * Copyright (c) 2015-2024 CESNET
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, is permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 *
22 * This product includes software developed by the University of Southern
23 * California Information Sciences Institute.
24 *
25 * 4. Neither the name of the University nor of the Institute may be used
26 * to endorse or promote products derived from this software without
27 * specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
31 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
32 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
33 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
34 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
35 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
36 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
38 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
39 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
40 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 */
51#include <assert.h> // for assert
52#include <errno.h> // for ETIMEDOUT
53#include <pthread.h>
54#include <stdbool.h>
55#include <stdint.h> // for uint8_t, uint32_t
56#include <stdio.h>
57#include <stdlib.h>
58#include <string.h>
59#include <time.h> // for timespec
60
61#include "audio/types.h"
62#include "config.h" // for PACKAGE_BUGREPORT
63#include "compat/strings.h" // for strncasecmp
64#include "debug.h"
65#include "host.h"
66#include "lib_common.h"
67#include "tv.h"
68#include "rtp/rtp.h"
69#include "rtp/rtp_callback.h"
70#include "rtp/rtpdec_h264.h"
71#include "rtp/rtpdec_jpeg.h"
72#include "rtp/rtpdec_state.h"
73#include "rtsp/rtsp_utils.h"
74#include "utils/color_out.h" // for color_printf, TBOLD
75#include "utils/macros.h" // for MIN, STR_LEN
76#include "utils/sdp.h" // for get_video_codec_from_pt_rtpmap
77#include "utils/text.h" // base64_decode
78#include "video_decompress.h"
79
80#include "pdb.h"
81#include "rtp/pbuf.h"
82
83#include "video.h"
84#include "video_codec.h"
85#include "video_capture.h"
86
87#include <curl/curl.h>
88
89#define KEEPALIVE_INTERVAL_S 5
90#define MAGIC to_fourcc('R', 'T', 'S', 'c')
91#define MOD_NAME "[rtsp] "
92#define VERSION_STR "V1.0"
93
94//TODO set lower initial video recv buffer size (to find the minimal?)
95#define DEFAULT_VIDEO_FRAME_WIDTH 1920
96#define DEFAULT_VIDEO_FRAME_HEIGHT 1080
97#define INITIAL_VIDEO_RECV_BUFFER_SIZE ((0.1*DEFAULT_VIDEO_FRAME_WIDTH*DEFAULT_VIDEO_FRAME_HEIGHT)*110/100) //command line net.core setup: sysctl -w net.core.rmem_max=9123840
98
99// compat
100#ifndef CURL_WRITEFUNC_ERROR
101#define CURL_WRITEFUNC_ERROR 0xFFFFFFFF
102#endif
103
104enum {
106};
107
108static const char *long_to_str(long l) {
109 _Thread_local static char buf[100];
110 snprintf(buf, sizeof buf, "%ld", l);
111 return buf;
112}
113
114static const char *pointer_to_str(void *p) {
115 _Thread_local static char buf[100];
116 snprintf(buf, sizeof buf, "%p", p);
117 return buf;
118}
119
120static const char *cstr_identity(const char *c) {
121 return c;
122}
123
124#define get_s(X) \
125 _Generic((X), \
126 int: long_to_str, \
127 long: long_to_str, \
128 char *: cstr_identity, \
129 const char *: cstr_identity, \
130 default: pointer_to_str)(X)
131
132/* error handling macros */
133#define my_curl_easy_setopt_ex(l, A, B, C, action_fail) \
134 { \
135 log_msg(l, MOD_NAME "Setting " #B " to %s\n", get_s(C)); \
136 const CURLcode res = curl_easy_setopt((A), (B), (C)); \
137 if (res != CURLE_OK) { \
138 log_msg(LOG_LEVEL_ERROR, MOD_NAME "curl_easy_setopt(%s, %s, %s) failed: %s (%d)\n", #A, #B, #C, curl_easy_strerror(res), res); \
139 printf("[rtsp error] could not configure rtsp capture properly, \n\t\tplease check your parameters. \nExiting...\n\n"); \
140 action_fail; \
141 } \
142 }
143
144#define my_curl_easy_perform_ex(l, A, action_fail) \
145 { \
146 log_msg(l, "Performing cURL operation(s)\n"); \
147 const CURLcode res = curl_easy_perform((A)); \
148 if (res != CURLE_OK) { \
149 log_msg(LOG_LEVEL_ERROR, MOD_NAME "[%s] curl_easy_perform(%s) failed: %s (%d)\n", __func__, #A, curl_easy_strerror(res), res); \
150 printf("[rtsp error] could not configure rtsp capture properly, \n\t\tplease check your parameters. \nExiting...\n\n"); \
151 action_fail; \
152 } \
153 }
154
155#define my_curl_easy_setopt(A, B, C, action_fail) \
156 my_curl_easy_setopt_ex(LOG_LEVEL_VERBOSE, A, B, C, action_fail)
157#define my_curl_easy_perform(A, action_fail) \
158 my_curl_easy_perform_ex(LOG_LEVEL_VERBOSE, A, action_fail)
159
160struct rtsp_state;
161struct audio_rtsp_state;
162struct video_rtsp_state;
163
164/* send RTSP GET_PARAMETERS request */
165static bool
166rtsp_get_parameters(CURL *curl, const char *uri);
167
168/* send RTSP OPTIONS request */
169static bool
170rtsp_options(CURL *curl, const char *uri);
171
172/* send RTSP DESCRIBE request and write sdp response to a file */
173static bool
174rtsp_describe(CURL *curl, const char *uri, FILE *sdp_fp);
175
176/* send RTSP SETUP request */
177static bool
178rtsp_setup(CURL *curl, const char *uri, const char *transport);
179
180/* send RTSP PLAY request */
181static bool
182rtsp_play(CURL *curl, const char *uri, const char *range);
183
184/* send RTSP TEARDOWN request */
185static void
186rtsp_teardown(CURL *curl, const char *uri);
187
188static int
189get_nals(FILE *sdp_file, char *nals, int *width, int *height);
190
191static bool setup_codecs_and_controls_from_sdp(FILE *sdp_file,
192 struct rtsp_state *rtspState);
193static bool
194init_rtsp(struct rtsp_state *s);
195
196static int
198
199static void *
200vidcap_rtsp_thread(void *args);
201
202void
204
205static void vidcap_rtsp_done(void *state);
206
207static const uint8_t start_sequence[] = { 0, 0, 0, 1 };
208
214
217
218 //struct std_frame_received *rx_data;
220
223
224 int port;
225 char *control;
226
227 struct rtp *device;
229 double rtcp_bw;
230 int ttl;
231 char *mcast_if;
233
234 pthread_t vrtsp_thread_id; //the worker_id
235
236 pthread_mutex_t lock;
237 pthread_cond_t worker_cv;
238 volatile bool worker_waiting;
239 pthread_cond_t boss_cv;
240 volatile bool boss_waiting;
241
243};
244
248
250
251 struct timeval last_audio_time;
252 unsigned int grab_audio:1;
253
254 int port;
255
256 char *control;
257
258 struct rtp *device;
260 double rtcp_bw;
261 int ttl;
262 char *mcast_if;
264
265 pthread_t artsp_thread_id; //the worker_id
266 pthread_mutex_t lock;
267 pthread_cond_t worker_cv;
268 volatile bool worker_waiting;
269 pthread_cond_t boss_cv;
270 volatile bool boss_waiting;
271
272 int pt;
273};
274
276 uint32_t magic;
277 CURL *curl;
278 char uri[1024];
279 char base_url[1024];
281 const char *addr;
282 char *sdp;
283
284 volatile bool should_exit;
287
288 pthread_t keep_alive_rtsp_thread_id; //the worker_id
289 pthread_mutex_t lock;
290 pthread_cond_t keepalive_cv;
291
294};
295
296static void
297show_help(bool full) {
298 color_printf(TBOLD("RTSP client") " usage:\n");
299 color_printf("\t" TBOLD(TRED("-t rtsp:<uri>") "[:decompress]"));
300 if (full) {
301 color_printf(TBOLD("[:rtp_rx_port=<port>]"));
302 }
303 color_printf("\n\t" TBOLD("-t rtsp:[full]help") "\n");
304 color_printf("\nOptions:\n");
305 color_printf("\t " TBOLD("<uri>") " - RTSP server URI\n");
306 printf("\t " TBOLD("decompress") " - decompress the stream "
307 "(default: disabled)\n");
308 if (full) {
309 printf("\t " TBOLD("<port>") " - video RTP receiver port number\n");
310 }
311 color_printf("\nExamples:\n");
312 color_printf("\t" TBOLD("uv -t rtsp://192.168.0.30/mystream") "\n");
313 color_printf("\t" TBOLD("uv -t rtsp://[fe80::30]/mystream") "\n");
314 color_printf("\t\t- capture streem on implict port (554)\n");
315 color_printf("\t"
316 TBOLD("uv -t rtsp://192.168.0.20:8554/mystream") "\n");
317 color_printf("\t\t- capture streem on port 8554 (optionally with "
318 "authentization)\n");
319 color_printf("\t"
320 TBOLD("uv -t rtsp://user:pass@[fe80::30]/mystream") "\n");
321 color_printf("\t\t- capture streem on default port with authentization\n");
323 "\t" TBOLD("uv -t rtsp://192.168.0.20/mystream:decompress") "\n");
324 color_printf("\t\t- same as first case but decompress the stream "
325 "(to allow to use a different compression)\n");
326 color_printf("\n");
327
329 "Supported audio codecs: none (support is currently broken/WIP)\n");
331 "Supported video codecs: " TBOLD("H.264") ", " TBOLD("JPEG") "\n");
332 color_printf("\n");
333}
334
335static void *
337 struct rtsp_state *s = (struct rtsp_state *) arg;
338
339 while (1) {
340 struct timeval tp;
341 gettimeofday(&tp, NULL);
342 struct timespec timeout = { .tv_sec = tp.tv_sec + KEEPALIVE_INTERVAL_S, .tv_nsec = tp.tv_usec * 1000 };
343 pthread_mutex_lock(&s->lock);
344 int rc = 0;
345 while (!s->should_exit && rc != ETIMEDOUT) {
346 rc = pthread_cond_timedwait(&s->keepalive_cv, &s->lock, &timeout);
347 }
348 if (s->should_exit) {
349 pthread_mutex_unlock(&s->lock);
350 break;
351 }
352 pthread_mutex_unlock(&s->lock);
353
354 // actual keepalive
355 MSG(DEBUG, "GET PARAMETERS %s:\n", s->uri);
356 if (!rtsp_get_parameters(s->curl, s->uri)) {
357 s->should_exit = TRUE;
358 exit_uv(1);
359 }
360 }
361 return NULL;
362}
363
364static int
365decode_frame_by_pt(struct coded_data *cdata, void *decode_data,
366 struct pbuf_stats *stats)
367{ UNUSED(stats);
368 rtp_packet *pckt = NULL;
369 pckt = cdata->data;
370 struct decode_data_rtsp *d = decode_data;
371 if (pckt->pt != d->video_pt) {
372 error_msg("Wrong Payload type: %u\n", pckt->pt);
373 return 0;
374 }
375 return d->decode(cdata, decode_data);
376}
377
378static void *
380 struct rtsp_state *s;
381 s = (struct rtsp_state *) arg;
382
384
385 struct video_frame *frame = vf_alloc(1);
386
387 while (!s->should_exit) {
388 time_ns_t curr_time = get_time_in_ns();
389 uint32_t timestamp = (curr_time - start_time) / (100*1000) * 9; // at 90000 Hz
390
391 rtp_update(s->vrtsp_state.device, curr_time);
392
393 struct timeval timeout;
394 timeout.tv_sec = 0;
395 timeout.tv_usec = 10000;
396
397 if (!rtp_recv_r(s->vrtsp_state.device, &timeout, timestamp)) {
398 pdb_iter_t it;
399 struct pdb_e *cp = pdb_iter_init(s->vrtsp_state.participants, &it);
400
401 while (cp != NULL) {
403 if (pbuf_decode(cp->playout_buffer, curr_time,
405 {
406 pthread_mutex_lock(&s->vrtsp_state.lock);
407 while (s->vrtsp_state.out_frame != NULL && !s->should_exit) {
408 s->vrtsp_state.worker_waiting = true;
409 pthread_cond_wait(&s->vrtsp_state.worker_cv, &s->vrtsp_state.lock);
410 s->vrtsp_state.worker_waiting = false;
411 }
412 if (s->vrtsp_state.out_frame == NULL) {
414 frame = vf_alloc(1); // alloc new
416 pthread_cond_signal(&s->vrtsp_state.boss_cv);
417 pthread_mutex_unlock(&s->vrtsp_state.lock);
418 } else {
419 pthread_mutex_unlock(&s->vrtsp_state.lock);
420 }
421 }
422 pbuf_remove(cp->playout_buffer, curr_time);
423 cp = pdb_iter_next(&it);
424 }
425
426 pdb_iter_done(&it);
427 }
428 }
429 vf_free(frame);
430 return NULL;
431}
432
433static struct video_frame *
435 struct rtsp_state *s;
436 s = (struct rtsp_state *) state;
437
438 *audio = NULL;
439
441 s->sps_pps_emitted = 1;
444 }
445
446 if(pthread_mutex_trylock(&s->vrtsp_state.lock)==0){
447 {
448 while (s->vrtsp_state.out_frame == NULL && !s->should_exit) {
449 struct timeval tp;
450 gettimeofday(&tp, NULL);
451 struct timespec timeout = { .tv_sec = tp.tv_sec, .tv_nsec = (tp.tv_usec + 100*1000) * 1000 };
452 if (timeout.tv_nsec >= 1000L*1000*1000) {
453 timeout.tv_nsec -= 1000L*1000*1000;
454 timeout.tv_sec += 1;
455 }
456 s->vrtsp_state.boss_waiting = true;
457 if (pthread_cond_timedwait(&s->vrtsp_state.boss_cv, &s->vrtsp_state.lock, &timeout) == ETIMEDOUT) {
458 pthread_mutex_unlock(&s->vrtsp_state.lock);
459 return NULL;
460 }
461 s->vrtsp_state.boss_waiting = false;
462 }
463
464 if (s->should_exit) {
465 pthread_mutex_unlock(&s->vrtsp_state.lock);
466 return NULL;
467 }
468
470 s->vrtsp_state.out_frame = NULL;
471 pthread_mutex_unlock(&s->vrtsp_state.lock);
472 pthread_cond_signal(&s->vrtsp_state.worker_cv);
473
474 if (frame->tiles[0].width != 0 &&
477 MSG(VERBOSE, "Setting the stream size to %ux%u\n",
478 frame->tiles[0].width, frame->tiles[0].height);
481 }
486 if (frame->tiles[0].width == 0) {
487 MSG(WARNING,
488 "Dropped zero-sized frame - the size was not published "
489 "in RTSP, waiting for first SPS...\n");
490 vf_free(frame);
491 return NULL;
492 }
493
494 if (s->vrtsp_state.decompress) {
495 struct video_desc curr_desc = video_desc_from_frame(frame);
496 if (!video_desc_eq(s->vrtsp_state.decompress_desc, curr_desc)) {
498 if (init_decompressor(&s->vrtsp_state, curr_desc) == 0) {
499 return NULL;
500 }
501 s->vrtsp_state.decompress_desc = curr_desc;
502 }
503
504 struct video_desc out_desc = s->vrtsp_state.decompress_desc;
505 out_desc.color_spec = UYVY;
506 struct video_frame *decompressed = vf_alloc_desc_data(out_desc);
507
508 decompress_frame(s->vrtsp_state.sd, (unsigned char *) decompressed->tiles[0].data,
509 (unsigned char *) frame->tiles[0].data,
510 frame->tiles[0].data_len, 0, NULL, NULL);
511 vf_free(frame);
512 frame = decompressed;
513 }
515 return frame;
516 }
517 } else {
518 return NULL;
519 }
520}
521
530static bool
531check_uri(size_t uri_len, char *uri)
532{
533 const char *rtsp_uri_pref = "rtsp://";
534 if (strcmp(uri, rtsp_uri_pref) == 0) {
535 MSG(ERROR, "No URI given!\n");
536 return false;
537 }
538 char *authority = uri + strlen(rtsp_uri_pref);
539 char *host = authority;
540 if (strchr(authority, '@') != NULL) { // skip userinfo
541 host = strchr(authority, '@') + 1;
542 }
543 if (strchr(host, ':') == NULL) { // add port 554
544 char *path = NULL;
545 if (strchr(host, '/') != NULL) { // store path
546 path = strdup(strchr(host, '/') + 1);
547 *strchr(host, '/') = '\0';
548 }
549 snprintf(uri + strlen(uri), uri_len - strlen(uri), ":%d",
551 if (path != NULL) {
552 snprintf(uri + strlen(uri), uri_len - strlen(uri), "/%s",
553 path);
554 free(path);
555 }
556 } else {
557 char *port = strchr(host, ':') + 1;
558 char *endptr = NULL;
559 strtol(port, &endptr, 10);
560 if (endptr == port) {
561 MSG(ERROR, "Non-numeric port \"%s\" (wrong option?)\n", port);
562 return false;
563 }
564 if (strchr(port, ':') != NULL) {
565 MSG(WARNING, "Colon in URI path - possibly wrong option?\n");
566 }
567 }
568 MSG(INFO, "Using URI %s\n", uri);
569 return true;
570}
571
572#define FAIL_SHOW_HELP \
573 vidcap_rtsp_done(s); \
574 show_help(false); \
575 return VIDCAP_INIT_FAIL;
576
577static int
579 char fmt[STR_LEN];
580 snprintf(fmt, sizeof fmt, "%s", vidcap_params_get_fmt(params));
581 if (strcmp(fmt, "help") == 0 || strcmp(fmt, "fullhelp") == 0) {
582 show_help(strcmp(fmt, "fullhelp") == 0);
583 return VIDCAP_INIT_NOERR;
584 }
585
587 log_msg(LOG_LEVEL_ERROR, "Audio is not entirely implemented in RTSP. "
588 "Please contact " PACKAGE_BUGREPORT " if you wish to use it.\n");
589 return VIDCAP_INIT_FAIL;
590 }
591
592 struct rtsp_state *s = (struct rtsp_state *) calloc(1, sizeof(struct rtsp_state));
593 if (s == NULL) {
594 return VIDCAP_INIT_FAIL;
595 }
596
597 //TODO now static codec assignment, to be dynamic as a function of supported codecs
598 s->vrtsp_state.codec[0] = '\0';
599 s->artsp_state.codec[0] = '\0';
600 s->artsp_state.control = strdup("");
601 s->artsp_state.control = strdup("");
602
603 char *save_ptr = NULL;
604 s->magic = MAGIC;
606
607 s->addr = "127.0.0.1";
608 s->vrtsp_state.device = NULL;
609 s->vrtsp_state.rtcp_bw = 5 * 1024 * 1024; /* FIXME */
610 s->vrtsp_state.ttl = 255;
611
612 s->vrtsp_state.mcast_if = NULL;
614
616
618
619 s->curl = NULL;
620
621 pthread_mutex_init(&s->lock, NULL);
622 pthread_cond_init(&s->keepalive_cv, NULL);
623 pthread_mutex_init(&s->vrtsp_state.lock, NULL);
624 pthread_cond_init(&s->vrtsp_state.boss_cv, NULL);
625 pthread_cond_init(&s->vrtsp_state.worker_cv, NULL);
626
627 char *tmp = fmt;
628 char *item = NULL;
629 strcpy(s->uri, "rtsp://");
630
632
633 bool in_uri = true;
634 while ((item = strtok_r(tmp, ":", &save_ptr))) {
635 tmp = NULL;
636 bool option_given = true;
637 if (strstr(item, "rtp_rx_port=") == item) {
638 s->vrtsp_state.port = atoi(strchr(item, '=') + 1);
639 } else if (strcmp(item, "decompress") == 0) {
640 s->vrtsp_state.decompress = true;
641 } else if (strstr(item, "size=")) {
642 MSG(WARNING, "size= parameter is not used! Will be removed in "
643 "future!\n");
644 } else {
645 option_given = false;
646 if (in_uri) {
647 if (strcmp(item, "rtsp") == 0) { // rtsp:
648 continue;
649 }
650 if (strstr(item, "//") == item) { // rtsp://
651 item += 2;
652 }
653 if (strcmp(s->uri, "rtsp://") != 0) {
654 strncat(s->uri, ":", sizeof s->uri - strlen(s->uri) - 1);
655 }
656 strncat(s->uri, item, sizeof s->uri - strlen(s->uri) - 1);
657 } else {
658 MSG(ERROR, "Unknown option: %s\n", item);
660 }
661 }
662 if (option_given) {
663 in_uri = false;
664 }
665 }
666
667 //re-check parameters
668 if (!check_uri(sizeof s->uri, s->uri)) {
670 }
671 snprintf(s->base_url, sizeof s->base_url, "%s/", s->uri); // default
672
674 0, rtp_recv_callback, (uint8_t *) s->vrtsp_state.participants, 0, false);
675 if (s->vrtsp_state.device == NULL) {
676 log_msg(LOG_LEVEL_ERROR, "[rtsp] Cannot intialize RTP device!\n");
678 return VIDCAP_INIT_FAIL;
679 }
681 error_msg("[rtsp] RTP INIT failed - set option\n");
682 return VIDCAP_INIT_FAIL;
683 }
685 RTCP_SDES_TOOL, PACKAGE_STRING, strlen(PACKAGE_STRING))) {
686 error_msg("[rtsp] RTP INIT failed - set sdes\n");
687 return VIDCAP_INIT_FAIL;
688 }
689
691 if (!ret) {
692 error_msg("[rtsp] RTP INIT failed - set recv buf \nset command: sudo sysctl -w net.core.rmem_max=9123840\n");
693 return VIDCAP_INIT_FAIL;
694 }
695
696 if (!rtp_set_send_buf(s->vrtsp_state.device, 1024 * 56)) {
697 error_msg("[rtsp] RTP INIT failed - set send buf\n");
698 return VIDCAP_INIT_FAIL;
699 }
701
702 verbose_msg("[rtsp] rtp receiver init done\n");
703
704 if (s->vrtsp_state.port == 0) {
706 assert(s->vrtsp_state.port != 0);
707 }
708
709 verbose_msg(MOD_NAME "selected flags:\n");
710 verbose_msg(MOD_NAME "\t uri: %s\n",s->uri);
711 verbose_msg(MOD_NAME "\t port: %d\n", s->vrtsp_state.port);
712 verbose_msg(MOD_NAME "\t decompress: %d\n\n",s->vrtsp_state.decompress);
713
714 if (!init_rtsp(s)) {
716 return VIDCAP_INIT_FAIL;
717 }
718
719 //TODO fps should be autodetected, now reset and controlled at vidcap_grab function
720 s->vrtsp_state.desc.fps = 30;
722
723 s->should_exit = FALSE;
724
725 s->vrtsp_state.boss_waiting = false;
726 s->vrtsp_state.worker_waiting = false;
727
728 if (s->vrtsp_state.decompress) {
729 struct video_desc decompress_desc = s->vrtsp_state.desc;
730 decompress_desc.color_spec = H264;
731 if (init_decompressor(&s->vrtsp_state, decompress_desc) == 0) {
733 return VIDCAP_INIT_FAIL;
734 }
735 }
736
737 pthread_create(&s->vrtsp_state.vrtsp_thread_id, NULL, vidcap_rtsp_thread, s);
738 pthread_create(&s->keep_alive_rtsp_thread_id, NULL, keep_alive_thread, s);
739
740 verbose_msg("[rtsp] rtsp capture init done\n");
741
742 *state = s;
743 return VIDCAP_INIT_OK;
744}
745
746static CURL *init_curl() {
747 CURL *curl;
748 /* initialize curl */
749 CURLcode res = curl_global_init(CURL_GLOBAL_ALL);
750 if (res != CURLE_OK) {
751 fprintf(stderr, "[rtsp] curl_global_init(%s) failed: %s (%d)\n",
752 "CURL_GLOBAL_ALL", curl_easy_strerror(res), res);
753 return NULL;
754 }
755 curl_version_info_data *data = curl_version_info(CURLVERSION_NOW);
756 fprintf(stderr, "[rtsp] cURL V%s loaded\n", data->version);
757
758 /* initialize this curl session */
759 curl = curl_easy_init();
760 if (curl == NULL) {
761 curl_global_cleanup();
762 fprintf(stderr, "[rtsp] curl_easy_init() failed\n");
763 return NULL;
764 }
765 my_curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1, );
766 return curl;
767}
768
769static size_t print_rtsp_header(char *buffer, size_t size, size_t nitems, void *userdata) {
770 int aggregate_size = size * nitems;
771 struct rtsp_state *s = (struct rtsp_state *) userdata;
772 assert(s->magic == MAGIC);
773 bool error_occured = false;
774 if (strncmp(buffer, "RTSP/1.0 ", MIN(strlen("RTSP/1.0 "), (size_t) aggregate_size)) == 0) {
775 int code = atoi(buffer + strlen("RTSP/1.0 "));
776 error_occured = code != 200;
777 }
778 if (log_level >= LOG_LEVEL_DEBUG || error_occured) {
779 log_msg(error_occured ? LOG_LEVEL_ERROR : log_level,
780 MOD_NAME "%.*s", aggregate_size, buffer);
781 }
782 return error_occured ? CURL_WRITEFUNC_ERROR : nitems;
783}
784
786static size_t
787process_rtsp_describe_header(char *buffer, size_t size, size_t nitems,
788 void *userdata)
789{
790 const size_t ret = print_rtsp_header(buffer, size, nitems, userdata);
791 struct rtsp_state *s = userdata;
792 char *save_ptr = NULL;
793 // doc for CURLOPT_HEADERFUNCTION is unclear if buffer is
794 // NULL-terminated - one place says so, another not, so do it for sure
795 char dup[CURL_MAX_HTTP_HEADER];
796 memcpy(dup, buffer, MIN(nitems * size, sizeof dup));
797 dup[MIN(sizeof dup - 1, nitems * size)] = '\0';
798
799 char *item = strtok_r(dup, " ", &save_ptr);
800 if (item == NULL) {
801 return ret;
802 }
803 if ((strcasecmp(item, "Content-Base:") != 0 &&
804 strcasecmp(item, "Content-Location:") != 0)) {
805 return ret;
806 }
807 item = strtok_r(NULL, " ", &save_ptr);
808 if (item == NULL) {
809 return ret;
810 }
811 snprintf(s->base_url, sizeof s->base_url - 1, "%s", item);
812 char *end = (s->base_url + strlen(s->base_url)) - 1;
813 // trim \r,\n
814 while (end >= s->base_url && (*end == '\r' || *end == '\n')) {
815 *end = '\0';
816 --end;
817 }
818 // append '/' if needed
819 if (end >= s->base_url && *end != '/') {
820 *end++ = '/';
821 *end++ = '\0';
822 }
823 MSG(VERBOSE, "Using base URL from headers: %s\n", s->base_url);
824 return ret;
825}
826
830static bool
832 /* initialize curl */
833 s->curl = init_curl();
834
835 if (!s->curl) {
836 return false;
837 }
838
839 const char *range = "0.000-";
840 verbose_msg(MOD_NAME "request %s\n", VERSION_STR);
841 verbose_msg(MOD_NAME " Project web site: http://code.google.com/p/rtsprequest/\n");
842 verbose_msg(MOD_NAME " Requires cURL V7.20 or greater\n\n");
843 char Atransport[256] = "";
844 char Vtransport[256] = "";
845 int port = s->vrtsp_state.port;
846 FILE *sdp_file = tmpfile();
847 if (sdp_file == NULL) {
848 sdp_file = fopen("rtsp.sdp", "w+");
849 if (sdp_file == NULL) {
850 perror("Creating SDP file");
851 goto error;
852 }
853 }
854
855 snprintf(Vtransport, sizeof Vtransport, "RTP/AVP;unicast;client_port=%d-%d", port, port + 1);
856
857 //THIS AUDIO PORTS ARE AS DEFAULT UG AUDIO PORTS BUT AREN'T RELATED...
858 snprintf(Atransport, sizeof Atransport, "RTP/AVP;unicast;client_port=%d-%d", port+2, port + 3);
859
860 my_curl_easy_setopt(s->curl, CURLOPT_NOSIGNAL, 1, goto error); //This tells curl not to use any functions that install signal handlers or cause signals to be sent to your process.
861 //my_curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, 1);
862 my_curl_easy_setopt(s->curl, CURLOPT_VERBOSE,
863 log_level >= LOG_LEVEL_DEBUG ? 1L : 0L, goto error);
864 my_curl_easy_setopt(s->curl, CURLOPT_NOPROGRESS, 1L, goto error);
865 my_curl_easy_setopt(s->curl, CURLOPT_HEADERDATA, s, goto error);
866 my_curl_easy_setopt(s->curl, CURLOPT_HEADERFUNCTION, print_rtsp_header, goto error);
867 my_curl_easy_setopt(s->curl, CURLOPT_URL, s->uri, goto error);
868
869 //TODO TO CHECK CONFIGURING ERRORS
870 //CURLOPT_ERRORBUFFER
871 //http://curl.haxx.se/libcurl/c/curl_easy_perform.html
872
873 /* request server options */
874 if (!rtsp_options(s->curl, s->uri)) {
875 goto error;
876 }
877
878 /* request session description and write response to sdp file */
879 if (!rtsp_describe(s->curl, s->uri, sdp_file)) {
880 goto error;
881 }
882
884 fprintf(stderr, MOD_NAME "SDP:\n" MOD_NAME);
885 int ch = 0;
886 while ((ch = getc(sdp_file)) != EOF) {
887 putc(ch, stderr);
888 if (ch == '\n') {
889 fprintf(stderr, MOD_NAME);
890 }
891 }
892 rewind(sdp_file);
893 fprintf(stderr, "\n\n");
894 }
895
896 if (!setup_codecs_and_controls_from_sdp(sdp_file, s)) {
897 goto error;
898 }
899 if (s->vrtsp_state.decode_data.video_pt > -1) {
903 goto error;
904 }
905 const char *uri = s->vrtsp_state.control;
906 verbose_msg(MOD_NAME " V URI = %s\n", uri);
907 if (!rtsp_setup(s->curl, uri, Vtransport)) {
908 goto error;
909 }
910 }
911 if (strcmp(s->artsp_state.codec, "PCMU") == 0){
912 const char *uri = s->vrtsp_state.control;
913 verbose_msg(MOD_NAME " A URI = %s\n", uri);
914 if (!rtsp_setup(s->curl, uri, Atransport)) {
915 goto error;
916 }
917 }
918 if (s->vrtsp_state.desc.color_spec == H264) {
920 /* get start nal size attribute from sdp file */
921 const int len_nals = get_nals(sdp_file,
923 (int *) &s->vrtsp_state.desc.width,
924 (int *) &s->vrtsp_state.desc.height);
925 s->vrtsp_state.decode_data.offset_len = len_nals;
926 MSG(VERBOSE, "playing H264 video from server (size: WxH = %d x %d)..."
928 } else if (s->vrtsp_state.desc.color_spec == JPEG) {
930 } else {
931 MSG(ERROR, "Video codec %s not yet supported by UG.\n",
933 goto error;
934 }
935
936 if (!rtsp_play(s->curl, s->uri, range)) {
937 goto error;
938 }
939 s->setup_completed = true;
940
941 fclose(sdp_file);
942 return true;
943
944error:
945 if(sdp_file)
946 fclose(sdp_file);
947 return false;
948}
949
950#define LEN 10
951
952static bool
953setup_codecs_and_controls_from_sdp(FILE *sdp_file, struct rtsp_state *rtspState)
954{
955 rtspState->artsp_state.pt =
956 rtspState->vrtsp_state.decode_data.video_pt = -1;
957
958 char line[STR_LEN];
959
960 enum {
961 MEDIA_NONE,
962 MEDIA_AUDIO,
963 MEDIA_VIDEO,
964 } media = MEDIA_NONE;
965
966 int advertised_pt = -1;
967
968 while (fgets(line, sizeof line, sdp_file) != NULL) {
969 char buf[2001];
970 int pt = -1;
971 // m=video 0 RTP/AVP 96
972 if (sscanf(line, "m=%2000s %*d RTP/AVP %d", buf, &pt) == 2) {
973 advertised_pt = pt;
974 if (strcmp(buf, "audio") == 0) {
975 media = MEDIA_AUDIO;
976 } else if (strcmp(buf, "video") == 0) {
977 media = MEDIA_VIDEO;
978 } else {
979 media = MEDIA_NONE;
980 MSG(VERBOSE, "Unknown media: %s\n", buf);
981 continue;
982 }
983 if ((media == MEDIA_AUDIO &&
984 rtspState->artsp_state.pt != -1) ||
985 rtspState->vrtsp_state.decode_data.video_pt != -1) {
986 MSG(WARNING, "Multiple media of same type, "
987 "using last one...");
988 }
989 *(media == MEDIA_AUDIO
990 ? &rtspState->artsp_state.pt
991 : &rtspState->vrtsp_state.decode_data.video_pt) = pt;
992 continue;
993 }
994
995 if (media == MEDIA_NONE) {
996 continue; // either on session level or unkown media
997 }
998
999 if (sscanf(line, "a=control:%2000s", buf) == 1) {
1000 const char *rtsp_scheme = "rtsp://";
1001 if (strncasecmp(buf, rtsp_scheme,
1002 strlen(rtsp_scheme)) != 0) {
1003 char relative_url[sizeof buf];
1004 strcpy(relative_url, buf);
1005 snprintf(buf, sizeof buf, "%s%s",
1006 rtspState->base_url, relative_url);
1007 }
1008 *(media == MEDIA_AUDIO
1009 ? &rtspState->artsp_state.control
1010 : &rtspState->vrtsp_state.control) = strdup(buf);
1011 continue;
1012 }
1014 if (sscanf(line, "a=rtpmap:%d %2000[^/]", &pt, buf) == 2) {
1015 char *codec = media == MEDIA_AUDIO
1016 ? rtspState->artsp_state.codec
1017 : rtspState->vrtsp_state.codec;
1018 if (pt != advertised_pt) {
1019 MSG(WARNING,
1020 "media packet type %d doesn't match "
1021 "media advertised PT %d!\n",
1022 pt, advertised_pt);
1023 snprintf(codec, SHORT_STR, "?");
1024 }
1025 snprintf(codec + strlen(codec),
1026 SHORT_STR - strlen(codec), "%s", buf);
1027 }
1028 }
1029
1030 verbose_msg(MOD_NAME "AUDIO TRACK = %s FOR CODEC = %s PT = %d\n",
1031 rtspState->artsp_state.control,
1032 rtspState->artsp_state.codec,
1033 rtspState->artsp_state.pt);
1034 verbose_msg(MOD_NAME "VIDEO TRACK = %s FOR CODEC = %s PT = %d\n",
1035 rtspState->vrtsp_state.control,
1036 rtspState->vrtsp_state.codec,
1037 rtspState->vrtsp_state.decode_data.video_pt);
1038 rewind(sdp_file);
1039 return true;
1040}
1041
1045static int
1047 if (decompress_init_multi(H264, (struct pixfmt_desc) { 0 }, UYVY, &sr->sd, 1)) {
1048 decompress_reconfigure(sr->sd, desc, 16, 8, 0,
1050 } else
1051 return 0;
1052 return 1;
1053}
1054
1058static bool
1059rtsp_get_parameters(CURL *curl, const char *uri) {
1060 my_curl_easy_setopt_ex(LOG_LEVEL_DEBUG, curl, CURLOPT_RTSP_STREAM_URI,
1061 uri, return false);
1062 my_curl_easy_setopt_ex(LOG_LEVEL_DEBUG, curl, CURLOPT_RTSP_REQUEST,
1063 (long )CURL_RTSPREQ_GET_PARAMETER, return false);
1065 return true;
1066}
1067
1068static void
1069rtsp_set_user_pass(CURL *curl, char *user_pass)
1070{
1071 char *save_ptr = NULL;
1072 char *user = strtok_r(user_pass, ":", &save_ptr);
1073 assert(user != NULL);
1074 my_curl_easy_setopt(curl, CURLOPT_USERNAME, user, return);
1075 char *pass = strtok_r(NULL, ":", &save_ptr);
1076 if (pass == NULL) {
1077 return;
1078 }
1079 my_curl_easy_setopt(curl, CURLOPT_PASSWORD, pass, return);
1080}
1081
1085static bool
1086rtsp_options(CURL *curl, const char *uri) {
1087 char control[1501] = "";
1088
1089 verbose_msg("\n[rtsp] OPTIONS %s\n", uri);
1090 my_curl_easy_setopt(curl, CURLOPT_RTSP_STREAM_URI, uri, return false);
1091
1092 sscanf(uri, "rtsp://%1500s", control);
1093
1094 if (strchr(control, '@') != NULL) {
1095 *strchr(control, '@') = '\0';
1096 rtsp_set_user_pass(curl, control);
1097 }
1098
1099 my_curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, (long) CURL_RTSPREQ_OPTIONS,
1100 return false);
1101
1102 my_curl_easy_perform(curl, return false);
1103 return true;
1104}
1105
1109static bool
1110rtsp_describe(CURL *curl, const char *uri, FILE *sdp_fp) {
1111 verbose_msg("\n[rtsp] DESCRIBE %s\n", uri);
1112 my_curl_easy_setopt(curl, CURLOPT_WRITEDATA, sdp_fp, return false);
1113 my_curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION,
1114 process_rtsp_describe_header, return false);
1115 my_curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST,
1116 (long )CURL_RTSPREQ_DESCRIBE, return false);
1117
1118 my_curl_easy_perform(curl, return false);
1119
1120 my_curl_easy_setopt(curl, CURLOPT_WRITEDATA, stdout, return false);
1121 my_curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, print_rtsp_header,
1122 return false);
1123 rewind(sdp_fp);
1124 return true;
1125}
1126
1130static bool
1131rtsp_setup(CURL *curl, const char *uri, const char *transport) {
1132 verbose_msg("\n[rtsp] SETUP %s\n", uri);
1133 verbose_msg(MOD_NAME "\t TRANSPORT %s\n", transport);
1134 my_curl_easy_setopt(curl, CURLOPT_RTSP_STREAM_URI, uri, return false);
1135 my_curl_easy_setopt(curl, CURLOPT_RTSP_TRANSPORT, transport, return false);
1136 my_curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, (long) CURL_RTSPREQ_SETUP,
1137 return false);
1138
1139 my_curl_easy_perform(curl, return false);
1140 return true;
1141}
1142
1146static bool
1147rtsp_play(CURL *curl, const char *uri, const char *range) {
1148 UNUSED(range);
1149 verbose_msg("\n[rtsp] PLAY %s\n", uri);
1150 my_curl_easy_setopt(curl, CURLOPT_RTSP_STREAM_URI, uri, return false);
1151 //my_curl_easy_setopt(curl, CURLOPT_RANGE, range); //range not set because we want (right now) no limit range for streaming duration
1152 my_curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, (long) CURL_RTSPREQ_PLAY,
1153 return false);
1154 my_curl_easy_perform(curl, return false);
1155 return true;
1156}
1157
1161static void
1162rtsp_teardown(CURL *curl, const char *uri) {
1163 verbose_msg("\n[rtsp] TEARDOWN %s\n", uri);
1164 my_curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST,
1165 (long )CURL_RTSPREQ_TEARDOWN, return);
1166
1167 my_curl_easy_perform(curl, return);
1168}
1169
1170static void vidcap_rtsp_probe(struct device_info **available_cards, int *count, void (**deleter)(void *)) {
1171 *deleter = free;
1172 *available_cards = NULL;
1173 *count = 0;
1174}
1175
1176static void
1178 struct rtsp_state *s = (struct rtsp_state *) state;
1179
1180 pthread_mutex_lock(&s->lock);
1181 pthread_mutex_lock(&s->vrtsp_state.lock);
1182 s->should_exit = true;
1183 pthread_mutex_unlock(&s->vrtsp_state.lock);
1184 pthread_mutex_unlock(&s->lock);
1185
1186 pthread_cond_signal(&s->keepalive_cv);
1187 pthread_cond_signal(&s->vrtsp_state.worker_cv);
1188
1190 pthread_join(s->vrtsp_state.vrtsp_thread_id, NULL);
1191 }
1193 pthread_join(s->keep_alive_rtsp_thread_id, NULL);
1194 }
1195
1196 if(s->vrtsp_state.sd)
1198
1199 if (s->vrtsp_state.device) {
1201 }
1202
1204 free(s->vrtsp_state.control);
1205 free(s->artsp_state.control);
1206
1207 if (s->curl != NULL) {
1208 if (s->setup_completed) {
1209 rtsp_teardown(s->curl, s->uri);
1210 }
1211
1212 curl_easy_cleanup(s->curl);
1213 curl_global_cleanup();
1214 s->curl = NULL;
1215 }
1216
1217 pthread_mutex_destroy(&s->lock);
1218 pthread_cond_destroy(&s->keepalive_cv);
1219 pthread_mutex_destroy(&s->vrtsp_state.lock);
1220 pthread_cond_destroy(&s->vrtsp_state.boss_cv);
1221 pthread_cond_destroy(&s->vrtsp_state.worker_cv);
1222
1223 free(s);
1224}
1225
1229static int
1230get_nals(FILE *sdp_file, char *nals, int *width, int *height) {
1231 int max_len = 1500, len_nals = 0;
1232 char *s = (char *) malloc(max_len);
1233 char *sprop;
1234 memset(s, 0, max_len);
1235 nals[0] = '\0';
1236
1237 while (fgets(s, max_len - 2, sdp_file) != NULL) {
1238 sprop = strstr(s, "sprop-parameter-sets=");
1239 if (sprop == NULL) {
1240 continue;
1241 }
1242 char *sprop_val = strstr(sprop, "=") + 1;
1243 char *term = strchr(sprop_val, ';');
1244 if (term) {
1245 *term = '\0';
1246 }
1247
1248 char *nal = 0;
1249 while ((nal = strtok(sprop_val, ","))) {
1250 sprop_val = NULL;
1251 unsigned int length = 0;
1252 //convert base64 to binary
1253 unsigned char *nal_decoded = base64_decode(nal, &length);
1254 if (length == 0) {
1255 free(nal_decoded);
1256 continue;
1257 }
1258
1259 memcpy(nals+len_nals, start_sequence, sizeof(start_sequence));
1260 len_nals += sizeof(start_sequence);
1261 memcpy(nals + len_nals, nal_decoded, length);
1262 len_nals += length;
1263 free(nal_decoded);
1264
1265 uint8_t nalInfo = (uint8_t) nals[len_nals - length];
1266 uint8_t type = nalInfo & 0x1f;
1267 debug_msg(MOD_NAME "sprop-parameter %d (base64): %s\n", (int) type, nal);
1268 if (type == NAL_H264_SPS){
1269 width_height_from_SDP(width, height, (unsigned char *) (nals+(len_nals - length)), length);
1270 }
1271 }
1272 }
1273
1274 free(s);
1275 rewind(sdp_file);
1276 return len_nals;
1277}
1278
1286
1288
1289/* vim: set expandtab sw=4: */
#define UNUSED(x)
void ** state
struct video_desc desc
struct video_frame * frame
const char * fmt
struct audio_frame ** audio
int void(** deleter)(void *))
struct video_frame * vf_alloc(int count)
Allocates blank video frame.
void vf_free(struct video_frame *buf)
Frees video_frame structure.
struct video_desc video_desc_from_frame(const struct video_frame *frame)
Returns struct video_desc from video frame.
int vc_get_linesize(unsigned int width, codec_t codec)
struct video_frame * vf_alloc_desc_data(struct video_desc desc)
const char * get_codec_name(codec_t codec)
This file contains definition of some common audio types.
static void show_help()
Definition wasapi.cpp:193
int color_printf(const char *format,...)
#define TRED(x)
Definition color_out.h:75
#define TBOLD(x)
Definition color_out.h:70
#define TRUE
#define FALSE
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define error_msg(...)
Definition debug.h:89
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define LOG_LEVEL_VERBOSE
Definition debug.h:63
#define MSG(l, fmt,...)
Definition debug.h:96
#define verbose_msg(...)
Definition debug.h:90
#define debug_msg(...)
#define debug_msg(...) log_msg(LOG_LEVEL_DEBUG, "[pid/%d +%d %s] ", getpid(), LINE,...
Definition debug.h:92
#define VIDCAP_INIT_NOERR
state not initialized, other action performed (typically help)
#define VIDCAP_INIT_OK
initialization successful
#define VIDEO_CAPTURE_ABI_VERSION
#define VIDCAP_INIT_FAIL
error ocured
decompress_status decompress_frame(struct state_decompress *s, unsigned char *dst, unsigned char *compressed, unsigned int compressed_len, int frame_seq, struct video_frame_callbacks *callbacks, struct pixfmt_desc *internal_prop)
Decompresses video frame.
void decompress_done(struct state_decompress *s)
int decompress_reconfigure(struct state_decompress *s, struct video_desc desc, int rshift, int gshift, int bshift, int pitch, codec_t out_codec)
bool decompress_init_multi(codec_t compression, struct pixfmt_desc internal_prop, codec_t out_codec, struct state_decompress **out, int count)
Initializes (multiple) decompress states.
int count
Definition hd-rum.c:44
void exit_uv(int status)
Definition host.cpp:625
#define LOG_LEVEL_DEBUG
Definition kernels.cu:48
volatile int log_level
Definition debug.cpp:65
@ LIBRARY_CLASS_VIDEO_CAPTURE
Definition lib_common.h:78
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
Definition lib_common.h:144
#define MIN(a, b)
Definition macros.h:63
@ SHORT_STR
Definition macros.h:133
@ STR_LEN
"standard" string length placeholder
Definition macros.h:134
#define DEBUG
Definition main.c:27
int pbuf_decode(struct pbuf *playout_buf, time_ns_t curr_time, decode_frame_t decode_func, void *data)
Definition pbuf.c:562
void pbuf_remove(struct pbuf *playout_buf, time_ns_t curr_time)
Definition pbuf.c:498
void pdb_iter_done(pdb_iter_t *it)
Definition pdb.c:412
struct pdb_e * pdb_iter_next(pdb_iter_t *it)
Definition pdb.c:402
struct pdb_e * pdb_iter_init(struct pdb *db, pdb_iter_t *it)
Definition pdb.c:393
struct pdb * pdb_init(volatile int *delay_ms)
Definition pdb.c:244
int pdb_add(struct pdb *db, uint32_t ssrc)
Definition pdb.c:299
void * pdb_iter_t
Definition pdb.h:106
bool rtp_set_send_buf(struct rtp *session, int bufsize)
Definition rtp.c:3954
bool rtp_set_recv_buf(struct rtp *session, int bufsize)
Definition rtp.c:3938
bool rtp_set_option(struct rtp *session, rtp_option optname, int optval)
Definition rtp.c:1308
void rtp_update(struct rtp *session, time_ns_t curr_time)
Definition rtp.c:3456
struct rtp * rtp_init_if(const char *addr, const char *iface, uint16_t rx_port, uint16_t tx_port, int ttl, double rtcp_bw, int tfrc_on, rtp_callback callback, uint8_t *userdata, int force_ip_version, bool multithreaded)
Definition rtp.c:1034
uint32_t rtp_my_ssrc(struct rtp *session)
Definition rtp.c:1401
bool rtp_set_sdes(struct rtp *session, uint32_t ssrc, rtcp_sdes_type type, const char *value, int length)
Definition rtp.c:2546
int rtp_get_udp_rx_port(struct rtp *session)
Definition rtp.c:4042
bool rtp_recv_r(struct rtp *session, struct timeval *timeout, uint32_t curr_rtp_ts)
Receive RTP packets and dispatch them.
Definition rtp.c:2338
void rtp_done(struct rtp *session)
Definition rtp.c:3676
@ RTCP_SDES_TOOL
Definition rtp.h:215
@ RTP_OPT_WEAK_VALIDATION
Definition rtp.h:229
rtp_packet
Definition rtp.h:126
void rtp_recv_callback(struct rtp *session, rtp_event *e)
int width_height_from_SDP(int *widthOut, int *heightOut, unsigned char *data, int data_len)
int decode_frame_h264(struct coded_data *cdata, void *decode_data)
struct video_frame * get_sps_pps_frame(const struct video_desc *desc, struct decode_data_rtsp *decode_data)
@ NAL_H264_SPS
Definition rtpdec_h264.h:62
int decode_frame_jpeg(struct coded_data *cdata, void *decode_data)
static int vidcap_rtsp_init(struct vidcap_params *params, void **state)
Definition rtsp.c:578
static bool rtsp_describe(CURL *curl, const char *uri, FILE *sdp_fp)
Definition rtsp.c:1110
#define KEEPALIVE_INTERVAL_S
Definition rtsp.c:89
static int init_decompressor(struct video_rtsp_state *sr, struct video_desc desc)
Definition rtsp.c:1046
#define FAIL_SHOW_HELP
Definition rtsp.c:572
static void vidcap_rtsp_probe(struct device_info **available_cards, int *count, void(**deleter)(void *))
Definition rtsp.c:1170
static const uint8_t start_sequence[]
Definition rtsp.c:207
static void rtsp_teardown(CURL *curl, const char *uri)
Definition rtsp.c:1162
static struct video_frame * vidcap_rtsp_grab(void *state, struct audio_frame **audio)
Definition rtsp.c:434
static const char * pointer_to_str(void *p)
Definition rtsp.c:114
static bool rtsp_options(CURL *curl, const char *uri)
Definition rtsp.c:1086
static void vidcap_rtsp_done(void *state)
Definition rtsp.c:1177
static size_t process_rtsp_describe_header(char *buffer, size_t size, size_t nitems, void *userdata)
currently only searches for Content-Base or Content-Location header
Definition rtsp.c:787
static const char * long_to_str(long l)
Definition rtsp.c:108
#define my_curl_easy_setopt_ex(l, A, B, C, action_fail)
Definition rtsp.c:133
@ DEFAULT_RTSP_PORT
Definition rtsp.c:105
#define CURL_WRITEFUNC_ERROR
Definition rtsp.c:101
static bool rtsp_get_parameters(CURL *curl, const char *uri)
Definition rtsp.c:1059
#define my_curl_easy_setopt(A, B, C, action_fail)
Definition rtsp.c:155
static int get_nals(FILE *sdp_file, char *nals, int *width, int *height)
Definition rtsp.c:1230
static bool rtsp_setup(CURL *curl, const char *uri, const char *transport)
Definition rtsp.c:1131
static bool init_rtsp(struct rtsp_state *s)
Definition rtsp.c:831
#define INITIAL_VIDEO_RECV_BUFFER_SIZE
Definition rtsp.c:97
#define MAGIC
Definition rtsp.c:90
static void rtsp_set_user_pass(CURL *curl, char *user_pass)
Definition rtsp.c:1069
static bool setup_codecs_and_controls_from_sdp(FILE *sdp_file, struct rtsp_state *rtspState)
Definition rtsp.c:953
static bool rtsp_play(CURL *curl, const char *uri, const char *range)
Definition rtsp.c:1147
static CURL * init_curl()
Definition rtsp.c:746
static void * vidcap_rtsp_thread(void *args)
Definition rtsp.c:379
#define MOD_NAME
Definition rtsp.c:91
void rtsp_keepalive(void *state)
#define my_curl_easy_perform(A, action_fail)
Definition rtsp.c:157
#define my_curl_easy_perform_ex(l, A, action_fail)
Definition rtsp.c:144
#define VERSION_STR
Definition rtsp.c:92
static const char * cstr_identity(const char *c)
Definition rtsp.c:120
static const struct video_capture_info vidcap_rtsp_info
Definition rtsp.c:1279
static bool check_uri(size_t uri_len, char *uri)
check URI validity + append port if not given
Definition rtsp.c:531
static size_t print_rtsp_header(char *buffer, size_t size, size_t nitems, void *userdata)
Definition rtsp.c:769
static void * keep_alive_thread(void *arg)
Definition rtsp.c:336
static int decode_frame_by_pt(struct coded_data *cdata, void *decode_data, struct pbuf_stats *stats)
Definition rtsp.c:365
rtsp_types_t
Definition rtsp_utils.h:4
@ rtsp_type_none
Definition rtsp_utils.h:5
codec_t get_video_codec_from_pt_rtpmap(int pt, const char *rtpmap_codec_name)
get UG video codec to given params
Definition sdp.c:622
Option::OptType type
Definition settings.cpp:194
struct used to comunicate with audio capture/playback device
Definition types.h:99
volatile bool worker_waiting
Definition rtsp.c:268
char codec[SHORT_STR]
Definition rtsp.c:249
volatile bool boss_waiting
Definition rtsp.c:270
struct pdb * participants
Definition rtsp.c:259
pthread_cond_t boss_cv
Definition rtsp.c:269
struct audio_frame audio
Definition rtsp.c:246
struct timeval last_audio_time
Definition rtsp.c:251
int play_audio_frame
Definition rtsp.c:247
pthread_cond_t worker_cv
Definition rtsp.c:267
pthread_mutex_t lock
Definition rtsp.c:266
pthread_t artsp_thread_id
Definition rtsp.c:265
char * control
Definition rtsp.c:256
struct rtp * device
Definition rtsp.c:258
unsigned int grab_audio
Definition rtsp.c:252
double rtcp_bw
Definition rtsp.c:260
int required_connections
Definition rtsp.c:263
char * mcast_if
Definition rtsp.c:262
rtp_packet * data
Definition pbuf.h:75
struct decode_data_rtsp::@46::@48 h264
struct video_frame * frame
int(* decode)(struct coded_data *cdata, void *decode_data)
unsigned char offset_buffer[2048]
SPS/PPS headers extracted from RTSP.
Definition hd-rum.c:27
Definition pdb.h:72
struct pbuf * playout_buffer
Definition pdb.h:84
Definition pdb.c:84
Definition rtp.c:274
pthread_t keep_alive_rtsp_thread_id
Definition rtsp.c:288
struct video_rtsp_state vrtsp_state
Definition rtsp.c:286
pthread_mutex_t lock
Definition rtsp.c:289
rtsp_types_t avType
Definition rtsp.c:280
CURL * curl
Definition rtsp.c:277
pthread_cond_t keepalive_cv
Definition rtsp.c:290
uint32_t magic
Definition rtsp.c:276
bool setup_completed
Definition rtsp.c:292
_Bool sps_pps_emitted
emit SPS/PPS once first to reduce decoding errors
Definition rtsp.c:293
struct audio_rtsp_state artsp_state
Definition rtsp.c:285
char * sdp
Definition rtsp.c:282
char uri[1024]
Definition rtsp.c:278
volatile bool should_exit
Definition rtsp.c:284
const char * addr
Definition rtsp.c:281
char base_url[1024]
for control URLs with relative path; '/' included
Definition rtsp.c:279
unsigned int width
Definition types.h:280
char * data
Raw tile data. Pointer must be at least 4B aligned.
Definition types.h:287
unsigned int data_len
length of the data
Definition types.h:288
unsigned int height
Definition types.h:281
unsigned int tile_count
Definition types.h:185
codec_t color_spec
Definition types.h:182
enum interlacing_t interlacing
Definition types.h:184
double fps
Definition types.h:183
unsigned int width
width of every tile (!)
Definition types.h:179
unsigned int height
height of every tile (!)
Definition types.h:180
void(* dispose)(struct video_frame *)
Definition types.h:245
Struct video_frame represents a video frame and contains video description.
Definition types.h:305
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
Definition types.h:345
int64_t timestamp
Definition types.h:331
double fps
Definition types.h:308
struct video_frame_callbacks callbacks
Definition types.h:324
codec_t color_spec
Definition types.h:306
int required_connections
Definition rtsp.c:232
volatile bool worker_waiting
Definition rtsp.c:238
pthread_cond_t worker_cv
Definition rtsp.c:237
struct pdb * participants
Definition rtsp.c:228
char * control
Definition rtsp.c:225
struct video_desc desc
Definition rtsp.c:215
double rtcp_bw
Definition rtsp.c:229
pthread_cond_t boss_cv
Definition rtsp.c:239
bool decompress
Definition rtsp.c:219
struct rtp * device
Definition rtsp.c:227
struct video_desc decompress_desc
Definition rtsp.c:222
pthread_t vrtsp_thread_id
Definition rtsp.c:234
char * mcast_if
Definition rtsp.c:231
struct video_frame * out_frame
Definition rtsp.c:216
pthread_mutex_t lock
Definition rtsp.c:236
struct state_decompress * sd
Definition rtsp.c:221
volatile bool boss_waiting
Definition rtsp.c:240
struct decode_data_rtsp decode_data
Definition rtsp.c:242
char codec[SHORT_STR]
Definition rtsp.c:213
static struct timeval start_time
Definition tv.c:57
long long time_ns_t
Definition tv.h:81
static time_ns_t get_time_in_ns()
Definition tv.h:101
@ PROGRESSIVE
progressive frame
Definition types.h:164
@ UYVY
YCbCr 422 8-bit - Cb Y0 Cr Y1.
Definition types.h:71
@ VC_NONE
Definition types.h:67
@ JPEG
JPEG image, restart intervals may be used. Compatible with GPUJPEG.
Definition types.h:81
@ H264
H.264 frame.
Definition types.h:83
unsigned char * base64_decode(const char *in, unsigned int *length)
Definition text.c:168
This is an umbrella header for video functions.
const char * vidcap_params_get_fmt(const struct vidcap_params *params)
unsigned int vidcap_params_get_flags(const struct vidcap_params *params)
#define VIDCAP_FLAG_AUDIO_ANY
API for video decompress drivers.
bool video_desc_eq(struct video_desc a, struct video_desc b)
Compares two video descriptions.