Esempio n. 1
0
static int capture_cbQueueRawDevFrame(void *pArg, const void *pData, uint32_t szData) {
  int rc = 0;
  CAP_QUEUERAW_FRAME_DATA_T *pFrameData = (CAP_QUEUERAW_FRAME_DATA_T *) pArg;
  PKTQ_EXTRADATA_T xtra;

  xtra.tm.pts = ((uint64_t)pFrameData->pPktData->tv.tv_sec * 90000) +
                ((double)pFrameData->pPktData->tv.tv_usec / TIME_VAL_US * 90000);
  xtra.tm.dts = 0;
  //xtra.flags = CAPTURE_SP_FLAG_KEYFRAME;
  xtra.pQUserData = NULL;
  //fprintf(stderr, "capture_cbWriteRawDevFrame len:%d %.3f(%llu) tv:%u:%u \n", szData, PTSF(xtra.tm.pts), xtra.tm.pts, pFrameData->pPktData->tv.tv_sec, pFrameData->pPktData->tv.tv_usec);

  rc = pktqueue_addpkt(pFrameData->pSp->pCapAction->pQueue, 
                         pFrameData->pPktData->payload.pData,
                         PKTLEN32(pFrameData->pPktData->payload), &xtra, 1);
  
  return rc;
}
Esempio n. 2
0
int stream_udp(STREAM_XMIT_NODE_T *pList, double durationSec) {
  STREAM_XMIT_NODE_T *pStream;
  COLLECT_STREAM_PKTDATA_T collectPkt;
  int triedXmit;
  unsigned int idxDest;
  TIME_VAL tmstart, tm1, tmnow;
  TIME_VAL tmprevbwdescr;
  int rc;
  int sz;
  int szPkt;
  unsigned int szData;
  const unsigned char *pData;
  unsigned int szDataPayload;
  const unsigned char *pDataPayload;
  uint64_t totBytes = 0;
  unsigned int totPkts = 0;
  unsigned int bytes = 0;
  unsigned int pkts = 0;
  unsigned int bytes2 = 0;
  unsigned int pkts2 = 0;
  //char dstStr[64];
#ifndef WIN32
  unsigned int countIterations = 0;
#endif // WIN32

  if(!pList 
#if defined(VSX_HAVE_LICENSE)
   || !pList->pLic
#endif // VSX_HAVE_LICENSE
     ) {
    return -1;
  }

  //snprintf(dstStr, sizeof(dstStr), "%s:%d", inet_ntoa(pList->pRtpMulti->pdests[0].saDsts.sin_addr), 
  //            ntohs(pList->pRtpMulti->pdests[0].saDsts.sin_port));

  tmstart = tmnow = timer_GetTime();
  tm1 = tmstart;
  tmprevbwdescr = tmstart;


  while(*pList->prunning == STREAMER_STATE_RUNNING && !g_proc_exit) {

    pStream = pList;
    triedXmit = 0;

    while(pStream) {

      if((rc = pStream->cbCanSend(pStream->pCbData)) > 0) {

        pData = stream_rtp_data(pStream->pRtpMulti);
        szData = stream_rtp_datalen(pStream->pRtpMulti);

        if(szData >= RTP_HEADER_LEN) {
          pDataPayload = pData + RTP_HEADER_LEN;
          szDataPayload = szData - RTP_HEADER_LEN;
        } else {
          pDataPayload = NULL;
          szDataPayload = 0;
        }

        if(pStream->pXmitAction->do_stream) {
          triedXmit = 1;

          totPkts++;
          pkts++;
          pkts2++;

          if(pStream->pXmitAction->do_output) {

            szPkt = 0;
            for(idxDest = 0; idxDest < pStream->pRtpMulti->numDests; idxDest++) {
  
              if(pStream->pXmitDestRc[idxDest] != 0) {
                continue;
              }
              if(pStream->rawSend) {
                if(pktgen_Queue(pData, szData) != 0) {
                  pStream->pXmitDestRc[idxDest] = -1; 
                  sz = -1;
                } else {
                  sz = szData;
                }
              } else {

                //
                // Check and send an rtcp sender report
                //
                if(*pStream->pfrtcp_sr_intervalsec > 0 &&
                  (tmnow - pStream->pRtpMulti->pdests[idxDest].tmLastRtcpSr) / TIME_VAL_MS  > 
                         *pStream->pfrtcp_sr_intervalsec * 1000) {
                  sendRtcpSr(pStream, idxDest);
                  pStream->pRtpMulti->pdests[idxDest].tmLastRtcpSr = tmnow;
                } 

                if((sz = sendPktUdpRtp(pStream, idxDest, pData, szData)) < 0) {
                  pStream->pXmitDestRc[idxDest] = sz; 
                }
              }
              if(szPkt == 0 && sz > 0) {
                szPkt = sz; 
              }
            } // end of for

            // Exit if there are no good transmitters in the list
            if(pStream->pXmitAction->do_output && szPkt == 0) {
              return -1;
            }

          } else {    // if do_output
            szPkt = szData;
          }

          if(!pStream->pXmitAction->do_output_rtphdr && szPkt > RTP_HEADER_LEN) {
            szPkt -= RTP_HEADER_LEN;
          }

          totBytes += szPkt;
          bytes += szPkt;

          //
          // Add the packet data to any outbound avclive subscribers
          //
          // TODO: do not hardcode szData > RTP_HEADER_LEN rtp hdr len
          if(pStream->pLiveQ && pStream->pLiveQ->numActive > 0 && szDataPayload > 0) {
            pthread_mutex_lock(&pStream->pLiveQ->mtx);
            for(sz = 0; (unsigned int) sz < pStream->pLiveQ->max; sz++) {
              if(pStream->pLiveQ->pQs[sz]) {
                pktqueue_addpkt(pStream->pLiveQ->pQs[sz], pDataPayload, szDataPayload, NULL, 0);
              }
            }
            pthread_mutex_unlock(&pStream->pLiveQ->mtx);
          }
          bytes2 += szPkt;

        } else {

          // preserve rtp sequence number during 'live pause'
          //pStream->pRtp->m_pRtp->sequence_num = 
          //  htons(htons(pStream->pRtp->m_pRtp->sequence_num) - 1);

          //During 'live pause', update the last seq #
          //if(pStream->pXmitAction->prior_do_stream && pStream->prtp_sequence_at_end) {
          //  *pStream->prtp_sequence_at_end = pStream->pRtp->m_pRtp->sequence_num;
          //}
          //fprintf(stderr, "not streaming\n");

        }

        //
        // Record output stream
        //
        if(pStream->pXmitAction->do_record_post && pStream->pXmitCbs->cbRecord && 
           pStream->pXmitCbs->pCbRecordData) {

          memset(&collectPkt, 0, sizeof(collectPkt));
          collectPkt.payload.pData = (unsigned char *) pDataPayload;
          PKTCAPLEN(collectPkt.payload) = szDataPayload;
          if((sz = pStream->pXmitCbs->cbRecord(pStream->pXmitCbs->pCbRecordData, &collectPkt)) < 0) {
            return -1;
          }
          if(triedXmit == 0) {
            triedXmit = 1;
          }
        }

        //
        // Call post processing function, such as http live streaming
        // callback to segment and package output ts files 
        //
        if(pStream->pXmitAction->do_httplive && pStream->pXmitCbs->cbPostProc &&
           pStream->pXmitCbs->pCbPostProcData && pStream->pXmitAction->do_stream) {

          if((sz = pStream->pXmitCbs->cbPostProc(pStream->pXmitCbs->pCbPostProcData, 
                                                pDataPayload, szDataPayload)) < 0) {
            return -1;
          }
          if(triedXmit == 0) {
            triedXmit = 1;
          }
        }


        //if(pStream->pXmitAction->do_stream != pStream->pXmitAction->prior_do_stream) {
        //  pStream->pXmitAction->prior_do_stream = pStream->pXmitAction->do_stream;
        //}


        pStream->pRtpMulti->payloadLen = 0;

        if((rc = pStream->cbPreparePkt(pStream->pCbData)) < 0) {
          return -1;
        }
        //fprintf(stderr, "streamer prepare pkt returned %d\n", rc);

      } else if(rc < 0) {
        LOG(X_DEBUG("Stream ending, sent: %"LL64"u bytes %u pkts"), totBytes, totPkts); 
        return -1;
      } else {
        //fprintf(stderr, "streamer cansend rc:%d\n", rc);
      } 

      pStream = pStream->pNext;
    } // while(pStream)

    pktgen_SendQueued();


    if(triedXmit == 0) {

#ifdef WIN32

      //sl1 = timer_GetTime();

      //Sleep(1) may sleep past its short bedtime on win32, even from a thread w/ SCHED_RR
      //However, sleep(0) uses alot more cpu slices
      //TODO: make this a WaitForSingleObject for any registered pktqueue writers
      

      if(pList->pSleepQ) {
        //TODO: this does not return if a pkt has been queued and no subsequent pkt arrives
        pktqueue_waitforunreaddata(pList->pSleepQ);
        //pthread_cond_wait(pList->pCond, pList->pMtxCond);
      } else {
        Sleep(1);
      }

    } else {
      // On windows Sleep 0 relinquishes execution for any waiting threads
      Sleep(0);

#else // WIN32

      VSX_DEBUG2(tmnow = timer_GetTime())

      usleep(1000);
      countIterations = 0;

      VSX_DEBUGLOG3("stream_udp slept for %lld ns\n", timer_GetTime() - tmnow);

    } else {

      if(countIterations++ > 10000) {
        // During continuous xmit, sleep to prevent unresponsive system
        usleep(1);
        countIterations = 0;
      } 
#endif // WIN32

    } 

    tmnow = timer_GetTime();

    if(pList->pBwDescr && (tmnow / TIME_VAL_US) > (tmprevbwdescr / TIME_VAL_US) + 1) {
      pList->pBwDescr->intervalMs = (float)(tmnow - tmprevbwdescr)/ TIME_VAL_MS;
      pList->pBwDescr->pkts = pkts2;
      pList->pBwDescr->bytes = bytes2;
      TV_FROM_TIMEVAL(pList->pBwDescr->updateTv, tmnow);
      //pList->pBwDescr->updateTv.tv_sec = tmnow / TIME_VAL_US;
      //pList->pBwDescr->updateTv.tv_usec = tmnow % TIME_VAL_US;
      bytes2 = 0;
      pkts2 = 0;
      tmprevbwdescr = tmnow;
    }

    if(durationSec > 0 && tmnow > tmstart + (durationSec * TIME_VAL_US)) {
      LOG(X_DEBUG("Stream duration %.1f sec limit reached"), durationSec);
      *pList->prunning = STREAMER_STATE_FINISHED;
    }

#if defined (VSX_HAVE_LICENSE)
    // Check if stream time is limited
    if(!(pList->pLic->capabilities & LIC_CAP_STREAM_TIME_UNLIMITED)) {
      if(tmnow > tmstart + (STREAM_LIMIT_SEC * TIME_VAL_US)) {
        LOG(X_INFO("Stream time limited.  Stopping stream transmission after %d sec"), 
                 (int) (tmnow - tmstart) / TIME_VAL_US);
        *pList->prunning = STREAMER_STATE_FINISHED;
        if(!(g_proc_exit_flags & PROC_EXIT_FLAG_NO_EXIT_ON_STREAM_TIME_LIMITED)) {
          g_proc_exit = 1;
        }
      }
    }
#endif // VSX_HAVE_LICENSE

#if defined(LITE_VERSION)
    if(tmnow > tmstart + (STREAM_LIMIT_LITE_SEC * TIME_VAL_US)) {
      LOG(X_INFO("Stream time limited.  Stopping stream transmission after %d sec"),
               (int) (tmnow - tmstart) / TIME_VAL_US);
      *pList->prunning = STREAMER_STATE_FINISHED;
      if(!(g_proc_exit_flags & PROC_EXIT_FLAG_NO_EXIT_ON_STREAM_TIME_LIMITED)) {
        g_proc_exit = 1;
      }
    }
#endif // (LITE_VERSION)

/*
    if(0 && pList->verbosity > 1 && tv2.tv_sec > tv1.tv_sec+3) {

      elapsedMs0 = ((tv2.tv_sec - tv0.tv_sec) * 1000) + 
                   ((tv2.tv_usec - tv0.tv_usec) /1000);
      elapsedMs1 = ((tv2.tv_sec - tv1.tv_sec) * 1000) + 
                   ((tv2.tv_usec - tv1.tv_usec) /1000);

      fprintf(stdout, "%u", elapsedMs0/1000);
         
      if(durationSec != 0) {
        fprintf(stdout, "/%.1f", durationSec);
      }

      fprintf(stdout, " sec, %s %.1fKb/s %.1fpkts/s (total: %u pkts, %.1fKB, %.1fKb/s)",
           dstStr,
           (double)(bytes  / 128.0f / ((double)elapsedMs1/1000.0f)),
           (double)(pkts/ ((double)elapsedMs1/1000.0f)),
                         totPkts, (double)totBytes/1024.0f,
                           (double)(totBytes /  128.0f / ((double)elapsedMs0/1000.0f))); 
      fprintf(stdout, "\n");

      bytes = 0;
      pkts = 0;
      tv1.tv_sec = tv2.tv_sec;
      tv1.tv_usec = tv2.tv_usec;
    }
 */  
  }
Esempio n. 3
0
int streamxmit_sendto(STREAM_RTP_DEST_T *pDest, const unsigned char *data, unsigned int len, 
                      int rtcp, int keyframe, int drop) {
  int rc = 0;
  NETIO_SOCK_T *pnetsock = NULL;
  const unsigned char *pData = data;
  PKTQ_EXTRADATA_T qXtra;
  STREAMXMIT_PKT_HDR_T pktHdr;
  unsigned char encBuf[PACKETGEN_PKT_UDP_DATA_SZ];

  //
  // If we're using DTLS-SRTP over audio/video mux (on same RTP port) then we need to choose
  // the right socket which has completed the DTLS handshake
  //
  if(rtcp) {
    pnetsock = STREAM_RTCP_PNETIOSOCK(*pDest);
  } else {
    pnetsock = STREAM_RTP_PNETIOSOCK(*pDest);
  }

  //LOG(X_DEBUG("STREAMXMIT_SENDTO len:%d, rtcp:%d, drop:%d, pDest: 0x%x, srtp:0x%x, pSrtpShared: 0x%x, 0x%x, lenK:%d"), len, rtcp, drop, pDest, &pDest->srtps[rtcp ? 1 : 0], pDest->srtps[rtcp ? 1 : 0].pSrtpShared, SRTP_CTXT_PTR(&pDest->srtps[rtcp ? 1 : 0]), SRTP_CTXT_PTR(&pDest->srtps[rtcp ? 1 : 0])->k.lenKey);LOGHEX_DEBUG(data, MIN(16, len));

  if((rc = srtp_dtls_protect(pnetsock, data, len, encBuf, sizeof(encBuf),
                      (const struct sockaddr *) (rtcp ? &pDest->saDstsRtcp : &pDest->saDsts), 
                      pDest->srtps[rtcp ? 1 : 0].pSrtpShared,
                      rtcp ? SENDTO_PKT_TYPE_RTCP : SENDTO_PKT_TYPE_RTP)) < 0) {
    if(rc == -2) {
      // DTLS handshake not complete
      return 0;
    } else {
      return -1;
    }
  } else if(rc > 0) {
    pData = encBuf;
    len = rc;
  }

  //
  // Queue the packet for async sending
  //
  if(pDest->asyncQ.pQ && (pDest->asyncQ.doAsyncXmit || (!rtcp && pDest->asyncQ.doRtcpNack))) {

    memset(&qXtra, 0, sizeof(qXtra));
    memset(&pktHdr, 0, sizeof(pktHdr));
    pktHdr.flags = 0;
    pktHdr.tvCreate = timer_GetTime();
    if(!pDest->asyncQ.doAsyncXmit) {
      pktHdr.tvXmit = pktHdr.tvCreate;
    }
    if(!(pktHdr.rtcp = rtcp)) {
      pktHdr.seqNum = htons(pDest->pRtpMulti->pRtp->sequence_num);
      pktHdr.timeStamp = htonl(pDest->pRtpMulti->pRtp->timeStamp);
      pktHdr.keyframe = keyframe;
    }
    qXtra.pQUserData = &pktHdr;

    pthread_mutex_lock(&pDest->asyncQ.mtx);

    if(!pDest->asyncQ.isCurPktKeyframe && keyframe) {
      pDest->asyncQ.haveLastKeyframeSeqNumStart = 1;
      pDest->asyncQ.lastKeyframeSeqNumStart = pktHdr.seqNum;
      //LOG(X_DEBUG("NACK - GOP start at packet %d"), pktHdr.seqNum);
    }

    if(pktqueue_addpkt(pDest->asyncQ.pQ, pData, len, &qXtra,
       (!pDest->asyncQ.isCurPktKeyframe && keyframe ? 1 : 0)) != PKTQUEUE_RC_OK) {
      pthread_mutex_unlock(&pDest->asyncQ.mtx);
      return -1;
    }
    //LOG(X_DEBUG("NACK q rd:[%d]/%d, wr:%d"), pDest->asyncQ.pQ->idxRd, pDest->asyncQ.pQ->cfg.maxPkts, pDest->asyncQ.pQ->idxWr);
    pDest->asyncQ.isCurPktKeyframe = keyframe;

    pthread_mutex_unlock(&pDest->asyncQ.mtx);
    rc = len;

    //pktqueue_dump(pDest->asyncQ.pQ,  pktqueue_cb_streamxmit_dump_pkthdr);
  } 

  if(!pDest->asyncQ.doAsyncXmit && !drop) {
    if((rc = srtp_sendto(pnetsock, (void *) pData, len, 0, 
                         (const struct sockaddr *) (rtcp ? &pDest->saDstsRtcp : &pDest->saDsts), NULL, 
                         rtcp ? SENDTO_PKT_TYPE_RTCP : SENDTO_PKT_TYPE_RTP, 1)) < 0) {
      return -1;
    }

  } else if(drop) {
    rc = len;
  }

  if(pDest->pstreamStats) {
    stream_stats_addPktSample(pDest->pstreamStats, &pDest->streamStatsMtx, len, !rtcp);
  }

  return rc;
}
Esempio n. 4
0
static int capture_send_dummy_frames(CAP_SEND_DUMMY_FRAMES_CTXT_T *pCtxt) {
  int rc = 0;
  CAPTURE_CBDATA_SP_T *pSp;
  CAPTURE_STREAM_T *pStream;
  PKTQ_EXTRADATA_T xtra;
  uint64_t pts;
  enum STREAM_NET_ADVFR_RC timeRc;
  unsigned int idx;
  unsigned char buf[16384];
  uint64_t pts0[CAPTURE_MAX_FILTERS];
  uint64_t frameIds[CAPTURE_MAX_FILTERS];
  unsigned int frameSz[CAPTURE_MAX_FILTERS];
  float fps[CAPTURE_MAX_FILTERS];
  TIME_VAL tvStart[CAPTURE_MAX_FILTERS];
  int is_init[CAPTURE_MAX_FILTERS];
  int haveSendOnly = 0;
  CAPTURE_FILTER_T *pFilters;
  unsigned int numFilters;
  CAP_ASYNC_DESCR_T *pCfg = pCtxt->pCfg;
  CAPTURE_STATE_T *pState = pCtxt->pState;

  buf[0] = 0x00;
  memset(frameIds, 0, sizeof(frameIds));
  memset(is_init, 0, sizeof(is_init));
  memset(fps, 0, sizeof(fps));
  memset(frameSz, 0, sizeof(frameSz));
  memset(pts0, 0, sizeof(pts0));
  memset(buf, 0, sizeof(buf));
  pFilters = pState->filt.filters;
  //pFilters = pCfg->pcommon->filters;
  numFilters = pState->filt.numFilters;

  LOG(X_DEBUG("Started dummy input frame processor"));

  while(pCfg->running == STREAMER_STATE_RUNNING  && g_proc_exit == 0 && 
        *pCtxt->prunning == STREAMER_STATE_RUNNING) {

    haveSendOnly = 0;

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

      if(pCfg->pStreamerCfg->cfgrtp.xmitType != SDP_XMIT_TYPE_SENDONLY &&
         pFilters[idx].xmitType != SDP_XMIT_TYPE_SENDONLY) {

        //
        // Clear the xcode decode input flag
        //
        setNoDecode(&pFilters[idx], pCfg->pStreamerCfg, 0);

        if(is_init[idx]) {

          //
          // Restore the xcode input file type
          //
          if(codectype_isVid(pFilters[idx].mediaType)) {
            pCfg->pStreamerCfg->xcode.vid.common.cfgFileTypeIn = pFilters[idx].mediaType;
          } else if(codectype_isAud(pFilters[idx].mediaType)) {
            pCfg->pStreamerCfg->xcode.aud.common.cfgFileTypeIn = pFilters[idx].mediaType;
          }

          pthread_mutex_lock(pCtxt->pmtx);

          if((pStream = findStream(pState, &pFilters[idx]))) {
            //
            // Clear the RTCP BYE reception flag since some clients may have sent an RTCP BYE when going on hold.
            //
            //pStream->haveRtcpBye = 0;
            capture_delete_stream(pState, pStream);
          }

          pthread_mutex_unlock(pCtxt->pmtx);

          is_init[idx] = 0;
        }

        continue;

      } else if(!is_init[idx]) {

        init_filter(pCfg, &pFilters[idx], &fps[idx], &frameSz[idx]); 
        if(frameSz[idx] > sizeof(buf)) {
          LOG(X_ERROR("Capture dummy stream frame size %d exceeds %d"), frameSz[idx], sizeof(buf));
          return -1;
        }

        pthread_mutex_lock(pCtxt->pmtx);

        if(!(pStream = on_new_stream(pState, &pFilters[idx], &pts0[idx]))) {
          pthread_mutex_unlock(pCtxt->pmtx);
          return -1;
        }

        pthread_mutex_unlock(pCtxt->pmtx);

        is_init[idx] = 1;

      }

      haveSendOnly = 1;

      pthread_mutex_lock(pCtxt->pmtx);

      if(!(pStream = findStream(pState, &pFilters[idx])) || !(pSp = pStream->pCbUserData)) {
        LOG(X_ERROR("Unable to find dummy stream for filter media type: %d"), pFilters[idx].mediaType);
        pthread_mutex_unlock(pCtxt->pmtx);
        return -1;
      }

      pthread_mutex_unlock(pCtxt->pmtx);

      //
      // Set the xcode decode input flag
      //
      setNoDecode(&pFilters[idx], pCfg->pStreamerCfg, 1);

      //
      // Add the dummy frame to the input capture queue.  The dummy frame timing is used to 
      // drive the stream frame processor.
      //
      memset(&xtra, 0, sizeof(xtra));
      //xtra.flags = CAPTURE_SP_FLAG_KEYFRAME;

      if((timeRc = stream_net_check_time(&tvStart[idx], &frameIds[idx], fps[idx], 1, &pts, NULL)) ==
        STREAM_NET_ADVFR_RC_OK) {
        xtra.tm.pts = pts + pts0[idx];
        //fprintf(stderr, "ADD_DUMMY_FRAME [%d] fps:%.3f, clockHz:%d pts:%.3f (%llu) (relative pts:%.3f)\n", idx, fps[idx], pSp->pStream->clockHz, PTSF(xtra.tm.pts), xtra.tm.pts, PTSF(pts));
        rc = pktqueue_addpkt(pSp->pCapAction->pQueue, buf, frameSz[idx], &xtra, 1);
        //capture_addCompleteFrameToQ(pSp, ts);
      }

    }

    if(!haveSendOnly) {
      usleep(20000);
    }

  }

  LOG(X_DEBUG("Finished dummy input frame processor"));

  return 0;
}