www.pudn.com > RTP通用开发库(for Linux).rar > frameread.c


/* frameread.c - frameread */

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define DEBUG(x)
#include 

/*------------------------------------------------------------------------
 * frameread - read a single frame (times number of channles) from stream
 * Notes: frameread implicitly begins at "now".
 *	  Buflen is in bytes.
 *	  Time gives the local time of the first sample in the data. On
 *          some errors, time gives the time of next available data. Its 
 *          initial value has no meaning.
 *        Tsout gives the media timestamp of the beginning of the data.
 *          Its initial value has no meaning. It has meaning only on
 *          success.
 *        On success, frameread returns the number of bytes copied.
 *        Frames must be of constant size and duration.
 *        Frameread copies extra per-packet headers (e.g., as described 
 *          in RFC 2250) as determined by pparam->fr_dataoffsetfcn.
 *        Frameread will re-assemble fragmented frames. If fragmentation
 *          is used, the stream can only be monaureal by the constraints
 *          laid out in RFC 1890. Only the extra headers in the first 
 *          fragment of a fragmented frame are returned. The length of
 *          the buffer for extraheaders is passed in by reference and on
 *          return contains the number of bytes copied into the buffer.
 *        All fragments from the same frame must have the same timestamp,
 *           and must arrive sequentially.
 *        When a packet contains a fraction of a frame, it may contain 
 *           no other frames or parts thereof.
 *------------------------------------------------------------------------
 */
int
frameread(struct synsession *pssn, struct synstream *psstm, struct timespec *time, mediatime_t *tsout, char *buf, int buflen, char *extraheaderbuf, int *extraheaderbuflen, bool *mark)
{

	struct frameparam	*pparam;
	struct timespec	now;
	struct rtp		*prtp;
	struct rtpln		*pln;
	mediatime_t		mnow, ts, readfrom, frameduration;
	bool			block, flush, aligned;
	int			bytesleft, rv, dataoffset, chan, framelen;
	char			*pframe;

	pparam = (struct frameparam *) psstm->sstm_parameters;
	block = (psstm->sstm_readflags & SYN_READ_BLOCK) != 0;
	flush = (psstm->sstm_readflags & SYN_READ_FLUSH) != 0;

	bzero(time, sizeof(struct timespec));
	*tsout = 0;

	while (TRUE) {    

		/* 
		 * Get next packet.
		 */
		if ((rv = synreadnextpacket(pssn, psstm, &pln)) < 0)
			return rv;

		prtp = &pln->rln_rtp;
		pframe = NULL;

		/*
		 * Get length (bytes) of any per-packet headers
		 */
		dataoffset = pparam->fp_dataoffset(prtp, pln->rln_len);
		if (dataoffset == ERROR) {
			bufpoolfreebuf(pln);
			continue;
		}

		bytesleft = pln->rln_len - RTP_HEADER_LEN(prtp) - dataoffset;
		ts = prtp->rtp_time;

		/*
		 * Obtain current time and convert to media time
		 */
		clock_gettime(CLOCK_REALTIME, &now);
		mnow = timeflatten(timesub(now, psstm->sstm_clkx), psstm->sstm_clkrt) + psstm->sstm_clky;
   
		readfrom = (flush == TRUE ? tsmax(mnow, psstm->sstm_lastread) : psstm->sstm_lastread);
  
		/*
		 * Find first frame that is 'current'
		 */
		aligned = pparam->fp_framealigned(prtp, pln->rln_len);
		if (aligned == (bool) ERROR) {
			bufpoolfreebuf(pln);
			continue;
		}

		if (aligned == TRUE) {
			pframe = RTP_DATA(prtp) + dataoffset;
			frameduration = pparam->fp_frameduration(pframe, bytesleft);
			if (frameduration == ERROR) {
				bufpoolfreebuf(pln);
				continue;
			}

			while(!tsgt(ts + frameduration, readfrom)) {
  
				ts += frameduration;

				/*
				 * Advance past all frames at this time (1 per channel).
				 */
				for (chan = 0; chan < pparam->fp_channels; chan++) {
					framelen = pparam->fp_framelength(pframe, bytesleft);

					if (framelen == ERROR) {
						bytesleft = 0;
						break; /* from for */
					}

					pframe += framelen;
					bytesleft -= framelen;
					if (bytesleft <= 0) 
						break; /* from for */
				} /* for */

				if (bytesleft <= 0) 
					break; /* from inner while */

				frameduration = pparam->fp_frameduration(pframe, bytesleft);
				if (frameduration == ERROR) {
					bytesleft = 0; 
					break; /* from inner while */
				}
			} /* while(ts + frameduration <= readfrom) */
  
			/*
			 * Check for no bytes left
			 */
			if (bytesleft <= 0) {
				bufpoolfreebuf(pln);
				continue; /* in outter while */
			}
		}

		/* 
		 * Check if the data is too new to return
		 */
		if ((rv = synreadwait(pssn, psstm, pln, ts, now, mnow, time)) < 0)
			return rv;
		else if (rv == SYN_CONTINUE)
			continue;

		/*
		 * We are now committed to this frame.
		 * Decide if it is a full frame or fragment of a frame.
		 */
		if (pframe != NULL) {
			framelen = pparam->fp_framelength(pframe, bytesleft);
			if (framelen == ERROR) {
				bufpoolfreebuf(pln);
				return ERROR;
			}
		}

		if (aligned && bytesleft >= framelen) {
			/* 
			 * Set mark true if mark bit set AND frame is first in packet.
			 */
			*mark = prtp->rtp_mark && ((char *) pframe == (char *) prtp + dataoffset);
			rv = framereadnonfragmented(pssn, psstm, time, tsout, buf, buflen, extraheaderbuf, extraheaderbuflen, pln, pframe, ts, frameduration, bytesleft);
		} else {
			/*
			 * Reinsert the packet into the queue
			 * and invoke framereadfragmented to reassemble the frame.
			 */
			rtpqinsert(pssn->ssn_session, psstm->sstm_ssrc, pln);
			rv = framereadfragmented(pssn, psstm, time, tsout, buf, buflen, extraheaderbuf, extraheaderbuflen, mark, ts);
		}
		if (rv != ERROR)
			return rv;
	} /* outter while */
}