diff --git a/Makefile.in b/Makefile.in index 45af71a..546eeb1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -37,7 +37,7 @@ VIDEO_OBJ = @VIDEO@ OBJ = motion.o logger.o conf.o draw.o jpegutils.o vloopback_motion.o $(VIDEO_OBJ) \ netcam.o netcam_ftp.o netcam_jpeg.o netcam_wget.o track.o \ alg.o event.o picture.o rotate.o webhttpd.o \ - stream.o md5.o @FFMPEG_OBJ@ @SDL_OBJ@ + stream.o md5.o @FFMPEG_OBJ@ @SDL_OBJ@ @RTPS_OBJ@ SRC = $(OBJ:.o=.c) DOC = CHANGELOG COPYING CREDITS INSTALL README motion_guide.html EXAMPLES = *.conf motion.init-Debian motion.init-Fedora motion.init-FreeBSD.sh diff --git a/config.h.in b/config.h.in index 26b86ec..31262da 100644 --- a/config.h.in +++ b/config.h.in @@ -114,6 +114,9 @@ /* Define to 1 if you have av_avformat_alloc_context support */ #undef have_av_avformat_alloc_context +/* Define to 1 if you have av_get_media_type_string support */ +#undef have_av_get_media_type_string + /* Define to 1 if you have av_register_protocol support */ #undef have_av_register_protocol diff --git a/configure b/configure index 826a590..7ba55d0 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for motion Git-aa2d317a553ea96300c56aac2f9f92af0014c925. +# Generated by GNU Autoconf 2.69 for motion trunkREVUNKNOWN. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -577,8 +577,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='motion' PACKAGE_TARNAME='motion' -PACKAGE_VERSION='Git-aa2d317a553ea96300c56aac2f9f92af0014c925' -PACKAGE_STRING='motion Git-aa2d317a553ea96300c56aac2f9f92af0014c925' +PACKAGE_VERSION='trunkREVUNKNOWN' +PACKAGE_STRING='motion trunkREVUNKNOWN' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -625,6 +625,7 @@ BIN_PATH EGREP GREP CPP +RTPS_OBJ FFMPEG_OBJ SDL_OBJ VIDEO @@ -1244,7 +1245,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures motion Git-aa2d317a553ea96300c56aac2f9f92af0014c925 to adapt to many kinds of systems. +\`configure' configures motion trunkREVUNKNOWN to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1305,7 +1306,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of motion Git-aa2d317a553ea96300c56aac2f9f92af0014c925:";; + short | recursive ) echo "Configuration of motion trunkREVUNKNOWN:";; esac cat <<\_ACEOF @@ -1453,7 +1454,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -motion configure Git-aa2d317a553ea96300c56aac2f9f92af0014c925 +motion configure trunkREVUNKNOWN generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2055,7 +2056,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by motion $as_me Git-aa2d317a553ea96300c56aac2f9f92af0014c925, which was +It was created by motion $as_me trunkREVUNKNOWN, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -4451,6 +4452,9 @@ $as_echo "not found" >&6; } FFMPEG_OBJ="ffmpeg.o" + RTPS_OBJ="netcam_rtsp.o" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking file_protocol is defined in ffmpeg ?" >&5 $as_echo_n "checking file_protocol is defined in ffmpeg ?... " >&6; } saved_CFLAGS=$CFLAGS @@ -6063,6 +6067,14 @@ $as_echo "#define have_av_register_protocol 1" >>confdefs.h fi +ac_fn_c_check_func "$LINENO" "av_get_media_type_string" "ac_cv_func_av_get_media_type_string" +if test "x$ac_cv_func_av_get_media_type_string" = xyes; then : + +$as_echo "#define have_av_get_media_type_string 1" >>confdefs.h + +fi +0 + # # Add the right exec path for rc scripts @@ -6593,7 +6605,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by motion $as_me Git-aa2d317a553ea96300c56aac2f9f92af0014c925, which was +This file was extended by motion $as_me trunkREVUNKNOWN, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -6655,7 +6667,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -motion config.status Git-aa2d317a553ea96300c56aac2f9f92af0014c925 +motion config.status trunkREVUNKNOWN configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.in b/configure.in index c25390b..2bf2b45 100644 --- a/configure.in +++ b/configure.in @@ -529,6 +529,9 @@ if test "${FFMPEG_OK}" = "found"; then FFMPEG_OBJ="ffmpeg.o" AC_SUBST(FFMPEG_OBJ) + RTPS_OBJ="netcam_rtsp.o" + AC_SUBST(RTPS_OBJ) + AC_MSG_CHECKING([file_protocol is defined in ffmpeg ?]) saved_CFLAGS=$CFLAGS saved_LIBS=$LIBS @@ -1218,6 +1221,8 @@ AC_CHECK_FUNC(avformat_alloc_context, AC_DEFINE([have_avformat_alloc_context],1, AC_CHECK_FUNC(av_avformat_alloc_context, AC_DEFINE([have_av_avformat_alloc_context],1,[Define to 1 if you have av_avformat_alloc_context support])) AC_CHECK_FUNC(av_register_protocol2, AC_DEFINE([have_av_register_protocol2],1,[Define to 1 if you have av_register_protocol2 support])) AC_CHECK_FUNC(av_register_protocol, AC_DEFINE([have_av_register_protocol],1,[Define to 1 if you have av_register_protocol support])) +AC_CHECK_FUNC(av_get_media_type_string, AC_DEFINE([have_av_get_media_type_string],1,[Define to 1 if you have av_get_media_type_string support]))0 + # # Add the right exec path for rc scripts diff --git a/netcam.c b/netcam.c index 8121859..e327a2f 100644 --- a/netcam.c +++ b/netcam.c @@ -45,6 +45,9 @@ #include #include "netcam_ftp.h" +#ifdef have_av_get_media_type_string +#include "netcam_rtsp.h" +#endif #define CONNECT_TIMEOUT 10 /* Timeout on remote connection attempt */ #define READ_TIMEOUT 5 /* Default timeout on recv requests */ @@ -146,8 +149,13 @@ static void netcam_url_parse(struct url_t *parse_url, const char *text_url) { char *s; int i; +#ifdef have_av_get_media_type_string + const char *re = "(http|ftp|mjpg|rtsp)://(((.*):(.*))@)?" + "([^/:]|[-.a-z0-9]+)(:([0-9]+))?($|(/[^:]*))"; +#else const char *re = "(http|ftp|mjpg)://(((.*):(.*))@)?" "([^/:]|[-.a-z0-9]+)(:([0-9]+))?($|(/[^:]*))"; +#endif regex_t pattbuf; regmatch_t matches[10]; @@ -203,6 +211,10 @@ static void netcam_url_parse(struct url_t *parse_url, const char *text_url) parse_url->port = 80; else if (!strcmp(parse_url->service, "ftp")) parse_url->port = 21; +#ifdef have_av_get_media_type_string + else if (!strcmp(parse_url->service, "rtsp") && parse_url->port == 0) + parse_url->port = 554; +#endif } regfree(&pattbuf); @@ -2401,6 +2413,71 @@ static int netcam_setup_ftp(netcam_context_ptr netcam, struct url_t *url) return 0; } +#ifdef have_av_get_media_type_string +static int netcam_setup_rtsp(netcam_context_ptr netcam, struct url_t *url) +{ + struct context *cnt = netcam->cnt; + const char *ptr; + + netcam->caps.streaming = NCS_RTSP; + netcam->rtsp = rtsp_new_context(); + + if (netcam->rtsp == NULL) { + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: unable to create rtsp context"); + return -1; + } + + /* + * Allocate space for a working string to contain the path. + * The extra 5 is for "://", ":" and string terminator. + */ + + // force port to a sane value + if (netcam->connect_port > 65536) { + netcam->connect_port = 65536; + } else if (netcam->connect_port < 0) { + netcam->connect_port = 0; + } + + ptr = mymalloc(strlen(url->service) + strlen(netcam->connect_host) + + 5 + strlen(url->path) + 5); + sprintf((char *)ptr, "%s://%s:%d%s", url->service, + netcam->connect_host, netcam->connect_port, url->path); + + netcam->rtsp->path = (char *)ptr; + + if (cnt->conf.netcam_userpass != NULL) { + ptr = cnt->conf.netcam_userpass; + } else { + ptr = url->userpass; /* Don't set this one NULL, gets freed. */ + } + + if (ptr != NULL) { + char *cptr; + + if ((cptr = strchr(ptr, ':')) == NULL) { + netcam->rtsp->user = mystrdup(ptr); + } else { + netcam->rtsp->user = mymalloc((cptr - ptr)); + memcpy(netcam->rtsp->user, ptr,(cptr - ptr)); + netcam->rtsp->pass = mystrdup(cptr + 1); + } + } + + netcam_url_free(url); + + /* + * The RTSP context should be all ready to attempt a connection with + * the server, so we try .... + */ + rtsp_connect(netcam); + + netcam->get_image = netcam_read_rtsp_image; + + return 0; +} +#endif + /** * netcam_recv * @@ -2631,6 +2708,11 @@ int netcam_next(struct context *cnt, unsigned char *image) pthread_mutex_unlock(&netcam->mutex); } + if (netcam->caps.streaming == NCS_RTSP) { + memcpy(image, netcam->latest->ptr, netcam->latest->used); + return 0; + } + /* * If an error occurs in the JPEG decompression which follows this, * jpeglib will return to the code within this 'if'. Basically, our @@ -2808,6 +2890,13 @@ int netcam_start(struct context *cnt) strcpy(url.service, "http"); /* Put back a real URL service. */ retval = netcam_setup_mjpg(netcam, &url); +#ifdef have_av_get_media_type_string + } else if ((url.service) && (!strcmp(url.service, "rtsp"))) { + MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO, "%s: now calling" + " netcam_setup_rtsp()"); + + retval = netcam_setup_rtsp(netcam, &url); +#endif } else { MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO, "%s: Invalid netcam service '%s' - " "must be http, ftp, mjpg or file.", url.service); @@ -2831,36 +2920,46 @@ int netcam_start(struct context *cnt) return -1; } - /* - * If an error occurs in the JPEG decompression which follows this, - * jpeglib will return to the code within this 'if'. If such an error - * occurs during startup, we will just abandon this attempt. - */ - if (setjmp(netcam->setjmp_buffer)) { - MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO, "%s: libjpeg decompression failure " - "on first frame - giving up!"); - return -1; - } +#ifdef have_av_get_media_type_string + if (netcam->caps.streaming != NCS_RTSP) { +#endif + /* + * If an error occurs in the JPEG decompression which follows this, + * jpeglib will return to the code within this 'if'. If such an error + * occurs during startup, we will just abandon this attempt. + */ + if (setjmp(netcam->setjmp_buffer)) { + MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO, "%s: libjpeg decompression failure " + "on first frame - giving up!"); + return -1; + } - netcam->netcam_tolerant_check = cnt->conf.netcam_tolerant_check; - netcam->JFIF_marker = 0; - netcam_get_dimensions(netcam); + netcam->netcam_tolerant_check = cnt->conf.netcam_tolerant_check; + netcam->JFIF_marker = 0; + netcam_get_dimensions(netcam); - /* - * Motion currently requires that image height and width is a - * multiple of 16. So we check for this. - */ - if (netcam->width % 8) { - MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO, "%s: netcam image width (%d)" - " is not modulo 8", netcam->width); - return -3; - } + /* + * Motion currently requires that image height and width is a + * multiple of 16. So we check for this. + */ + if (netcam->width % 8) { + MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO, "%s: netcam image width (%d)" + " is not modulo 8", netcam->width); + return -3; + } - if (netcam->height % 8) { - MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO, "%s: netcam image height (%d)" - " is not modulo 8", netcam->height); - return -3; + if (netcam->height % 8) { + MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO, "%s: netcam image height (%d)" + " is not modulo 8", netcam->height); + return -3; + } +#ifdef have_av_get_media_type_string + } else { + // not jpeg, get the dimensions + netcam->width = netcam->rtsp->codec_context->width; + netcam->height = netcam->rtsp->codec_context->height; } +#endif /* Fill in camera details into context structure. */ cnt->imgs.width = netcam->width; diff --git a/netcam.h b/netcam.h index f335304..6062edf 100644 --- a/netcam.h +++ b/netcam.h @@ -105,6 +105,7 @@ typedef struct file_context { #define NCS_UNSUPPORTED 0 /* streaming is not supported */ #define NCS_MULTIPART 1 /* streaming is done via multipart */ #define NCS_BLOCK 2 /* streaming is done via MJPG-block */ +#define NCS_RTSP 3 /* streaming is done via RTSP */ /* * struct netcam_context contains all the structures and other data @@ -199,6 +200,9 @@ typedef struct netcam_context { struct file_context *file; /* this structure contains the context for FILE connection */ + struct rtsp_context *rtsp; /* this structure contains the + context for RTSP connection */ + int (*get_image)(netcam_context_ptr); /* Function to fetch the image from the netcam. It is initialised in diff --git a/netcam_rtsp.c b/netcam_rtsp.c new file mode 100644 index 0000000..1fe1357 --- /dev/null +++ b/netcam_rtsp.c @@ -0,0 +1,332 @@ +#include +#include "netcam_rtsp.h" +#include "motion.h" + +#ifdef have_av_get_media_type_string + +/**************************************************** + * Duplicated static functions - FIXME + ****************************************************/ + +/** + * netcam_check_buffsize + * + * This routine checks whether there is enough room in a buffer to copy + * some additional data. If there is not enough room, it will re-allocate + * the buffer and adjust it's size. + * + * Parameters: + * buff Pointer to a netcam_image_buffer structure. + * numbytes The number of bytes to be copied. + * + * Returns: Nothing + */ +static void netcam_check_buffsize(netcam_buff_ptr buff, size_t numbytes) +{ + int min_size_to_alloc; + int real_alloc; + int new_size; + + if ((buff->size - buff->used) >= numbytes) + return; + + min_size_to_alloc = numbytes - (buff->size - buff->used); + real_alloc = ((min_size_to_alloc / NETCAM_BUFFSIZE) * NETCAM_BUFFSIZE); + + if ((min_size_to_alloc - real_alloc) > 0) + real_alloc += NETCAM_BUFFSIZE; + + new_size = buff->size + real_alloc; + + MOTION_LOG(DBG, TYPE_NETCAM, NO_ERRNO, "%s: expanding buffer from [%d/%d] to [%d/%d] bytes.", + (int) buff->used, (int) buff->size, + (int) buff->used, new_size); + + buff->ptr = myrealloc(buff->ptr, new_size, + "netcam_check_buf_size"); + buff->size = new_size; +} + +/**************************************************** + * End Duplicated static functions - FIXME + ****************************************************/ + +static int decode_packet(AVPacket *packet, netcam_buff_ptr buffer, AVFrame *frame, AVCodecContext *cc) +{ + int check = 0; + int ret = avcodec_decode_video2(cc, frame, &check, packet); + + if (ret < 0) { + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Error decoding video packet"); + return 0; + } + + if (check == 0) { + // no frame could be decoded...keep trying + return 0; + } + + int frame_size = av_image_get_buffer_size(cc->pix_fmt, cc->width, cc->height, 1); + + /* Assure there's enough room in the buffer. */ + netcam_check_buffsize(buffer, frame_size); + + av_image_copy_to_buffer((uint8_t *)buffer->ptr, frame_size, + (const uint8_t **)(frame->data), frame->linesize, + cc->pix_fmt, cc->width, cc->height, 1); + + buffer->used = frame_size; + + return frame_size; +} + +static int open_codec_context(int *stream_idx, AVFormatContext *fmt_ctx, enum AVMediaType type) +{ + int ret; + AVStream *st; + AVCodecContext *dec_ctx = NULL; + AVCodec *dec = NULL; + ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0); + if (ret < 0) { + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Could not find stream %s in input!", av_get_media_type_string(type)); + return ret; + } else { + *stream_idx = ret; + st = fmt_ctx->streams[*stream_idx]; + /* find decoder for the stream */ + dec_ctx = st->codec; + dec = avcodec_find_decoder(dec_ctx->codec_id); + if (!dec) { + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Failed to find %s codec!", av_get_media_type_string(type)); + return ret; + } + if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) { + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Failed to open %s codec!", av_get_media_type_string(type)); + return ret; + } + } + return 0; +} + +/** +* rtsp_new_context +* +* Create a new RTSP context structure. +* +* Parameters +* +* None +* +* Returns: Pointer to the newly-created structure, NULL if error. +* +*/ +struct rtsp_context *rtsp_new_context(void) +{ + struct rtsp_context *ret; + + /* Note that mymalloc will exit on any problem. */ + ret = mymalloc(sizeof(struct rtsp_context)); + + memset(ret, 0, sizeof(struct rtsp_context)); + + return ret; +} + +/** +* rtsp_free_context +* +* Free the resources allocated for this context. +* +* Parameters +* +* ctxt Pointer to the rtsp_context structure. +* +* Returns: Nothing +* +*/ +static void rtsp_free_context(struct rtsp_context *ctxt) +{ + if (ctxt == NULL) + return; + + if (ctxt->path != NULL) + free(ctxt->path); + + if (ctxt->user) + free(ctxt->user); + + if (ctxt->pass) + free(ctxt->pass); + + if (ctxt->format_context != NULL) { + avformat_close_input(&ctxt->format_context); + } + + if (ctxt->codec_context != NULL) { + avcodec_close(ctxt->codec_context); + } + + free(ctxt); +} + +int rtsp_connect(netcam_context_ptr netcam) +{ + if (netcam->rtsp == NULL) { + netcam->rtsp = rtsp_new_context(); + + if (netcam->rtsp == NULL) { + MOTION_LOG(ALR, TYPE_NETCAM, NO_ERRNO, "%s: unable to create context(%s)", netcam->rtsp->path); + return -1; + } + } + + // open the network connection + AVDictionary *opts = 0; + av_dict_set(&opts, "rtsp_transport", "tcp", 0); + + int ret = avformat_open_input(&netcam->rtsp->format_context, netcam->rtsp->path, NULL, &opts); + if (ret < 0) { + MOTION_LOG(ALR, TYPE_NETCAM, NO_ERRNO, "%s: unable to open input(%s): %d - %s", netcam->rtsp->path, ret, av_err2str(ret)); + rtsp_free_context(netcam->rtsp); + netcam->rtsp = NULL; + return -1; + } + + // fill out stream information + ret = avformat_find_stream_info(netcam->rtsp->format_context, NULL); + if (ret < 0) { + MOTION_LOG(ALR, TYPE_NETCAM, NO_ERRNO, "%s: unable to find stream info: %d", ret); + rtsp_free_context(netcam->rtsp); + netcam->rtsp = NULL; + return -1; + } + + ret = open_codec_context(&netcam->rtsp->video_stream_index, netcam->rtsp->format_context, AVMEDIA_TYPE_VIDEO); + if (ret < 0) { + MOTION_LOG(ALR, TYPE_NETCAM, NO_ERRNO, "%s: unable to open codec context: %d", ret); + rtsp_free_context(netcam->rtsp); + netcam->rtsp = NULL; + return -1; + } + + netcam->rtsp->codec_context = netcam->rtsp->format_context->streams[netcam->rtsp->video_stream_index]->codec; + + // start up the feed + av_read_play(netcam->rtsp->format_context); + + return 0; +} + +int netcam_read_rtsp_image(netcam_context_ptr netcam) +{ + if (netcam->rtsp == NULL) { + if (rtsp_connect(netcam) < 0) { + return -1; + } + } + + AVCodecContext *cc = netcam->rtsp->codec_context; + AVFormatContext *fc = netcam->rtsp->format_context; + netcam_buff_ptr buffer; + + /* Point to our working buffer. */ + buffer = netcam->receiving; + buffer->used = 0; + + AVFrame *frame = avcodec_alloc_frame(); + + AVPacket packet; + + av_init_packet(&packet); + + packet.data = NULL; + packet.size = 0; + + int size_decoded = 0; + static int usual_size_decoded = 0; + + while (size_decoded == 0 && av_read_frame(fc, &packet) >= 0) { + + if(packet.stream_index != netcam->rtsp->video_stream_index) { + // not our packet, skip + continue; + } + + size_decoded = decode_packet(&packet, buffer, frame, cc); + } + + if (size_decoded == 0) { + // something went wrong, end of stream? + MOTION_LOG(ERR, TYPE_NETCAM, SHOW_ERRNO, "%s: invalid frame!"); + return -1; + } + + if (size_decoded != usual_size_decoded) { + MOTION_LOG(WRN, TYPE_NETCAM, SHOW_ERRNO, "%s: unusual frame size of %d!", size_decoded); + usual_size_decoded = size_decoded; + } + + // at this point, we are finished with the packet and frame, so free them. + av_free_packet(&packet); + av_free(frame); + + struct timeval curtime; + + if (gettimeofday(&curtime, NULL) < 0) { + MOTION_LOG(WRN, TYPE_NETCAM, SHOW_ERRNO, "%s: gettimeofday"); + } + + netcam->receiving->image_time = curtime; + + /* + * Calculate our "running average" time for this netcam's + * frame transmissions (except for the first time). + * Note that the average frame time is held in microseconds. + */ + if (netcam->last_image.tv_sec) { + netcam->av_frame_time = ((9.0 * netcam->av_frame_time) + 1000000.0 * + (curtime.tv_sec - netcam->last_image.tv_sec) + + (curtime.tv_usec- netcam->last_image.tv_usec)) / 10.0; + + MOTION_LOG(DBG, TYPE_NETCAM, NO_ERRNO, "%s: Calculated frame time %f", + netcam->av_frame_time); + } + + netcam->last_image = curtime; + + netcam_buff *xchg; + + /* + * read is complete - set the current 'receiving' buffer atomically + * as 'latest', and make the buffer previously in 'latest' become + * the new 'receiving'. + */ + pthread_mutex_lock(&netcam->mutex); + + xchg = netcam->latest; + netcam->latest = netcam->receiving; + netcam->receiving = xchg; + netcam->imgcnt++; + + /* + * We have a new frame ready. We send a signal so that + * any thread (e.g. the motion main loop) waiting for the + * next frame to become available may proceed. + */ + pthread_cond_signal(&netcam->pic_ready); + + pthread_mutex_unlock(&netcam->mutex); + + return 0; +} + + +void netcam_shutdown_rtsp(netcam_context_ptr netcam) +{ + if (netcam->rtsp != NULL) { + rtsp_free_context(netcam->rtsp); + netcam->rtsp = NULL; + } +} + +#endif diff --git a/netcam_rtsp.h b/netcam_rtsp.h new file mode 100644 index 0000000..38ef565 --- /dev/null +++ b/netcam_rtsp.h @@ -0,0 +1,22 @@ +#include "netcam.h" +#include +#include +#include +#include +#include + + +struct rtsp_context { + AVFormatContext* format_context; + AVCodecContext* codec_context; + int video_stream_index; + char* path; + char* user; + char* pass; +}; + +//int netcam_setup_rtsp(netcam_context_ptr netcam, struct url_t *url); +struct rtsp_context *rtsp_new_context(void); +void netcam_shutdown_rtsp(netcam_context_ptr netcam); +int rtsp_connect(netcam_context_ptr netcam); +int netcam_read_rtsp_image(netcam_context_ptr netcam);