Return to rtsp.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / docs / examples |
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: }