int tsmClearCachedFrameTs(void* pHandle)
{
	TSM_OBJ* pObj=(TSM_OBJ*)pHandle;
	int nBlkCnt;
	TSM_TIMESTAMP ts;
	/*in this function, we only clear those frame be decoded already*/
	if(pObj->pHandleOri){
		/*in old design, all input ts will be inserted into ready list, no matter how it is decoded or not*/
		TS_DEBUG("%s: unsupported by original ts manager! \r\n",__FUNCTION__);
		return 0;
	}
	if(pObj->pHandle2){
		/*in new design, only decoded frame is inserted the ready list, so we can clear them*/
		nBlkCnt=getTSManagerPreBufferCnt(pObj->pHandle2);
		TS_DEBUG("nBlkCnt: %d , nInTsCnt2: %d \r\n",nBlkCnt,pObj->nInTsCnt2);
		while(nBlkCnt>0){
			nBlkCnt--;
			ts=TSManagerSend2(pObj->pHandle2, NULL);
			TS_DEBUG("drop %lld \r\n",ts);
			if(ts==TS_INVALIDTS){
				break;
			}
		}
	}
	return 1;
}
static int DataDepthIsEnough(void* pHandle, void* pTsHandle)
{
	TSM_OBJ* pObj=(TSM_OBJ*)pHandle;
	int nBlkCnt;
	int isEnough;
	int isDurationEnough=0;
	int isBlkEnough=0;
	if((pObj->nDurationMsThr>0)
		&& (TS_INVALIDTS!=pObj->nCurInputTs)&&(TS_INVALIDTS!=pObj->nCurOutputTs)
		&& (pObj->nCurInputTs > pObj->nCurOutputTs+pObj->nDurationMsThr*1000)){
		TS_DEBUG("input ts(us): %lld, output ts(us): %lld, duration threshold(ms): %lld \r\n",pObj->nCurInputTs,pObj->nCurOutputTs,pObj->nDurationMsThr);
		isDurationEnough=1;
	}
	nBlkCnt=getTSManagerPreBufferCnt(pTsHandle);
	if((pObj->nBlkCntThr>0)&&(nBlkCnt>pObj->nBlkCntThr)){
		TS_DEBUG("cached blk cnt: %d, blkcnt threshold: %d \r\n",nBlkCnt,pObj->nBlkCntThr);
		isBlkEnough=1;
	}
	isEnough = isDurationEnough & isBlkEnough;
	return isEnough;
}
int tsmSetFrmBoundary(void* pHandle,int nStuffSize,int nFrmSize,void* pfrmHandle)
{
	/*pfrmHandle==NULL: the frame is skipped for skipmode/corrupt/... cases*/
	TSM_OBJ* pObj=(TSM_OBJ*)pHandle;
	if(pObj->pHandleOri){
		//nothing
	}
	if(pObj->pHandle2){
		if(pObj->nIsActived2==0){
			pObj->nIsActived2=1;	//accurate frame size is reported by decoder
		}
		pObj->nAccFrmOffset2+=nStuffSize;
#if 1	//consider special case: config data contain valid frames, as result, stuffsize < 0
		if(pObj->nAccFrmOffset2+nFrmSize<=0)
		{
			TS_API("new:calling TSManagerValid2(0): [%lld(0x%llX)]: discarded frame size: %d \n",pObj->nAccFrmOffset2,pObj->nAccFrmOffset2,nFrmSize);
			TSManagerValid2(pObj->pHandle2,0,pfrmHandle);
		}
		else if(pObj->nAccFrmOffset2<=0)
		{
			TS_API("new:calling TSManagerValid2(*): [%lld(0x%llX)]: discarded frame size: %d \n",pObj->nAccFrmOffset2,pObj->nAccFrmOffset2,nFrmSize);
			TSManagerValid2(pObj->pHandle2,pObj->nAccFrmOffset2+nFrmSize,pfrmHandle);			
		}
		else
#endif		
		{
			if(NULL==pfrmHandle){
				TS_API("new:calling TSManagerValid2: [%lld(0x%llX)]: flush %d bytes, skipped frame size: %d \n",pObj->nAccFrmOffset2,pObj->nAccFrmOffset2,nStuffSize,nFrmSize);
				TSManagerValid2(pObj->pHandle2,nStuffSize+nFrmSize,pfrmHandle);
			}
			else{
				TS_API("new:calling TSManagerFlush2/TSManagerValid2: [%lld(0x%llX)]: flush %d bytes, frame size: %d, frm: 0x%X \n",pObj->nAccFrmOffset2,pObj->nAccFrmOffset2,nStuffSize,nFrmSize,pfrmHandle);
				TSManagerFlush2(pObj->pHandle2,nStuffSize);
				TSManagerValid2(pObj->pHandle2,nFrmSize,pfrmHandle);
			}
		}
		//In fact, nInTsCnt2 may be changed after calling TSManagerValid2(), so nInTsCnt2 become unmeaningful
		pObj->nAccFrmOffset2+=nFrmSize;
#ifndef TS_ENA_MULTI_STRATEGY
		//disable original method automatically, only one strategy is enabled
		if(pObj->pHandleOri){
			TS_DEBUG("new strategy is detected, original will be disabled automatically\n");
			TS_API("ori: calling destroyTSManager\n");
			destroyTSManager(pObj->pHandleOri);
			pObj->pHandleOri=NULL;
		}
#endif
	}
	return 1;
}
TSM_TIMESTAMP tsmGetFrmTs(void* pHandle,void* pfrmHandle)
{
	/*nfrmHandle==NULL: 
		(1) only need to pop one time stamp. (e.g. frame is not decoded at all by vpu for skipmode/corrupt/... cases); 
		(2) mosaic frame which is dropped by vpu for non-gop case
	*/
	TSM_TIMESTAMP ts=TS_INVALIDTS;
	TSM_TIMESTAMP tsOri=TS_INVALIDTS;
	TSM_TIMESTAMP ts2=TS_INVALIDTS;
	TSM_TIMESTAMP tsDiff;
	TSM_OBJ* pObj=(TSM_OBJ*)pHandle;
	if(pObj->pHandleOri){
		if(pObj->nInCurTsOri != TS_INVALIDTS) {
			tsOri = pObj->nInCurTsOri;
			pObj->nInCurTsOri = TS_INVALIDTS;
		}
		else{
			tsOri = TSManagerSend(pObj->pHandleOri);
			TS_API("ori: calling TSManagerSend: returned ts(ns): %lld, total: %d \n",tsOri, (int)pObj->nInTsCntOri);
			tsOri=(tsOri==TS_INVALIDTS)?tsOri:(tsOri/TS_SCALE);
			pObj->nInTsCntOri--;
		}
		ts=tsOri;
	}
	if(pObj->pHandle2){
		if(pObj->nIsActived2==0){
			TS_DEBUG("new strategy isn't detected, it will be disabled automatically\n");
			TS_API("new: calling destroyTSManager\n");
			destroyTSManager(pObj->pHandle2);
			pObj->pHandle2=NULL;
		}
		else{				
			if(pObj->nInCurTs2 != TS_INVALIDTS) {
				ts2 = pObj->nInCurTs2;
				pObj->nInCurTs2 = TS_INVALIDTS;
			}
			else{
				if(NULL==pfrmHandle){
					ts2=TSManagerSend2(pObj->pHandle2, NULL);
					TS_API("new: calling TSManagerSend2(NULL): returned ts(ns): %lld, total: %d \n",ts2, (int)pObj->nInTsCnt2);
				}
				else{
					ts2=TSManagerSend2(pObj->pHandle2, pfrmHandle);
					TS_API("new: calling TSManagerSend2: frm: 0x%X, returned ts(ns): %lld, total: %d \n",pfrmHandle,ts2, (int)pObj->nInTsCnt2);
				}
				ts2=(ts2==TS_INVALIDTS)?ts2:(ts2/TS_SCALE);
				pObj->nInTsCnt2--;
			}
			//TS_DEBUG("new: get one ts: %lld, total: %d\n", ts2, (int)pObj->nInTsCnt2);
			ts=ts2;
			pObj->nCurOutputTs=ts;
		}
	}

	//double check the ts for different schema
	if(pObj->pHandleOri && pObj->pHandle2){
		tsDiff=TS_ABS(tsOri,ts2);
		if(tsDiff>=TS_MAX_DIFF_US){
			TS_ERROR("LEVEL: 1 %s: the time stamp is conflict: ori ts(us): %lld, new ts(us): %lld, diff(us): %lld \n",__FUNCTION__,tsOri,ts2,tsDiff);
		}
	}

	if(ts==TS_INVALIDTS){
		TS_ERROR("%s: warning: can't get one valid ts \n",__FUNCTION__);
	}
#ifdef TS_DEBUG	
	if(pObj->nLastTs!=TS_INVALIDTS){
		pObj->nDeltaTs=ts-pObj->nLastTs;
	}		
	pObj->nLastTs=ts;
	TS_DEBUG("%s: current ts(us): %lld, delta(us): %lld \n",__FUNCTION__,pObj->nLastTs,pObj->nDeltaTs);
#endif	
	return ts;
}
Example #5
0
/**
 * tsmux_stream_get_data:
 * @stream: a #TsMuxStream
 * @buf: a buffer to hold the result
 * @len: the length of @buf
 *
 * Copy up to @len available data in @stream into the buffer @buf.
 *
 * Returns: TRUE if @len bytes could be retrieved.
 */
gboolean
tsmux_stream_get_data (TsMuxStream * stream, guint8 * buf, guint len)
{
  g_return_val_if_fail (stream != NULL, FALSE);
  g_return_val_if_fail (buf != NULL, FALSE);

  if (stream->state == TSMUX_STREAM_STATE_HEADER) {
    guint8 pes_hdr_length;

    pes_hdr_length = tsmux_stream_pes_header_length (stream);

    /* Submitted buffer must be at least as large as the PES header */
    if (len < pes_hdr_length)
      return FALSE;

    TS_DEBUG ("Writing PES header of length %u and payload %d",
        pes_hdr_length, stream->cur_pes_payload_size);
    tsmux_stream_write_pes_header (stream, buf);

    len -= pes_hdr_length;
    buf += pes_hdr_length;

    stream->state = TSMUX_STREAM_STATE_PACKET;
  }

  if (len > (guint) tsmux_stream_bytes_avail (stream))
    return FALSE;

  stream->pes_bytes_written += len;

  if (stream->cur_pes_payload_size != 0 &&
      stream->pes_bytes_written == stream->cur_pes_payload_size) {
    TS_DEBUG ("Finished PES packet");
    stream->state = TSMUX_STREAM_STATE_HEADER;
    stream->pes_bytes_written = 0;
  }

  while (len > 0) {
    guint32 avail;
    guint8 *cur;

    if (stream->cur_buffer == NULL) {
      /* Start next packet */
      if (stream->buffers == NULL)
        return FALSE;
      stream->cur_buffer = (TsMuxStreamBuffer *) (stream->buffers->data);
      stream->cur_buffer_consumed = 0;
    }

    /* Take as much as we can from the current buffer */
    avail = stream->cur_buffer->size - stream->cur_buffer_consumed;
    cur = stream->cur_buffer->data + stream->cur_buffer_consumed;
    if (avail < len) {
      memcpy (buf, cur, avail);
      tsmux_stream_consume (stream, avail);

      buf += avail;
      len -= avail;
    } else {
      memcpy (buf, cur, len);
      tsmux_stream_consume (stream, len);

      len = 0;
    }
  }

  return TRUE;
}