示例#1
0
static int sendPktUdpRtp(STREAM_XMIT_NODE_T *pStream, unsigned int idxDest,
                      const unsigned char *pData, unsigned int len) {
  int rc = 0;

  if(!pStream->pXmitAction->do_output_rtphdr) {
    if(len >= RTP_HEADER_LEN) {
      pData += RTP_HEADER_LEN;
      len -= RTP_HEADER_LEN;
    } else {
      len = 0;
    }
  }

  if(len == 0) {
    LOG(X_WARNING("sendto called with 0 length"));
    return 0;
  }

  pStream->pRtpMulti->pdests[idxDest].rtcp.sr.rtpts = pStream->pRtpMulti->pRtp->timeStamp;
  pStream->pRtpMulti->pdests[idxDest].rtcp.pktcnt++;
  pStream->pRtpMulti->pdests[idxDest].rtcp.octetcnt += len ;

  //fprintf(stderr, "sendto [dest:%d] %s:%d %d bytes seq:%u ts:%u ssrc:0x%x\n", idxDest, inet_ntoa(pStream->saDsts[idxDest].sin_addr), ntohs(pStream->saDsts[idxDest].sin_port), len, htons(pStream->pRtpMulti[idxDest].m_pRtp->sequence_num), htonl(pStream->pRtpMulti[idxDest].m_pRtp->timeStamp), pStream->pRtpMulti[idxDest].m_pRtp->ssrc);

  if((rc = sendto(STREAM_RTP_FD(pStream->pRtpMulti->pdests[idxDest]),
                  (void *) pData, len, 0,
                  (struct sockaddr *) &pStream->pRtpMulti->pdests[idxDest].saDsts,
                  sizeof(pStream->pRtpMulti->pdests[idxDest].saDsts))) != len) {

    LOG(X_ERROR("sendto %s:%d for %d bytes failed with "ERRNO_FMT_STR),
                inet_ntoa(pStream->pRtpMulti->pdests[idxDest].saDsts.sin_addr),
                ntohs(pStream->pRtpMulti->pdests[idxDest].saDsts.sin_port),
                len, ERRNO_FMT_ARGS);
    return -1;
  }


  return rc;
}
示例#2
0
int mediadb_parseprefixes(const char *prefixstr, const char *prefixOutArr[], 
                          unsigned int maxPrefix) {
  unsigned int prefixIdx = 0;
  const char *p, *p2;
  int inside = 0;

  //TODO: this should use strutil_parse_csv

  if(!prefixstr) {
    return prefixIdx;
  }

  p = p2 = prefixstr;

  while(*p2 != '\0') {


    if(!inside && *p2 == '"') {
      p = ++p2;
      inside = 1;
    }

    if(inside && *p2 == '"') {
      if(prefixIdx >= maxPrefix) {
        LOG(X_WARNING("Max number %d of prefixes reached"), maxPrefix);
        break;
      }
      prefixOutArr[prefixIdx++] = (char *) p;
      *((char *) p2) = '\0';
      inside = 0;
    }
    p2++;
       
  }

  return prefixIdx;
}
示例#3
0
SESSION_DESCR_T *session_add(SESSION_CACHE_T *pCache, struct sockaddr *pSockAddr) {
  SESSION_DESCR_T *pSession = NULL;
  SESSION_DESCR_T *pSessionPrev = NULL;
  unsigned int numSessions = 0;
  char tmp[128];

  //TODO: need a hash

  while(pSession) {
    if(pSession->cookie[0] == '\0') {
      break;
    }
    numSessions++;
    pSessionPrev = pSession;
    pSession = pSession->pnext;
  }

  if(!pSession) {
    if(numSessions < SESSION_CACHE_MAX) {
      pSession = avc_calloc(1, sizeof(SESSION_DESCR_T)); 
      if(pSessionPrev) {
        pSessionPrev->pnext = pSession;
      } else {
        pCache->plist = pSession;
      }
    } else {
      LOG(X_WARNING("No available session for %s:%d"), 
           FORMAT_NETADDR(*pSockAddr, tmp, sizeof(tmp)),  ntohs(PINET_PORT(pSockAddr)));
      return NULL;
    }
  }

  pSession->lastTm = time(NULL);

  return pSession;
}
示例#4
0
int xcode_frame_vid(IXCODE_VIDEO_CTXT_T *pIn, unsigned char *bufIn, unsigned int lenIn,
                    IXCODE_OUTBUF_T *pout) {
  XCODE_IPC_MEM_T *pMem;
  IXCODE_VIDEO_CTXT_T *pXcodeV;
  unsigned int lenCopied;
  int rc;
  unsigned char *bufOut = pout->buf;
  unsigned int lenOut = pout->lenbuf;

  if(!pIn->common.pIpc) {
    return -1;
  }

  if(bufIn && bufIn != bufOut) {
    LOG(X_ERROR("buffer output does not match input")); 
    return -1;
  }

  pMem = ((XCODE_IPC_DESCR_T *) pIn->common.pIpc)->pmem;
  pXcodeV = &pMem->hdr.ctxt.vid;

  pXcodeV->common.inpts90Khz = pIn->common.inpts90Khz;
  pXcodeV->common.outpts90Khz = pIn->common.outpts90Khz;
  pXcodeV->common.decodeInIdx = pIn->common.decodeInIdx;
  pXcodeV->common.decodeOutIdx = pIn->common.decodeOutIdx;
  pXcodeV->common.encodeInIdx = pIn->common.encodeInIdx;
  pXcodeV->common.encodeOutIdx = pIn->common.encodeOutIdx;
  pXcodeV->out[0].cfgForceIDR = pIn->out[0].cfgForceIDR;
  pXcodeV->out[0].qTot = pIn->out[0].qTot;
  pXcodeV->out[0].qSamples = pIn->out[0].qSamples;
  pXcodeV->out[0].pts = pIn->out[0].pts;
  pXcodeV->out[0].dts = pIn->out[0].dts;

  if((lenCopied = lenIn) > XCODE_IPC_MEM_DATASZ(pMem)) {
    lenCopied = XCODE_IPC_MEM_DATASZ(pMem);
    LOG(X_WARNING("Video frame length to be decoded truncated from %d to %d"), lenIn, lenCopied);
  }
  if(bufIn) {
    memcpy(XCODE_IPC_MEM_DATA(pMem), bufIn, lenCopied);
  }
  pMem->hdr.cmdrc = (enum IXCODE_RC) lenCopied;
  pMem->hdr.offsetOut = 0;

  if((rc = xcode_call_ipc(pIn->common.pIpc, XCODE_IPC_CMD_ENCODE_VID)) != -1) {
    pIn->common.inpts90Khz = pXcodeV->common.inpts90Khz;
    pIn->common.outpts90Khz = pXcodeV->common.outpts90Khz;
    pIn->common.decodeInIdx = pXcodeV->common.decodeInIdx;
    pIn->common.decodeOutIdx = pXcodeV->common.decodeOutIdx;
    pIn->common.encodeInIdx = pXcodeV->common.encodeInIdx;
    pIn->common.encodeOutIdx = pXcodeV->common.encodeOutIdx;
    pIn->out[0].qTot = pXcodeV->out[0].qTot;
    pIn->out[0].qSamples = pXcodeV->out[0].qSamples;
    pIn->out[0].frameType = pXcodeV->out[0].frameType;
    pIn->out[0].pts = pXcodeV->out[0].pts;
    pIn->out[0].dts = pXcodeV->out[0].dts;

    if((lenCopied = rc) > XCODE_IPC_MEM_DATASZ(pMem)) {
      lenCopied = XCODE_IPC_MEM_DATASZ(pMem);
      LOG(X_WARNING("Encoded video frame length truncated from %d to %d"), rc, lenCopied);
      rc = lenCopied;
    } else if(lenCopied > lenOut) {
      lenCopied = lenOut;
      LOG(X_WARNING("Encoded video frame length truncated from %d to %d"), rc, lenCopied);
      rc = lenCopied;
    }
    memcpy(bufOut, XCODE_IPC_MEM_DATA(pMem), lenCopied);
  }

  return rc;
}
示例#5
0
static int update_fileentry(FILE_LIST_T *pFileList, const char *mediaName, 
                            const char *mediaPath, FILE_LIST_ENTRY_T **ppEntry) {
  MEDIA_DESCRIPTION_T mediaDescr;
  FILE_STREAM_T fileStream;
  FILE_LIST_ENTRY_T *pFileEntryCur = NULL;
  FILE_LIST_ENTRY_T *pFileEntryNew = NULL;
  FILE_LIST_ENTRY_T fileEntry;
  char buf[VSX_MAX_PATH_LEN];
  struct stat st;
  struct stat st2;
  int havestat = 0;
  size_t szt;
  int fileChanged = 1;

  memset(&fileEntry, 0, sizeof(fileEntry));
      
//fprintf(stdout, "looking for '%s'\n", mediaName);
  if((pFileEntryCur = file_list_find(pFileList, mediaName))) {

    //fprintf(stdout, "found entry '%s' numTn:%d\n", pFileEntryCur->name, pFileEntryCur->numTn);

    // mark the entry as current to avoid deletion
    pFileEntryCur->flag = 1;
        
    if((havestat = !fileops_stat(mediaPath, &st)) == 0) {
      LOG(X_ERROR("Unable to stat '%s'"), mediaPath);
    } else if(st.st_size == pFileEntryCur->size &&
              st.st_ctime == pFileEntryCur->tm) {

      fileChanged = 0;

      //
      // Special case to probe for recent creation .seek file
      // since the last time this entry was written
      //
      if(pFileEntryCur->duration == 0) {
        buf[sizeof(buf) - 1] = '\0';
        strncpy(buf, mediaPath, sizeof(buf) - 1);
        if((szt = strlen(buf))) {
          strncpy(&buf[szt], MP2TS_FILE_SEEKIDX_NAME, sizeof(buf) - szt - 1);
        }
        if(fileops_stat(buf, &st2) == 0) {
          fileChanged = 1;        
        }
      }

    }
    pFileEntryNew = pFileEntryCur;

  } else {

    // Check for invalid chars - ',' is used as a delimeter in .avcfidx
    if(strchr(mediaName, ',') || mediaName[0] == '#' || mediaName[0] == ' ' ||
              mediaName[0] == '=') {
      LOG(X_WARNING("Illegal filename '%s' not added to database"), mediaPath);
      pFileEntryNew = NULL;
      fileChanged = 0;
    } else {
      LOG(X_DEBUG("Could not find database entry '%s'"), mediaPath);
      pFileEntryNew = &fileEntry;
    }
  }

  if(fileChanged) {

    if(OpenMediaReadOnly(&fileStream, mediaPath) == 0) {

      memset(&mediaDescr, 0, sizeof(mediaDescr));

      if(filetype_getdescr(&fileStream, &mediaDescr, 1) == 0) {

         pFileEntryNew->flag = 1;
         pFileEntryNew->duration = mediaDescr.durationSec; 
         pFileEntryNew->size = mediaDescr.totSz;

         if(!havestat && (havestat = !fileops_stat(mediaPath, &st)) == 0) {
           LOG(X_ERROR("Unable to stat new entry '%s'"), mediaPath);
         }
         if(havestat) {
           pFileEntryNew->tm = st.st_ctime;
//fprintf(stderr, "-----------set tm:%ld %s\n", pFileEntryNew->tm, mediaPath);
         }

         if(mediaDescr.haveVid) {
           create_viddescrstr(&mediaDescr, pFileEntryNew->vstr, sizeof(pFileEntryNew->vstr));
         }
         if(mediaDescr.haveAud) {
           create_auddescrstr(&mediaDescr, pFileEntryNew->astr, sizeof(pFileEntryNew->astr));
           //fprintf(stdout, "aud descr:'%s'\n", pFileEntryNew->astr);
         }

       } else {
         pFileEntryNew->flag = 1;
         pFileEntryNew->size = fileStream.size;
       }

       CloseMediaFile(&fileStream);
    } // end of OpenMediaReadOnly

    if(pFileEntryCur == NULL) {
      pFileEntryNew->name[sizeof(pFileEntryNew->name) - 1] = '\0';
      strncpy(pFileEntryNew->name, mediaName, sizeof(pFileEntryNew->name) - 1);
      pFileEntryCur = file_list_addcopy(pFileList, pFileEntryNew);
    }
  } // end of if(fileChanged)

  if(ppEntry) {
    *ppEntry = pFileEntryCur;
  }

  return fileChanged; 
}
示例#6
0
文件: h264.c 项目: openvcx/openvcx
static int h264_decodeSlice(H264_DECODER_CTXT_T *pCtxt, BIT_STREAM_T *pStream, uint8_t nalType) {
  int first_mb_in_slice = 0;
  unsigned int slice_type = 0;
  unsigned int slice_type0 = 0;
  unsigned int pps_id = 0;
  unsigned int frame_idx = 0;
  int idr_pic_id = 0;
  int picture_structure = 0;
  int tmp;
  H264_NAL_SPS_T *pSps;
  H264_NAL_PPS_T *pPps;

  if(pStream->sz - pStream->byteIdx < 4) {
    LOG(X_WARNING("Slice given length to decode below minimum: %d"), pStream->sz - pStream->byteIdx);
    // Fail gracefully to accomodate empty NALs
    return H264_RC_OK;  
  }

  pCtxt->sliceIdx++;

  first_mb_in_slice = bits_readExpGolomb(pStream);
  if((slice_type0 = slice_type = (unsigned int) bits_readExpGolomb(pStream)) > H264_SLICE_TYPE_SI) {
    slice_type -= (H264_SLICE_TYPE_SI + 1);
  }

  if(slice_type > H264_SLICE_TYPE_SI) {
    LOG(X_WARNING("Invalid slice type: %d"), slice_type);
    return H264_RC_ERR;
  } 
  pCtxt->lastSliceType = slice_type;

  if((pps_id = bits_readExpGolomb(pStream)) >= H264_MAX_PPS_CNT ||
    !pCtxt->pps[pps_id].is_ok) {
    LOG(X_WARNING("Slice references unknown pps:%d"), pps_id);
    return -1;
  }

  pPps = &pCtxt->pps[pps_id];
  pSps = &pCtxt->sps[ pPps->seq_param_set_id ];
  if((frame_idx = bits_read(pStream, pSps->log2_max_frame_num)) != pCtxt->frameIdx) {
    pCtxt->frameIdx = frame_idx;
    pCtxt->sliceIdx = 0;
  } 


  if(!pSps->frame_mbs_only_flag && bits_read(pStream, 1)) {  // field pic flag
    picture_structure = 1 + bits_read(pStream, 1);  // pic_order_cnt_lsb
  } else {
    picture_structure = 3;
  }

  if(nalType == NAL_TYPE_IDR) {
    idr_pic_id = bits_readExpGolomb(pStream);
  }

  if(pSps->pic_order_cnt_type == 0) {
    pCtxt->picOrderCnt = bits_read(pStream, pSps->log2_max_pic_order_cnt_lsb);
    if(pPps->pic_order_present_flag == 1 && picture_structure == 3) {
      bits_readExpGolomb(pStream);  // delta_poc_bottom
    }
       
  } else if(pSps->pic_order_cnt_type == 1 && !pSps->pic_delta_pic_order) {
     bits_readExpGolomb(pStream);  // delta_poc[0]
     if(pPps->pic_order_present_flag == 1 &&  picture_structure == 3) {
       bits_readExpGolomb(pStream);  // delta_poc[1]
     }
  }


  if(pPps->redundant_pic_cnt_present_flag) {
    bits_readExpGolomb(pStream); // bits_readExpGolomb(pStream);
  }

  //fprintf(stderr, "slice: first_mb_in_slice:%d, slice_type:%d,%d, sps:%d, pps:%d, fridx:%d, picstruct:%d, idr_pic_id:%d, sps poctype:%d, poc:%d, pps_pic_order_present:%d, pps_redundant_pic_cnt_present:%d\n", first_mb_in_slice, slice_type, slice_type0, pPps->seq_param_set_id, pps_id, frame_idx, picture_structure, idr_pic_id, pSps->pic_order_cnt_type, pCtxt->picOrderCnt, pPps->pic_order_present_flag, pPps->redundant_pic_cnt_present_flag);

  if(slice_type != H264_SLICE_TYPE_I) {
    if(slice_type != H264_SLICE_TYPE_B) {
      bits_read(pStream, 1); // direct_spatial_mv_pred
    }
    if((bits_read(pStream, 1))) {  // num_ref_idx_active_override_flag
      bits_readExpGolomb(pStream); // ref_count[0] + 1
      if(slice_type != H264_SLICE_TYPE_B) {
        bits_readExpGolomb(pStream); // ref_count[1] + 1
      }
    }
    if(pPps->entropy_coding_mode_flag) {
      bits_readExpGolomb(pStream);
    }
  }

  if(slice_type == H264_SLICE_TYPE_SP) {
    bits_read(pStream, 1);  // sp_for_switch_flag
  }
  if(slice_type == H264_SLICE_TYPE_SP || slice_type == H264_SLICE_TYPE_SI) {
    bits_readExpGolomb(pStream);  // slice_qs_delta
  }

  if(pPps->deblocking_filter_control_present_flag) {
    tmp = bits_readExpGolomb(pStream);
    if(tmp < 2) {
      tmp^=1;
    }
    if(tmp) {
      bits_readExpGolomb(pStream);  // slice_alpha_c0_offset
      bits_readExpGolomb(pStream);  // slice_beta_offset

    }

  }
 
  return H264_RC_OK;
}
示例#7
0
void streamxmit_async_proc(void *pArg) {
  STREAMXMIT_WRAP_T wrap;
  int rc;
  STREAM_RTP_MULTI_T *pRtp = NULL;
  STREAM_RTP_DEST_T *pDest;
  unsigned int idx;
  struct timespec ts;
  struct timeval tv;
  int haveRequestedRetransmission = 0;

  memcpy(&wrap, (STREAMXMIT_WRAP_T *) pArg, sizeof(wrap));
  logutil_tid_add(pthread_self(), wrap.tid_tag);
  pRtp = wrap.pRtp;
  pRtp->asyncRtpRunning = 1;

  LOG(X_DEBUG("RTP output thread started"));

  while(pRtp->asyncRtpRunning == 1 && !g_proc_exit) {

    gettimeofday(&tv, NULL);
    if(haveRequestedRetransmission) {
      ts.tv_sec = tv.tv_sec;
      ts.tv_nsec = tv.tv_usec + 20000;
      //LOG(X_DEBUG("RTP output thread going to wait for 20ms.."));
    } else {
      ts.tv_sec = tv.tv_sec + 2;
      ts.tv_nsec = tv.tv_usec;
      //LOG(X_DEBUG("RTP output thread going to wait for 2 sec.."));
    }

    if((rc = pthread_cond_timedwait(&pRtp->asyncRtpCond.cond, &pRtp->asyncRtpCond.mtx, &ts)) < 0) {
      LOG(X_WARNING("RTP output thread pthread_cond_timedwait failed"));
      usleep(20000);
    }

    if(pRtp->asyncRtpRunning != 1 || g_proc_exit) {
      break;
    }

    haveRequestedRetransmission = 0;
    pthread_mutex_lock(&pRtp->mtx);

    //LOG(X_DEBUG("RTP output thread doing its thing.."));
    if(pRtp->numDests > 0) {

      for(idx = 0; idx < pRtp->maxDests; idx++) {
        pDest = &pRtp->pdests[idx];

//if(pDest->isactive) { LOG(X_DEBUG("ACTIVE[%d]"), idx);  stream_abr_notifyitrate(pDest->pstreamStats, &pDest->streamStatsMtx, STREAM_ABR_UPDATE_REASON_NACK_REQ, .5f); }

        if(pDest->isactive && pDest->asyncQ.haveRequestedRetransmission) {
          if((rc = streamxmit_retransmitRtp(pDest)) > 0) {
            haveRequestedRetransmission = 1;
          }
        }
      }

    }

    pthread_mutex_unlock(&pRtp->mtx);

  }

  LOG(X_DEBUG("RTP output thread ending"));
  pRtp->asyncRtpRunning = -1;

  logutil_tid_remove(pthread_self());
}
示例#8
0
int http_gethttplive(CAP_ASYNC_DESCR_T *pCfg,
                         CAPTURE_CBDATA_T *pStreamsOut,
                         CAPTURE_STREAM_T *pStream,
                         const char *puri,
                         HTTP_RESP_T *pHttpResp,
                         HTTP_PARSE_CTXT_T *pHdrCtxt) {
  int rc = 0;
  char *path;
  const char *pbuf = pHdrCtxt->pbuf;
  unsigned int szbuf = pHdrCtxt->szbuf;
  const char *pm3ubuf;
  pthread_t ptd;
  pthread_attr_t attr;
  HTTPLIVE_CLIENT_T client;
  int highestIdx, lowestIdx, firstIdx;

  memset(&client, 0, sizeof(client));
  client.pCfg = pCfg;
  NETIOSOCK_FD(client.netsock) = INVALID_SOCKET;
  client.netsock.flags = pCfg->pSockList->netsockets[0].flags;
  client.pStreamsOut = pStreamsOut;
  client.pStream = pStream;
  client.running = -1;

  pthread_mutex_init(&client.mtx, NULL);

  do {

    //fprintf(stderr, "HTTP_GETHTTPLIVE sock: %d\n", NETIOSOCK_FD(pCfg->pSockList->netsockets[0]));

    if(NETIOSOCK_FD(pCfg->pSockList->netsockets[0]) == INVALID_SOCKET) {

//fprintf(stderr, "GOING TO CONNECT FOR M3U...\n");
      if((rc = httpcli_connect(&pCfg->pSockList->netsockets[0], &pCfg->pSockList->salist[0], 
                               "HTTPLive playlist thread")) < 0) {
        break;
      }

      memset(pHdrCtxt, 0, sizeof(HTTP_PARSE_CTXT_T));
      memset(pHttpResp, 0, sizeof(HTTP_RESP_T));
      pHdrCtxt->pnetsock = &pCfg->pSockList->netsockets[0];
      pHdrCtxt->pbuf = pbuf;
      pHdrCtxt->szbuf = szbuf;
      pHdrCtxt->tmtms = 0;
    }

    if((rc = mediadb_getdirlen(puri)) > 0) {
      if(rc >= sizeof(client.uriprefix)) {
        rc = sizeof(client.uriprefix) - 1;
      }
      memcpy(client.uriprefix, puri, rc);
    }

    if((pm3ubuf = get_m3u8(pCfg, puri, pHttpResp, pHdrCtxt, (unsigned char *) pbuf, 
                           szbuf))) {
      m3u_free(&client.pl, 0);
      memset(&client.pl, 0, sizeof(client.pl));

/*
pm3ubuf="#EXTM3U\r\n"
        "#EXT-X-VERSION:3\r\n"
        "#EXT-X-ALLOW-CACHE:NO\r\n"
        "#EXT-X-TARGETDURATION:14\r\n"
        "#EXT-X-MEDIA-SEQUENCE:2699\r\n"
        "#EXTINF:10,\r\n"
        "media_2699.ts?wowzasessionid=1144297750\r\n"
        "#EXTINF:10,\r\n"
        "media_2700.ts?wowzasessionid=1144297750\r\n"
        "#EXTINF:7,\r\n"
        "media_2701.ts?wowzasessionid=1144297750\r\n";
*/

      VSX_DEBUGLOG("Got m3u contents '%s'", pm3ubuf);
      //fprintf(stderr, "Got m3u contents '%s'\n", pm3ubuf);

      pthread_mutex_lock(&client.mtx);
      rc = m3u_create_buf(&client.pl, pm3ubuf);
      pthread_mutex_unlock(&client.mtx);

      if(rc > 0) {

        path = NULL;
        lowestIdx = find_lowest_idx(&client.pl, NULL);
        highestIdx = find_highest_idx(&client.pl, NULL);

        if(!client.insession) {

          if(highestIdx < 0) {
            LOG(X_WARNING("Unable to find httplive starting index from %s"), puri);
          } else {

            //
            // Some segmentors may write the last chunk to the playlist file even though
            // the chunk is still being appended on disk
            //
            //if(highestIdx > lowestIdx) {
            //  firstIdx = highestIdx - 1;
            //} else {
              firstIdx = highestIdx;
            //}

            client.curidx  = firstIdx;
            client.nextidx = client.curidx;
            client.insession = 1;

            pthread_attr_init(&attr);
            pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
            client.running = 1;

            if(pthread_create(&ptd, &attr, (void *) httplive_mediaproc, 
                              &client) != 0) {
              LOG(X_ERROR("Unable to create httplive media download thread"));
              rc = -1; 
              client.running = -1;
            }
          }

        } else { // client.insession

          //fprintf(stderr, "check playlist falling behind curidx:%d nextidx:%d, lowestIdx:%d, highestIdx:%d\n", client.curidx, client.nextidx, lowestIdx, highestIdx);
          //
          // Prevent falling behind playlist, a warning will be printed in the ts get thread
          //
          pthread_mutex_lock(&client.mtx);
          if(client.nextidx < lowestIdx) {
            client.nextidx = lowestIdx;
          }
          pthread_mutex_unlock(&client.mtx);
        }

        //if(rc >= 0) {
        //  m3u_dump(&client.pl);
        //}

      }

    } else { // get_m3u8
      rc = -1;
    }

    netio_closesocket(&pCfg->pSockList->netsockets[0]);

    if(rc >= 0) {
//fprintf(stderr, "M3U SLEEPING FOR %d\n", client.pl.targetDuration);
      if(client.pl.targetDuration > 0) {
        sleep(client.pl.targetDuration);
      } else {
        sleep(9);
      }
    }

  } while(rc >= 0);

  client.insession = 0;

  while(client.running != -1) {
    usleep(20000);
  } 

  m3u_free(&client.pl, 0);
  pthread_mutex_destroy(&client.mtx);

  return rc;
}
示例#9
0
int cbparse_entry_metafile(void *pArg, const char *p) {
  int rc = 0;
  PARSE_ENTRY_DATA_T *pEntryData = (PARSE_ENTRY_DATA_T *) pArg;
  
  if(!strncasecmp(p, METAFILE_KEY_FILE, strlen(METAFILE_KEY_FILE))) {

    store_parse_entry(p, METAFILE_KEY_FILE, &pEntryData->flags, PARSE_FLAG_HAVE_FILENAME,  
               pEntryData->filename, sizeof(pEntryData->filename));
  } else if(!strncasecmp(p, METAFILE_KEY_RTMP_PROXY, strlen(METAFILE_KEY_RTMP_PROXY))) {

    store_parse_entry(p, METAFILE_KEY_RTMP_PROXY, &pEntryData->flags, PARSE_FLAG_HAVE_RTMP_PROXY,  
               pEntryData->rtmpproxy, sizeof(pEntryData->rtmpproxy));

  } else if(!strncasecmp(p, METAFILE_KEY_RTSP_PROXY, strlen(METAFILE_KEY_RTSP_PROXY))) {

    store_parse_entry(p, METAFILE_KEY_RTSP_PROXY, &pEntryData->flags, PARSE_FLAG_HAVE_RTSP_PROXY,  
               pEntryData->rtspproxy, sizeof(pEntryData->rtspproxy));

  } else if(!strncasecmp(p, METAFILE_KEY_HTTP_PROXY, strlen(METAFILE_KEY_HTTP_PROXY))) {

    store_parse_entry(p, METAFILE_KEY_HTTP_PROXY, &pEntryData->flags, PARSE_FLAG_HAVE_HTTP_PROXY,  
               pEntryData->httpproxy, sizeof(pEntryData->httpproxy));

  } else if(!strncasecmp(p, METAFILE_KEY_HTTPLINK, strlen(METAFILE_KEY_HTTPLINK))) {

    store_parse_entry(p, METAFILE_KEY_HTTPLINK, &pEntryData->flags, PARSE_FLAG_HAVE_HTTPLINK,  
               pEntryData->link, sizeof(pEntryData->link));

  } else if(!strncasecmp(p, METAFILE_KEY_INPUT, strlen(METAFILE_KEY_INPUT))) {

    store_parse_entry(p, METAFILE_KEY_INPUT, &pEntryData->flags, PARSE_FLAG_HAVE_INPUT,  
               pEntryData->input, sizeof(pEntryData->input));

  } else if(!strncasecmp(p, METAFILE_KEY_DEVICE, strlen(METAFILE_KEY_DEVICE))) {

    store_parse_entry(p, METAFILE_KEY_DEVICE, &pEntryData->flags, PARSE_FLAG_HAVE_DEVNAME,  
               pEntryData->devname, sizeof(pEntryData->devname));

  } else if(!strncasecmp(p, METAFILE_KEY_PROFILE, strlen(METAFILE_KEY_PROFILE))) {

    store_parse_entry(p, METAFILE_KEY_PROFILE, &pEntryData->flags, PARSE_FLAG_HAVE_PROFILE,  
               pEntryData->profile, sizeof(pEntryData->profile));

  } else if(!strncasecmp(p, METAFILE_KEY_SHARED, strlen(METAFILE_KEY_SHARED))) {

    if((p = store_parse_entry(p, METAFILE_KEY_SHARED, &pEntryData->flags, PARSE_FLAG_HAVE_SHARED, NULL, 0))) {

      if(IS_CONF_VAL_TRUE(p)) {
        pEntryData->shared = BOOL_ENABLED_OVERRIDE;
      } else if(IS_CONF_VAL_FALSE(p)) {
        pEntryData->shared = BOOL_DISABLED_OVERRIDE;
      }
    }

  } else if(!strncasecmp(p, METAFILE_KEY_SECURE, strlen(METAFILE_KEY_SECURE))) {

    if((p = store_parse_entry(p, METAFILE_KEY_SECURE, &pEntryData->flags, PARSE_FLAG_HAVE_SECURE, NULL, 0))) {

      if(IS_CONF_VAL_TRUE(p)) {
        pEntryData->secure = BOOL_ENABLED_OVERRIDE;
      } else if(IS_CONF_VAL_FALSE(p)) {
        pEntryData->secure = BOOL_DISABLED_OVERRIDE;
      }
    }

  } else if(!strncasecmp(p, METAFILE_KEY_XCODEARGS, strlen(METAFILE_KEY_XCODEARGS))) {

    store_parse_entry(p, METAFILE_KEY_XCODEARGS, &pEntryData->flags, PARSE_FLAG_HAVE_XCODEARGS,  
               pEntryData->xcodestr, sizeof(pEntryData->xcodestr));

  } else if(!strncasecmp(p, METAFILE_KEY_DIGESTAUTH, strlen(METAFILE_KEY_DIGESTAUTH))) {

    store_parse_entry(p, METAFILE_KEY_DIGESTAUTH, &pEntryData->flags, PARSE_FLAG_HAVE_DIGESTAUTH,  
               pEntryData->userpass, sizeof(pEntryData->userpass));
    //TODO: verify ascii chars delimited by colon...

  } else if(!strncasecmp(p, METAFILE_KEY_TOKEN, strlen(METAFILE_KEY_TOKEN))) {

    store_parse_entry(p, METAFILE_KEY_TOKEN, &pEntryData->flags, PARSE_FLAG_HAVE_TOKEN,  
               pEntryData->tokenId, sizeof(pEntryData->tokenId));

  } else if(!strncasecmp(p, METAFILE_KEY_METHODS, strlen(METAFILE_KEY_METHODS))) {

    p = store_parse_entry(p, METAFILE_KEY_METHODS, &pEntryData->flags, PARSE_FLAG_HAVE_METHODS, NULL, 0);
    strutil_parse_csv(cbparse_methods_csv, pEntryData, p);

  } else if(!strncasecmp(p, METAFILE_KEY_ID, strlen(METAFILE_KEY_ID))) {

    store_parse_entry(p, METAFILE_KEY_ID, &pEntryData->flags, PARSE_FLAG_HAVE_ID,  
               pEntryData->id, sizeof(pEntryData->id));

  } else if(!strncasecmp(p, METAFILE_KEY_IGNORE, strlen(METAFILE_KEY_IGNORE))) {

    store_parse_entry(p, METAFILE_KEY_IGNORE, &pEntryData->flags, PARSE_FLAG_HAVE_IGNORE,  
               pEntryData->ignore, sizeof(pEntryData->ignore));

  } else if(!strncasecmp(p, METAFILE_KEY_TITLE, strlen(METAFILE_KEY_TITLE))) {

    store_parse_entry(p, METAFILE_KEY_TITLE, &pEntryData->flags, PARSE_FLAG_HAVE_TITLE,  
               pEntryData->title, sizeof(pEntryData->title));

  //
  // 'description' has been deprecated in favor of 'title'
  //
  } else if(!strncasecmp(p, METAFILE_KEY_DESCRIPTION, strlen(METAFILE_KEY_DESCRIPTION))) {

    store_parse_entry(p, METAFILE_KEY_DESCRIPTION, &pEntryData->flags, PARSE_FLAG_HAVE_TITLE,  
               pEntryData->title, sizeof(pEntryData->title));


  } else {

    LOG(X_WARNING("Unhandled metafile parameter '%s' in %s line:%d"), p, pEntryData->path, pEntryData->linenum);

  }

  return rc;
}
示例#10
0
int sdputil_createSdp(STREAMER_CFG_T *pCfg, SDP_DESCR_T *pSdp) {
  int rc = 0;
  unsigned char header[256];
  unsigned int headerLen = sizeof(header);
  STREAM_XCODE_CTXT_T xcodeCtxt;
  unsigned int outidx = 0;
  SDP_CODEC_PARAM_T codecParam;
  union {
    SPSPPS_RAW_T spspps;
  } uvidhdr;


  if(!pCfg || !pSdp) {
    return -1;
  }

  memset(pSdp, 0, sizeof(SDP_DESCR_T));
  memset(&uvidhdr, 0, sizeof(uvidhdr));
  memset(&xcodeCtxt, 0, sizeof(xcodeCtxt));
  xcodeCtxt.vidData.piXcode = &pCfg->xcode;


  if(!pCfg->novid && pCfg->xcode.vid.common.cfgDo_xcode) {
    codecParam.u.pktzMode = PKTZ_H264_MODE_NOTSET;

    if(sdputil_init(pSdp,
               codecType_getRtpPT(pCfg->xcode.vid.common.cfgFileTypeOut, pCfg->cfgrtp.payloadTypesMin1),
               90000,  // TODO: may vary
               pCfg->xcode.vid.common.cfgFileTypeOut,
               pCfg->pdestsCfg[0].dstHost,
               pCfg->pdestsCfg[0].ports[0],  
               pCfg->pdestsCfg[0].portsRtcp[0],
               NULL,
               NULL,
               NULL,
               &codecParam,
               NULL,
               &pCfg->fbReq) < 0) {
      return -1;
    }

    if(!pCfg->xcode.vid.pUserData) {
      pCfg->xcode.vid.pUserData = &xcodeCtxt.vidUData;
    }

    rc = xcode_getvidheader(&xcodeCtxt.vidData, outidx, header, &headerLen);

    if(pCfg->xcode.vid.pUserData == &xcodeCtxt.vidUData) {
      pCfg->xcode.vid.pUserData = NULL;
    }

    if(rc == 0) {
      switch(pCfg->xcode.vid.common.cfgFileTypeOut) {
        case XC_CODEC_TYPE_H264:
          //TODO: this should be xcoder output index specific
          if((rc = xcode_h264_find_spspps(&xcodeCtxt.vidUData.out[outidx].uout.xh264,
                   header, headerLen, &uvidhdr.spspps)) < 0) {
            return rc;
          }
          if(uvidhdr.spspps.sps_len <= 0) {
            LOG(X_WARNING("H.264 SPS not available"));
            return -1;
          }
          memcpy(pSdp->vid.u.h264.profile_level_id, &uvidhdr.spspps.sps[1], 3);
          memcpy(&pSdp->vid.u.h264.spspps, &uvidhdr.spspps, sizeof(SPSPPS_RAW_T));

          break;
        default:
          break; 
      }


    }

  }


  return rc;
}
示例#11
0
void mediadb_proc(void *parg) {
  MEDIADB_DESCR_T *pMediaDb = (MEDIADB_DESCR_T *) parg;
  struct stat st;
  char buf[VSX_MAX_PATH_LEN];
  const char *avcthumb = NULL;
  size_t sz;
  int rc;
  unsigned int iterIdx = 0;

  if(!pMediaDb->mediaDir) {
    return;
  }

  memset(buf, 0, sizeof(buf));
  sz = mediadb_getdirlen(pMediaDb->dbDir);
  strncpy(buf,  pMediaDb->dbDir, sizeof(buf) - 1);
  buf[sz] = '\0';

  LOG(X_DEBUG("Database dir: '%s'"), pMediaDb->dbDir);

  if(fileops_stat(buf, &st) != 0) {
    //
    // Create database root dir
    //
    LOG(X_DEBUG("Creating dir '%s'"), buf);
    if(fileops_MkDir(buf, S_IRWXU | S_IRWXG | S_IRWXO ) < 0) {
      LOG(X_CRITICAL("Unable to create database dir '%s'"), buf);
      return;
    }
  }

  if(fileops_stat(pMediaDb->dbDir, &st) != 0) {
    //
    // Create database subdir specific for mediaDir
    //
    LOG(X_DEBUG("Creating dir '%s'"), pMediaDb->dbDir);
    if(fileops_MkDir(pMediaDb->dbDir, S_IRWXU | S_IRWXG | S_IRWXO ) < 0) {
      LOG(X_CRITICAL("Unable to create database dir '%s'"), pMediaDb->dbDir);
      return;
    }
  }

  //
  // Check thumbnail creation script
  //
  if(pMediaDb->avcthumb) {

    if(fileops_stat(pMediaDb->avcthumb, &st) == 0) {

      //
      // Truncate the avcthumblog 
      //
      if(pMediaDb->avcthumblog) {
        snprintf(buf, sizeof(buf), DATE_CMD" > %s", pMediaDb->avcthumblog);
        //LOG(X_DEBUG("Executing system command '%s'"), buf);
        rc = system(buf);
        if(fileops_stat(pMediaDb->avcthumblog, &st) != 0) {
          pMediaDb->avcthumblog = NULL;
        }

      }

      if(pMediaDb->lgTnWidth == 0 || pMediaDb->lgTnWidth == 0) {
        pMediaDb->lgTnWidth = LG_THUMB_WIDTH;
        pMediaDb->lgTnHeight = LG_THUMB_HEIGHT;
      }
      if(pMediaDb->smTnWidth == 0 || pMediaDb->smTnHeight == 0) {
        pMediaDb->smTnWidth = SM_THUMB_WIDTH;
        pMediaDb->smTnHeight = SM_THUMB_HEIGHT;
      }

      LOG(X_DEBUG("Using %s to generate thumbnails %dx%d %dx%d"), 
                  pMediaDb->avcthumb,
                  pMediaDb->smTnWidth, pMediaDb->smTnHeight,
                  pMediaDb->lgTnWidth, pMediaDb->lgTnHeight);

    } else {

      LOG(X_WARNING("Unable to find %s  Video thumbnails disabled."), pMediaDb->avcthumb);
      pMediaDb->avcthumb = NULL;
    } 

  } else {
    LOG(X_WARNING("Not using video thumbnails.  Please set '%s=' in the configuration file."),
        SRV_CONF_KEY_AVCTHUMB);
  }

  //
  // Set avchumb to null and do not create thumbnails on first 
  // iteration to allow all avcfidx files to be created quickly
  //
  avcthumb = pMediaDb->avcthumb; 
  pMediaDb->avcthumb = NULL; 
  if(g_proc_exit == 0) {
    iterate_subdirs(pMediaDb, pMediaDb->dbDir, pMediaDb->mediaDir, 1, 0);
    pMediaDb->avcthumb = avcthumb; 
    usleep(2000000);
  }

  while(g_proc_exit == 0) {
    iterate_subdirs(pMediaDb, pMediaDb->dbDir, pMediaDb->mediaDir, 1, iterIdx++);
    usleep(10000000);
  }

}
示例#12
0
DIR_ENTRY_LIST_T *direntry_getentries(const MEDIADB_DESCR_T *pMediaDb, 
                                      const char *dir, 
                                      const char *fidxdir, 
                                      const char *searchstr,
                                      int includedirs,
                                      unsigned int startidx,
                                      unsigned int max,
                                      enum DIR_SORT sort) {
  DIR *pdir;
  int rc = 0;
  struct dirent *direntry;
  char path[VSX_MAX_PATH_LEN];
  struct stat st;
  int addEntry;
  FILE_LIST_T fileList;
  FILE_LIST_ENTRY_T *pFileEntry = NULL;
  META_FILE_T metaFile;
  DIR_ENTRY_LIST_T *pEntryList = NULL;
  DIR_ENTRY_T entry;
  DIR_ENTRY_T *pEntry;
  const char *pdispname;
  unsigned int idx = 0;
  unsigned int cnt = 0;
  unsigned int cntInDir = 0;
  COMPARE_DIR_ENTRY compareFunc = direntry_getcompfunc(sort);

  VSX_DEBUG_MGR( LOG(X_DEBUG("MGR - direntry_getentries dir: '%s', fidxdir: '%s', searchstr: '%s', "
                             "includedirs: %d, startidx: %d, max: %d"), 
                            dir, fidxdir, searchstr, includedirs, startidx, max));

  if(!(pdir = fileops_OpenDir(dir))) {
    return NULL;
  }

  memset(&fileList, 0, sizeof(fileList));
  if(fidxdir) { 
    file_list_read(fidxdir, &fileList);
  }

  //
  // Read the directory wide metafile to get a list of 'ignore' entries
  //
  memset(&metaFile, 0, sizeof(metaFile));
  mediadb_prepend_dir(dir, METAFILE_DEFAULT, path, sizeof(path));
  if(fileops_stat(path, &st) == 0) {
    metafile_open(path, &metaFile, 1, 1);
  }

  while((direntry = fileops_ReadDir(pdir))) {

    VSX_DEBUG_MGR( LOG(X_DEBUGV("MGR - direntry_getentries d_name: '%s', isdir: %d"), 
           direntry->d_name, (direntry->d_type & DT_DIR)) );

    if(is_entry_ignored(metaFile.pignoreList, direntry->d_name)) {
      continue;
    }

    if(!(pdispname = find_entry_description(metaFile.pDescriptionList,
                                     direntry->d_name))) {
      pdispname = direntry->d_name;
    }

    if(searchstr && !is_match_search(pdispname, NULL, searchstr)) {
      continue;
    }

    memset(&entry, 0, sizeof(entry));
    strncpy(entry.d_name, direntry->d_name, sizeof(entry.d_name) - 1); 
    if(pdispname != direntry->d_name) {
      strncpy(entry.displayname, pdispname, sizeof(entry.displayname) - 1); 
    }
    entry.d_type = direntry->d_type;
    addEntry = 0;

    if(direntry->d_type & DT_DIR) {

      if(includedirs && mediadb_isvalidDirName(pMediaDb, direntry->d_name)) {
        addEntry = 1;
      }

    } else if(mediadb_isvalidFileName(pMediaDb, direntry->d_name, 1, 1)) {

      mediadb_prepend_dir(dir, direntry->d_name, path, sizeof(path));
      if(fileops_stat(path, &st) == 0) {
        entry.size = st.st_size;
        //entry.tm = st.st_mtime;
        entry.tm = st.st_ctime;

        if(fidxdir && (pFileEntry = file_list_find(&fileList, direntry->d_name))) {
          entry.numTn = pFileEntry->numTn; 
          entry.duration = pFileEntry->duration;
        }
        addEntry = 1;
      }

    }

    if(addEntry) {
      VSX_DEBUG_MGR( LOG(X_DEBUGV("MGR - direntry_getentries add d_name: '%s', isdir: %d"), 
           direntry->d_name, (direntry->d_type & DT_DIR)) );

      if(compareFunc || (idx >= startidx && (max == 0 || cnt < max))) {

        if(cnt >= DIR_ENTRY_LIST_BUFNUM) {
          LOG(X_WARNING("Not showing more than %d entries in %s"), cnt, dir);
          break;
        } else if(!(pEntry = direntry_addsorted(&pEntryList, &entry, compareFunc))) {
          LOG(X_ERROR("Failed to add directory entry '%s' to list"), direntry->d_name);
          rc = -1;
          break;
        }
        cnt++;
      }

      idx++;
      cntInDir++;
    }

  }

  //
  // Since when a sort is requested we have to sort every entry in the directory.  Now we can move the head pointer
  // to the first desired entry
  //
  if(pEntryList && compareFunc && startidx > 0) {
    pEntry = pEntryList->pHead;
    for(idx = 0; idx < startidx; idx++) {
      pEntry = pEntry->pnext;
      cnt--;
    }
    pEntryList->pHead = pEntry;
    if(cnt > max) {
      cnt = max;
    }
    //fprintf(stderr, "moved phead to %s, cnt:%d, cntInDir:%d\n", pEntryList->pHead ? pEntryList->pHead->d_name : NULL, cnt, cntInDir);
  }
  

  fileops_CloseDir(pdir);
  if(fidxdir) {
    file_list_close(&fileList);
  }
  metafile_close(&metaFile);

  if(rc == 0 && !pEntryList) {
    // If the user requested an index out of bounds, return an empty list with
    // a valid cntTotalInDir
    pEntryList = (DIR_ENTRY_LIST_T *) avc_calloc(1, sizeof(DIR_ENTRY_LIST_T));
  }

  if(pEntryList) {
    pEntryList->cntTotal = cnt; 
    pEntryList->cntTotalInDir = cntInDir; 
  }

  //if(pEntryList) fprintf(stderr, "DIR '%s' num:%d numAlloc:%d pnext:0x%x TOTAL:%d/%d\n", dir, pEntryList->num, pEntryList->numAlloc, pEntryList->pnext, pEntryList->cntTotal, pEntryList->cntTotalInDir);
 
  return pEntryList;
}
示例#13
0
static int readFramesFromDev(CAP_DEV_CFG_T *pCapDevCfg) {
  int rc = 0;
  TIME_VAL tv0, tv, tvSleep, tvStart;
  TIME_VAL tvElapsed = 0;
  TIME_VAL tvMark = 0;
  unsigned int frameIdx = 0;
  COLLECT_STREAM_PKTDATA_T pktdata;
  CAP_DEV_CTXT_T capDevCtxt;
  CAPTURE_FILTER_T *pFilter = &pCapDevCfg->pCapCfg->pcommon->filt.filters[pCapDevCfg->idxFilter];
  //BMP_FILE_T bmp;

  //memset(&bmp, 0, sizeof(bmp));
  memset(&capDevCtxt, 0, sizeof(capDevCtxt));
  capDevCtxt.dev = pCapDevCfg->pCapCfg->pcommon->localAddrs[pCapDevCfg->idxFilter];
  //capDevCtxt.dev = "./rawfmt.bmp";
  if(readFramesSetup(pFilter, &capDevCtxt.frame) < 0) {
    return -1;
  }

  //TODO: seperate out and maintain better throttle mechanism

  tv0 = tvStart = timer_GetTime();
  while(!g_proc_exit && pCapDevCfg->pCapCfg->running == 0) {

    //
    // Reading too slow, reset time reference
    //
    if(tvElapsed > tvMark + 300000) {
      LOG(X_WARNING("Resetting read time for %s after %llu ms > %llu ms (%.3ffps x %ufr)"),
        capDevCtxt.dev, tvElapsed / TIME_VAL_MS, 
        (TIME_VAL)((1000.0f / pFilter->fps) * frameIdx), pFilter->fps, frameIdx); 
      tv0 = timer_GetTime();
      frameIdx = 0;
    }    

    do {
      tv = timer_GetTime();
      tvElapsed = (tv - tv0);
      tvMark = (frameIdx / pFilter->fps) * TIME_VAL_US;

      if(tvElapsed < tvMark) {
        if((tvSleep = (tvMark - tvElapsed)) < 1000) {
          tvSleep = 1;
        }
        //fprintf(stderr, "sleeping %lld ns\n", tvSleep);
        usleep(tvSleep);
        tv = timer_GetTime();
        tvElapsed = (tv - tv0);
      }

    } while(tvElapsed < tvMark);

//if(frameIdx > 50) usleep(50000);
     

    //fprintf(stderr, "reading frame %d supposed to be:%lld  at:%lld\n", frameIdx, (TIME_VAL) (frameIdx*1000.0f/pFilter->fps),(timer_GetTime() - tv0)/ TIME_VAL_MS);

    if((rc = readFrameFromDev(&capDevCtxt)) < 0) {
      break;
    }

/*
    if((rc = bmp_create(&bmp, pFilter->mediaType,
               pFilter->width, pFilter->height,
               capDevCtxt.frame.pData)) < 0) {
      LOG(X_ERROR("Failed to create bmp %d x %d for format %d"), 
           pFilter->width, pFilter->height, pFilter->mediaType);
      break;
    }
    PKTLEN32(pktdata.payload) = BMP_GET_LEN(&bmp);
    pktdata.payload.pData = BMP_GET_DATA(&bmp);
*/

    pktdata.tv.tv_sec = (tv - tvStart) / TIME_VAL_US;
    pktdata.tv.tv_usec = (tv - tvStart) % TIME_VAL_US;
    PKTLEN32(pktdata.payload) = capDevCtxt.frame.len;
    pktdata.payload.pData = capDevCtxt.frame.pData;

    //fprintf(stderr, "got %d  bmp %d from %s %llu\n", capDevCtxt.frame.len, BMP_GET_LEN(&bmp), capDevCtxt.dev, tv - tvStart);

    pCapDevCfg->pStream->cbOnPkt(&pCapDevCfg->pStreamCbData->sp[0],
                                 (const COLLECT_STREAM_PKTDATA_T *) &pktdata);

    frameIdx++;
  }

  if(capDevCtxt.fd > 0) {
    close(capDevCtxt.fd);
  }
  free(capDevCtxt.frame.pBuf);
  //bmp_destroy(&bmp);

  return rc;
}
示例#14
0
int stream_net_h264_getSliceBytes(void *pArg, unsigned char *pBuf, unsigned int len) {
  STREAM_H264_T *pStreamH264 = (STREAM_H264_T *) pArg;
  uint32_t szSlice;
  unsigned int lenToRead = len;
  unsigned int bufIdx = 0;
  unsigned int fsIdxInSlice;

  if(pStreamH264->frame.pSlice == NULL) {
    return 0;
  }

  fsIdxInSlice = pStreamH264->frame.idxInSlice;
  szSlice = pStreamH264->frame.pSlice->content.sizeWr;
  if(pStreamH264->includeAnnexBHdr) {
    szSlice += 4;
  }

  if(len > szSlice - pStreamH264->frame.idxInSlice) {
    LOG(X_WARNING("Decreasing copy length from %u to (%u - %u)"), 
                  len, szSlice, pStreamH264->frame.idxInSlice);
    len = szSlice - pStreamH264->frame.idxInSlice;
  }

  if(pStreamH264->includeAnnexBHdr) {

    if(pStreamH264->frame.idxInSlice < 4) {

      while(pStreamH264->frame.idxInAnnexBHdr < 4 && bufIdx < len) {
        pBuf[bufIdx++] = (pStreamH264->frame.idxInAnnexBHdr == 3 ? 0x01 : 0x00);
        pStreamH264->frame.idxInAnnexBHdr++;
        lenToRead--;
        pStreamH264->frame.idxInSlice++;
      }
    
    }
    if(pStreamH264->frame.idxInSlice < 4) {
      return pStreamH264->frame.idxInSlice;
    } else {
      fsIdxInSlice = pStreamH264->frame.idxInSlice - 4;
    }

  }

/*
  if(pStreamH264->frame.pSlice == &pStreamH264->audSlice) {

    if(fsIdxInSlice + lenToRead > 2) {
      LOG(X_ERROR("Attempt to read AUD[%d] + %d > AUD len: 2\n"),  
                  fsIdxInSlice, lenToRead, 2);
      return -1;
    }

    pBuf[bufIdx] =  pStreamH264->audSlice.hdr;

    //
    // Mpeg4-Part10AVC Table 7-2 "Meaning of primary_pic_type"
    // 3 bits 0 - 7 ((7 << 5) = I,Si,P,SP,B possible slice types in primary coded picture)
    //
    pBuf[bufIdx + 1] = H264_AUD_I_SI_P_SP_B; 

  } else 
*/
  if(pStreamH264->frame.pSlice == &pStreamH264->spsSlice) {

    if(fsIdxInSlice + lenToRead > pStreamH264->pH264->spspps.sps_len) {
      LOG(X_ERROR("Attempt to read sps[%d] + %d > sps len: %d\n"),  
        fsIdxInSlice, lenToRead, pStreamH264->pH264->spspps.sps_len);
      return -1;
    }

    memcpy(&pBuf[bufIdx], &pStreamH264->pH264->spspps.sps[fsIdxInSlice], lenToRead);

  } else if(pStreamH264->frame.pSlice == &pStreamH264->ppsSlice) {

    if(fsIdxInSlice + lenToRead > pStreamH264->pH264->spspps.pps_len) {
      LOG(X_ERROR("Attempt to read pps[%d] + %d > pps len: %d\n"),  
        fsIdxInSlice, lenToRead, pStreamH264->pH264->spspps.pps_len);
      return -1;
    }

    memcpy(&pBuf[bufIdx], &pStreamH264->pH264->spspps.pps[fsIdxInSlice], lenToRead);


  } else {

    if(SeekMediaFile(pStreamH264->frame.pFileStream, 
                      pStreamH264->frame.pSlice->content.fileOffset + 
                      fsIdxInSlice, SEEK_SET) != 0) {
      return -1;
    }

    if(ReadFileStream(pStreamH264->frame.pFileStream, &pBuf[bufIdx], lenToRead) < 0) {
      return -1;
    }

  }

//if(pStreamH264->frame.idxInSlice <= 4) {
//fprintf(stderr, "h264 frameId:%d\n", pStreamH264->frame.frameId);
//if(pStreamH264->frame.pSlice->content.sizeWr > 65530) fprintf(stderr, "\n\n\n\nh264 size:%d\n", pStreamH264->frame.pSlice->content.sizeWr); 
//fprintf(stderr, "h264 size:%d\n", pStreamH264->frame.pSlice->content.sizeWr); 
//avc_dumpHex(stderr, pBuf, 16, 1);
//}

  pStreamH264->frame.idxInSlice += lenToRead;

  return len;
}
示例#15
0
int flvsrv_create_vidframe_h264(BYTE_STREAM_T *bs, CODEC_VID_CTXT_T *pFlvV, 
                                const OUTFMT_FRAME_DATA_T *pFrame, 
                                uint32_t *pmspts, int32_t *pmsdts, int keyframe) {

  int rc = 0;
  unsigned int frameIdx = 0;
  uint32_t mspts = 0;
  int32_t msdts = 0;
  uint8_t frameType;
  unsigned char *pData = NULL;
  unsigned int lenData = 0;

  if(!pFlvV || !pFrame) {
    return -1;
  }

  if(!pmspts) {
    pmspts = &mspts;
  }
  if(!pmsdts) {
    pmsdts = &msdts;
  }

  //
  // Omit NAL AUD
  //
  if((rc = h264_check_NAL_AUD(OUTFMT_DATA(pFrame), OUTFMT_LEN(pFrame))) > 0) {
    frameIdx = rc;
  }

  if(OUTFMT_LEN(pFrame) < frameIdx) {
    LOG(X_ERROR("Invalid video frame length: %d"), OUTFMT_LEN(pFrame));
    return -1;
  }

  if(OUTFMT_PTS(pFrame) > pFlvV->tmprev) {
    *pmspts = (uint32_t) (OUTFMT_PTS(pFrame) - pFlvV->tmprev) / 90.0f;
  }
  pFlvV->tmprev += (*pmspts * 90);
  //hdrsz = 8; // hdr size < 12 has relative timestamps

  //if(*pmspts > 50 || *pmspts <= 0) fprintf(stderr, "funky mspts:%d\n", *pmspts);
  //if(pFrame->pts > pFlvV->tm0) {
  //  *pmspts = (pFrame->pts - pFlvV->tm0) / 90.0f;
  //}


  if(OUTFMT_DTS(pFrame) != 0) {
    *pmsdts = (int32_t) (OUTFMT_DTS(pFrame) / 90.0f);
  }
  //*pmsdts = *pmspts;
  //if(pFrame->pts > pRtmp->av.vid.tmprev) {
  //  *pmsdts = (uint32_t) (pFrame->pts - pFlvV->tmprev) / 90.0f;
  //}
  //pFlvV->tmprev = pFrame->pts;

  //TODO: check if the dts is actually a +/- offset from the pts, or an absolute time
  //pFlvV->tmprev = pFrame->pts + pFrame->dts - pFlvV->tm0;
  //pFlvV->tmprev = pFrame->pts - pFlvV->tm0;
  //tm = (uint32_t) (pFlvV->tmprev / 90.0f);
  //tm = (pFlvV->tmprev / 90.0f) - *pmsdts; hdrsz = 8; // hdr size < 12 has relative timestamps

  if(OUTFMT_LEN(pFrame) - frameIdx > pFlvV->tmpFrame.sz) {
    LOG(X_ERROR("h264 frame size too large %d for buffer size %d"),
                OUTFMT_LEN(pFrame) - frameIdx, pFlvV->tmpFrame.sz);
    return -1;
  }

  memcpy(pFlvV->tmpFrame.buf, &OUTFMT_DATA(pFrame)[frameIdx], OUTFMT_LEN(pFrame) - frameIdx);
  pData = pFlvV->tmpFrame.buf;
  lenData = OUTFMT_LEN(pFrame) - frameIdx;

  //LOG(X_DEBUG("Before convert to h264b len:%d"), lenData); LOGHEX_DEBUG(pData, MIN(48, lenData));

  //
  // Remove any SPS/PPS, which could potentially contain 3 byte start codes
  //
  pData = vidframe_h264_removenals(pData, &lenData);
  //LOG(X_DEBUG("lenData:%d, orig:%d"), lenData, OUTFMT_LEN(pFrame));
  if(lenData <= 0) {
    LOG(X_WARNING("h264 flv/rtmp/mkv frame length is %d, original: %d"), lenData, OUTFMT_LEN(pFrame));
  }

  h264_converth264bToAvc(pData, lenData);

  //LOG(X_DEBUG("After convert to h264b len:%d"), lenData); LOGHEX_DEBUG(pData, MIN(48, lenData));

/*
  //fprintf(stderr, "len:%d 0x%x 0x%x\n", lenData, pData[3], pData[4]);
  while(lenData > 4 && ((pData[4] & NAL_TYPE_MASK) == NAL_TYPE_SEQ_PARAM ||
                        (pData[4] & NAL_TYPE_MASK) == NAL_TYPE_PIC_PARAM)) {
    rc = (int) htonl( *(uint32_t *)pData );
    pData += (4 + rc);
    lenData -= (4 + rc);
    //fprintf(stderr, "decrement vid size to:%d by 4 + %d\n", lenData, rc);
  }
  //fprintf(stderr, "now len:%d 0x%x 0x%x\n", lenData, pData[3], pData[4]);
  LOG(X_DEBUG("After convert to h264b and remove of seq params len:%d"), lenData); LOGHEX_DEBUG(pData, MIN(16, lenData));

*/

  //if((pData[4] & NAL_NRI_MASK) == NAL_NRI_HI) {
  //  pData[4] &= ~NAL_NRI_MASK;
  //  pData[4] |= NAL_NRI_MED;
  //}

  if(bs) {
    //bs.idx = hdrsz;
    //bs.buf = &pRtmp->out.buf[pRtmp->out.idx];
    //bs.sz = pRtmp->out.sz - pRtmp->out.idx;

    frameType = keyframe ? FLV_VID_FRM_KEYFRAME : FLV_VID_FRM_INTERFRAME;
    bs->buf[bs->idx++] = (frameType << 4) | (FLV_VID_CODEC_AVC);
    bs->buf[bs->idx++] = FLV_VID_AVC_PKTTYPE_NALU;
    flv_write_int24(bs, *pmsdts); // composition time
  }

  pFlvV->tmpFrame.idx = (pData - pFlvV->tmpFrame.buf);

  return lenData;
}
示例#16
0
static const char *get_m3u8(CAP_ASYNC_DESCR_T *pCfg,
                         const char *puri,
                         HTTP_RESP_T *pHttpResp,
                         HTTP_PARSE_CTXT_T *pHdrCtxt,
                         unsigned char *pbuf, unsigned int szbuf) {
  int sz = 0;
  struct timeval tv0, tv1;
  unsigned int consumed = 0;
  unsigned int contentLen = 0;
  unsigned int tmtms = 0;
  unsigned char *pdata = NULL;

  gettimeofday(&tv0, NULL);

  //fprintf(stderr, "GET M3U... puri:'%s', hdrslen:%d\n", puri, pHdrCtxt->hdrslen);

  if(pHdrCtxt->hdrslen == 0) {

    if((httpcli_gethdrs(pHdrCtxt, pHttpResp, &pCfg->pSockList->salist[0], puri,
          http_getConnTypeStr(HTTP_CONN_TYPE_CLOSE), 0, 0, pCfg->pcommon->addrsExtHost[0], NULL)) < 0) {
      return NULL;
    }

  }

  if((pdata = http_get_contentlen_start(pHttpResp, pHdrCtxt, pbuf, szbuf, 1, &contentLen))) {
    consumed = pHdrCtxt->idxbuf - pHdrCtxt->hdrslen;
  }

  if(pdata && net_setsocknonblock(NETIOSOCK_FD(pCfg->pSockList->netsockets[0]), 1) < 0) {
 
    pdata = NULL;
  }

//fprintf(stderr, "NET_RECV in m3u... %d < %d idxbuf:%d hdrslen:%d pdata:0x%x\n", consumed, contentLen, pHdrCtxt->idxbuf, pHdrCtxt->hdrslen, pdata);

  while(pdata && consumed < contentLen && !g_proc_exit) {

    if((sz = netio_recvnb(&pCfg->pSockList->netsockets[0],
                          (unsigned char *) &pdata[consumed],
                          contentLen - consumed, 500)) > 0) {
      consumed += sz;
    }
//fprintf(stderr, "NET REceiving... %d < %d, %d tmtms:%d\n", consumed, contentLen, sz, tmtms);
    gettimeofday(&tv1, NULL);
    if(tmtms > 0 && consumed < contentLen && TIME_TV_DIFF_MS(tv1, tv0) > (unsigned int) tmtms) {
      LOG(X_WARNING("HTTP %s:%d%s timeout %d ms exceeded"),
           inet_ntoa(pCfg->pSockList->salist[0].sin_addr),
           ntohs(pCfg->pSockList->salist[0].sin_port), puri, tmtms);
      pdata = NULL;
      break;
    }
  }

  if(pdata && contentLen > 0 && consumed >= contentLen) {
    pdata[consumed] = '\0';
  } else {
    pdata = NULL;
  }

  //fprintf(stderr, "GOT m3u...0x%x %d < %d\n", pdata, consumed, contentLen);avc_dumpHex(stderr, pdata, consumed, 1);
  return (const char *) pdata;
}
示例#17
0
static int createTn(const MEDIADB_DESCR_T *pMediaDb,
                    FILE_LIST_ENTRY_T *pFileListEntry, 
                    const char *pathMedia, const char *pathTn,
                    int numTn, int maxTnInIter) {
  int rc = 0;
  int highestTn = 0;
  struct stat st;
  unsigned int idx;
  char buf[VSX_MAX_PATH_LEN];
  char cmd[VSX_MAX_PATH_LEN];
  char cmdnice[64];
  char tmpfile[VSX_MAX_PATH_LEN];
  int numTnCreated = 0;
  char avcthumbsize[32];
  unsigned int secOffset;
  const char *avcthumb = pMediaDb->avcthumb;
  const char *avcthumblog = pMediaDb->avcthumblog;
  const char *avcthumb_file = avcthumb;
  const char *avcthumblog2 = avcthumblog;
#ifdef WIN32
  char curdir[VSX_MAX_PATH_LEN];
  char avcthumblogpath[VSX_MAX_PATH_LEN];
  char avcthumblogpath2[VSX_MAX_PATH_LEN];
  char avcthumblogprefix[64];
  size_t sz;
#endif // WIN32
#if defined(FFMPEG_THUMB_NEW)
  const char thumbsizedelim = ':';
#else // (FFMPEG_THUMB_NEW)
  const char thumbsizedelim = 'x';
#endif //  (FFMPEG_THUMB_NEW)

  tmpfile[0] = '\0';
  cmdnice[0] = '\0';

  //fprintf(stdout, "createTn '%s' numTn:%d, maxTnIter:%d, TN_MAX:%d, g_proc_exit:%d (0x%x)\n", pathTn, numTn, maxTnInIter, SRVMEDIA_TN_MAX, g_proc_exit, &g_proc_exit);

  for(idx = 0; idx < SRVMEDIA_TN_MAX; idx++) {

    if(idx > 0) {
      secOffset = (idx - 1) * SRVMEDIA_TN_INTERVAL_SEC;
    } else {
      secOffset = 4;
    }


    if(pFileListEntry->duration == 0) {

      snprintf(tmpfile, sizeof(tmpfile), "%s%s"VSXTMP_EXT, pathTn, pMediaDb->tn_suffix);
      if(fileops_stat(tmpfile, &st) != 0) {
 
        if(numTn == 0 && idx == 0) {
//fprintf(stdout, "creating tmp file '%s'\n", tmpfile);
          //
          // Create tmpfile which should only exist during 
          // creation of thumbnails for source of unknown duration
          // Since the "tn=" parameter in the index file denotes
          // the current number of thumbnails available
          //
          if(fileops_touchfile(tmpfile) != 0) {
            LOG(X_ERROR("Failed to create %s"), tmpfile);
          }
        } else if((int) idx >= numTn) {
//fprintf(stdout, "breaking out, have all the tns %d > %d\n", idx, numTn);
          break;
        }

      } else if(idx == SRVMEDIA_TN_MAX - 1) {
//fprintf(stdout, "removing tmp file '%s'\n", tmpfile);
        fileops_DeleteFile(tmpfile);
      }

    } else if(pFileListEntry->duration > 0 && secOffset >= pFileListEntry->duration - 1) {
      break;
    }

    if(idx == 0) {
      snprintf(avcthumbsize, sizeof(avcthumbsize), "%d%c%d", 
               pMediaDb->smTnWidth, thumbsizedelim, pMediaDb->smTnHeight);
      snprintf(buf, sizeof(buf), "%s%s.jpg", pathTn, pMediaDb->tn_suffix);    
    } else {
      snprintf(avcthumbsize, sizeof(avcthumbsize), "%d%c%d", 
               pMediaDb->lgTnWidth, thumbsizedelim, pMediaDb->lgTnHeight);
      snprintf(buf, sizeof(buf), "%s%s%u.jpg", pathTn, pMediaDb->tn_suffix, idx - 1);    
    }

    if(fileops_stat(buf, &st) < 0  || st.st_size == 0) {

#ifdef WIN32

      //
      // cd into directory of avcthumb script
      //
      avcthumblogprefix[0] = '\0';
      curdir[0] = '\0';
      fileops_getcwd(curdir, sizeof(curdir));
      if((sz = mediadb_getdirlen(avcthumb)) > 0) {
        if(sz >= sizeof(tmpfile)) {
          sz = sizeof(tmpfile) - 1;
        }
        tmpfile[sizeof(tmpfile) - 1] = '\0';
        strncpy(tmpfile, avcthumb, sizeof(tmpfile));
        if(sz > 0) {
          tmpfile[sz] = '\0';
          fileops_setcwd(tmpfile);
          avcthumb_file = &avcthumb[sz];
          snprintf(avcthumblogprefix, sizeof(avcthumblogprefix), "..\\");
        }
      }
      if(avcthumblog) {
        snprintf(avcthumblogpath, sizeof(avcthumblogpath), "%s%s", 
                 avcthumblogprefix, avcthumblog);
        snprintf(avcthumblogpath2, sizeof(avcthumblogpath2), "%s%s.err", 
                 avcthumblogprefix, avcthumblog);
        avcthumblog2 = avcthumblogpath2;
        avcthumblog = avcthumblogpath;
      }

#else

      snprintf(cmdnice, sizeof(cmdnice), "nice -n19 ");

#endif // WIN32
      

#if defined(FFMPEG_THUMB_NEW)
      //
      //TODO: create multiple thumbs on one run... will speed thnigs up alot!
      // '-ss 4 -vf "thumbnail,scale=164:90,fps=1/4" -frames:v 8'
      //
      snprintf(cmd, sizeof(cmd), "%s%s -v warning -i \"%s\" -an -vf \"thumbnail,scale=%s\" "
               "-frames:v 1 -f image2 -vcodec mjpeg -ss %u \"%s\" %s%s %s%s", 
               cmdnice,
               avcthumb_file, pathMedia, avcthumbsize, secOffset, buf, 
               avcthumblog ? ">>" : "", avcthumblog ? avcthumblog : "",
               avcthumblog2 ? "2>>" : "", avcthumblog2 ? avcthumblog2 : "");

#else // (FFMPEG_THUMB_NEW)
      snprintf(cmd, sizeof(cmd), "%s%s -i \"%s\" -an -s \"%s\" "
               "-vframes 1 -f image2 -vcodec mjpeg -ss %u \"%s\" %s%s %s%s", 
               cmdnice,
               avcthumb_file, pathMedia, avcthumbsize, secOffset, buf, 
               avcthumblog ? ">>" : "", avcthumblog ? avcthumblog : "",
               avcthumblog2 ? "2>>" : "", avcthumblog2 ? avcthumblog2 : "");
#endif // (FFMPEG_THUMB_NEW)
    
//if(numcmd++ > 2) {
//  return 0;
//}
      LOG(X_DEBUG("Creating thumbnail '%s'"), cmd);
      //TODO: seems that we're not getting SIGINT in the parent here... need a way to spawn (async?) & wait/poll
      rc = system(cmd);

#ifdef WIN32
      if(curdir[0] != '\0') {
        fileops_setcwd(curdir);
      }
#endif // WIN3

      //LOG(X_DEBUG("DOING STAT ON '%s'"), buf);
      if(fileops_stat(buf, &st) == 0  && st.st_size > 0) {
        rc = 0;
        highestTn = idx + 1;
        if(maxTnInIter > 0 && ++numTnCreated >= maxTnInIter) {
          break;
        }
      } else {
        rc = -1;
        LOG(X_WARNING("Failed to generate thumbnail '%s'"), buf);

        if(pFileListEntry->duration == 0) {
          snprintf(tmpfile, sizeof(tmpfile), "%s%s"VSXTMP_EXT, pathTn, pMediaDb->tn_suffix);    

          if(fileops_stat(tmpfile, &st) == 0) {
            fileops_DeleteFile(tmpfile);
          }
        } else {
          snprintf(tmpfile, sizeof(tmpfile), "%s%s."NOTN_EXT, pathTn, pMediaDb->tn_suffix);    
          if(fileops_touchfile(tmpfile) != 0) {
            LOG(X_ERROR("Failed to create %s"), tmpfile);
          }
        }

        if(idx == 0) {
          return -1;
        }
        break;
      }

    } else {
      highestTn = idx + 1;
    }

  }
  
  return highestTn;
}
示例#18
0
static int onPkt_h264(CAPTURE_CBDATA_SP_T *pSp, CAPTURE_STORE_CBDATA_T *pCbData,
              const unsigned char *pData, const unsigned int len, int recurselevel) {

  int nalType;
  int rc = 0;
  uint16_t nalLen;
  unsigned int idx = 0;

  if(pData == NULL || len == 0) {
    // TODO: write empty NAL
    LOG(X_WARNING("RTP H.264 lost slice len:%d, %s, ssrc: 0x%x"), 
        len, pSp->pStream->strSrcDst, pSp->pStream->hdr.key.ssrc);
    pSp->spFlags |= (CAPTURE_SP_FLAG_DAMAGEDFRAME | CAPTURE_SP_FLAG_PREVLOST);
    return 0;
  } else if(recurselevel > 10) {
    LOG(X_WARNING("RTP H.264 maximum STAP nesting level reached:%d"), recurselevel);
    return 0;
  }


  nalType = pData[idx] & NAL_TYPE_MASK;
  //fprintf(stderr, "nal: %d\n", nalType); avc_dumpHex(stderr, &pData[idx], 4, 0);

  switch(nalType) {

    case NAL_TYPE_IDR:
    case NAL_TYPE_SEI:

      //
      // Prepend any SPS/PPS (from SDP) if not present in this GOP
      //
      if(pSp->pStream->pFilter->u_seqhdrs.vid.u.h264.spspps.sps_len > 0 &&
        !(pSp->spFlags & CAPTURE_SP_FLAG_H264_HAVESPS)) {

        if((rc = writeNALFromNet(pCbData, 
                 pSp->pStream->pFilter->u_seqhdrs.vid.u.h264.spspps.sps_buf,
                 pSp->pStream->pFilter->u_seqhdrs.vid.u.h264.spspps.sps_len, 1)) < 0) {
          return rc; 
        }
        pSp->spFlags |= CAPTURE_SP_FLAG_H264_HAVESPS;
      }

      if((pSp->spFlags & CAPTURE_SP_FLAG_H264_HAVESPS) &&
        pSp->pStream->pFilter->u_seqhdrs.vid.u.h264.spspps.pps_len > 0 &&
        !(pSp->spFlags & CAPTURE_SP_FLAG_H264_HAVEPPS)) {

        if((rc = writeNALFromNet(pCbData, 
                 pSp->pStream->pFilter->u_seqhdrs.vid.u.h264.spspps.pps_buf,
                 pSp->pStream->pFilter->u_seqhdrs.vid.u.h264.spspps.pps_len, 1)) < 0) {
          return rc; 
        }
        pSp->spFlags |= CAPTURE_SP_FLAG_H264_HAVEPPS;
      }


      pSp->spFlags |= CAPTURE_SP_FLAG_KEYFRAME;

      if((rc = writeNALFromNet(pCbData, pData, len, 1)) < 0) {
        return rc; 
      }
      break;

    case NAL_TYPE_NONSPECIFIC:
    case NAL_TYPE_SLICE:
    case NAL_TYPE_PARTITION_2:
    case NAL_TYPE_PARTITION_3:
    case NAL_TYPE_PARTITION_4:

      if((rc = writeNALFromNet(pCbData, pData, len, 1)) < 0) {
        return rc; 
      }
      break;

    case NAL_TYPE_SEQ_PARAM:

      pSp->spFlags |= CAPTURE_SP_FLAG_H264_HAVESPS;

      if((rc = writeNALFromNet(pCbData, pData, len, 1)) < 0) {
        return rc; 
      }
      break;

    case NAL_TYPE_PIC_PARAM:
      pSp->spFlags |= CAPTURE_SP_FLAG_H264_HAVEPPS;

      if((rc = writeNALFromNet(pCbData, pData, len, 1)) < 0) {
        return rc; 
      }
      break;

    case NAL_TYPE_STAP_A:

      idx++;
      do {
        nalLen = htons(*((uint16_t *) &pData[idx]));
        idx += 2;
        if(nalLen + idx > len) {
          LOG(X_WARNING("RTP H.264 Invalid STAP-A NAL length: %d  (%u/%d, "), 
            nalLen, idx, len - idx);
          return -1;
        } else if(nalLen > 0) {
          if((rc = onPkt_h264(pSp, pCbData, &pData[idx], nalLen, recurselevel + 1)) < 0) {
            return rc;
          }
        }
        idx += nalLen;

      } while(idx + 3 < len);

      break;

    case NAL_TYPE_FRAG_A:

     // Frag Unit header 1 bit start, 1 bit end, 1 bit reserved=0, 5 bits nal type
      nalType = pData[++idx] & NAL_TYPE_MASK;

      if(nalType == NAL_TYPE_IDR) {
        pSp->spFlags |= CAPTURE_SP_FLAG_KEYFRAME;
      }

      if(pData[idx] & 0x80) { // start bit set

        pSp->spFlags |= CAPTURE_SP_FLAG_HAVEFRAGMENTSTART;

        //fprintf(stderr, "frag start nal: %d flag:%d\n", nalType, pSp->spFlags); avc_dumpHex(stderr, &pData[idx], 4, 0);

        ((unsigned char *)pData)[idx] &= 0x1f;
        ((unsigned char *)pData)[idx] |= (NAL_NRI_MASK & pData[idx - 1]);
        if((rc = writeNALFromNet(pCbData, &pData[idx], len - idx, 1)) < 0) {
          return rc;
        }

      } else {

        //
        // If the previous packet(s) were lost, and this is a fragment,
        // ensure it is not a fragment continuation
        //
        if(!(pSp->spFlags & CAPTURE_SP_FLAG_HAVEFRAGMENTSTART) || (pSp->spFlags & CAPTURE_SP_FLAG_PREVLOST)) {
          //fprintf(stderr, "setting H.264 DROPFRAME flag\n");
          pSp->spFlags |= (CAPTURE_SP_FLAG_DAMAGEDFRAME | CAPTURE_SP_FLAG_DROPFRAME);
        }

        //fprintf(stderr, "frag cont nal: %d flag:%d\n", nalType, pSp->spFlags); avc_dumpHex(stderr, &pData[idx], 4, 0);

        idx++;
        if((rc = writeNALFromNet(pCbData, &pData[idx], len - idx, 
                               (pSp->spFlags & CAPTURE_SP_FLAG_HAVEFRAGMENTSTART) ? 0 : 1)) < 0) {
          return rc;
        }

        pSp->spFlags |= CAPTURE_SP_FLAG_HAVEFRAGMENTSTART;

      }

      break;

    default:
      LOG(X_WARNING("RTP H.264 Unsupported nal type: %d"), nalType);
      break;

  }

  return (int)(len - idx);
}
示例#19
0
static int iterate_subdirs(const MEDIADB_DESCR_T *pMediaDb, const char *pathDb, 
                           const char *pathMedia, int level, unsigned int iterIdx) {
  DIR *pdir;
  FILE_LIST_T fileList;
  FILE_LIST_ENTRY_T *pFileListEntry;
  struct dirent *direntry;
  char bufMedia[VSX_MAX_PATH_LEN];
  char bufDb[VSX_MAX_PATH_LEN];
  char tmpfile[VSX_MAX_PATH_LEN];
  int rc = 0;
  int rcsub = 0;
  int fileListChanged = 0;
  int numTnCreated = 0;
  int highestTn;
  struct stat st;

//fprintf(stdout, "%d dir:'%s' '%s'\n", level, pathDb, pathMedia);

  //
  // TODO: escape invalid chars in pathnames ' , & # $ '
  // 

  if(level >= SRVMEDIA_MAX_LEVELS) {
    LOG(X_WARNING("Path '%s' exceeded max number of subdirs under %s"), 
        pathMedia, pMediaDb->mediaDir);
    return -1;
  }

  if(!(pdir = fileops_OpenDir(pathMedia))) {
    return -1;
  }

  memset(&fileList, 0, sizeof(fileList));
  file_list_read(pathDb, &fileList);
  strncpy(fileList.pathmedia, pathMedia, sizeof(fileList.pathmedia) - 1);


  while((direntry = fileops_ReadDir(pdir)) && g_proc_exit == 0) {
//fprintf(stdout, "- %d %s\n", level, direntry->d_name);
    if(direntry->d_type & DT_DIR) {

      if(mediadb_isvalidDirName(pMediaDb, direntry->d_name)) {

        if(mediadb_prepend_dir(pathDb, direntry->d_name, bufDb, sizeof(bufDb)) < 0) {
          LOG(X_WARNING("Unable to concatenate subdir %s %s"), bufDb, direntry->d_name);
        } else if(mediadb_prepend_dir(pathMedia, direntry->d_name, bufMedia, sizeof(bufMedia)) < 0) {
          LOG(X_WARNING("Unable to concatenate subdir %s %s"), bufMedia, direntry->d_name);
        } else {

          if(numTnCreated > 1) {
            file_list_write(pathDb, &fileList);
          }

          if((rcsub = iterate_subdirs(pMediaDb, bufDb, bufMedia, 
                                      level+1, iterIdx)) < 0) {
            rc = rcsub;
          }
          if(g_proc_exit != 0) {
            break;
          }

        }

      } else if(direntry->d_name[0] != '.') {
        //fprintf(stderr, "skipping directory '%s'\n", direntry->d_name);
      }

    } else if(mediadb_isvalidFileName(pMediaDb, direntry->d_name, 1, 0)) {

//fprintf(stdout, "%d media file %s '%s'\n", level, pathMedia, direntry->d_name);

      if(fileops_stat(pathDb, &st) != 0 && mediadb_mkdirfull(pMediaDb->dbDir, pathDb) < 0) {
        continue;
      } 

      if(mediadb_prepend_dir(pathDb, direntry->d_name, bufDb, sizeof(bufDb)) < 0) {
        LOG(X_ERROR("Unable to concatenate subdir %s %s"), bufDb, direntry->d_name);
        continue;
      } else if(mediadb_prepend_dir(pathMedia, direntry->d_name, bufMedia, sizeof(bufMedia)) < 0) {
        LOG(X_ERROR("Unable to concatenate subdir %s %s"), bufMedia, direntry->d_name);
        continue;
      }

      if(update_fileentry(&fileList, direntry->d_name, bufMedia, &pFileListEntry) > 0) {

        LOG(X_DEBUG("'%s' changed ('%s')"), direntry->d_name, pFileListEntry->name);

        fileListChanged = 1;
        if(pFileListEntry->numTn < 0) {
          pFileListEntry->numTn = 0;
        }

      }

      if(pMediaDb->avcthumb && pFileListEntry && pFileListEntry->vstr[0] != '\0' &&
         pFileListEntry->numTn != -1) {

        //
        // On very first iteration, check all thumbnails
        //
        snprintf(tmpfile, sizeof(tmpfile), "%s%s."NOTN_EXT, bufDb, pMediaDb->tn_suffix);

        if(fileops_stat(tmpfile, &st) == 0 && iterIdx > 0) {
          //  
          // Ignore thumbnail creation if the .notn file has been
          // previously created on an error condition
          //

        } else 
        //
        // Update thumbnail info
        //
        if((highestTn = createTn(pMediaDb, pFileListEntry, bufMedia, bufDb, 
            pFileListEntry->numTn, 1)) > pFileListEntry->numTn || highestTn == -1) {

          pFileListEntry->numTn = highestTn;
          fileListChanged = 1;

          // Periodically update the db file
          if(numTnCreated > 10) {
            file_list_write(pathDb, &fileList);
            numTnCreated = 0;
          }

        }

      }

    } else {
//fprintf(stdout, "skipping %s '%s'\n", pathMedia, direntry->d_name);
    }

  }

  fileops_CloseDir(pdir);

  if(g_proc_exit == 0) {

    if(file_list_removeunmarked(&fileList) || fileListChanged) {

       LOG(X_DEBUG("Writing file index in %s"), pathDb);
//fprintf(stdout, "level:%u\n", level);
      file_list_write(pathDb, &fileList);
    }

    //
    //Remove thumbnails which are not included in the fileList
    //
    clearTn(pathMedia, pathDb, &fileList);
  }

  file_list_close(&fileList);

  return rc;
}
示例#20
0
int mp4_extractRaw(const MP4_CONTAINER_T *pMp4, const char *outPrfx, 
                   float fStart, float fDuration, int overwrite,
                   int extractVid, int extractAud) {

  BOX_HDLR_T *pBoxHdlr;
  BOX_T *pBoxTrak;
  BOX_T *pBox;
  MP4_TRAK_T mp4Trak;
  char *outPath = NULL;
  size_t szPath;
  FILE_HANDLE fp;
  int rc = 0;

  if(!pMp4|| !pMp4->pStream || !pMp4->pStream->cbCheckFd(pMp4->pStream) ||
     !outPrfx) {
    return -1;
  } else if(!extractVid && !extractAud) {
    return -1;
  }

  if(!(pBoxTrak = mp4_findBoxInTree(pMp4->proot, *((uint32_t *) "moov"))) || 
     !(pBoxTrak = pBoxTrak->child)) {
    LOG(X_ERROR("No tracks found in mp4"));
    return -1;
  }

  while(pBoxTrak) {

    if(pBoxTrak->type != *((uint32_t *) "trak") ||
       !(pBoxHdlr = (BOX_HDLR_T *) mp4_findBoxInTree(pBoxTrak, *((uint32_t *) "hdlr")))) {

      pBoxTrak = pBoxTrak->pnext;
      continue;
    }

    memset(&mp4Trak, 0, sizeof(MP4_TRAK_T));
    mp4Trak.pTrak = pBoxTrak;
    pBox = fillTrack(&mp4Trak, 0);

    if(!pBox) {
      pBoxTrak = pBoxTrak->pnext;
      continue;
    }

    szPath = strlen(outPrfx);
    outPath = (char *) avc_calloc(1, szPath + 8);
    memcpy(outPath, outPrfx, szPath);
    rc = 0;

    if(pBoxHdlr->handlertype == *((uint32_t *) "soun") ||
       pBoxHdlr->handlertype == *((uint32_t *) "sdsm")) {

      if(extractAud) {
        if(mp4_findBoxInTree(pBoxTrak,  *((uint32_t *) "mp4a"))) {
          strncpy(&outPath[szPath], ".aac", 7);
        } else {
          LOG(X_WARNING("Unknown audio track %c%c%c%c written as raw output"), 
                ((unsigned char *)&pBox->type)[0], ((unsigned char *)&pBox->type)[1],
                ((unsigned char *)&pBox->type)[2], ((unsigned char *)&pBox->type)[3]);
          strncpy(&outPath[szPath], ".araw", 7);
        }
      } else {
        pBox = NULL;
      }    

    } else if(pBoxHdlr->handlertype == *((uint32_t *) "vide")) {

      if(extractVid) {
        if(mp4_findBoxInTree(pBoxTrak,  *((uint32_t *) "avc1"))) {
          strncpy(&outPath[szPath], ".h264", 7);
        } else if(mp4_findBoxInTree(pBoxTrak,  *((uint32_t *) "mp4v"))) {
          strncpy(&outPath[szPath], ".mpg4", 7);
        } else {
          LOG(X_WARNING("Unknown video track %c%c%c%c written as raw output"), 
                ((unsigned char *)&pBox->type)[0], ((unsigned char *)&pBox->type)[1],
                ((unsigned char *)&pBox->type)[2], ((unsigned char *)&pBox->type)[3]);
          strncpy(&outPath[szPath], ".vraw", 7);
        }
      } else {
        pBox = NULL;
      }    

    } else {
      pBox = NULL; 
    }

    if(pBox) {

      if(!overwrite && (fp = fileops_Open(outPath, O_RDONLY)) != FILEOPS_INVALID_FP) {
         fileops_Close(fp);
         LOG(X_ERROR("File %s already exists.  Will not overwrite."), outPath);
         free(outPath);
         pBoxTrak = pBoxTrak->pnext;
         continue;
      }

      if(pBox->type == *((uint32_t *) "avc1")) {
        rc = mp4_extractAvcVid(pMp4, outPath, fStart, fDuration);
      } else if(pBox->type == *((uint32_t *) "mp4v")) {
        rc = mp4_extractMp4Vid(pMp4, outPath, fStart, fDuration);
      } else if(pBox->type == *((uint32_t *) "mp4a")) {
        rc = mp4_extractAacAud(pMp4, outPath, fStart, fDuration);
      } else {
        rc = extractGenericTrak(pMp4, &mp4Trak, outPath, fStart, fDuration);
      }

      if(rc == 0) {
        LOG(X_INFO("Created %s"), outPath);
      }
      free(outPath);

    }

    pBoxTrak = pBoxTrak->pnext;
  }


  return rc;
} 
示例#21
0
int sdputil_init(SDP_DESCR_T *pSdp,
                 uint8_t payloadType,
                 unsigned int clockRateHz,
                 XC_CODEC_TYPE_T codecType,
                 const char *pDstHost,
                 uint16_t dstPort,
                 uint16_t dstPortRtcp,
                 const SRTP_CTXT_T *pSrtp,
                 const DTLS_CFG_T *pDtlsCfg,
                 const STUN_REQUESTOR_CFG_T *pStunCfg,
                 const SDP_CODEC_PARAM_T *pCodecSpecific,
                 const FRAME_RATE_T *pFps,
                 const VID_ENCODER_FBREQUEST_T *pFbReq) {

  int rc = 0;
  char tmp[128];
  struct sockaddr_storage connectip;

  if(!pSdp || payloadType > 0x7f || !pDstHost) {
    return -1;
  }

  memset(&connectip, 0, sizeof(connectip));
  if(!net_isipv4(pDstHost) && !net_isipv6(pDstHost)) {
    //
    // INADDR_NONE
    //
    pDstHost = "0.0.0.0";
  }

  net_getaddress(pDstHost, &connectip);
  if(INET_ADDR_VALID(connectip) && INET_IS_MULTICAST(connectip)) {
    pSdp->c.ttl = 64;
  } else if(INET_ADDR_VALID(connectip) && INET_ADDR_LOCALHOST(connectip)) {
    pSdp->c.ttl = 0;
  } else {
    //connectip.s_addr = net_getlocalip();

    //
    // For remote unicast destinations, leave the remote ip into the 'c=' field
    // which may be contrary to RFC4566
    //
    //connectip.s_addr = INADDR_ANY;

    pSdp->c.ttl = 0;
  }

  pSdp->c.ip_family = connectip.ss_family;
  strncpy(pSdp->c.iphost, INET_NTOP(connectip, tmp, sizeof(tmp)), sizeof(pSdp->c.iphost));

  //
  // Only write the RTCP port attribute in the SDP if using a non-default port
  //
  if(dstPortRtcp == RTCP_PORT_FROM_RTP(dstPort)) {
    dstPortRtcp = 0;   
  } 

  if(pFps && pFps->clockHz > 0 && pFps->frameDeltaHz > 0) {
    memcpy(&pSdp->vid.fps, pFps, sizeof(pSdp->vid.fps));
  }
  switch(codecType) {

    case XC_CODEC_TYPE_H264:
    case XC_CODEC_TYPE_MPEG4V:
    case XC_CODEC_TYPE_H263:
    case XC_CODEC_TYPE_H263_PLUS:
    case XC_CODEC_TYPE_VP8:
      pSdp->vid.common.available = 1;
      pSdp->vid.common.codecType = codecType;
      pSdp->vid.common.payloadType = payloadType;
      pSdp->vid.common.port = dstPort;
      pSdp->vid.common.portRtcp = dstPortRtcp;
      pSdp->vid.common.clockHz = clockRateHz;
      pSdp->vid.common.transType = SDP_TRANS_TYPE_RTP_UDP;

      if(pDtlsCfg) {
        if(pDtlsCfg->dtls_srtp) {
          pSdp->vid.common.transType = SDP_TRANS_TYPE_SRTP_DTLS_UDP;
        } else {
          pSdp->vid.common.transType = SDP_TRANS_TYPE_DTLS_UDP;
        }
        memcpy(&pSdp->vid.common.fingerprint, &pDtlsCfg->fingerprint, sizeof(pSdp->vid.common.fingerprint));
      }
      if(pSrtp) {
        pSdp->vid.common.transType =  SDP_TRANS_TYPE_SRTP_SDES_UDP;
        if((rc = sdputil_initsrtp(&pSdp->vid.common.srtp, pSrtp)) < 0) {
          return rc;
        }
      }
      if(pStunCfg && pStunCfg->bindingRequest) {
        if(pStunCfg->reqUsername) {
          strncpy(pSdp->vid.common.ice.ufrag, pStunCfg->reqUsername, STUN_STRING_MAX - 1);
        }
        if(pStunCfg->reqPass) {
          strncpy(pSdp->vid.common.ice.pwd, pStunCfg->reqPass, STUN_STRING_MAX - 1);
        }
      }
      
      if(codecType == XC_CODEC_TYPE_H264) {
        strncpy(pSdp->vid.common.encodingName, SDP_RTPMAP_ENCODINGNAME_H264,
          sizeof(pSdp->vid.common.encodingName));
      } else if(codecType == XC_CODEC_TYPE_MPEG4V) {
        strncpy(pSdp->vid.common.encodingName, SDP_RTPMAP_ENCODINGNAME_MPEG4V,
          sizeof(pSdp->vid.common.encodingName));
      } else if(codecType == XC_CODEC_TYPE_H263) {
        strncpy(pSdp->vid.common.encodingName, SDP_RTPMAP_ENCODINGNAME_H263,
          sizeof(pSdp->vid.common.encodingName));
      } else if(codecType == XC_CODEC_TYPE_H263_PLUS) {
        strncpy(pSdp->vid.common.encodingName, SDP_RTPMAP_ENCODINGNAME_H263_PLUS,
          sizeof(pSdp->vid.common.encodingName));
      } else if(codecType == XC_CODEC_TYPE_VP8) {
        strncpy(pSdp->vid.common.encodingName, SDP_RTPMAP_ENCODINGNAME_VP8,
          sizeof(pSdp->vid.common.encodingName));
      }

      break;
    case XC_CODEC_TYPE_AAC:
    case XC_CODEC_TYPE_AMRNB:
    case XC_CODEC_TYPE_SILK:
    case XC_CODEC_TYPE_OPUS:
    case XC_CODEC_TYPE_G711_MULAW:
    case XC_CODEC_TYPE_G711_ALAW:
      pSdp->aud.common.available = 1;
      pSdp->aud.common.codecType = codecType;
      pSdp->aud.common.payloadType = payloadType;
      pSdp->aud.common.port = dstPort;
      pSdp->aud.common.portRtcp = dstPortRtcp;
      pSdp->aud.common.clockHz = clockRateHz;
      pSdp->aud.common.transType = SDP_TRANS_TYPE_RTP_UDP;

      if(pDtlsCfg) {
        if(pDtlsCfg->dtls_srtp) {
          pSdp->aud.common.transType = SDP_TRANS_TYPE_SRTP_DTLS_UDP;
        } else {
          pSdp->aud.common.transType = SDP_TRANS_TYPE_DTLS_UDP;
        }
        memcpy(&pSdp->aud.common.fingerprint, &pDtlsCfg->fingerprint, sizeof(pSdp->aud.common.fingerprint));
      }
      if(pSrtp) {
        pSdp->aud.common.transType =  SDP_TRANS_TYPE_SRTP_SDES_UDP;
        if((rc = sdputil_initsrtp(&pSdp->aud.common.srtp, pSrtp)) < 0) {
          return rc;
        }
      }

      if(pStunCfg && pStunCfg->bindingRequest) { 
        if(pStunCfg->reqUsername) {
          strncpy(pSdp->aud.common.ice.ufrag, pStunCfg->reqUsername, STUN_STRING_MAX - 1);
        }
        if(pStunCfg->reqPass) {
          strncpy(pSdp->aud.common.ice.pwd, pStunCfg->reqPass, STUN_STRING_MAX - 1);
        }
      }

      if(codecType == XC_CODEC_TYPE_AAC) {
        strncpy(pSdp->aud.common.encodingName, SDP_RTPMAP_ENCODINGNAME_AAC,
          sizeof(pSdp->aud.common.encodingName));
      } else if(codecType == XC_CODEC_TYPE_AMRNB) {
        strncpy(pSdp->aud.common.encodingName, SDP_RTPMAP_ENCODINGNAME_AMR,
          sizeof(pSdp->aud.common.encodingName));
      } else if(codecType == XC_CODEC_TYPE_SILK) {
        strncpy(pSdp->aud.common.encodingName, SDP_RTPMAP_ENCODINGNAME_SILK,
          sizeof(pSdp->aud.common.encodingName));
      } else if(codecType == XC_CODEC_TYPE_OPUS) {
        strncpy(pSdp->aud.common.encodingName, SDP_RTPMAP_ENCODINGNAME_OPUS,
          sizeof(pSdp->aud.common.encodingName));
      } else if(codecType == XC_CODEC_TYPE_G711_MULAW) {
        strncpy(pSdp->aud.common.encodingName, SDP_RTPMAP_ENCODINGNAME_PCMU,
          sizeof(pSdp->aud.common.encodingName));
      } else if(codecType == XC_CODEC_TYPE_G711_ALAW) {
        strncpy(pSdp->aud.common.encodingName, SDP_RTPMAP_ENCODINGNAME_PCMA,
          sizeof(pSdp->aud.common.encodingName));
      }

      break;
    case MEDIA_FILE_TYPE_MP2TS:
      pSdp->vid.common.available = 1;
      pSdp->vid.common.codecType = MEDIA_FILE_TYPE_MP2TS;
      pSdp->vid.common.payloadType = payloadType;
      pSdp->vid.common.port = dstPort;
      pSdp->vid.common.portRtcp = dstPortRtcp;
      pSdp->vid.common.clockHz = 90000;

      if(pSrtp) {
        pSdp->vid.common.transType =  SDP_TRANS_TYPE_SRTP_SDES_UDP;
        if((rc = sdputil_initsrtp(&pSdp->vid.common.srtp, pSrtp)) < 0) {
          return rc;
        }
      }

      strncpy(pSdp->vid.common.encodingName, SDP_RTPMAP_ENCODINGNAME_MP2TS,
          sizeof(pSdp->vid.common.encodingName));
      break;
    default:
      return -1;
  }
 
  //
  // Advertise any a=rtcp-fb:  SDP flags
  //
  if(pSdp->vid.common.available) {
   if(pFbReq && (pFbReq->firCfg.fir_send_from_decoder || pFbReq->firCfg.fir_send_from_local ||
                 pFbReq->firCfg.fir_send_from_remote || pFbReq->firCfg.fir_send_from_capture)) {
      pSdp->vid.common.rtcpfb.fmtidmin1 = pSdp->vid.common.payloadType + 1;
      pSdp->vid.common.rtcpfb.flags |= SDP_RTCPFB_TYPE_CCM | SDP_RTCPFB_TYPE_CCM_FIR;
    }
   if(pFbReq && pFbReq->nackRtpRetransmit) {
    pSdp->vid.common.rtcpfb.flags |= SDP_RTCPFB_TYPE_NACK | SDP_RTCPFB_TYPE_NACK_GENERIC;
   }
    //pSdp->vid.common.rtcpfb.flags |= SDP_RTCPFB_TYPE_TRRINT;
    //pSdp->vid.common.rtcpfb.trrIntervalMs |= 30;
  }

  //
  // Codec specific default settings
  //
  switch(codecType) {

    case XC_CODEC_TYPE_H264:

      if(pCodecSpecific && (pCodecSpecific->flags & SDP_CODEC_PARAM_FLAGS_PKTZMODE)) {

        switch(pCodecSpecific->u.pktzMode) {
          case PKTZ_H264_MODE_0:
            pSdp->vid.u.h264.packetization_mode = 0;
            break;
          case PKTZ_H264_MODE_2:
            LOG(X_WARNING("H.264 NAL Packetization mode 2 not supported.  Using mode 1")); 
          case PKTZ_H264_MODE_1:
          case PKTZ_H264_MODE_NOTSET:
          default:
            pSdp->vid.u.h264.packetization_mode = 1;
            break;
       }

     }

     break;

    case XC_CODEC_TYPE_MPEG4V:

      pSdp->vid.u.mpg4v.profile_level_id = 1;
      break;

    case XC_CODEC_TYPE_VP8:
      break;

    case XC_CODEC_TYPE_AAC:
      strncpy(pSdp->aud.u.aac.mode, "AAC-hbr", sizeof(pSdp->aud.u.aac.mode));
      pSdp->aud.u.aac.sizelength = 13;
      pSdp->aud.u.aac.indexlength = 3;
      pSdp->aud.u.aac.indexdeltalength = 3;
      break;

    case XC_CODEC_TYPE_AMRNB:

      pSdp->aud.channels = 1;
      pSdp->aud.u.amr.octet_align = 1;

      break;

    case XC_CODEC_TYPE_SILK:

      if(pCodecSpecific && (pCodecSpecific->flags & SDP_CODEC_PARAM_FLAGS_CHANNELS)) {
        pSdp->aud.channels = pCodecSpecific->u.channels;
      } else {
        pSdp->aud.channels = 1;
      }

      //pSdp->aud.u.silk.dummy = 0;

      break;

    case XC_CODEC_TYPE_OPUS:

      if(pCodecSpecific && (pCodecSpecific->flags & SDP_CODEC_PARAM_FLAGS_CHANNELS)) {
        pSdp->aud.channels = pCodecSpecific->u.channels;;
      } else {
        pSdp->aud.channels = 1;
      }

      break;

    case XC_CODEC_TYPE_G711_MULAW:
    case XC_CODEC_TYPE_G711_ALAW:

      pSdp->aud.channels = 1;
      break;

    default:
      break;
  }

  return rc;
}
示例#22
0
static void httplive_mediaproc(void *pArg) {
  HTTPLIVE_CLIENT_T *pClient = (HTTPLIVE_CLIENT_T *) pArg;
  int rc = 0;
  const char *p;
  const char *puri = NULL;
  char path[VSX_MAX_PATH_LEN];

  pClient->running = 0;

  LOG(X_DEBUG("Starting HTTPLive client media thread"));

  path[sizeof(path) - 1] = '\0';

  while(rc >= 0 && pClient->pCfg->running == 0 && pClient->insession) {

    path[0] = '\0';

    pthread_mutex_lock(&pClient->mtx);

    if(pClient->nextidx > pClient->curidx) {
      LOG(X_WARNING("HTTPLive skipping playlist media chunk index %d - %d"),
                     pClient->curidx, pClient->nextidx - 1);
      pClient->curidx = pClient->nextidx;
      //pClient->nextidx++;
    }

    if((p = find_path(&pClient->pl, pClient->curidx))) {
      strncpy(path, p, sizeof(path) - 1);
    } else {

    }
    pthread_mutex_unlock(&pClient->mtx);

    if(!(puri = get_uri_from_path(pClient, path))) {
      rc = -1;
      break;
    }

    if(puri && puri[0] != '\0') {

      // TODO: create httplive retrieval flag forcing new socket... lame
      if(NETIOSOCK_FD(pClient->netsock) != INVALID_SOCKET && net_issockremotelyclosed(NETIOSOCK_FD(pClient->netsock), 1)) {
        LOG(X_DEBUG("HTTPLive media socket has been closed")); 
        netio_closesocket(&pClient->netsock);
      }

      if(NETIOSOCK_FD(pClient->netsock) == INVALID_SOCKET) {

      //fprintf(stderr, "----MEDIA GET for '%s' '%s'\n", path, puri);

        if((rc = httpcli_connect(&pClient->netsock, &pClient->sa, "HTTPLive media thread")) < 0) {
          break;
        }

      }

      //fprintf(stderr, "may call get_ts puri:'%s', idx:%d, next:%d\n", puri, pClient->curidx, pClient->nextidx);

      if((rc = get_ts(pClient, puri)) >= 0) {

        //fprintf(stderr, "HTTPLive ts retrieval '%s' returned %d\n", puri, rc);

        pthread_mutex_lock(&pClient->mtx);
        pClient->nextidx++;
        pClient->curidx = pClient->nextidx;
        pthread_mutex_unlock(&pClient->mtx);
      }

    } // end of if(puri && puri[0] != '\0' ...

    sleep(1);

  }

  netio_closesocket(&pClient->netsock);

  pClient->insession = 0;
  pClient->running = -1;

  LOG(X_DEBUG("HTTPLive media download thread exiting with code %d"), rc);
}
示例#23
0
static BOX_T *mp4_loadMovieFrag(BOX_T *pPrevMoof, MP4_MOOF_TRAK_T *pMoofTrak, uint32_t trackid) {
  BOX_TRAF_T *pBoxTraf;
  BOX_TFHD_T *pBoxTfhd = NULL;
  int64_t dataOffset = 0;

  if(!pPrevMoof) {
    return NULL;
  }

  //memset(pMoofTrak, 0, sizeof(MP4_MOOF_TRAK_T));
  pMoofTrak->pTfhd = NULL;

  //fprintf(stderr, "loadMovieFrag called for trackid:%d, pTfhd: 0x%x, mdat:0x%x\n", trackid, pMoofTrak->pTfhd, pMoofTrak->pMdat);

  do {

    if(!(pMoofTrak->pMoof = mp4_findBoxNext(pPrevMoof, *((uint32_t *) "moof")))) {
      //LOG(X_ERROR("Unable to find moof box"));
      return NULL;
    }

    if(!(pMoofTrak->pMdat = mp4_findBoxNext(pMoofTrak->pMdat ? pMoofTrak->pMdat : pPrevMoof, 
                                            *((uint32_t *) "mdat")))) {
      LOG(X_ERROR("Unable to find moof mdat box"));
      return NULL;
    }

    if(!(pMoofTrak->pMfhd = (BOX_MFHD_T *) mp4_findBoxChild(pMoofTrak->pMoof, *((uint32_t *) "mfhd")))) {
      LOG(X_ERROR("Unable to find mfhd box"));
      return NULL;
    }

    //
    // TODO: A moof w/ audio + video, may contain multiple traf / tfhd boxes
    // the 'continue' below should first try to look for a next 'traf / tfhd box
    //
    if(!(pBoxTraf = mp4_findBoxNext((BOX_T *) pMoofTrak->pMfhd, *((uint32_t *) "traf")))) {
      LOG(X_ERROR("Unable to find traf box"));
      return NULL;
    }

    if(!(pBoxTfhd = (BOX_TFHD_T *) mp4_findBoxChild(pBoxTraf, *((uint32_t *) "tfhd")))) {
      LOG(X_ERROR("Unable to find tfhd box"));
      return NULL;
    } else if(pBoxTfhd->trackid != trackid) {
      pPrevMoof = pMoofTrak->pMoof;
      //fprintf(stderr, "loadMovieFrag skipping moof trackid:%d\n", pBoxTfhd->trackid);
      continue;
    }
    pMoofTrak->pTfhd = pBoxTfhd;

    if(!(pMoofTrak->pTrun = (BOX_TRUN_T *) mp4_findBoxChild(pBoxTraf, *((uint32_t *) "trun")))) {
      LOG(X_ERROR("Unable to find trun box"));
      return NULL;
    }

    if((pMoofTrak->pTfhd->flags & TFHD_FLAG_BASE_DATA_OFFSET)) {
      dataOffset += pMoofTrak->pTfhd->base_data_offset;
    }
    if((pMoofTrak->pTrun->flags & TRUN_FLAG_DATA_OFFSET)) {
      dataOffset += pMoofTrak->pTrun->data_offset;
    }

    pMoofTrak->fileOffset = pMoofTrak->pMoof->fileOffset + dataOffset;

    //fprintf(stderr, "loadMovieFrag called for trackid:%d fileOffset: 0x%llx (0x%llx + 0x%llx)\n", trackid, pMoofTrak->fileOffset, pMoofTrak->pMoof->fileOffset,  dataOffset);

    if((pMoofTrak->fileOffset != pMoofTrak->pMdat->fileOffsetData)) {
      LOG(X_WARNING("Moof data offset mismatch mdat 0x%"LL64"x + 0x%"LL64"x != 0x%"LL64"x"),
                    pMoofTrak->pMoof->fileOffset, dataOffset, pMoofTrak->pMdat->fileOffsetData);
    }
 
  } while(!pMoofTrak->pTfhd || pMoofTrak->pTfhd->trackid != trackid);

  //fprintf(stderr, "loadMovieFrag returning...\n");

  return pMoofTrak->pMoof;
}
示例#24
0
static void srv_rtmp_proc(void *pfuncarg) {
  CLIENT_CONN_T *pConn = (CLIENT_CONN_T *) pfuncarg;
  STREAMER_CFG_T *pStreamerCfg = NULL;
  STREAMER_OUTFMT_T *pLiveFmt = NULL;
  STREAM_STATS_T *pstats = NULL;
  RTMP_CTXT_T rtmpCtxt;
  unsigned int numQFull = 0;
  char buf[SAFE_INET_NTOA_LEN_MAX];
  OUTFMT_CFG_T *pOutFmt = NULL;

  pStreamerCfg = GET_STREAMER_FROM_CONN(pConn);

  if(pStreamerCfg && pStreamerCfg->action.liveFmts.out[STREAMER_OUTFMT_IDX_RTMP].do_outfmt) {

    pLiveFmt = &pStreamerCfg->action.liveFmts.out[STREAMER_OUTFMT_IDX_RTMP];

    if(pStreamerCfg->pMonitor && pStreamerCfg->pMonitor->active) {
      if(!(pstats = stream_monitor_createattach(pStreamerCfg->pMonitor,
                      &pConn->sd.sain, STREAM_METHOD_RTMP, STREAM_MONITOR_ABR_NONE))) {
      }
    }

    //
    // Add a livefmt cb
    //
    pOutFmt = outfmt_setCb(pLiveFmt, rtmp_addFrame, &rtmpCtxt, &pLiveFmt->qCfg, pstats, 1, pStreamerCfg->frameThin, &numQFull);

  } 

  if(pOutFmt) {

    memset(&rtmpCtxt, 0, sizeof(rtmpCtxt));

    rtmp_init(&rtmpCtxt, MAX(pLiveFmt->qCfg.maxPktLen, pLiveFmt->qCfg.growMaxPktLen));
    rtmpCtxt.pSd = &pConn->sd;
    rtmpCtxt.novid = pStreamerCfg->novid;
    rtmpCtxt.noaud = pStreamerCfg->noaud;
    rtmpCtxt.av.vid.pStreamerCfg = pStreamerCfg;
    rtmpCtxt.av.aud.pStreamerCfg = pStreamerCfg;

    //
    // Unpause the outfmt callback mechanism now that rtmp_init was called
    //
    outfmt_pause(pOutFmt, 0);

    LOG(X_INFO("Starting rtmp stream[%d] %d/%d to %s:%d"), pOutFmt->cbCtxt.idx, numQFull + 1, 
           pLiveFmt->max,
           net_inet_ntoa(pConn->sd.sain.sin_addr, buf), ntohs(pConn->sd.sain.sin_port));

    rtmp_handle_conn(&rtmpCtxt);

    LOG(X_INFO("Ending rtmp stream[%d] to %s:%d"), pOutFmt->cbCtxt.idx,
           net_inet_ntoa(pConn->sd.sain.sin_addr, buf), ntohs(pConn->sd.sain.sin_port));

    //
    // Remove the livefmt cb
    //
    outfmt_removeCb(pOutFmt);

    rtmp_close(&rtmpCtxt);

  } else {

    if(pstats) {
      //
      // Destroy automatically detaches the stats from the monitor linked list
      //
      stream_stats_destroy(&pstats, NULL);
    }

    LOG(X_WARNING("No rtmp resource available (max:%d) for %s:%d"), 
        (pLiveFmt ? pLiveFmt->max : 0),
       net_inet_ntoa(pConn->sd.sain.sin_addr, buf), ntohs(pConn->sd.sain.sin_port));

  }

  netio_closesocket(&pConn->sd.netsocket);

  LOG(X_DEBUG("RTMP connection thread ended %s:%d"), net_inet_ntoa(pConn->sd.sain.sin_addr, buf),
                                        ntohs(pConn->sd.sain.sin_port));

}
示例#25
0
static int mp4_readSampleFromTrack_int(MP4_EXTRACT_STATE_INT_T *pState, 
                                       MP4_MDAT_CONTENT_NODE_T *pContent,
                                       uint32_t *pSampleDurationHz) {
  int sampleSize;
  int sampleHz;

  //fprintf(stderr, "readSampleFromTrack tkhdid:%d, mdat: 0x%x, isobmff:%d, tkhd_id:%d, chunk_idx:%d, file:%llu/%llu %lluHz\n", pState->pExtSt->trak.pTkhd->trackid, pState->pExtSt->trak.pMdat, pState->pExtSt->trak.moofTrak.pMp4Root, pContent->tkhd_id, pContent->chunk_idx, pContent->fileOffset, pContent->pStreamIn ? pContent->pStreamIn->size : 0, pContent->playOffsetHz);
  //fprintf(stderr, "readSampleFromTrack sample[%d], chunk[%d], sampleinchunk[%d]/%d, chunkOffset:%d, stsc[%d]\n", pState->u.tk.idxSample, pState->u.tk.idxChunk, pState->u.tk.idxSampleInChunk, pState->u.tk.samplesInChunk, pState->u.tk.chunkOffset,  pState->u.tk.idxStsc);

  //
  // If this is a fragmented mp4 look at the moof data
  //
  if(pState->pExtSt->trak.moofTrak.pMp4Root) {
    return readSampleFromISOBMFF(pState, pContent, pSampleDurationHz);
  }

  if(!pState->u.tk.isinit ||
     pState->u.tk.idxSampleInChunk >= (unsigned int) pState->u.tk.samplesInChunk) {

    pState->u.tk.chunkOffset = 0;
    pState->u.tk.idxSampleInChunk = 0;

    if(pState->u.tk.isinit) {
      pState->u.tk.idxChunk++;
    }

    if((pState->u.tk.samplesInChunk = getSamplesInChunk(pState->pExtSt->trak.pStsc, 
                                                pState->u.tk.idxChunk, 
                                                &pState->u.tk.idxStsc)) < 0) {

      if(pState->u.tk.idxChunk == 0 && pState->u.tk.idxStsc == 0) {
        pState->pExtSt->atEndOfTrack = 1;
      } else {
        LOG(X_ERROR("Invalid samples in chunks for chunk[%d], stsc[%d]"), 
                    pState->u.tk.idxChunk, pState->u.tk.idxStsc);
      }
      return -1;
    }

  }
  //fprintf(stderr, "IDXCHUNK:%d/%d, IDXSTSC:%d\n", pState->u.tk.idxChunk, pState->pExtSt->trak.pStco->entrycnt, pState->u.tk.idxStsc); 
  if(pState->u.tk.idxChunk >= pState->pExtSt->trak.pStco->entrycnt) {

    //
    // Reached the end of the track
    //
    pState->pExtSt->atEndOfTrack = 1;
    LOG(X_WARNING("sample table chunk sample index end[%d/%d], stsc[%d]"), 
        pState->u.tk.idxChunk, pState->pExtSt->trak.pStco->entrycnt, pState->u.tk.idxStsc);

    return -1;
  }

  if((sampleSize = getSamplesSize(pState->pExtSt->trak.pStsz, pState->u.tk.idxSample)) < 0) {
    LOG(X_ERROR("Invalid sample size for sample[%d], chunk[%d] (sample:%u)"), 
          pState->u.tk.idxSampleInChunk, pState->u.tk.idxChunk, pState->u.tk.idxSample);
    return -1;
  }     

  if((sampleHz = getSampleDuration(pState->pExtSt->trak.pStts, &pState->u.tk.idxSampleInStts, 
                                   &pState->u.tk.idxStts)) < 0) {
    return -1;
  }

  if(isSyncSample(pState->pExtSt->trak.pStss, &pState->u.tk.idxStss, pState->u.tk.idxSample)) {
    pContent->flags = MP4_MDAT_CONTENT_FLAG_SYNCSAMPLE;
  } else {
    pContent->flags = 0;
  }

  pContent->sizeRd = sampleSize;
  pContent->chunk_idx = pState->u.tk.idxChunk; 
  pContent->fileOffset = pState->pExtSt->trak.pStco->pSamples[pState->u.tk.idxChunk] +
                         pState->u.tk.chunkOffset;

//fprintf(stdout, "chunk:%d smpl:%u(%u)%d chk in file:0x%x +0x%x (0x%llx)\n", pState->u.tk.idxChunk, pState->u.tk.idxSampleInChunk,pState->u.tk.idxSample,pContent->flags,pState->pExtSt->trak.pStco->pSamples[pState->u.tk.idxChunk],pState->u.tk.chunkOffset, pContent->fileOffset);

  if(pSampleDurationHz) {
    *pSampleDurationHz = sampleHz;
  }

  pState->u.tk.idxSample++;
  pState->u.tk.idxSampleInChunk++;
  pState->u.tk.chunkOffset += sampleSize;

  if(pState->u.tk.isinit == 0) {
    pState->u.tk.isinit = 1;
  }

  return 0;
}
示例#26
0
static void srvlisten_http_proc(void *pArg) {

  SRV_LISTENER_CFG_T *pListenCfg = (SRV_LISTENER_CFG_T *) pArg;
  NETIO_SOCK_T netsocksrv;
  struct sockaddr_in  sa;
  CLIENT_CONN_T *pConn;
  unsigned int tsMax = 0;
  unsigned int flvMax = 0;
  unsigned int mkvMax = 0;
/*
  int haveMkvAuth = 0; 
  int haveFlvAuth = 0; 
  int haveTsliveAuth = 0; 
  int haveHttpliveAuth = 0; 
  int haveMoofAuth = 0; 
  int haveConfigAuth = 0; 
  int havePipAuth = 0; 
  int haveStatusAuth = 0; 
  int haveRootAuth = 0; 
*/
  int haveAuth = 0;
  int rc = 0;
  char buf[SAFE_INET_NTOA_LEN_MAX];

  logutil_tid_add(pthread_self(), pListenCfg->tid_tag);

  if((pListenCfg->urlCapabilities & (URL_CAP_TSLIVE | URL_CAP_TSHTTPLIVE | URL_CAP_FLVLIVE |
                                     URL_CAP_MKVLIVE | URL_CAP_LIVE | URL_CAP_STATUS | URL_CAP_MOOFLIVE |
                                     URL_CAP_PIP | URL_CAP_CONFIG | URL_CAP_BROADCAST)) == 0) {
    LOG(X_WARNING("http listener exiting because no capabilities enabled on %s:%d"),
        inet_ntoa(pListenCfg->sain.sin_addr), ntohs(pListenCfg->sain.sin_port));
    logutil_tid_remove(pthread_self());
    return;
  }

  memset(&sa, 0, sizeof(sa));
  memset(&netsocksrv, 0, sizeof(netsocksrv));
  sa.sin_family = PF_INET;
  sa.sin_addr = pListenCfg->sain.sin_addr;
  sa.sin_port = pListenCfg->sain.sin_port;
  netsocksrv.flags = pListenCfg->netflags;

  if((NETIOSOCK_FD(netsocksrv) = net_listen(&sa, 5)) == INVALID_SOCKET) {
    logutil_tid_remove(pthread_self());
    return;
  }

  pthread_mutex_lock(&pListenCfg->mtx);
  pListenCfg->pnetsockSrv = &netsocksrv;
  pthread_mutex_unlock(&pListenCfg->mtx);

  if(pListenCfg->pAuthStore && IS_AUTH_CREDENTIALS_SET(pListenCfg->pAuthStore)) {
    haveAuth = 1;
  }

  pConn = (CLIENT_CONN_T *) pListenCfg->pConnPool->pElements;
  if(pConn) {
    tsMax = pConn->pStreamerCfg0->liveQs[0].max;
    flvMax = pConn->pStreamerCfg0->action.liveFmts.out[STREAMER_OUTFMT_IDX_FLV].max;
    mkvMax = pConn->pStreamerCfg0->action.liveFmts.out[STREAMER_OUTFMT_IDX_MKV].max;

/*
    if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_FLV].stores[pListenCfg->idxCfg])) {
      haveFlvAuth = 1;
    }
    if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_MKV].stores[pListenCfg->idxCfg])) {
      haveMkvAuth = 1;
    }
    if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_TSLIVE].stores[pListenCfg->idxCfg])) {
      haveTsliveAuth = 1;
    }
    if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_HTTPLIVE].stores[pListenCfg->idxCfg])) {
      haveHttpliveAuth = 1; 
    }
    if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_MOOFLIVE].stores[pListenCfg->idxCfg])) {
      haveMoofAuth = 1; 
    }
    if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_CONFIG].stores[pListenCfg->idxCfg])) {
      haveConfigAuth = 1; 
    }
    if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_PIP].stores[pListenCfg->idxCfg])) {
      havePipAuth = 1; 
    }
    if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_STATUS].stores[pListenCfg->idxCfg])) {
      haveStatusAuth = 1; 
    }
    if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_ROOT].stores[pListenCfg->idxCfg])) {
      haveRootAuth = 1; 
    }
*/

    //if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds.auths[STREAMER_AUTH_IDX_ROOT])) {
    //  LOG(X_DEBUG("LIVE/ROOT AUTH ON")); 
    //}
  }

  if((pListenCfg->urlCapabilities & URL_CAP_ROOTHTML)) {
    LOG(X_INFO("broadcast interface available at "URL_HTTP_FMT_STR"%s%s%s max:%d"), 
           URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_ROOT_URL,
           //(haveRootAuth ? " (Using auth)" : ""),
           (haveAuth ? " (Using auth)" : ""),
           (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), pListenCfg->max);
  }

  if((pListenCfg->urlCapabilities & URL_CAP_LIVE)) {
    LOG(X_INFO("live available at "URL_HTTP_FMT_STR"%s%s%s max:%d"), 
           URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_LIVE_URL,
           //(haveRootAuth ? " (Using auth)" : ""),
           (haveAuth ? " (Using auth)" : ""),
           (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), pListenCfg->max);
  }

  if((pListenCfg->urlCapabilities & URL_CAP_TSLIVE)) {
    LOG(X_INFO("tslive available at "URL_HTTP_FMT_STR"%s%s%s max:%d"), 
           URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_TSLIVE_URL,
           //(haveTsliveAuth ? " (Using auth)" : ""),
           (haveAuth ? " (Using auth)" : ""),
           (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), tsMax);
  }

  if((pListenCfg->urlCapabilities & URL_CAP_TSHTTPLIVE)) {
    LOG(X_INFO("httplive available at "URL_HTTP_FMT_STR"%s%s%s max:%d"), 
           URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_HTTPLIVE_URL,
           //(haveHttpliveAuth ? " (Using auth)" : ""),
           (haveAuth ? " (Using auth)" : ""),
           (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), pListenCfg->max);
  }

  if((pListenCfg->urlCapabilities & URL_CAP_FLVLIVE)) {
    LOG(X_INFO("flvlive available at "URL_HTTP_FMT_STR"%s%s%s max:%d"), 
           URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_FLVLIVE_URL,
           //(haveFlvAuth ? " (Using auth)" : ""),
           (haveAuth ? " (Using auth)" : ""),
           (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), flvMax);
  }

  if((pListenCfg->urlCapabilities & URL_CAP_MKVLIVE)) {
    LOG(X_INFO("mkvlive available at "URL_HTTP_FMT_STR"%s%s%s max:%d"), 
           URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_MKVLIVE_URL,
           //(haveMkvAuth ? " (Using auth)" : ""),
           (haveAuth ? " (Using auth)" : ""),
           (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), mkvMax);
  }

  if((pListenCfg->urlCapabilities & URL_CAP_MOOFLIVE)) {
    LOG(X_INFO("dash available at "URL_HTTP_FMT_STR"%s%s%s max:%d"), 
           URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_DASH_URL,
           // (haveMoofAuth ? " (Using auth)" : ""),
           (haveAuth ? " (Using auth)" : ""),
           (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), pListenCfg->max);
  }

  if((pListenCfg->urlCapabilities & URL_CAP_STATUS)) {
    LOG(X_INFO("status available at "URL_HTTP_FMT_STR"%s%s%s"), 
           URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_STATUS_URL,
            //(haveStatusAuth ? " (Using auth)" : ""),
            (haveAuth ? " (Using auth)" : ""),
           (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""));
  }

  if((pListenCfg->urlCapabilities & URL_CAP_PIP)) {
    LOG(X_INFO("pip available at "URL_HTTP_FMT_STR"%s%s%s"), 
           URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_PIP_URL,
            //(havePipAuth ? " (Using auth)" : ""),
            (haveAuth ? " (Using auth)" : ""),
           (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""));
  }

  if((pListenCfg->urlCapabilities & URL_CAP_CONFIG)) {
    LOG(X_INFO("config available at "URL_HTTP_FMT_STR"%s%s%s"), 
           URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_CONFIG_URL,
            //(haveConfigAuth ? " (Using auth)" : ""),
            (haveAuth ? " (Using auth)" : ""),
           (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""));
  }

  //fprintf(stderr, "LISTENER THREAD %s %s:%d active:%d cap: 0x%x\n", pListenCfg->netflags & NETIO_FLAG_SSL_TLS ? "SSL" : "", inet_ntoa(sa.sin_addr), ntohs(sa.sin_port), pListenCfg->active, pListenCfg->urlCapabilities);

  //
  // Service any client connections on the live listening port
  //
  rc = srvlisten_loop(pListenCfg, srv_cmd_proc);

  pthread_mutex_lock(&pListenCfg->mtx);
  pListenCfg->pnetsockSrv = NULL; 
  netio_closesocket(&netsocksrv);
  pthread_mutex_unlock(&pListenCfg->mtx);

  LOG(X_WARNING("HTTP listener thread exiting with code: %d"), rc);

  logutil_tid_remove(pthread_self());

  return;
}
示例#27
0
int srvlisten_loop(SRV_LISTENER_CFG_T *pListenCfg, void *thread_func) {

  int salen;
  THREAD_FUNC_WRAPPER_ARG_T wrapArg;
  CLIENT_CONN_T *pConn;
  SOCKET_DESCR_T sdclient;
  int rc = -1;
  const char *s;
  //pthread_cond_t cond;
  pthread_mutex_t mtx;
  TIME_VAL tv0, tv1;
  char tmp[128];

#if defined(__APPLE__) 
  int sockopt = 0;
#endif // __APPLE__

  if(!pListenCfg || !pListenCfg->pnetsockSrv || !pListenCfg->pConnPool || !thread_func || 
     pListenCfg->pConnPool->numElements <= 0) {
    return -1;
  }

  //memset(&saSrv, 0, sizeof(saSrv));
  memset(&sdclient.netsocket, 0, sizeof(sdclient.netsocket));
  //salen = sizeof(saSrv);

  //if(getsockname(pListenCfg->pnetsockSrv->sock, (struct sockaddr *) &saSrv,  (socklen_t *) &salen) != 0) {
  //  LOG(X_ERROR("getsockopt failed on server socket"));
  //}

  pthread_mutex_init(&mtx, NULL);
  //pthread_cond_init(&cond, NULL);

  while(!g_proc_exit) {

    salen = sizeof(sdclient.sa);
    if((NETIOSOCK_FD(sdclient.netsocket) = 
                 accept(PNETIOSOCK_FD(pListenCfg->pnetsockSrv), (struct sockaddr *) &sdclient.sa, 
                                      (socklen_t *) &salen)) == INVALID_SOCKET) {
      if(!g_proc_exit) {
        LOG(X_ERROR("%saccept failed on %s:%d"), 
             ((pListenCfg->pnetsockSrv->flags & NETIO_FLAG_SSL_TLS) ? "SSL " : ""),
                 //inet_ntoa(saSrv.sin_addr), ntohs(saSrv.sin_port));
                 FORMAT_NETADDR(pListenCfg->sa, tmp, sizeof(tmp)), ntohs(INET_PORT(pListenCfg->sa)));
      }
      break;
    }

    if(g_proc_exit) {
      break;
    }

    sdclient.netsocket.flags = pListenCfg->pnetsockSrv->flags;

    //
    // Find an available client thread to process the client request
    //
    if((pConn = (CLIENT_CONN_T *) pool_get(pListenCfg->pConnPool)) == NULL) {
      LOG(X_WARNING("No available connection for %s:%d (max:%d) on port %d"), 
           FORMAT_NETADDR(sdclient.sa, tmp, sizeof(tmp)), ntohs(INET_PORT(sdclient.sa)), 
           pListenCfg->pConnPool->numElements, ntohs(INET_PORT(pListenCfg->sa)));

      netio_closesocket(&sdclient.netsocket);
      continue;
    }

#if defined(__APPLE__) 
    sockopt = 1;
    if(setsockopt(NETIOSOCK_FD(sdclient.netsocket), SOL_SOCKET, SO_NOSIGPIPE,
                 (char*) &sockopt, sizeof(sockopt)) != 0) {
      LOG(X_ERROR("Failed to set SO_NOSIGPIPE"));
    }
#endif // __APPLE__

    //pConn->psrvsaListen = &saSrv;
    //memcpy(&pConn->srvsaListen, &saSrv, sizeof(pConn->srvsaListen));

    LOG(X_DEBUG("Accepted connection on port %d from %s:%d"), htons(INET_PORT(pListenCfg->sa)), 
        FORMAT_NETADDR(sdclient.sa, tmp, sizeof(tmp)), htons(INET_PORT(sdclient.sa)));

    pthread_attr_init(&pConn->attr);
    pthread_attr_setdetachstate(&pConn->attr, PTHREAD_CREATE_DETACHED);
    memset(&pConn->sd.netsocket, 0, sizeof(pConn->sd.netsocket));
    NETIO_SET(pConn->sd.netsocket, sdclient.netsocket);
    memcpy(&pConn->sd.sa, &sdclient.sa, INET_SIZE(sdclient));
    pConn->pListenCfg = pListenCfg;
    NETIOSOCK_FD(sdclient.netsocket) = INVALID_SOCKET;

    wrapArg.thread_func = thread_func;
    wrapArg.pConnPool = pListenCfg->pConnPool;
    wrapArg.pConn = pConn;
    wrapArg.flags = 1;
    wrapArg.tid_tag[0] = '\0';
    if((s = logutil_tid_lookup(pthread_self(), 0)) && s[0] != '\0') {
      snprintf(wrapArg.tid_tag, sizeof(wrapArg.tid_tag), "%s-%u", s, pConn->pool.id);
    }
    //wrapArg.pcond = &cond;

  //fprintf(stderr, "%d CALLING wrap: 0x%x pConn:0x%x\n", pthread_self(), &wrapArg, wrapArg.pConn);

    if((rc = pthread_create(&pConn->ptd,
                    &pConn->attr,
                    (void *) thread_func_wrapper,
                    (void *) &wrapArg)) != 0) {
      LOG(X_ERROR("Unable to create connection handler thread on port %d from %s:%d (%d %s)"), 
          htons(INET_PORT(pListenCfg->sa)), FORMAT_NETADDR(sdclient.sa, tmp, sizeof(tmp)),
          htons(INET_PORT(sdclient.sa)), rc, strerror(rc));
      netio_closesocket(&pConn->sd.netsocket);
      pool_return(pListenCfg->pConnPool, &pConn->pool);
      wrapArg.flags = 0;
      //pthread_cond_broadcast(&cond);
      break;
    }

    pthread_attr_destroy(&pConn->attr);

    //
    // be careful not to reuse the same wrapArg instance 
    // since the stack variable arguments could get
    // overwritten by the next loop iteration, before the thread proc is 
    // invoked
    //
    //fprintf(stderr, "wait start\n");
    tv0 = timer_GetTime();
    //if(wrapArg.flags == 1) {

      //
      // It seems that calling pthread_cond_wait here to check if the thread creation is
      // complete is not completely reliable and portable, so we do the lame way 
      // of sleeping and polling.
      //
      //pthread_cond_wait(&cond, &mtx);

      while(wrapArg.flags == 1) {
        usleep(100);
        if(((tv1 = timer_GetTime()) - tv0) / TIME_VAL_MS > 1000) {
          LOG(X_WARNING("Abandoning wait for connection thread start on port %d from %s:%d"),
               htons(INET_PORT(pListenCfg->sa)),
              FORMAT_NETADDR(pListenCfg->sa, tmp, sizeof(tmp)), ntohs(INET_PORT(pListenCfg->sa)));
          break;
        } 
      }
      //fprintf(stderr, "THREAD STARTED AFTER %lld ns\n", (timer_GetTime() - tv0));
    //}

    //fprintf(stderr, "wait done\n");

    //while(wrapArg.flag == 1) {
    //  usleep(10000); 
    //}

  }

  //pthread_cond_destroy(&cond);
  pthread_mutex_destroy(&mtx);

  return rc;
}
示例#28
0
int srv_rtmp_proc(CLIENT_CONN_T *pConn, const unsigned char *prebuf, unsigned int prebufsz, int istunneled) {
  int rc = 0;
  STREAMER_CFG_T *pStreamerCfg = NULL;
  STREAMER_OUTFMT_T *pLiveFmt = NULL;
  STREAM_STATS_T *pstats = NULL;
  RTMP_CTXT_T rtmpCtxt;
  unsigned int numQFull = 0;
  char tmps[2][128];
  OUTFMT_CFG_T *pOutFmt = NULL;

  if(!pConn) {
    return -1;
  }

  if(!HAVE_URL_CAP_RTMP(pConn->pListenCfg->urlCapabilities)) {
    LOG(X_ERROR("Listener %s:%d not enabled for rtmp%s%s stream to %s:%d"), 
          FORMAT_NETADDR(pConn->pListenCfg->sa, tmps[1], sizeof(tmps[1])), ntohs(INET_PORT(pConn->pListenCfg->sa)),
          istunneled > 0 ? "t" : "",      
          (pConn->sd.netsocket.flags & NETIO_FLAG_SSL_TLS) ? "s" : "", 
          FORMAT_NETADDR(pConn->sd.sa, tmps[0], sizeof(tmps[0])), ntohs(INET_PORT(pConn->sd.sa)));
    return -1;
  }

  pStreamerCfg = GET_STREAMER_FROM_CONN(pConn);

  if(pStreamerCfg && pStreamerCfg->action.liveFmts.out[STREAMER_OUTFMT_IDX_RTMP].do_outfmt) {

    pLiveFmt = &pStreamerCfg->action.liveFmts.out[STREAMER_OUTFMT_IDX_RTMP];

    if(pStreamerCfg->pMonitor && pStreamerCfg->pMonitor->active) {
      if(!(pstats = stream_monitor_createattach(pStreamerCfg->pMonitor,
             (const struct sockaddr *) &pConn->sd.sa, STREAM_METHOD_RTMP, STREAM_MONITOR_ABR_NONE))) {
      }
    }

    //
    // Add a livefmt cb
    //
    pOutFmt = outfmt_setCb(pLiveFmt, rtmp_addFrame, &rtmpCtxt, &pLiveFmt->qCfg, pstats, 
                           1, pStreamerCfg->frameThin, &numQFull);

  } 

  if(pOutFmt) {

    memset(&rtmpCtxt, 0, sizeof(rtmpCtxt));

    rtmp_init(&rtmpCtxt, MAX(pLiveFmt->qCfg.maxPktLen, pLiveFmt->qCfg.growMaxPktLen));
    rtmpCtxt.pSd = &pConn->sd;
    rtmpCtxt.novid = pStreamerCfg->novid;
    rtmpCtxt.noaud = pStreamerCfg->noaud;
    rtmpCtxt.av.vid.pStreamerCfg = pStreamerCfg;
    rtmpCtxt.av.aud.pStreamerCfg = pStreamerCfg;
    rtmpCtxt.pAuthTokenId = pConn->pListenCfg->pAuthTokenId;
    if(pstats) {
      rtmpCtxt.pStreamMethod = &pstats->method;
    }
    rtmpCtxt.pOutFmt = pOutFmt;
    rtmpCtxt.prebufdata = (unsigned char *) prebuf;
    rtmpCtxt.prebufsz = prebufsz;

    if(!(pConn->pListenCfg->urlCapabilities & URL_CAP_RTMPLIVE)) {
      rtmpCtxt.donotunnel = 1;
    }
    if((pConn->pListenCfg->urlCapabilities & URL_CAP_RTMPTLIVE)) {
      rtmpCtxt.dohttptunnel = 1;
    }

    //
    // Unpause the outfmt callback mechanism now that rtmp_init was called
    //
    outfmt_pause(pOutFmt, 0);

    LOG(X_INFO("Starting rtmp%s%s stream[%d] %d/%d to %s:%d"), 
          istunneled > 0 ? "t" : "",      
          (pConn->sd.netsocket.flags & NETIO_FLAG_SSL_TLS) ? "s" : "", pOutFmt->cbCtxt.idx, numQFull + 1, 
          pLiveFmt->max, FORMAT_NETADDR(pConn->sd.sa, tmps[0], sizeof(tmps[0])), ntohs(INET_PORT(pConn->sd.sa)));

    rtmp_handle_conn(&rtmpCtxt);

    LOG(X_INFO("Ending rtmp%s%s stream[%d] to %s:%d"), 
         istunneled > 0 ? "t" : "",      
         (pConn->sd.netsocket.flags & NETIO_FLAG_SSL_TLS) ? "s" : "", pOutFmt->cbCtxt.idx, 
         FORMAT_NETADDR(pConn->sd.sa, tmps[0], sizeof(tmps[0])), ntohs(INET_PORT(pConn->sd.sa)));

    //
    // Remove the livefmt cb
    //
    outfmt_removeCb(pOutFmt);

    rtmp_close(&rtmpCtxt);

  } else {

    if(pstats) {
      //
      // Destroy automatically detaches the stats from the monitor linked list
      //
      stream_stats_destroy(&pstats, NULL);
    }

    LOG(X_WARNING("No rtmp resource available (max:%d) for %s:%d"), 
        (pLiveFmt ? pLiveFmt->max : 0),
        FORMAT_NETADDR(pConn->sd.sa, tmps[0], sizeof(tmps[0])), ntohs(INET_PORT(pConn->sd.sa)));

    rc = -1;
  }

  netio_closesocket(&pConn->sd.netsocket);

  LOG(X_DEBUG("RTMP connection thread ended %s:%d"), FORMAT_NETADDR(pConn->sd.sa, tmps[0], sizeof(tmps[0])), 
                                                     ntohs(INET_PORT(pConn->sd.sa)));

  return rc;
}
示例#29
0
文件: h264.c 项目: openvcx/openvcx
static int h264_decode_NAL_int(H264_DECODER_CTXT_T *pCtxt, BIT_STREAM_T *pStream) {

  int rc = H264_RC_OK;
  int nalType = pStream->buf[pStream->byteIdx];

  if(nalType & 0x80) {
    LOG(X_ERROR("NAL forbidden bit set!"));
    return -1;
  }
  H264_STREAM_INCR_BYTE(pStream);
  pCtxt->lastSliceType = H264_SLICE_TYPE_UNKNOWN;
                
  switch(nalType & NAL_TYPE_MASK) {

    case NAL_TYPE_SEQ_PARAM:     
      //fprintf(stderr, "SPS:\n");avc_dumpHex(stderr, &pStream->buf[pStream->byteIdx], 32, 1);
      rc = h264_decodeSPS_int(pCtxt, pStream);
      pCtxt->lastSliceType = H264_SLICE_TYPE_SPS;
      H264_STREAM_ENDOF_BYTE(pStream);
      break;

    case NAL_TYPE_PIC_PARAM:
      //fprintf(stderr, "PPS:\n");avc_dumpHex(stderr, &pStream->buf[pStream->byteIdx], 32, 1);

      // Prevent attempting to decode PPS w/o having received SPS context
      if(!(pCtxt->flag & H264_DECODER_CTXT_HAVE_SPS)) {
        return H264_RC_IGNORED;
      }

      rc = h264_decodePPS_int(pCtxt, pStream);
      pCtxt->lastSliceType = H264_SLICE_TYPE_PPS;
      H264_STREAM_ENDOF_BYTE(pStream);
      break;

    case NAL_TYPE_SEI:

      //rc = h264_decodeSEI_int(pCtxt, pStream);
      rc = H264_RC_OK;
      pCtxt->lastSliceType = H264_SLICE_TYPE_SEI;
      H264_STREAM_ENDOF_BYTE(pStream);
      break;

    case NAL_TYPE_SLICE:
    case NAL_TYPE_IDR:

      // Prevent attempting to decode VCL data w/o having received SPS & PPS context
      if(!(pCtxt->flag & (H264_DECODER_CTXT_HAVE_SPS | H264_DECODER_CTXT_HAVE_PPS))) {
        return H264_RC_IGNORED;
      }

      rc = h264_decodeSlice(pCtxt, pStream, (nalType & NAL_TYPE_MASK));
      H264_STREAM_ENDOF_BYTE(pStream);
      break;

    case NAL_TYPE_ACCESS_UNIT_DELIM:
      // quietly ignore
      break;

    default:

      LOG(X_WARNING("No handler for NAL type: %d"), nalType);
      rc = H264_RC_ERR;
      break;

  }
 
  return rc;
}
示例#30
0
static void srvlisten_media_proc(void *pArg) {

  SRV_LISTENER_CFG_T *pListenCfg = (SRV_LISTENER_CFG_T *) pArg;
  NETIO_SOCK_T netsocksrv;
  struct sockaddr_storage sa;
  CLIENT_CONN_T *pConnTmp;
  char tmp[128];
  char bufses[32];
  const int backlog = NET_BACKLOG_DEFAULT;
  unsigned int tsMax = 0;
  unsigned int flvMax = 0;
  unsigned int mkvMax = 0;
  unsigned int rtmpMax = 0;
  unsigned int rtspMax = 0;
  int haveAuth = 0;
  int haveRtmpAuth = 0;
  int haveRtspAuth = 0;
  int haveToken = 0;
  int rc = 0;

  logutil_tid_add(pthread_self(), pListenCfg->tid_tag);

  if((pListenCfg->urlCapabilities & (URL_CAP_TSLIVE | URL_CAP_TSHTTPLIVE | URL_CAP_FLVLIVE |
                                     URL_CAP_MKVLIVE | URL_CAP_LIVE | URL_CAP_STATUS | URL_CAP_MOOFLIVE |
                                     URL_CAP_PIP | URL_CAP_CONFIG | URL_CAP_BROADCAST |
                                     URL_CAP_RTMPLIVE | URL_CAP_RTMPTLIVE | URL_CAP_RTSPLIVE)) == 0) {

    LOG(X_WARNING("Server listener exiting because no capabilities enabled on %s:%d"),
         FORMAT_NETADDR(pListenCfg->sa, tmp, sizeof(tmp)), ntohs(INET_PORT(pListenCfg->sa)));
    logutil_tid_remove(pthread_self());
    return;
  } else if(!(pConnTmp = (CLIENT_CONN_T *) pListenCfg->pConnPool->pElements)) {
    return;
  }

  memset(&netsocksrv, 0, sizeof(netsocksrv));
  memcpy(&sa, &pListenCfg->sa, sizeof(pListenCfg->sa));
  netsocksrv.flags = pListenCfg->netflags;

  if((NETIOSOCK_FD(netsocksrv) = net_listen((const struct sockaddr *) &sa, backlog)) == INVALID_SOCKET) {
    logutil_tid_remove(pthread_self());
    return;
  }

  pthread_mutex_lock(&pListenCfg->mtx);
  pListenCfg->pnetsockSrv = &netsocksrv;
  pthread_mutex_unlock(&pListenCfg->mtx);

  if(pListenCfg->pAuthStore && IS_AUTH_CREDENTIALS_SET(pListenCfg->pAuthStore)) {
    haveAuth = 1;
  }
  if(pListenCfg->pAuthTokenId && pListenCfg->pAuthTokenId[0] != '\0') {
    haveToken = 1;
  }

  tsMax = pConnTmp->pStreamerCfg0->liveQs[0].max;
  flvMax = pConnTmp->pStreamerCfg0->action.liveFmts.out[STREAMER_OUTFMT_IDX_FLV].max;
  mkvMax = pConnTmp->pStreamerCfg0->action.liveFmts.out[STREAMER_OUTFMT_IDX_MKV].max;
  rtmpMax = pConnTmp->pStreamerCfg0->action.liveFmts.out[STREAMER_OUTFMT_IDX_RTMP].max;
  rtspMax = pConnTmp->pStreamerCfg0->pRtspSessions->max;

  if(HAVE_URL_CAP_RTMP(pListenCfg->urlCapabilities)) {

    if(IS_AUTH_CREDENTIALS_SET(&pConnTmp->pStreamerCfg0->creds[STREAMER_AUTH_IDX_RTMP].stores[pListenCfg->idxCfg])) {
      //
      // RTMP server streaming credentials not implemented 
      //
      //haveRtmpAuth = 1;
    }

    LOG(X_INFO("rtmp %s%s available at "URL_RTMP_FMT_STR"%s max:%d"),
       ((pListenCfg->netflags & NETIO_FLAG_PLAINTEXT) && (pListenCfg->netflags & NETIO_FLAG_SSL_TLS) ) ? "(SSL) " :
       ((pListenCfg->netflags & NETIO_FLAG_SSL_TLS) ? "(SSL only) " : ""),
           ((pListenCfg->urlCapabilities & URL_CAP_RTMPTLIVE) && !(pListenCfg->urlCapabilities & URL_CAP_RTMPLIVE) ?
            "(tunneled only) " : ((pListenCfg->urlCapabilities & URL_CAP_RTMPTLIVE) ? "(tunneled) " : "")),
           URL_PROTO_FMT2_ARGS(
               (pListenCfg->netflags & NETIO_FLAG_SSL_TLS),
                 FORMAT_NETADDR(sa, tmp, sizeof(tmp))), ntohs(INET_PORT(sa)),
           (haveRtmpAuth ? " (Using auth)" : ""), rtmpMax);
  }

  if(pListenCfg->urlCapabilities & URL_CAP_RTSPLIVE) {

    if(IS_AUTH_CREDENTIALS_SET(&pConnTmp->pStreamerCfg0->creds[STREAMER_AUTH_IDX_RTSP].stores[pListenCfg->idxCfg])) {
      haveRtspAuth = 1;
    }

    if(pListenCfg->pCfg->prtspsessiontimeout && *pListenCfg->pCfg->prtspsessiontimeout != 0) {
      snprintf(bufses, sizeof(bufses), ", timeout:%u sec", *pListenCfg->pCfg->prtspsessiontimeout);
    } else {
      bufses[0] = '\0';
    }

    LOG(X_INFO("rtsp %s available at "URL_RTSP_FMT_STR"%s max:%d%s"),
       ((pListenCfg->netflags & NETIO_FLAG_PLAINTEXT) && (pListenCfg->netflags & NETIO_FLAG_SSL_TLS) ) ? "(SSL) " :
       ((pListenCfg->netflags & NETIO_FLAG_SSL_TLS) ? "(SSL only) " : ""),
             URL_PROTO_FMT2_ARGS(
                 (pListenCfg->netflags & NETIO_FLAG_SSL_TLS),
                   FORMAT_NETADDR(sa, tmp, sizeof(tmp))), ntohs(INET_PORT(sa)),
             (haveRtspAuth ? " (Using auth)" : ""), rtspMax, bufses);
  }

  if((pListenCfg->urlCapabilities & URL_CAP_ROOTHTML)) {
    LOG(X_INFO("broadcast interface available at "URL_HTTP_FMT_STR"%s%s%s max:%d"), 
           URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_ROOT_URL,
           (haveAuth ? " (Using auth)" : ""),
           (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), pListenCfg->max);
  }

  if((pListenCfg->urlCapabilities & URL_CAP_LIVE)) {
    LOG(X_INFO("live available at "URL_HTTP_FMT_STR"%s%s%s%s max:%d"), 
           URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_LIVE_URL,
           (haveAuth ? " (Using auth)" : ""),
           (haveToken ? " (Using token)" : ""),
           (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), pListenCfg->max);
  }

  if((pListenCfg->urlCapabilities & URL_CAP_TSLIVE)) {
    LOG(X_INFO("tslive available at "URL_HTTP_FMT_STR"%s%s%s%s max:%d"), 
           URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_TSLIVE_URL,
           (haveAuth ? " (Using auth)" : ""),
           (haveToken ? " (Using token)" : ""),
           (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), tsMax);
  }

  if((pListenCfg->urlCapabilities & URL_CAP_TSHTTPLIVE)) {
    LOG(X_INFO("httplive available at "URL_HTTP_FMT_STR"%s%s%s%s max:%d"), 
           URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_HTTPLIVE_URL,
           (haveAuth ? " (Using auth)" : ""),
           (haveToken ? " (Using token)" : ""),
           (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), pListenCfg->max);
  }

  if((pListenCfg->urlCapabilities & URL_CAP_FLVLIVE)) {
    LOG(X_INFO("flvlive available at "URL_HTTP_FMT_STR"%s%s%s%s max:%d"), 
           URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_FLVLIVE_URL,
           (haveAuth ? " (Using auth)" : ""),
           (haveToken ? " (Using token)" : ""),
           (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), flvMax);
  }

  if((pListenCfg->urlCapabilities & URL_CAP_MKVLIVE)) {
    LOG(X_INFO("mkvlive available at "URL_HTTP_FMT_STR"%s%s%s%s max:%d"), 
           URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_MKVLIVE_URL,
           (haveAuth ? " (Using auth)" : ""),
           (haveToken ? " (Using token)" : ""),
           (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), mkvMax);
  }

  if((pListenCfg->urlCapabilities & URL_CAP_MOOFLIVE)) {
    LOG(X_INFO("dash available at "URL_HTTP_FMT_STR"%s%s%s%s max:%d"), 
           URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_DASH_URL,
           (haveAuth ? " (Using auth)" : ""),
           (haveToken ? " (Using token)" : ""),
           (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), pListenCfg->max);
  }

  if((pListenCfg->urlCapabilities & URL_CAP_STATUS)) {
    LOG(X_INFO("status available at "URL_HTTP_FMT_STR"%s%s%s"), 
           URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_STATUS_URL,
            (haveAuth ? " (Using auth)" : ""),
           (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""));
  }

  if((pListenCfg->urlCapabilities & URL_CAP_PIP)) {
    LOG(X_INFO("pip available at "URL_HTTP_FMT_STR"%s%s%s"), 
           URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_PIP_URL,
            (haveAuth ? " (Using auth)" : ""),
           (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""));
  }

  if((pListenCfg->urlCapabilities & URL_CAP_CONFIG)) {
    LOG(X_INFO("config available at "URL_HTTP_FMT_STR"%s%s%s"), 
           URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_CONFIG_URL,
            (haveAuth ? " (Using auth)" : ""),
           (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""));
  }

  //fprintf(stderr, "LISTENER THREAD %s %s:%d active:%d cap: 0x%x\n", pListenCfg->netflags & NETIO_FLAG_SSL_TLS ? "SSL" : "", inet_ntoa(sa.sin_addr), ntohs(sa.sin_port), pListenCfg->active, pListenCfg->urlCapabilities);

  //
  // Service any client connections on the live listening port
  //
  rc = srvlisten_loop(pListenCfg, srv_cmd_proc);

  pthread_mutex_lock(&pListenCfg->mtx);
  pListenCfg->pnetsockSrv = NULL; 
  netio_closesocket(&netsocksrv);
  pthread_mutex_unlock(&pListenCfg->mtx);

  LOG(X_WARNING("HTTP listener thread exiting with code: %d"), rc);

  logutil_tid_remove(pthread_self());

  return;
}