Annotation of embedaddon/curl/docs/examples/rtsp.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (c) 2011 - 2019, Jim Hollinger
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms, with or without
                      6:  * modification, are permitted provided that the following conditions
                      7:  * are met:
                      8:  *   * Redistributions of source code must retain the above copyright
                      9:  *     notice, this list of conditions and the following disclaimer.
                     10:  *   * Redistributions in binary form must reproduce the above copyright
                     11:  *     notice, this list of conditions and the following disclaimer in the
                     12:  *     documentation and/or other materials provided with the distribution.
                     13:  *   * Neither the name of Jim Hollinger nor the names of its contributors
                     14:  *     may be used to endorse or promote products derived from this
                     15:  *     software without specific prior written permission.
                     16:  *
                     17:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
                     18:  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
                     19:  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
                     20:  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
                     21:  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
                     22:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
                     23:  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     24:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     25:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     26:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
                     27:  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     28:  *
                     29:  */
                     30: /* <DESC>
                     31:  * A basic RTSP transfer
                     32:  * </DESC>
                     33:  */
                     34: 
                     35: #include <stdio.h>
                     36: #include <stdlib.h>
                     37: #include <string.h>
                     38: 
                     39: #if defined (WIN32)
                     40: #  include <conio.h>  /* _getch() */
                     41: #else
                     42: #  include <termios.h>
                     43: #  include <unistd.h>
                     44: 
                     45: static int _getch(void)
                     46: {
                     47:   struct termios oldt, newt;
                     48:   int ch;
                     49:   tcgetattr(STDIN_FILENO, &oldt);
                     50:   newt = oldt;
                     51:   newt.c_lflag &= ~( ICANON | ECHO);
                     52:   tcsetattr(STDIN_FILENO, TCSANOW, &newt);
                     53:   ch = getchar();
                     54:   tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
                     55:   return ch;
                     56: }
                     57: #endif
                     58: 
                     59: #include <curl/curl.h>
                     60: 
                     61: #define VERSION_STR  "V1.0"
                     62: 
                     63: /* error handling macros */
                     64: #define my_curl_easy_setopt(A, B, C)                             \
                     65:   res = curl_easy_setopt((A), (B), (C));                         \
                     66:   if(res != CURLE_OK)                                            \
                     67:     fprintf(stderr, "curl_easy_setopt(%s, %s, %s) failed: %d\n", \
                     68:             #A, #B, #C, res);
                     69: 
                     70: #define my_curl_easy_perform(A)                                     \
                     71:   res = curl_easy_perform(A);                                       \
                     72:   if(res != CURLE_OK)                                               \
                     73:     fprintf(stderr, "curl_easy_perform(%s) failed: %d\n", #A, res);
                     74: 
                     75: 
                     76: /* send RTSP OPTIONS request */
                     77: static void rtsp_options(CURL *curl, const char *uri)
                     78: {
                     79:   CURLcode res = CURLE_OK;
                     80:   printf("\nRTSP: OPTIONS %s\n", uri);
                     81:   my_curl_easy_setopt(curl, CURLOPT_RTSP_STREAM_URI, uri);
                     82:   my_curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_OPTIONS);
                     83:   my_curl_easy_perform(curl);
                     84: }
                     85: 
                     86: 
                     87: /* send RTSP DESCRIBE request and write sdp response to a file */
                     88: static void rtsp_describe(CURL *curl, const char *uri,
                     89:                           const char *sdp_filename)
                     90: {
                     91:   CURLcode res = CURLE_OK;
                     92:   FILE *sdp_fp = fopen(sdp_filename, "wb");
                     93:   printf("\nRTSP: DESCRIBE %s\n", uri);
                     94:   if(sdp_fp == NULL) {
                     95:     fprintf(stderr, "Could not open '%s' for writing\n", sdp_filename);
                     96:     sdp_fp = stdout;
                     97:   }
                     98:   else {
                     99:     printf("Writing SDP to '%s'\n", sdp_filename);
                    100:   }
                    101:   my_curl_easy_setopt(curl, CURLOPT_WRITEDATA, sdp_fp);
                    102:   my_curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_DESCRIBE);
                    103:   my_curl_easy_perform(curl);
                    104:   my_curl_easy_setopt(curl, CURLOPT_WRITEDATA, stdout);
                    105:   if(sdp_fp != stdout) {
                    106:     fclose(sdp_fp);
                    107:   }
                    108: }
                    109: 
                    110: /* send RTSP SETUP request */
                    111: static void rtsp_setup(CURL *curl, const char *uri, const char *transport)
                    112: {
                    113:   CURLcode res = CURLE_OK;
                    114:   printf("\nRTSP: SETUP %s\n", uri);
                    115:   printf("      TRANSPORT %s\n", transport);
                    116:   my_curl_easy_setopt(curl, CURLOPT_RTSP_STREAM_URI, uri);
                    117:   my_curl_easy_setopt(curl, CURLOPT_RTSP_TRANSPORT, transport);
                    118:   my_curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_SETUP);
                    119:   my_curl_easy_perform(curl);
                    120: }
                    121: 
                    122: 
                    123: /* send RTSP PLAY request */
                    124: static void rtsp_play(CURL *curl, const char *uri, const char *range)
                    125: {
                    126:   CURLcode res = CURLE_OK;
                    127:   printf("\nRTSP: PLAY %s\n", uri);
                    128:   my_curl_easy_setopt(curl, CURLOPT_RTSP_STREAM_URI, uri);
                    129:   my_curl_easy_setopt(curl, CURLOPT_RANGE, range);
                    130:   my_curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_PLAY);
                    131:   my_curl_easy_perform(curl);
                    132: 
                    133:   /* switch off using range again */
                    134:   my_curl_easy_setopt(curl, CURLOPT_RANGE, NULL);
                    135: }
                    136: 
                    137: 
                    138: /* send RTSP TEARDOWN request */
                    139: static void rtsp_teardown(CURL *curl, const char *uri)
                    140: {
                    141:   CURLcode res = CURLE_OK;
                    142:   printf("\nRTSP: TEARDOWN %s\n", uri);
                    143:   my_curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_TEARDOWN);
                    144:   my_curl_easy_perform(curl);
                    145: }
                    146: 
                    147: 
                    148: /* convert url into an sdp filename */
                    149: static void get_sdp_filename(const char *url, char *sdp_filename,
                    150:                              size_t namelen)
                    151: {
                    152:   const char *s = strrchr(url, '/');
                    153:   strcpy(sdp_filename, "video.sdp");
                    154:   if(s != NULL) {
                    155:     s++;
                    156:     if(s[0] != '\0') {
                    157:       snprintf(sdp_filename, namelen, "%s.sdp", s);
                    158:     }
                    159:   }
                    160: }
                    161: 
                    162: 
                    163: /* scan sdp file for media control attribute */
                    164: static void get_media_control_attribute(const char *sdp_filename,
                    165:                                         char *control)
                    166: {
                    167:   int max_len = 256;
                    168:   char *s = malloc(max_len);
                    169:   FILE *sdp_fp = fopen(sdp_filename, "rb");
                    170:   control[0] = '\0';
                    171:   if(sdp_fp != NULL) {
                    172:     while(fgets(s, max_len - 2, sdp_fp) != NULL) {
                    173:       sscanf(s, " a = control: %s", control);
                    174:     }
                    175:     fclose(sdp_fp);
                    176:   }
                    177:   free(s);
                    178: }
                    179: 
                    180: 
                    181: /* main app */
                    182: int main(int argc, char * const argv[])
                    183: {
                    184: #if 1
                    185:   const char *transport = "RTP/AVP;unicast;client_port=1234-1235";  /* UDP */
                    186: #else
                    187:   /* TCP */
                    188:   const char *transport = "RTP/AVP/TCP;unicast;client_port=1234-1235";
                    189: #endif
                    190:   const char *range = "0.000-";
                    191:   int rc = EXIT_SUCCESS;
                    192:   char *base_name = NULL;
                    193: 
                    194:   printf("\nRTSP request %s\n", VERSION_STR);
                    195:   printf("    Project web site: "
                    196:     "https://github.com/BackupGGCode/rtsprequest\n");
                    197:   printf("    Requires curl V7.20 or greater\n\n");
                    198: 
                    199:   /* check command line */
                    200:   if((argc != 2) && (argc != 3)) {
                    201:     base_name = strrchr(argv[0], '/');
                    202:     if(base_name == NULL) {
                    203:       base_name = strrchr(argv[0], '\\');
                    204:     }
                    205:     if(base_name == NULL) {
                    206:       base_name = argv[0];
                    207:     }
                    208:     else {
                    209:       base_name++;
                    210:     }
                    211:     printf("Usage:   %s url [transport]\n", base_name);
                    212:     printf("         url of video server\n");
                    213:     printf("         transport (optional) specifier for media stream"
                    214:            " protocol\n");
                    215:     printf("         default transport: %s\n", transport);
                    216:     printf("Example: %s rtsp://192.168.0.2/media/video1\n\n", base_name);
                    217:     rc = EXIT_FAILURE;
                    218:   }
                    219:   else {
                    220:     const char *url = argv[1];
                    221:     char *uri = malloc(strlen(url) + 32);
                    222:     char *sdp_filename = malloc(strlen(url) + 32);
                    223:     char *control = malloc(strlen(url) + 32);
                    224:     CURLcode res;
                    225:     get_sdp_filename(url, sdp_filename, strlen(url) + 32);
                    226:     if(argc == 3) {
                    227:       transport = argv[2];
                    228:     }
                    229: 
                    230:     /* initialize curl */
                    231:     res = curl_global_init(CURL_GLOBAL_ALL);
                    232:     if(res == CURLE_OK) {
                    233:       curl_version_info_data *data = curl_version_info(CURLVERSION_NOW);
                    234:       CURL *curl;
                    235:       fprintf(stderr, "    curl V%s loaded\n", data->version);
                    236: 
                    237:       /* initialize this curl session */
                    238:       curl = curl_easy_init();
                    239:       if(curl != NULL) {
                    240:         my_curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L);
                    241:         my_curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
                    242:         my_curl_easy_setopt(curl, CURLOPT_HEADERDATA, stdout);
                    243:         my_curl_easy_setopt(curl, CURLOPT_URL, url);
                    244: 
                    245:         /* request server options */
                    246:         snprintf(uri, strlen(url) + 32, "%s", url);
                    247:         rtsp_options(curl, uri);
                    248: 
                    249:         /* request session description and write response to sdp file */
                    250:         rtsp_describe(curl, uri, sdp_filename);
                    251: 
                    252:         /* get media control attribute from sdp file */
                    253:         get_media_control_attribute(sdp_filename, control);
                    254: 
                    255:         /* setup media stream */
                    256:         snprintf(uri, strlen(url) + 32, "%s/%s", url, control);
                    257:         rtsp_setup(curl, uri, transport);
                    258: 
                    259:         /* start playing media stream */
                    260:         snprintf(uri, strlen(url) + 32, "%s/", url);
                    261:         rtsp_play(curl, uri, range);
                    262:         printf("Playing video, press any key to stop ...");
                    263:         _getch();
                    264:         printf("\n");
                    265: 
                    266:         /* teardown session */
                    267:         rtsp_teardown(curl, uri);
                    268: 
                    269:         /* cleanup */
                    270:         curl_easy_cleanup(curl);
                    271:         curl = NULL;
                    272:       }
                    273:       else {
                    274:         fprintf(stderr, "curl_easy_init() failed\n");
                    275:       }
                    276:       curl_global_cleanup();
                    277:     }
                    278:     else {
                    279:       fprintf(stderr, "curl_global_init(%s) failed: %d\n",
                    280:               "CURL_GLOBAL_ALL", res);
                    281:     }
                    282:     free(control);
                    283:     free(sdp_filename);
                    284:     free(uri);
                    285:   }
                    286: 
                    287:   return rc;
                    288: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>