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; }
/** * 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; }