"Fossies" - the Fresh Open Source Software Archive

Member "motion-Release-4.3.0/src/netcam_rtsp.c" (14 Jan 2020, 65249 Bytes) of package /linux/misc/motion-Release-4.3.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "netcam_rtsp.c" see the Fossies "Dox" file reference documentation.

    1 /***********************************************************
    2  *  In the top section are the functions that are used
    3  *  when processing the camera feed.  Since these functions
    4  *  are internal to the RTSP module, and many require FFmpeg
    5  *  structures in their declarations, they are within the
    6  *  HAVE_FFMPEG block that eliminates them entirely when
    7  *  FFmpeg is not present.
    8  *
    9  *  The functions:
   10  *      netcam_rtsp_setup
   11  *      netcam_rtsp_next
   12  *      netcam_rtsp_cleanup
   13  *  are called from video_common.c therefore must be defined even
   14  *  if FFmpeg is not present.  They must also not have FFmpeg
   15  *  structures in the declarations.  Simple error
   16  *  messages are raised if called when no FFmpeg is found.
   17  *
   18  *  Additional note:  Although this module is called netcam_rtsp,
   19  *  it actually handles more camera types than just rtsp.
   20  *  Within its current construct, it could be set up to handle
   21  *  whatever types of capture devices that ffmpeg can use.
   22  *  As of this writing it includes rtsp, http, files and v4l2.
   23  *
   24  ***********************************************************/
   25 
   26 #include <stdio.h>
   27 #include "translate.h"
   28 #include "rotate.h"    /* already includes motion.h */
   29 #include "netcam_rtsp.h"
   30 #include "video_v4l2.h"  /* Needed to validate palette for v4l2 via netcam */
   31 
   32 #ifdef HAVE_FFMPEG
   33 
   34 #include "ffmpeg.h"
   35 
   36 static int netcam_rtsp_check_pixfmt(struct rtsp_context *rtsp_data){
   37     /* Determine if the format is YUV420P */
   38     int retcd;
   39 
   40     retcd = -1;
   41     if ((rtsp_data->codec_context->pix_fmt == MY_PIX_FMT_YUV420P) ||
   42         (rtsp_data->codec_context->pix_fmt == MY_PIX_FMT_YUVJ420P)) retcd = 0;
   43 
   44     return retcd;
   45 
   46 }
   47 
   48 static void netcam_rtsp_pktarray_free(struct rtsp_context *rtsp_data){
   49 
   50     int indx;
   51     pthread_mutex_lock(&rtsp_data->mutex_pktarray);
   52         if (rtsp_data->pktarray_size > 0){
   53             for(indx = 0; indx < rtsp_data->pktarray_size; indx++) {
   54                 if (rtsp_data->pktarray[indx].packet.data != NULL) {
   55                     my_packet_unref(rtsp_data->pktarray[indx].packet);
   56                 }
   57             }
   58         }
   59         free(rtsp_data->pktarray);
   60         rtsp_data->pktarray = NULL;
   61         rtsp_data->pktarray_size = 0;
   62         rtsp_data->pktarray_index = -1;
   63     pthread_mutex_unlock(&rtsp_data->mutex_pktarray);
   64 
   65 }
   66 
   67 static void netcam_rtsp_null_context(struct rtsp_context *rtsp_data){
   68 
   69     rtsp_data->swsctx          = NULL;
   70     rtsp_data->swsframe_in     = NULL;
   71     rtsp_data->swsframe_out    = NULL;
   72     rtsp_data->frame           = NULL;
   73     rtsp_data->codec_context   = NULL;
   74     rtsp_data->format_context  = NULL;
   75     rtsp_data->transfer_format = NULL;
   76 
   77 }
   78 
   79 static void netcam_rtsp_close_context(struct rtsp_context *rtsp_data){
   80 
   81     if (rtsp_data->swsctx       != NULL) sws_freeContext(rtsp_data->swsctx);
   82     if (rtsp_data->swsframe_in  != NULL) my_frame_free(rtsp_data->swsframe_in);
   83     if (rtsp_data->swsframe_out != NULL) my_frame_free(rtsp_data->swsframe_out);
   84     if (rtsp_data->frame        != NULL) my_frame_free(rtsp_data->frame);
   85     if (rtsp_data->pktarray     != NULL) netcam_rtsp_pktarray_free(rtsp_data);
   86     if (rtsp_data->codec_context    != NULL) my_avcodec_close(rtsp_data->codec_context);
   87     if (rtsp_data->format_context   != NULL) avformat_close_input(&rtsp_data->format_context);
   88     if (rtsp_data->transfer_format != NULL) avformat_close_input(&rtsp_data->transfer_format);
   89     netcam_rtsp_null_context(rtsp_data);
   90 
   91 }
   92 
   93 static void netcam_rtsp_pktarray_resize(struct context *cnt, int is_highres){
   94     /* This is called from netcam_rtsp_next and is on the motion loop thread
   95      * The rtsp_data->mutex is locked around the call to this function.
   96     */
   97 
   98     /* Remember that this is a ring and we have two threads chasing around it
   99      * the ffmpeg is writing out of this ring while we are filling it up.  "Bad"
  100      * things will occur if the "add" thread catches up with the "write" thread.
  101      * We need this ring to be big enough so they don't collide.
  102      * The alternative is that we'd need to make a copy of the entire packet
  103      * array in the ffmpeg module and do our writing from that copy.  The
  104      * downside is that is a lot to be copying around for each image we want
  105      * to write out.  And putting a mutex on the array during adding function would
  106      * slow down the capture thread to the speed of the writing thread.  And that
  107      * writing thread operates at the user specified FPS which could be really slow
  108      * ...So....make this array big enough so we never catch our tail.  :)
  109      */
  110 
  111     int64_t               idnbr_last, idnbr_first;
  112     int                   indx;
  113     struct rtsp_context  *rtsp_data;
  114     struct packet_item   *tmp;
  115     int                   newsize;
  116 
  117     if (is_highres){
  118         idnbr_last = cnt->imgs.image_ring[cnt->imgs.image_ring_out].idnbr_high;
  119         idnbr_first = cnt->imgs.image_ring[cnt->imgs.image_ring_in].idnbr_high;
  120         rtsp_data = cnt->rtsp_high;
  121     } else {
  122         idnbr_last = cnt->imgs.image_ring[cnt->imgs.image_ring_out].idnbr_norm;
  123         idnbr_first = cnt->imgs.image_ring[cnt->imgs.image_ring_in].idnbr_norm;
  124         rtsp_data = cnt->rtsp;
  125     }
  126 
  127     if (!rtsp_data->passthrough) return;
  128 
  129     /* The 30 is arbitrary */
  130     /* Double the size plus double last diff so we don't catch our tail */
  131     newsize =((idnbr_first - idnbr_last) * 2 ) + ((rtsp_data->idnbr - idnbr_last ) * 2);
  132     if (newsize < 30) newsize = 30;
  133 
  134     pthread_mutex_lock(&rtsp_data->mutex_pktarray);
  135         if ((rtsp_data->pktarray_size < newsize) ||  (rtsp_data->pktarray_size < 30)){
  136             tmp = mymalloc(newsize * sizeof(struct packet_item));
  137             if (rtsp_data->pktarray_size > 0 ){
  138                 memcpy(tmp, rtsp_data->pktarray, sizeof(struct packet_item) * rtsp_data->pktarray_size);
  139             }
  140             for(indx = rtsp_data->pktarray_size; indx < newsize; indx++) {
  141                 av_init_packet(&tmp[indx].packet);
  142                 tmp[indx].packet.data=NULL;
  143                 tmp[indx].packet.size=0;
  144                 tmp[indx].idnbr = 0;
  145                 tmp[indx].iskey = FALSE;
  146                 tmp[indx].iswritten = FALSE;
  147             }
  148 
  149             if (rtsp_data->pktarray != NULL) free(rtsp_data->pktarray);
  150             rtsp_data->pktarray = tmp;
  151             rtsp_data->pktarray_size = newsize;
  152 
  153             MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
  154                 ,_("%s: Resized packet array to %d"), rtsp_data->cameratype,newsize);
  155         }
  156     pthread_mutex_unlock(&rtsp_data->mutex_pktarray);
  157 
  158 }
  159 
  160 static void netcam_rtsp_pktarray_add(struct rtsp_context *rtsp_data){
  161 
  162     int indx_next;
  163     int retcd;
  164     char errstr[128];
  165 
  166     pthread_mutex_lock(&rtsp_data->mutex_pktarray);
  167 
  168         if (rtsp_data->pktarray_size == 0){
  169             pthread_mutex_unlock(&rtsp_data->mutex_pktarray);
  170             return;
  171         }
  172 
  173         /* Recall pktarray_size is one based but pktarray is zero based */
  174         if (rtsp_data->pktarray_index == (rtsp_data->pktarray_size-1) ){
  175             indx_next = 0;
  176         } else {
  177             indx_next = rtsp_data->pktarray_index + 1;
  178         }
  179 
  180         rtsp_data->pktarray[indx_next].idnbr = rtsp_data->idnbr;
  181 
  182         my_packet_unref(rtsp_data->pktarray[indx_next].packet);
  183         av_init_packet(&rtsp_data->pktarray[indx_next].packet);
  184         rtsp_data->pktarray[indx_next].packet.data = NULL;
  185         rtsp_data->pktarray[indx_next].packet.size = 0;
  186 
  187         retcd = my_copy_packet(&rtsp_data->pktarray[indx_next].packet, &rtsp_data->packet_recv);
  188         if ((rtsp_data->interrupted) || (retcd < 0)) {
  189             av_strerror(retcd, errstr, sizeof(errstr));
  190             MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
  191                 ,_("%s: av_copy_packet: %s ,Interrupt: %s")
  192                 ,rtsp_data->cameratype
  193                 ,errstr, rtsp_data->interrupted ? _("True"):_("False"));
  194             my_packet_unref(rtsp_data->pktarray[indx_next].packet);
  195             rtsp_data->pktarray[indx_next].packet.data = NULL;
  196             rtsp_data->pktarray[indx_next].packet.size = 0;
  197         }
  198 
  199         if (rtsp_data->pktarray[indx_next].packet.flags & AV_PKT_FLAG_KEY) {
  200             rtsp_data->pktarray[indx_next].iskey = TRUE;
  201         } else {
  202             rtsp_data->pktarray[indx_next].iskey = FALSE;
  203         }
  204         rtsp_data->pktarray[indx_next].iswritten = FALSE;
  205         rtsp_data->pktarray[indx_next].timestamp_tv.tv_sec = rtsp_data->img_recv->image_time.tv_sec;
  206         rtsp_data->pktarray[indx_next].timestamp_tv.tv_usec = rtsp_data->img_recv->image_time.tv_usec;
  207         rtsp_data->pktarray_index = indx_next;
  208     pthread_mutex_unlock(&rtsp_data->mutex_pktarray);
  209 
  210 }
  211 
  212 
  213 /* netcam_rtsp_decode_video
  214  *
  215  * Return values:
  216  *   <0 error
  217  *   0 invalid but continue
  218  *   1 valid data
  219  */
  220 static int netcam_rtsp_decode_video(struct rtsp_context *rtsp_data){
  221 
  222 #if (LIBAVFORMAT_VERSION_MAJOR >= 58) || ((LIBAVFORMAT_VERSION_MAJOR == 57) && (LIBAVFORMAT_VERSION_MINOR >= 41))
  223 
  224     int retcd;
  225     char errstr[128];
  226 
  227     /* The Invalid data problem comes frequently.  Usually at startup of rtsp cameras.
  228      * We now ignore those packets so this function would need to fail on a different error.
  229      * We should consider adding a maximum count of these errors and reset every time
  230      * we get a good image.
  231      */
  232     if (rtsp_data->finish) return 0;   /* This just speeds up the shutdown time */
  233 
  234     retcd = avcodec_send_packet(rtsp_data->codec_context, &rtsp_data->packet_recv);
  235     if ((rtsp_data->interrupted) || (rtsp_data->finish)) return -1;
  236     if (retcd == AVERROR_INVALIDDATA) {
  237         MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
  238             ,_("Ignoring packet with invalid data"));
  239         return 0;
  240     }
  241     if (retcd < 0 && retcd != AVERROR_EOF){
  242         av_strerror(retcd, errstr, sizeof(errstr));
  243         MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
  244             ,_("Error sending packet to codec: %s"), errstr);
  245         return -1;
  246     }
  247 
  248     retcd = avcodec_receive_frame(rtsp_data->codec_context, rtsp_data->frame);
  249     if ((rtsp_data->interrupted) || (rtsp_data->finish)) return -1;
  250 
  251     if (retcd == AVERROR(EAGAIN)) return 0;
  252 
  253     if (retcd == AVERROR_INVALIDDATA) {
  254         MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
  255             ,_("Ignoring packet with invalid data"));
  256         return 0;
  257     }
  258 
  259     if (retcd < 0) {
  260         av_strerror(retcd, errstr, sizeof(errstr));
  261         MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
  262             ,_("Error receiving frame from codec: %s"), errstr);
  263         return -1;
  264     }
  265 
  266     return 1;
  267 
  268 #else
  269 
  270     int retcd;
  271     int check = 0;
  272     char errstr[128];
  273 
  274     if (rtsp_data->finish) return 0;   /* This just speeds up the shutdown time */
  275 
  276     retcd = avcodec_decode_video2(rtsp_data->codec_context, rtsp_data->frame, &check, &rtsp_data->packet_recv);
  277     if ((rtsp_data->interrupted) || (rtsp_data->finish)) return -1;
  278 
  279     if (retcd == AVERROR_INVALIDDATA) {
  280         MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO, _("Ignoring packet with invalid data"));
  281         return 0;
  282     }
  283 
  284     if (retcd < 0) {
  285         av_strerror(retcd, errstr, sizeof(errstr));
  286         MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO, _("Error decoding packet: %s"),errstr);
  287         return -1;
  288     }
  289 
  290     if (check == 0 || retcd == 0) return 0;
  291 
  292     return 1;
  293 
  294 #endif
  295 
  296 }
  297 
  298 static int netcam_rtsp_decode_packet(struct rtsp_context *rtsp_data){
  299 
  300     int frame_size;
  301     int retcd;
  302 
  303     if (rtsp_data->finish) return -1;   /* This just speeds up the shutdown time */
  304 
  305     retcd = netcam_rtsp_decode_video(rtsp_data);
  306     if (retcd <= 0) return retcd;
  307 
  308     frame_size = my_image_get_buffer_size(rtsp_data->codec_context->pix_fmt
  309                                           ,rtsp_data->codec_context->width
  310                                           ,rtsp_data->codec_context->height);
  311 
  312     netcam_check_buffsize(rtsp_data->img_recv, frame_size);
  313     netcam_check_buffsize(rtsp_data->img_latest, frame_size);
  314 
  315     retcd = my_image_copy_to_buffer(rtsp_data->frame
  316                                     ,(uint8_t *)rtsp_data->img_recv->ptr
  317                                     ,rtsp_data->codec_context->pix_fmt
  318                                     ,rtsp_data->codec_context->width
  319                                     ,rtsp_data->codec_context->height
  320                                     ,frame_size);
  321     if ((retcd < 0) || (rtsp_data->interrupted)) {
  322         MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO
  323             ,_("Error decoding video packet: Copying to buffer"));
  324         return -1;
  325     }
  326 
  327     rtsp_data->img_recv->used = frame_size;
  328 
  329     return frame_size;
  330 }
  331 
  332 static void netcam_rtsp_decoder_error(struct rtsp_context *rtsp_data, int retcd, const char* fnc_nm){
  333 
  334     char errstr[128];
  335 
  336     if (retcd < 0){
  337         av_strerror(retcd, errstr, sizeof(errstr));
  338         MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO
  339             ,_("%s: %s: %s,Interrupt %s")
  340             ,rtsp_data->cameratype,fnc_nm, errstr, rtsp_data->interrupted ? _("True"):_("False"));
  341     } else {
  342         MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO
  343             ,_("%s: %s: Failed,Interrupt %s"),rtsp_data->cameratype
  344             ,fnc_nm, rtsp_data->interrupted ? _("True"):_("False"));
  345     }
  346 
  347     if (rtsp_data->decoder_nm != NULL){
  348         MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO
  349             ,_("%s: Ignoring user requested decoder %s"),rtsp_data->cameratype
  350             ,rtsp_data->decoder_nm);
  351         free(rtsp_data->cnt->netcam_decoder);
  352         rtsp_data->cnt->netcam_decoder = NULL;
  353         rtsp_data->decoder_nm = NULL;
  354     }
  355 
  356 }
  357 
  358 static int netcam_rtsp_open_codec(struct rtsp_context *rtsp_data){
  359 
  360 #if (LIBAVFORMAT_VERSION_MAJOR >= 58) || ((LIBAVFORMAT_VERSION_MAJOR == 57) && (LIBAVFORMAT_VERSION_MINOR >= 41))
  361     int retcd;
  362     AVStream *st;
  363     AVCodec *decoder = NULL;
  364 
  365     if (rtsp_data->finish) return -1;   /* This just speeds up the shutdown time */
  366 
  367     retcd = av_find_best_stream(rtsp_data->format_context, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
  368     if ((retcd < 0) || (rtsp_data->interrupted)){
  369         netcam_rtsp_decoder_error(rtsp_data, retcd, "av_find_best_stream");
  370         return -1;
  371     }
  372     rtsp_data->video_stream_index = retcd;
  373     st = rtsp_data->format_context->streams[rtsp_data->video_stream_index];
  374 
  375     if (rtsp_data->decoder_nm != NULL){
  376         decoder = avcodec_find_decoder_by_name(rtsp_data->decoder_nm);
  377         if (decoder == NULL) {
  378             netcam_rtsp_decoder_error(rtsp_data, 0, "avcodec_find_decoder_by_name");
  379         } else {
  380             MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO,_("%s: Using decoder %s")
  381                 ,rtsp_data->cameratype,rtsp_data->decoder_nm);
  382         }
  383     }
  384 
  385     if (decoder == NULL) {
  386         decoder = avcodec_find_decoder(st->codecpar->codec_id);
  387     }
  388 
  389     if ((decoder == NULL) || (rtsp_data->interrupted)){
  390         netcam_rtsp_decoder_error(rtsp_data, 0, "avcodec_find_decoder");
  391         return -1;
  392     }
  393 
  394     rtsp_data->codec_context = avcodec_alloc_context3(decoder);
  395     if ((rtsp_data->codec_context == NULL) || (rtsp_data->interrupted)){
  396         netcam_rtsp_decoder_error(rtsp_data, 0, "avcodec_alloc_context3");
  397         return -1;
  398     }
  399 
  400     retcd = avcodec_parameters_to_context(rtsp_data->codec_context, st->codecpar);
  401     if ((retcd < 0) || (rtsp_data->interrupted)) {
  402         netcam_rtsp_decoder_error(rtsp_data, retcd, "avcodec_alloc_context3");
  403         return -1;
  404     }
  405 
  406     retcd = avcodec_open2(rtsp_data->codec_context, decoder, NULL);
  407     if ((retcd < 0) || (rtsp_data->interrupted)){
  408         netcam_rtsp_decoder_error(rtsp_data, retcd, "avcodec_open2");
  409         return -1;
  410     }
  411 
  412     return 0;
  413 #else
  414 
  415     int retcd;
  416     AVStream *st;
  417     AVCodec *decoder = NULL;
  418 
  419     if (rtsp_data->finish) return -1;   /* This just speeds up the shutdown time */
  420 
  421     retcd = av_find_best_stream(rtsp_data->format_context, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
  422     if ((retcd < 0) || (rtsp_data->interrupted)){
  423         netcam_rtsp_decoder_error(rtsp_data, retcd, "av_find_best_stream");
  424         return -1;
  425     }
  426     rtsp_data->video_stream_index = retcd;
  427     st = rtsp_data->format_context->streams[rtsp_data->video_stream_index];
  428 
  429     rtsp_data->codec_context = st->codec;
  430     decoder = avcodec_find_decoder(rtsp_data->codec_context->codec_id);
  431     if ((decoder == NULL) || (rtsp_data->interrupted)) {
  432         netcam_rtsp_decoder_error(rtsp_data, 0, "avcodec_find_decoder");
  433         return -1;
  434      }
  435     retcd = avcodec_open2(rtsp_data->codec_context, decoder, NULL);
  436     if ((retcd < 0) || (rtsp_data->interrupted)){
  437         netcam_rtsp_decoder_error(rtsp_data, retcd, "avcodec_open2");
  438         return -1;
  439     }
  440 
  441     return 0;
  442 #endif
  443 
  444 
  445 }
  446 
  447 static struct rtsp_context *rtsp_new_context(void){
  448     struct rtsp_context *ret;
  449 
  450     /* Note that mymalloc will exit on any problem. */
  451     ret = mymalloc(sizeof(struct rtsp_context));
  452 
  453     memset(ret, 0, sizeof(struct rtsp_context));
  454 
  455     return ret;
  456 }
  457 
  458 static int netcam_rtsp_interrupt(void *ctx){
  459     struct rtsp_context *rtsp_data = ctx;
  460 
  461     if (rtsp_data->finish){
  462         rtsp_data->interrupted = TRUE;
  463         return TRUE;
  464     }
  465 
  466     if (rtsp_data->status == RTSP_CONNECTED) {
  467         return FALSE;
  468     } else if (rtsp_data->status == RTSP_READINGIMAGE) {
  469         if (gettimeofday(&rtsp_data->interruptcurrenttime, NULL) < 0) {
  470             MOTION_LOG(ERR, TYPE_NETCAM, SHOW_ERRNO, "gettimeofday");
  471         }
  472         if ((rtsp_data->interruptcurrenttime.tv_sec - rtsp_data->interruptstarttime.tv_sec ) > rtsp_data->interruptduration){
  473             MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
  474                 ,_("%s: Camera reading (%s) timed out")
  475                 , rtsp_data->cameratype, rtsp_data->camera_name);
  476             rtsp_data->interrupted = TRUE;
  477             return TRUE;
  478         } else{
  479             return FALSE;
  480         }
  481     } else {
  482         /* This is for NOTCONNECTED and RECONNECTING status.  We give these
  483          * options more time because all the ffmpeg calls that are inside the
  484          * rtsp_connect function will use the same start time.  Otherwise we
  485          * would need to reset the time before each call to a ffmpeg function.
  486         */
  487         if (gettimeofday(&rtsp_data->interruptcurrenttime, NULL) < 0) {
  488             MOTION_LOG(ERR, TYPE_NETCAM, SHOW_ERRNO, "gettimeofday");
  489         }
  490         if ((rtsp_data->interruptcurrenttime.tv_sec - rtsp_data->interruptstarttime.tv_sec ) > rtsp_data->interruptduration){
  491             MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
  492                 ,_("%s: Camera (%s) timed out")
  493                 , rtsp_data->cameratype, rtsp_data->camera_name);
  494             rtsp_data->interrupted = TRUE;
  495             return TRUE;
  496         } else{
  497             return FALSE;
  498         }
  499     }
  500 
  501     /* should not be possible to get here */
  502     return FALSE;
  503 }
  504 
  505 static int netcam_rtsp_resize(struct rtsp_context *rtsp_data){
  506 
  507     int      retcd;
  508     char     errstr[128];
  509     uint8_t *buffer_out;
  510 
  511     if (rtsp_data->finish) return -1;   /* This just speeds up the shutdown time */
  512 
  513     retcd=my_image_fill_arrays(
  514         rtsp_data->swsframe_in
  515         ,(uint8_t*)rtsp_data->img_recv->ptr
  516         ,rtsp_data->codec_context->pix_fmt
  517         ,rtsp_data->codec_context->width
  518         ,rtsp_data->codec_context->height);
  519     if (retcd < 0) {
  520         if (rtsp_data->status == RTSP_NOTCONNECTED){
  521             av_strerror(retcd, errstr, sizeof(errstr));
  522             MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO
  523                 ,_("Error allocating picture in: %s"), errstr);
  524         }
  525         netcam_rtsp_close_context(rtsp_data);
  526         return -1;
  527     }
  528 
  529     buffer_out=(uint8_t *)av_malloc(rtsp_data->swsframe_size*sizeof(uint8_t));
  530 
  531     retcd=my_image_fill_arrays(
  532         rtsp_data->swsframe_out
  533         ,buffer_out
  534         ,MY_PIX_FMT_YUV420P
  535         ,rtsp_data->imgsize.width
  536         ,rtsp_data->imgsize.height);
  537     if (retcd < 0) {
  538         if (rtsp_data->status == RTSP_NOTCONNECTED){
  539             av_strerror(retcd, errstr, sizeof(errstr));
  540             MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO
  541                 ,_("Error allocating picture out: %s"), errstr);
  542         }
  543         netcam_rtsp_close_context(rtsp_data);
  544         return -1;
  545     }
  546 
  547     retcd = sws_scale(
  548         rtsp_data->swsctx
  549         ,(const uint8_t* const *)rtsp_data->swsframe_in->data
  550         ,rtsp_data->swsframe_in->linesize
  551         ,0
  552         ,rtsp_data->codec_context->height
  553         ,rtsp_data->swsframe_out->data
  554         ,rtsp_data->swsframe_out->linesize);
  555     if (retcd < 0) {
  556         if (rtsp_data->status == RTSP_NOTCONNECTED){
  557             av_strerror(retcd, errstr, sizeof(errstr));
  558             MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO
  559                 ,_("Error resizing/reformatting: %s"), errstr);
  560         }
  561         netcam_rtsp_close_context(rtsp_data);
  562         return -1;
  563     }
  564 
  565     retcd=my_image_copy_to_buffer(
  566          rtsp_data->swsframe_out
  567         ,(uint8_t *)rtsp_data->img_recv->ptr
  568         ,MY_PIX_FMT_YUV420P
  569         ,rtsp_data->imgsize.width
  570         ,rtsp_data->imgsize.height
  571         ,rtsp_data->swsframe_size);
  572     if (retcd < 0) {
  573         if (rtsp_data->status == RTSP_NOTCONNECTED){
  574             av_strerror(retcd, errstr, sizeof(errstr));
  575             MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO
  576                 ,_("Error putting frame into output buffer: %s"), errstr);
  577         }
  578         netcam_rtsp_close_context(rtsp_data);
  579         return -1;
  580     }
  581     rtsp_data->img_recv->used = rtsp_data->swsframe_size;
  582 
  583     av_free(buffer_out);
  584 
  585     return 0;
  586 
  587 }
  588 
  589 static int netcam_rtsp_read_image(struct rtsp_context *rtsp_data){
  590 
  591     int  size_decoded;
  592     int  retcd;
  593     int  haveimage;
  594     char errstr[128];
  595     netcam_buff *xchg;
  596 
  597     if (rtsp_data->finish) return -1;   /* This just speeds up the shutdown time */
  598 
  599     av_init_packet(&rtsp_data->packet_recv);
  600     rtsp_data->packet_recv.data = NULL;
  601     rtsp_data->packet_recv.size = 0;
  602 
  603     rtsp_data->interrupted=FALSE;
  604     if (gettimeofday(&rtsp_data->interruptstarttime, NULL) < 0) {
  605         MOTION_LOG(ERR, TYPE_NETCAM, SHOW_ERRNO, "gettimeofday");
  606     }
  607     rtsp_data->interruptduration = 10;
  608 
  609     rtsp_data->status = RTSP_READINGIMAGE;
  610     rtsp_data->img_recv->used = 0;
  611     size_decoded = 0;
  612     haveimage = FALSE;
  613 
  614     while ((!haveimage) && (!rtsp_data->interrupted)) {
  615         retcd = av_read_frame(rtsp_data->format_context, &rtsp_data->packet_recv);
  616         if ((rtsp_data->interrupted) || (retcd < 0)) {
  617             av_strerror(retcd, errstr, sizeof(errstr));
  618             MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
  619                 ,_("%s: av_read_frame: %s ,Interrupt: %s")
  620                 ,rtsp_data->cameratype
  621                 ,errstr, rtsp_data->interrupted ? _("True"):_("False"));
  622             my_packet_unref(rtsp_data->packet_recv);
  623             netcam_rtsp_close_context(rtsp_data);
  624             return -1;
  625         }
  626 
  627         if (rtsp_data->packet_recv.stream_index == rtsp_data->video_stream_index){
  628             /* For a high resolution pass-through we don't decode the image */
  629             if (rtsp_data->high_resolution && rtsp_data->passthrough){
  630                 if (rtsp_data->packet_recv.data != NULL) size_decoded = 1;
  631             } else {
  632                 size_decoded = netcam_rtsp_decode_packet(rtsp_data);
  633             }
  634         }
  635 
  636         if (size_decoded > 0 ){
  637             haveimage = TRUE;
  638         } else if (size_decoded == 0){
  639             /* Did not fail, just didn't get anything.  Try again */
  640             my_packet_unref(rtsp_data->packet_recv);
  641             av_init_packet(&rtsp_data->packet_recv);
  642             rtsp_data->packet_recv.data = NULL;
  643             rtsp_data->packet_recv.size = 0;
  644         } else {
  645             my_packet_unref(rtsp_data->packet_recv);
  646             netcam_rtsp_close_context(rtsp_data);
  647             return -1;
  648         }
  649     }
  650     if (gettimeofday(&rtsp_data->img_recv->image_time, NULL) < 0) {
  651         MOTION_LOG(ERR, TYPE_NETCAM, SHOW_ERRNO, "gettimeofday");
  652     }
  653 
  654     /* Skip status change on our first image to keep the "next" function waiting
  655      * until the handler thread gets going
  656      */
  657     if (!rtsp_data->first_image) rtsp_data->status = RTSP_CONNECTED;
  658 
  659     /* Skip resize/pix format for high pass-through */
  660     if (!(rtsp_data->high_resolution && rtsp_data->passthrough)){
  661         if ((rtsp_data->imgsize.width  != rtsp_data->codec_context->width) ||
  662             (rtsp_data->imgsize.height != rtsp_data->codec_context->height) ||
  663             (netcam_rtsp_check_pixfmt(rtsp_data) != 0) ){
  664             if (netcam_rtsp_resize(rtsp_data) < 0){
  665                 my_packet_unref(rtsp_data->packet_recv);
  666                 netcam_rtsp_close_context(rtsp_data);
  667                 return -1;
  668             }
  669         }
  670     }
  671 
  672     pthread_mutex_lock(&rtsp_data->mutex);
  673         rtsp_data->idnbr++;
  674         if (rtsp_data->passthrough) netcam_rtsp_pktarray_add(rtsp_data);
  675         if (!(rtsp_data->high_resolution && rtsp_data->passthrough)) {
  676             xchg = rtsp_data->img_latest;
  677             rtsp_data->img_latest = rtsp_data->img_recv;
  678             rtsp_data->img_recv = xchg;
  679         }
  680     pthread_mutex_unlock(&rtsp_data->mutex);
  681 
  682     my_packet_unref(rtsp_data->packet_recv);
  683 
  684     if (rtsp_data->format_context->streams[rtsp_data->video_stream_index]->avg_frame_rate.den > 0){
  685         rtsp_data->src_fps = (
  686             (rtsp_data->format_context->streams[rtsp_data->video_stream_index]->avg_frame_rate.num /
  687             rtsp_data->format_context->streams[rtsp_data->video_stream_index]->avg_frame_rate.den) +
  688             0.5);
  689     }
  690 
  691     return 0;
  692 }
  693 
  694 static int netcam_rtsp_ntc(struct rtsp_context *rtsp_data){
  695 
  696     if ((rtsp_data->finish) || (!rtsp_data->first_image)) return 0;
  697 
  698     if ((rtsp_data->imgsize.width  != rtsp_data->codec_context->width) ||
  699         (rtsp_data->imgsize.height != rtsp_data->codec_context->height) ||
  700         (netcam_rtsp_check_pixfmt(rtsp_data) != 0) ){
  701         MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "");
  702         MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "******************************************************");
  703         if ((rtsp_data->imgsize.width  != rtsp_data->codec_context->width) ||
  704             (rtsp_data->imgsize.height != rtsp_data->codec_context->height)) {
  705             if (netcam_rtsp_check_pixfmt(rtsp_data) != 0) {
  706                 MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, _("The network camera is sending pictures in a different"));
  707                 MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, _("size than specified in the config and also a "));
  708                 MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, _("different picture format.  The picture is being"));
  709                 MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, _("transcoded to YUV420P and into the size requested"));
  710                 MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, _("in the config file.  If possible change netcam to"));
  711                 MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, _("be in YUV420P format and the size requested in the"));
  712                 MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, _("config to possibly lower CPU usage."));
  713             } else {
  714                 MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, _("The network camera is sending pictures in a different"));
  715                 MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, _("size than specified in the configuration file."));
  716                 MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, _("The picture is being transcoded into the size "));
  717                 MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, _("requested in the configuration.  If possible change"));
  718                 MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, _("netcam or configuration to indicate the same size"));
  719                 MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, _("to possibly lower CPU usage."));
  720             }
  721             MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, _("Netcam: %d x %d => Config: %d x %d")
  722             ,rtsp_data->codec_context->width,rtsp_data->codec_context->height
  723             ,rtsp_data->imgsize.width,rtsp_data->imgsize.height);
  724         } else {
  725             MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, _("The image sent is being "));
  726             MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, _("trancoded to YUV420P.  If possible change netcam "));
  727             MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, _("picture format to YUV420P to possibly lower CPU usage."));
  728         }
  729         MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "******************************************************");
  730         MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "");
  731     }
  732 
  733     return 0;
  734 
  735 }
  736 
  737 static int netcam_rtsp_open_sws(struct rtsp_context *rtsp_data){
  738 
  739     if (rtsp_data->finish) return -1;   /* This just speeds up the shutdown time */
  740 
  741     rtsp_data->swsframe_in = my_frame_alloc();
  742     if (rtsp_data->swsframe_in == NULL) {
  743         if (rtsp_data->status == RTSP_NOTCONNECTED){
  744             MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, _("Unable to allocate swsframe_in."));
  745         }
  746         netcam_rtsp_close_context(rtsp_data);
  747         return -1;
  748     }
  749 
  750     rtsp_data->swsframe_out = my_frame_alloc();
  751     if (rtsp_data->swsframe_out == NULL) {
  752         if (rtsp_data->status == RTSP_NOTCONNECTED){
  753             MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, _("Unable to allocate swsframe_out."));
  754         }
  755         netcam_rtsp_close_context(rtsp_data);
  756         return -1;
  757     }
  758 
  759     /*
  760      *  The scaling context is used to change dimensions to config file and
  761      *  also if the format sent by the camera is not YUV420.
  762      */
  763     rtsp_data->swsctx = sws_getContext(
  764          rtsp_data->codec_context->width
  765         ,rtsp_data->codec_context->height
  766         ,rtsp_data->codec_context->pix_fmt
  767         ,rtsp_data->imgsize.width
  768         ,rtsp_data->imgsize.height
  769         ,MY_PIX_FMT_YUV420P
  770         ,SWS_BICUBIC,NULL,NULL,NULL);
  771     if (rtsp_data->swsctx == NULL) {
  772         if (rtsp_data->status == RTSP_NOTCONNECTED){
  773             MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, _("Unable to allocate scaling context."));
  774         }
  775         netcam_rtsp_close_context(rtsp_data);
  776         return -1;
  777     }
  778 
  779     rtsp_data->swsframe_size = my_image_get_buffer_size(
  780             MY_PIX_FMT_YUV420P
  781             ,rtsp_data->imgsize.width
  782             ,rtsp_data->imgsize.height);
  783     if (rtsp_data->swsframe_size <= 0) {
  784         if (rtsp_data->status == RTSP_NOTCONNECTED){
  785             MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, _("Error determining size of frame out"));
  786         }
  787         netcam_rtsp_close_context(rtsp_data);
  788         return -1;
  789     }
  790 
  791     /* the image buffers must be big enough to hold the final frame after resizing */
  792     netcam_check_buffsize(rtsp_data->img_recv, rtsp_data->swsframe_size);
  793     netcam_check_buffsize(rtsp_data->img_latest, rtsp_data->swsframe_size);
  794 
  795     return 0;
  796 
  797 }
  798 
  799 static void netcam_rtsp_set_http(struct rtsp_context *rtsp_data){
  800 
  801     rtsp_data->format_context->iformat = av_find_input_format("mjpeg");
  802     MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
  803         ,_("%s: Setting http input_format mjpeg"),rtsp_data->cameratype);
  804 
  805 }
  806 
  807 static void netcam_rtsp_set_rtsp(struct rtsp_context *rtsp_data){
  808 
  809     if (rtsp_data->rtsp_uses_tcp) {
  810         av_dict_set(&rtsp_data->opts, "rtsp_transport", "tcp", 0);
  811         av_dict_set(&rtsp_data->opts, "allowed_media_types", "video", 0);
  812         if (rtsp_data->status == RTSP_NOTCONNECTED)
  813             MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
  814                 ,_("%s: Setting rtsp transport to tcp"),rtsp_data->cameratype);
  815     } else {
  816         av_dict_set(&rtsp_data->opts, "rtsp_transport", "udp", 0);
  817         av_dict_set(&rtsp_data->opts, "max_delay", "500000", 0);  /* 100000 is the default */
  818         if (rtsp_data->status == RTSP_NOTCONNECTED)
  819             MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
  820                 ,_("%s: Setting rtsp transport to udp"),rtsp_data->cameratype);
  821     }
  822 }
  823 
  824 static void netcam_rtsp_set_file(struct rtsp_context *rtsp_data){
  825 
  826     /* This is a place holder for the moment.  We will add into
  827      * this function any options that must be set for ffmpeg to
  828      * read a particular file.  To date, it does not need any
  829      * additional options and works fine with defaults.
  830      */
  831     MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
  832         ,_("%s: Setting attributes to read file"),rtsp_data->cameratype);
  833 
  834 }
  835 
  836 static void netcam_rtsp_set_v4l2(struct rtsp_context *rtsp_data){
  837 
  838     char optsize[10], optfmt[10], optfps[10];
  839     char *fourcc;
  840 
  841     rtsp_data->format_context->iformat = av_find_input_format("video4linux2");
  842 
  843     fourcc=malloc(5*sizeof(char));
  844 
  845     v4l2_palette_fourcc(rtsp_data->v4l2_palette, fourcc);
  846 
  847     if (strcmp(fourcc,"MJPG") == 0) {
  848         if (v4l2_palette_valid(rtsp_data->path,rtsp_data->v4l2_palette)){
  849             sprintf(optfmt, "%s","mjpeg");
  850             av_dict_set(&rtsp_data->opts, "input_format", optfmt, 0);
  851         } else {
  852             sprintf(optfmt, "%s","default");
  853         }
  854     } else if (strcmp(fourcc,"H264") == 0){
  855         if (v4l2_palette_valid(rtsp_data->path,rtsp_data->v4l2_palette)){
  856             sprintf(optfmt, "%s","h264");
  857             av_dict_set(&rtsp_data->opts, "input_format", optfmt, 0);
  858         } else {
  859             sprintf(optfmt, "%s","default");
  860         }
  861     } else {
  862         sprintf(optfmt, "%s","default");
  863     }
  864 
  865     if (strcmp(optfmt,"default") != 0) {
  866         if (v4l2_parms_valid(rtsp_data->path
  867                              ,rtsp_data->v4l2_palette
  868                              ,rtsp_data->framerate
  869                              ,rtsp_data->imgsize.width
  870                              ,rtsp_data->imgsize.height)) {
  871             sprintf(optfps, "%d",rtsp_data->framerate);
  872             av_dict_set(&rtsp_data->opts, "framerate", optfps, 0);
  873 
  874             sprintf(optsize, "%dx%d",rtsp_data->imgsize.width,rtsp_data->imgsize.height);
  875             av_dict_set(&rtsp_data->opts, "video_size", optsize, 0);
  876         } else {
  877             sprintf(optfps, "%s","default");
  878             sprintf(optsize, "%s","default");
  879         }
  880     } else {
  881         sprintf(optfps, "%s","default");
  882         sprintf(optsize, "%s","default");
  883     }
  884 
  885     if (rtsp_data->status == RTSP_NOTCONNECTED){
  886         MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
  887             ,_("%s: Requested v4l2_palette option: %d")
  888             ,rtsp_data->cameratype,rtsp_data->v4l2_palette);
  889         MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
  890             ,_("%s: Requested FOURCC code: %s"),rtsp_data->cameratype,fourcc);
  891         MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
  892             ,_("%s: Setting v4l2 input_format: %s"),rtsp_data->cameratype,optfmt);
  893         MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
  894             ,_("%s: Setting v4l2 framerate: %s"),rtsp_data->cameratype, optfps);
  895         MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
  896             ,_("%s: Setting v4l2 video_size: %s"),rtsp_data->cameratype, optsize);
  897     }
  898 
  899     free(fourcc);
  900 
  901 }
  902 
  903 static void netcam_rtsp_set_path (struct context *cnt, struct rtsp_context *rtsp_data ) {
  904 
  905     char        *userpass = NULL;
  906     struct url_t url;
  907 
  908     rtsp_data->path = NULL;
  909 
  910     memset(&url, 0, sizeof(url));
  911 
  912     if (rtsp_data->high_resolution){
  913         netcam_url_parse(&url, cnt->conf.netcam_highres);
  914     } else {
  915         netcam_url_parse(&url, cnt->conf.netcam_url);
  916     }
  917 
  918     if (cnt->conf.netcam_proxy) {
  919         MOTION_LOG(WRN, TYPE_NETCAM, NO_ERRNO
  920             ,_("Proxies not supported using for %s"),url.service);
  921     }
  922 
  923     if (cnt->conf.netcam_userpass != NULL) {
  924         userpass = mystrdup(cnt->conf.netcam_userpass);
  925     } else if (url.userpass != NULL) {
  926         userpass = mystrdup(url.userpass);
  927     }
  928 
  929     if (strcmp(url.service, "v4l2") == 0) {
  930         rtsp_data->path = mymalloc(strlen(url.path) + 1);
  931         sprintf(rtsp_data->path, "%s",url.path);
  932         MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
  933             ,_("Setting up v4l2 via ffmpeg netcam"));
  934     } else if (strcmp(url.service, "file") == 0) {
  935         rtsp_data->path = mymalloc(strlen(url.path) + 1);
  936         sprintf(rtsp_data->path, "%s",url.path);
  937         MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
  938             ,_("Setting up file via ffmpeg netcam"));
  939     } else {
  940         if (!strcmp(url.service, "mjpeg")) {
  941             sprintf(url.service, "%s","http");
  942             MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
  943                 ,_("Setting up http via ffmpeg netcam"));
  944         } else {
  945             MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
  946                 ,_("Setting up %s via ffmpeg netcam"),url.service);
  947         }
  948         if (userpass != NULL) {
  949             rtsp_data->path = mymalloc(strlen(url.service) + 3 + strlen(userpass)
  950                   + 1 + strlen(url.host) + 6 + strlen(url.path) + 2 );
  951             sprintf((char *)rtsp_data->path, "%s://%s@%s:%d%s",
  952                     url.service, userpass, url.host, url.port, url.path);
  953         } else {
  954             rtsp_data->path = mymalloc(strlen(url.service) + 3 + strlen(url.host)
  955                   + 6 + strlen(url.path) + 2);
  956             sprintf((char *)rtsp_data->path, "%s://%s:%d%s", url.service,
  957                 url.host, url.port, url.path);
  958         }
  959     }
  960 
  961     sprintf(rtsp_data->service, "%s",url.service);
  962 
  963     netcam_url_free(&url);
  964     if (userpass) free (userpass);
  965 
  966 }
  967 
  968 static void netcam_rtsp_set_parms (struct context *cnt, struct rtsp_context *rtsp_data ) {
  969     /* Set the parameters to be used with our camera */
  970 
  971     if (rtsp_data->high_resolution) {
  972         rtsp_data->imgsize.width = 0;
  973         rtsp_data->imgsize.height = 0;
  974         snprintf(rtsp_data->cameratype,29, "%s",_("High resolution"));
  975     } else {
  976         rtsp_data->imgsize.width = cnt->conf.width;
  977         rtsp_data->imgsize.height = cnt->conf.height;
  978         snprintf(rtsp_data->cameratype,29, "%s",_("Normal resolution"));
  979     }
  980     MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
  981         ,_("Setting up %s stream."),rtsp_data->cameratype);
  982 
  983     util_check_passthrough(cnt); /* In case it was turned on via webcontrol */
  984     rtsp_data->status = RTSP_NOTCONNECTED;
  985     rtsp_data->rtsp_uses_tcp =cnt->conf.netcam_use_tcp;
  986     rtsp_data->v4l2_palette = cnt->conf.v4l2_palette;
  987     rtsp_data->framerate = cnt->conf.framerate;
  988     rtsp_data->src_fps =  cnt->conf.framerate; /* Default to conf fps */
  989     rtsp_data->conf = &cnt->conf;
  990     rtsp_data->camera_name = cnt->conf.camera_name;
  991     rtsp_data->img_recv = mymalloc(sizeof(netcam_buff));
  992     rtsp_data->img_recv->ptr = mymalloc(NETCAM_BUFFSIZE);
  993     rtsp_data->img_latest = mymalloc(sizeof(netcam_buff));
  994     rtsp_data->img_latest->ptr = mymalloc(NETCAM_BUFFSIZE);
  995     rtsp_data->pktarray_size = 0;
  996     rtsp_data->pktarray_index = -1;
  997     rtsp_data->pktarray = NULL;
  998     rtsp_data->handler_finished = TRUE;
  999     rtsp_data->first_image = TRUE;
 1000     rtsp_data->reconnect_count = 0;
 1001     rtsp_data->decoder_nm = cnt->netcam_decoder;
 1002     rtsp_data->cnt = cnt;
 1003 
 1004     snprintf(rtsp_data->threadname, 15, "%s",_("Unknown"));
 1005 
 1006     if (gettimeofday(&rtsp_data->interruptstarttime, NULL) < 0) {
 1007         MOTION_LOG(ERR, TYPE_NETCAM, SHOW_ERRNO, "gettimeofday");
 1008     }
 1009     if (gettimeofday(&rtsp_data->interruptcurrenttime, NULL) < 0) {
 1010         MOTION_LOG(ERR, TYPE_NETCAM, SHOW_ERRNO, "gettimeofday");
 1011     }
 1012     /* If this is the norm and we have a highres, then disable passthru on the norm */
 1013     if ((!rtsp_data->high_resolution) &&
 1014         (cnt->conf.netcam_highres)) {
 1015         rtsp_data->passthrough = FALSE;
 1016     } else {
 1017         rtsp_data->passthrough = util_check_passthrough(cnt);
 1018     }
 1019     rtsp_data->interruptduration = 5;
 1020     rtsp_data->interrupted = FALSE;
 1021 
 1022     if (gettimeofday(&rtsp_data->frame_curr_tm, NULL) < 0) {
 1023         MOTION_LOG(ERR, TYPE_NETCAM, SHOW_ERRNO, "gettimeofday");
 1024     }
 1025     if (gettimeofday(&rtsp_data->frame_prev_tm, NULL) < 0) {
 1026         MOTION_LOG(ERR, TYPE_NETCAM, SHOW_ERRNO, "gettimeofday");
 1027     }
 1028 
 1029     netcam_rtsp_set_path(cnt, rtsp_data);
 1030 
 1031 }
 1032 
 1033 static int netcam_rtsp_set_dimensions (struct context *cnt) {
 1034 
 1035     cnt->imgs.width = 0;
 1036     cnt->imgs.height = 0;
 1037     cnt->imgs.size_norm = 0;
 1038     cnt->imgs.motionsize = 0;
 1039 
 1040     cnt->imgs.width_high  = 0;
 1041     cnt->imgs.height_high = 0;
 1042     cnt->imgs.size_high   = 0;
 1043 
 1044     if (cnt->conf.width % 8) {
 1045         MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO
 1046             ,_("Image width (%d) requested is not modulo 8."), cnt->conf.width);
 1047         cnt->conf.width = cnt->conf.width - (cnt->conf.width % 8) + 8;
 1048         MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO
 1049             ,_("Adjusting width to next higher multiple of 8 (%d)."), cnt->conf.width);
 1050     }
 1051     if (cnt->conf.height % 8) {
 1052         MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO
 1053             ,_("Image height (%d) requested is not modulo 8."), cnt->conf.height);
 1054         cnt->conf.height = cnt->conf.height - (cnt->conf.height % 8) + 8;
 1055         MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO
 1056             ,_("Adjusting height to next higher multiple of 8 (%d)."), cnt->conf.height);
 1057     }
 1058 
 1059     /* Fill in camera details into context structure. */
 1060     cnt->imgs.width = cnt->conf.width;
 1061     cnt->imgs.height = cnt->conf.height;
 1062     cnt->imgs.size_norm = (cnt->conf.width * cnt->conf.height * 3) / 2;
 1063     cnt->imgs.motionsize = cnt->conf.width * cnt->conf.height;
 1064 
 1065     return 0;
 1066 }
 1067 
 1068 static int netcam_rtsp_copy_stream(struct rtsp_context *rtsp_data){
 1069     /* Make a static copy of the stream information for use in passthrough processing */
 1070 #if (LIBAVFORMAT_VERSION_MAJOR >= 58) || ((LIBAVFORMAT_VERSION_MAJOR == 57) && (LIBAVFORMAT_VERSION_MINOR >= 41))
 1071     AVStream  *transfer_stream, *stream_in;
 1072     int        retcd;
 1073 
 1074     pthread_mutex_lock(&rtsp_data->mutex_transfer);
 1075         if (rtsp_data->transfer_format != NULL) avformat_close_input(&rtsp_data->transfer_format);
 1076         rtsp_data->transfer_format = avformat_alloc_context();
 1077         transfer_stream = avformat_new_stream(rtsp_data->transfer_format, NULL);
 1078         stream_in = rtsp_data->format_context->streams[rtsp_data->video_stream_index];
 1079         retcd = avcodec_parameters_copy(transfer_stream->codecpar, stream_in->codecpar);
 1080         if (retcd < 0){
 1081             MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO
 1082                 ,_("Unable to copy codec parameters"));
 1083             pthread_mutex_unlock(&rtsp_data->mutex_transfer);
 1084             return -1;
 1085         }
 1086         transfer_stream->time_base         = stream_in->time_base;
 1087     pthread_mutex_unlock(&rtsp_data->mutex_transfer);
 1088 
 1089     MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO, _("Stream copied for pass-through"));
 1090     return 0;
 1091 #elif (LIBAVFORMAT_VERSION_MAJOR >= 55)
 1092 
 1093     AVStream  *transfer_stream, *stream_in;
 1094     int        retcd;
 1095 
 1096     pthread_mutex_lock(&rtsp_data->mutex_transfer);
 1097         if (rtsp_data->transfer_format != NULL) avformat_close_input(&rtsp_data->transfer_format);
 1098         rtsp_data->transfer_format = avformat_alloc_context();
 1099         transfer_stream = avformat_new_stream(rtsp_data->transfer_format, NULL);
 1100         stream_in = rtsp_data->format_context->streams[rtsp_data->video_stream_index];
 1101         retcd = avcodec_copy_context(transfer_stream->codec, stream_in->codec);
 1102         if (retcd < 0){
 1103             MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, _("Unable to copy codec parameters"));
 1104             pthread_mutex_unlock(&rtsp_data->mutex_transfer);
 1105             return -1;
 1106         }
 1107         transfer_stream->time_base         = stream_in->time_base;
 1108     pthread_mutex_unlock(&rtsp_data->mutex_transfer);
 1109 
 1110     MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO, _("Stream copied for pass-through"));
 1111     return 0;
 1112 #else
 1113     /* This is disabled in the util_check_passthrough but we need it here for compiling */
 1114     if (rtsp_data != NULL) MOTION_LOG(INF, TYPE_ENCODER, NO_ERRNO, _("ffmpeg too old"));
 1115     return -1;
 1116 #endif
 1117 
 1118 }
 1119 
 1120 static int netcam_rtsp_open_context(struct rtsp_context *rtsp_data){
 1121 
 1122     int  retcd;
 1123     char errstr[128];
 1124 
 1125     if (rtsp_data->finish) return -1;
 1126 
 1127     if (rtsp_data->path == NULL) {
 1128         if (rtsp_data->status == RTSP_NOTCONNECTED){
 1129             MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, _("Null path passed to connect"));
 1130         }
 1131         return -1;
 1132     }
 1133 
 1134     rtsp_data->opts = NULL;
 1135     rtsp_data->format_context = avformat_alloc_context();
 1136     rtsp_data->format_context->interrupt_callback.callback = netcam_rtsp_interrupt;
 1137     rtsp_data->format_context->interrupt_callback.opaque = rtsp_data;
 1138     rtsp_data->interrupted = FALSE;
 1139 
 1140     if (gettimeofday(&rtsp_data->interruptstarttime, NULL) < 0) {
 1141         MOTION_LOG(ERR, TYPE_NETCAM, SHOW_ERRNO, "gettimeofday");
 1142     }
 1143 
 1144     rtsp_data->interruptduration = 20;
 1145 
 1146     if (strncmp(rtsp_data->service, "http", 4) == 0 ){
 1147         netcam_rtsp_set_http(rtsp_data);
 1148     } else if (strncmp(rtsp_data->service, "rtsp", 4) == 0 ){
 1149         netcam_rtsp_set_rtsp(rtsp_data);
 1150     } else if (strncmp(rtsp_data->service, "rtmp", 4) == 0 ){
 1151         netcam_rtsp_set_rtsp(rtsp_data);
 1152     } else if (strncmp(rtsp_data->service, "v4l2", 4) == 0 ){
 1153         netcam_rtsp_set_v4l2(rtsp_data);
 1154     } else if (strncmp(rtsp_data->service, "file", 4) == 0 ){
 1155         netcam_rtsp_set_file(rtsp_data);
 1156     } else {
 1157         av_dict_free(&rtsp_data->opts);
 1158         MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
 1159             ,_("%s: Invalid camera service"), rtsp_data->cameratype);
 1160         return -1;
 1161     }
 1162     /*
 1163      * There is not many av functions above this (av_dict_free?) but we are not getting clean
 1164      * interrupts or shutdowns via valgrind and they all point to issues with the avformat_open_input
 1165      * right below so we make sure that we are not in a interrupt / finish situation before calling it
 1166      */
 1167     if ((rtsp_data->interrupted) || (rtsp_data->finish) ){
 1168         if (rtsp_data->status == RTSP_NOTCONNECTED){
 1169             MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO
 1170                 ,_("%s: Unable to open camera(%s)")
 1171                 , rtsp_data->cameratype, rtsp_data->camera_name);
 1172         }
 1173         av_dict_free(&rtsp_data->opts);
 1174         if (rtsp_data->interrupted) netcam_rtsp_close_context(rtsp_data);
 1175         return -1;
 1176     }
 1177 
 1178     retcd = avformat_open_input(&rtsp_data->format_context, rtsp_data->path, NULL, &rtsp_data->opts);
 1179     if ((retcd < 0) || (rtsp_data->interrupted) || (rtsp_data->finish) ){
 1180         if (rtsp_data->status == RTSP_NOTCONNECTED){
 1181             av_strerror(retcd, errstr, sizeof(errstr));
 1182             MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO
 1183                 ,_("%s: Unable to open camera(%s): %s")
 1184                 , rtsp_data->cameratype, rtsp_data->camera_name, errstr);
 1185         }
 1186         av_dict_free(&rtsp_data->opts);
 1187         if (rtsp_data->interrupted) netcam_rtsp_close_context(rtsp_data);
 1188         return -1;
 1189     }
 1190     av_dict_free(&rtsp_data->opts);
 1191     MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
 1192         ,_("%s: Opened camera(%s)"), rtsp_data->cameratype, rtsp_data->camera_name);
 1193 
 1194     /* fill out stream information */
 1195     retcd = avformat_find_stream_info(rtsp_data->format_context, NULL);
 1196     if ((retcd < 0) || (rtsp_data->interrupted) || (rtsp_data->finish) ){
 1197         if (rtsp_data->status == RTSP_NOTCONNECTED){
 1198             av_strerror(retcd, errstr, sizeof(errstr));
 1199             MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO
 1200                 ,_("%s: Unable to find stream info: %s")
 1201                 ,rtsp_data->cameratype, errstr);
 1202         }
 1203         netcam_rtsp_close_context(rtsp_data);
 1204         return -1;
 1205     }
 1206 
 1207     /* there is no way to set the avcodec thread names, but they inherit
 1208      * our thread name - so temporarily change our thread name to the
 1209      * desired name */
 1210 
 1211     util_threadname_get(rtsp_data->threadname);
 1212 
 1213     util_threadname_set("av",rtsp_data->threadnbr,rtsp_data->camera_name);
 1214 
 1215     retcd = netcam_rtsp_open_codec(rtsp_data);
 1216 
 1217     util_threadname_set(NULL, 0, rtsp_data->threadname);
 1218 
 1219     if ((retcd < 0) || (rtsp_data->interrupted) || (rtsp_data->finish) ){
 1220         if (rtsp_data->status == RTSP_NOTCONNECTED){
 1221             av_strerror(retcd, errstr, sizeof(errstr));
 1222             MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO
 1223                 ,_("%s: Unable to open codec context: %s")
 1224                 ,rtsp_data->cameratype, errstr);
 1225         }
 1226         netcam_rtsp_close_context(rtsp_data);
 1227         return -1;
 1228     }
 1229 
 1230     if (rtsp_data->codec_context->width <= 0 ||
 1231         rtsp_data->codec_context->height <= 0) {
 1232         MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO
 1233             ,_("%s: Camera image size is invalid"),rtsp_data->cameratype);
 1234         netcam_rtsp_close_context(rtsp_data);
 1235         return -1;
 1236     }
 1237 
 1238     if (rtsp_data->high_resolution){
 1239         rtsp_data->imgsize.width = rtsp_data->codec_context->width;
 1240         rtsp_data->imgsize.height = rtsp_data->codec_context->height;
 1241     } else {
 1242         if (netcam_rtsp_open_sws(rtsp_data) < 0) return -1;
 1243     }
 1244 
 1245     rtsp_data->frame = my_frame_alloc();
 1246     if (rtsp_data->frame == NULL) {
 1247         if (rtsp_data->status == RTSP_NOTCONNECTED){
 1248             MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO
 1249                 ,_("%s: Unable to allocate frame."),rtsp_data->cameratype);
 1250         }
 1251         netcam_rtsp_close_context(rtsp_data);
 1252         return -1;
 1253     }
 1254 
 1255     if (rtsp_data->passthrough){
 1256         retcd = netcam_rtsp_copy_stream(rtsp_data);
 1257         if ((retcd < 0) || (rtsp_data->interrupted)){
 1258             if (rtsp_data->status == RTSP_NOTCONNECTED){
 1259                 MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO
 1260                     ,_("%s: Failed to copy stream for pass-through.")
 1261                     ,rtsp_data->cameratype);
 1262             }
 1263             rtsp_data->passthrough = FALSE;
 1264         }
 1265     }
 1266 
 1267     /* Validate that the previous steps opened the camera */
 1268     retcd = netcam_rtsp_read_image(rtsp_data);
 1269     if ((retcd < 0) || (rtsp_data->interrupted)){
 1270         if (rtsp_data->status == RTSP_NOTCONNECTED){
 1271             MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO
 1272                 ,_("%s: Failed to read first image"),rtsp_data->cameratype);
 1273         }
 1274         netcam_rtsp_close_context(rtsp_data);
 1275         return -1;
 1276     }
 1277 
 1278     return 0;
 1279 
 1280 }
 1281 
 1282 static int netcam_rtsp_connect(struct rtsp_context *rtsp_data){
 1283 
 1284     if (netcam_rtsp_open_context(rtsp_data) < 0) return -1;
 1285 
 1286     if (netcam_rtsp_ntc(rtsp_data) < 0 ) return -1;
 1287 
 1288     if (netcam_rtsp_read_image(rtsp_data) < 0) return -1;
 1289 
 1290     /* We use the status for determining whether to grab a image from
 1291      * the Motion loop(see "next" function).  When we are initially starting,
 1292      * we open and close the context and during this process we do not want the
 1293      * Motion loop to start quite yet on this first image so we do
 1294      * not set the status to connected
 1295      */
 1296     if (!rtsp_data->first_image) rtsp_data->status = RTSP_CONNECTED;
 1297 
 1298     MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO
 1299         ,_("%s: Camera (%s) connected")
 1300         , rtsp_data->cameratype,rtsp_data->camera_name);
 1301 
 1302     return 0;
 1303 }
 1304 
 1305 static void netcam_rtsp_shutdown(struct rtsp_context *rtsp_data){
 1306 
 1307     if (rtsp_data) {
 1308         netcam_rtsp_close_context(rtsp_data);
 1309 
 1310         if (rtsp_data->path != NULL) free(rtsp_data->path);
 1311 
 1312         if (rtsp_data->img_latest != NULL){
 1313             free(rtsp_data->img_latest->ptr);
 1314             free(rtsp_data->img_latest);
 1315         }
 1316         if (rtsp_data->img_recv != NULL){
 1317             free(rtsp_data->img_recv->ptr);
 1318             free(rtsp_data->img_recv);
 1319         }
 1320 
 1321         rtsp_data->path    = NULL;
 1322         rtsp_data->img_latest = NULL;
 1323         rtsp_data->img_recv   = NULL;
 1324     }
 1325 
 1326 }
 1327 
 1328 static void netcam_rtsp_handler_wait(struct rtsp_context *rtsp_data){
 1329     /* This function slows down the handler loop to try to
 1330      * get in sync with the main motion loop in the capturing
 1331      * of images while also trying to not go so slow that the
 1332      * connection to the  network camera is lost and we end up
 1333      * with lots of reconnects or fragmented images
 1334      */
 1335 
 1336     int framerate;
 1337     long usec_maxrate, usec_delay;
 1338 
 1339     framerate = rtsp_data->conf->framerate;
 1340     if (framerate < 2) framerate = 2;
 1341 
 1342     if (strcmp(rtsp_data->service,"file") == 0) {
 1343         /* For file processing, we try to match exactly the motion loop rate */
 1344         usec_maxrate = (1000000L / framerate);
 1345     } else {
 1346         /* We set the capture rate to be a bit faster than the frame rate.  This
 1347          * should provide the motion loop with a picture whenever it wants one.
 1348          */
 1349         if (framerate < rtsp_data->src_fps) framerate = rtsp_data->src_fps;
 1350         usec_maxrate = (1000000L / (framerate + 3));
 1351     }
 1352 
 1353     if (gettimeofday(&rtsp_data->frame_curr_tm, NULL) < 0) {
 1354         MOTION_LOG(ERR, TYPE_NETCAM, SHOW_ERRNO, "gettimeofday");
 1355     }
 1356 
 1357     usec_delay = usec_maxrate -
 1358         ((rtsp_data->frame_curr_tm.tv_sec - rtsp_data->frame_prev_tm.tv_sec) * 1000000L) -
 1359         (rtsp_data->frame_curr_tm.tv_usec - rtsp_data->frame_prev_tm.tv_usec);
 1360     if ((usec_delay > 0) && (usec_delay < 1000000L)){
 1361         SLEEP(0, usec_delay * 1000);
 1362     }
 1363 
 1364 }
 1365 
 1366 static void netcam_rtsp_handler_reconnect(struct rtsp_context *rtsp_data){
 1367 
 1368     int retcd;
 1369 
 1370     if ((rtsp_data->status == RTSP_CONNECTED) ||
 1371         (rtsp_data->status == RTSP_READINGIMAGE)){
 1372         MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO
 1373             ,_("%s: Reconnecting with camera...."),rtsp_data->cameratype);
 1374     }
 1375     rtsp_data->status = RTSP_RECONNECTING;
 1376 
 1377     /*
 1378     * The retry count of 100 is arbritrary.
 1379     * We want to try many times quickly to not lose too much information
 1380     * before we go into the long wait phase
 1381     */
 1382     retcd = netcam_rtsp_connect(rtsp_data);
 1383     if (retcd < 0){
 1384         if (rtsp_data->reconnect_count < 100){
 1385             rtsp_data->reconnect_count++;
 1386         } else if (rtsp_data->reconnect_count == 100){
 1387             MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO
 1388                 ,_("%s: Camera did not reconnect."), rtsp_data->cameratype);
 1389             MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO
 1390                 ,_("%s: Checking for camera every 10 seconds."),rtsp_data->cameratype);
 1391             rtsp_data->reconnect_count++;
 1392             SLEEP(10,0);
 1393         } else {
 1394             SLEEP(10,0);
 1395         }
 1396     } else {
 1397         rtsp_data->reconnect_count = 0;
 1398     }
 1399 
 1400 }
 1401 
 1402 static void *netcam_rtsp_handler(void *arg){
 1403 
 1404     struct rtsp_context *rtsp_data = arg;
 1405 
 1406     rtsp_data->handler_finished = FALSE;
 1407 
 1408     util_threadname_set("nc",rtsp_data->threadnbr, rtsp_data->camera_name);
 1409 
 1410     pthread_setspecific(tls_key_threadnr, (void *)((unsigned long)rtsp_data->threadnbr));
 1411 
 1412     MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO
 1413         ,_("%s: Camera handler thread [%d] started")
 1414         ,rtsp_data->cameratype, rtsp_data->threadnbr);
 1415 
 1416     while (!rtsp_data->finish) {
 1417         if (!rtsp_data->format_context) {      /* We must have disconnected.  Try to reconnect */
 1418             if (gettimeofday(&rtsp_data->frame_prev_tm, NULL) < 0) {
 1419                 MOTION_LOG(ERR, TYPE_NETCAM, SHOW_ERRNO, "gettimeofday");
 1420             }
 1421             netcam_rtsp_handler_reconnect(rtsp_data);
 1422             continue;
 1423         } else {            /* We think we are connected...*/
 1424             if (gettimeofday(&rtsp_data->frame_prev_tm, NULL) < 0) {
 1425                 MOTION_LOG(ERR, TYPE_NETCAM, SHOW_ERRNO, "gettimeofday");
 1426             }
 1427             if (netcam_rtsp_read_image(rtsp_data) < 0) {
 1428                 if (!rtsp_data->finish) {   /* Nope.  We are not or got bad image.  Reconnect*/
 1429                     netcam_rtsp_handler_reconnect(rtsp_data);
 1430                 }
 1431                 continue;
 1432             }
 1433             netcam_rtsp_handler_wait(rtsp_data);
 1434         }
 1435     }
 1436 
 1437     MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
 1438         ,_("%s: Handler loop finished."),rtsp_data->cameratype);
 1439     netcam_rtsp_shutdown(rtsp_data);
 1440 
 1441     /* Our thread is finished - decrement motion's thread count. */
 1442     pthread_mutex_lock(&global_lock);
 1443         threads_running--;
 1444     pthread_mutex_unlock(&global_lock);
 1445 
 1446     MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
 1447         ,_("netcam camera handler: finish set, exiting"));
 1448     rtsp_data->handler_finished = TRUE;
 1449 
 1450     pthread_exit(NULL);
 1451 }
 1452 
 1453 static int netcam_rtsp_start_handler(struct rtsp_context *rtsp_data){
 1454 
 1455     int retcd;
 1456     int wait_counter;
 1457     pthread_attr_t handler_attribute;
 1458 
 1459     pthread_mutex_init(&rtsp_data->mutex, NULL);
 1460     pthread_mutex_init(&rtsp_data->mutex_pktarray, NULL);
 1461     pthread_mutex_init(&rtsp_data->mutex_transfer, NULL);
 1462 
 1463     pthread_attr_init(&handler_attribute);
 1464     pthread_attr_setdetachstate(&handler_attribute, PTHREAD_CREATE_DETACHED);
 1465 
 1466     pthread_mutex_lock(&global_lock);
 1467         rtsp_data->threadnbr = ++threads_running;
 1468     pthread_mutex_unlock(&global_lock);
 1469 
 1470     retcd = pthread_create(&rtsp_data->thread_id, &handler_attribute, &netcam_rtsp_handler, rtsp_data);
 1471     if (retcd < 0) {
 1472         MOTION_LOG(ALR, TYPE_NETCAM, SHOW_ERRNO
 1473             ,_("%s: Error starting handler thread"),rtsp_data->cameratype);
 1474         pthread_attr_destroy(&handler_attribute);
 1475         return -1;
 1476     }
 1477     pthread_attr_destroy(&handler_attribute);
 1478 
 1479 
 1480     /* Now give a few tries to check that an image has been captured.
 1481      * This ensures that by the time the setup routine exits, the
 1482      * handler is completely set up and has images available
 1483      */
 1484     wait_counter = 60;
 1485     while (wait_counter > 0) {
 1486         pthread_mutex_lock(&rtsp_data->mutex);
 1487             if (rtsp_data->img_latest->ptr != NULL ) wait_counter = -1;
 1488         pthread_mutex_unlock(&rtsp_data->mutex);
 1489 
 1490         if (wait_counter > 0 ){
 1491             MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
 1492                 ,_("%s: Waiting for first image from the handler."),rtsp_data->cameratype);
 1493             SLEEP(0,5000000);
 1494             wait_counter--;
 1495         }
 1496     }
 1497     /* Warn the user about a mismatch of camera FPS vs handler capture rate*/
 1498     if (rtsp_data->conf->framerate < rtsp_data->src_fps){
 1499         MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO
 1500             , _("Requested frame rate %d FPS is less than camera frame rate %d FPS")
 1501             , rtsp_data->conf->framerate,rtsp_data->src_fps);
 1502         MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO
 1503             , _("Increasing capture rate to %d FPS to match camera.")
 1504             , rtsp_data->src_fps);
 1505         MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO
 1506             , _("To lower CPU, change camera FPS to lower rate and decrease I frame interval.")
 1507             , rtsp_data->src_fps);
 1508 
 1509     }
 1510 
 1511     return 0;
 1512 
 1513 }
 1514 
 1515 /*********************************************************
 1516  *  This ends the section of functions that rely upon FFmpeg
 1517  ***********************************************************/
 1518 #endif /* End HAVE_FFMPEG */
 1519 
 1520 
 1521 int netcam_rtsp_setup(struct context *cnt){
 1522 #ifdef HAVE_FFMPEG
 1523 
 1524     int retcd;
 1525     int indx_cam, indx_max;
 1526     struct rtsp_context *rtsp_data;
 1527 
 1528     cnt->rtsp = NULL;
 1529     cnt->rtsp_high = NULL;
 1530 
 1531     if (netcam_rtsp_set_dimensions(cnt) < 0 ) return -1;
 1532 
 1533     indx_cam = 1;
 1534     indx_max = 1;
 1535     if (cnt->conf.netcam_highres) indx_max = 2;
 1536 
 1537     while (indx_cam <= indx_max){
 1538         if (indx_cam == 1){
 1539             cnt->rtsp = rtsp_new_context();
 1540             if (cnt->rtsp == NULL) {
 1541                 MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO
 1542                     ,_("unable to create rtsp context"));
 1543                 return -1;
 1544             }
 1545             rtsp_data = cnt->rtsp;
 1546             rtsp_data->high_resolution = FALSE;           /* Set flag for this being the normal resolution camera */
 1547         } else {
 1548             cnt->rtsp_high = rtsp_new_context();
 1549             if (cnt->rtsp_high == NULL) {
 1550                 MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO
 1551                     ,_("unable to create rtsp high context"));
 1552                 return -1;
 1553             }
 1554             rtsp_data = cnt->rtsp_high;
 1555             rtsp_data->high_resolution = TRUE;            /* Set flag for this being the high resolution camera */
 1556         }
 1557 
 1558         netcam_rtsp_null_context(rtsp_data);
 1559 
 1560         netcam_rtsp_set_parms(cnt, rtsp_data);
 1561 
 1562         if (netcam_rtsp_connect(rtsp_data) < 0) return -1;
 1563 
 1564         retcd = netcam_rtsp_read_image(rtsp_data);
 1565         if (retcd < 0){
 1566             MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO
 1567                 ,_("Failed trying to read first image - retval:%d"), retcd);
 1568             rtsp_data->status = RTSP_NOTCONNECTED;
 1569             return -1;
 1570         }
 1571         /* When running dual, there seems to be contamination across norm/high with codec functions. */
 1572         netcam_rtsp_close_context(rtsp_data);       /* Close in this thread to open it again within handler thread */
 1573         rtsp_data->status = RTSP_RECONNECTING;      /* Set as reconnecting to avoid excess messages when starting */
 1574         rtsp_data->first_image = FALSE;             /* Set flag that we are not processing our first image */
 1575 
 1576         /* For normal resolution, we resize the image to the config parms so we do not need
 1577          * to set the dimension parameters here (it is done in the set_parms).  For high res
 1578          * we must get the dimensions from the first image captured
 1579          */
 1580         if (rtsp_data->high_resolution){
 1581             cnt->imgs.width_high = rtsp_data->imgsize.width;
 1582             cnt->imgs.height_high = rtsp_data->imgsize.height;
 1583         }
 1584 
 1585         if (netcam_rtsp_start_handler(rtsp_data) < 0 ) return -1;
 1586 
 1587         indx_cam++;
 1588     }
 1589 
 1590     return 0;
 1591 
 1592 #else  /* No FFmpeg/Libav */
 1593     /* Stop compiler warnings */
 1594     if (cnt)
 1595         MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, _("FFmpeg/Libav not found on computer.  No RTSP support"));
 1596     return -1;
 1597 #endif /* End #ifdef HAVE_FFMPEG */
 1598 }
 1599 
 1600 int netcam_rtsp_next(struct context *cnt, struct image_data *img_data){
 1601 #ifdef HAVE_FFMPEG
 1602     /* This is called from the motion loop thread */
 1603 
 1604     if ((cnt->rtsp->status == RTSP_RECONNECTING) ||
 1605         (cnt->rtsp->status == RTSP_NOTCONNECTED)){
 1606             return 1;
 1607         }
 1608     pthread_mutex_lock(&cnt->rtsp->mutex);
 1609         netcam_rtsp_pktarray_resize(cnt, FALSE);
 1610         memcpy(img_data->image_norm
 1611                , cnt->rtsp->img_latest->ptr
 1612                , cnt->rtsp->img_latest->used);
 1613         img_data->idnbr_norm = cnt->rtsp->idnbr;
 1614     pthread_mutex_unlock(&cnt->rtsp->mutex);
 1615 
 1616     if (cnt->rtsp_high){
 1617         if ((cnt->rtsp_high->status == RTSP_RECONNECTING) ||
 1618             (cnt->rtsp_high->status == RTSP_NOTCONNECTED)) return 1;
 1619 
 1620         pthread_mutex_lock(&cnt->rtsp_high->mutex);
 1621             netcam_rtsp_pktarray_resize(cnt, TRUE);
 1622             if (!(cnt->rtsp_high->high_resolution && cnt->rtsp_high->passthrough)) {
 1623                 memcpy(img_data->image_high
 1624                        ,cnt->rtsp_high->img_latest->ptr
 1625                        ,cnt->rtsp_high->img_latest->used);
 1626             }
 1627             img_data->idnbr_high = cnt->rtsp_high->idnbr;
 1628         pthread_mutex_unlock(&cnt->rtsp_high->mutex);
 1629     }
 1630 
 1631     /* Rotate images if requested */
 1632     rotate_map(cnt, img_data);
 1633 
 1634     return 0;
 1635 
 1636 #else  /* No FFmpeg/Libav */
 1637     /* Stop compiler warnings */
 1638     if ((cnt) || (img_data))
 1639         MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, _("FFmpeg/Libav not found on computer.  No RTSP support"));
 1640     return -1;
 1641 #endif /* End #ifdef HAVE_FFMPEG */
 1642 }
 1643 
 1644 void netcam_rtsp_cleanup(struct context *cnt, int init_retry_flag){
 1645 #ifdef HAVE_FFMPEG
 1646      /*
 1647      * If the init_retry_flag is not set this function was
 1648      * called while retrying the initial connection and there is
 1649      * no camera-handler started yet and thread_running must
 1650      * not be decremented.
 1651      */
 1652     int wait_counter;
 1653     int indx_cam, indx_max;
 1654     struct rtsp_context *rtsp_data;
 1655 
 1656     indx_cam = 1;
 1657     indx_max = 1;
 1658     if (cnt->rtsp_high) indx_max = 2;
 1659 
 1660     while (indx_cam <= indx_max) {
 1661         if (indx_cam == 1){
 1662             rtsp_data = cnt->rtsp;
 1663         } else {
 1664             rtsp_data = cnt->rtsp_high;
 1665         }
 1666 
 1667         if (rtsp_data){
 1668             MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO
 1669                 ,_("%s: Shutting down network camera."),rtsp_data->cameratype);
 1670 
 1671             /* Throw the finish flag in context and wait a bit for it to finish its work and close everything
 1672              * This is shutting down the thread so for the moment, we are not worrying about the
 1673              * cross threading and protecting these variables with mutex's
 1674             */
 1675             rtsp_data->finish = TRUE;
 1676             rtsp_data->interruptduration = 0;
 1677             wait_counter = 0;
 1678             while ((!rtsp_data->handler_finished) && (wait_counter < 10)) {
 1679                 SLEEP(1,0);
 1680                 wait_counter++;
 1681             }
 1682             if (!rtsp_data->handler_finished) {
 1683                 MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO
 1684                     ,_("%s: No response from handler thread."),rtsp_data->cameratype);
 1685                 /* Last resort.  Kill the thread. Not safe for posix but if no response, what to do...*/
 1686                 /* pthread_kill(rtsp_data->thread_id); */
 1687                 pthread_cancel(rtsp_data->thread_id);
 1688                 pthread_kill(rtsp_data->thread_id, SIGVTALRM); /* This allows the cancel to be processed */
 1689                 if (!init_retry_flag){
 1690                     pthread_mutex_lock(&global_lock);
 1691                         threads_running--;
 1692                     pthread_mutex_unlock(&global_lock);
 1693                 }
 1694             }
 1695             /* If we never connect we don't have a handler but we still need to clean up some */
 1696             netcam_rtsp_shutdown(rtsp_data);
 1697 
 1698             pthread_mutex_destroy(&rtsp_data->mutex);
 1699             pthread_mutex_destroy(&rtsp_data->mutex_pktarray);
 1700             pthread_mutex_destroy(&rtsp_data->mutex_transfer);
 1701 
 1702             free(rtsp_data);
 1703             rtsp_data = NULL;
 1704             if (indx_cam == 1){
 1705                 MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO
 1706                     ,_("Normal resolution: Shut down complete."));
 1707             } else {
 1708                 MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO
 1709                     ,_("High resolution: Shut down complete."));
 1710             }
 1711         }
 1712         indx_cam++;
 1713     }
 1714     cnt->rtsp = NULL;
 1715     cnt->rtsp_high = NULL;
 1716 
 1717 #else  /* No FFmpeg/Libav */
 1718     /* Stop compiler warnings */
 1719     if ((cnt) || (init_retry_flag))
 1720         MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, _("FFmpeg/Libav not found on computer.  No RTSP support"));
 1721     return;
 1722 #endif /* End #ifdef HAVE_FFMPEG */
 1723 
 1724 }
 1725