rtp.c
资源名称:chapter15.rar [点击查看]
上传用户:hjq518
上传日期:2021-12-09
资源大小:5084k
文件大小:19k
源码类别:
Audio
开发平台:
Visual C++
- /*!
- *****************************************************************************
- * file rtp.c
- *
- * brief
- * Functions to handle RTP headers and packets per RFC 3984
- * with restricted functionality.
- *
- * author
- * Stephan Wenger stewe@cs.tu-berlin.de
- *****************************************************************************/
- #ifdef WIN32
- #include <Winsock2.h>
- #else
- #include <netinet/in.h>
- #endif
- #include "global.h"
- #include "rtp.h"
- #include "sei.h"
- // A little trick to avoid those horrible #if TRACE all over the source code
- #if TRACE
- #define SYMTRACESTRING(s) strncpy(sym.tracestring,s,TRACESTRING_SIZE)
- #else
- #define SYMTRACESTRING(s) // to nothing
- #endif
- int CurrentRTPTimestamp = 0; //! The RTP timestamp of the current packet,
- //! incremented with all P and I frames
- unsigned short CurrentRTPSequenceNumber = 0; //! The RTP sequence number of the current packet
- //! incremented by one for each sent packet
- FILE *f;
- /*!
- *****************************************************************************
- *
- * brief
- * ComposeRTPpacket composes the complete RTP packet using the various
- * structure members of the RTPpacket_t structure
- *
- * return
- * 0 in case of success
- * negative error code in case of failure
- *
- * par Parameters
- * Caller is responsible to allocate enough memory for the generated packet
- * in parameter->packet. Typically a malloc of 12+paylen bytes is sufficient
- *
- * par Side effects
- * none
- *
- * note
- * Function contains assert() tests for debug purposes (consistency checks
- * for RTP header fields
- *
- * date
- * 30 September 2001
- *
- * author
- * Stephan Wenger stewe@cs.tu-berlin.de
- *****************************************************************************/
- int ComposeRTPPacket (RTPpacket_t *p)
- {
- unsigned int temp32;
- unsigned short temp16;
- // Consistency checks through assert, only used for debug purposes
- assert (p->v == 2);
- assert (p->p == 0);
- assert (p->x == 0);
- assert (p->cc == 0); // mixer designers need to change this one
- assert (p->m == 0 || p->m == 1);
- assert (p->pt < 128);
- assert (p->payload != NULL);
- assert (p->paylen < 65536 - 40); // 2**16 -40 for IP/UDP/RTP header
- assert (p->packet != NULL);
- // Compose RTP header, little endian
- p->packet[0] = (byte)
- ( ((p->v & 0x03) << 6)
- | ((p->p & 0x01) << 5)
- | ((p->x & 0x01) << 4)
- | ((p->cc & 0x0F) << 0) );
- p->packet[1] = (byte)
- ( ((p->m & 0x01) << 7)
- | ((p->pt & 0x7F) << 0) );
- // sequence number, msb first
- temp16 = htons((unsigned short)p->seq);
- memcpy (&p->packet[2], &temp16, 2); // change to shifts for unified byte sex
- //declare a temporary variable to perform network byte order conversion
- temp32 = htonl(p->timestamp);
- memcpy (&p->packet[4], &temp32, 4); // change to shifts for unified byte sex
- temp32 = htonl(p->ssrc);
- memcpy (&p->packet[8], &temp32, 4);// change to shifts for unified byte sex
- // Copy payload
- memcpy (&p->packet[12], p->payload, p->paylen);
- p->packlen = p->paylen+12;
- return 0;
- }
- /*!
- *****************************************************************************
- *
- * brief
- * WriteRTPPacket writes the supplied RTP packet to the output file
- *
- * return
- * 0 in case of access
- * <0 in case of write failure (typically fatal)
- *
- * param p
- * the RTP packet to be written (after ComposeRTPPacket() )
- * param f
- * output file
- *
- * date
- * October 23, 2001
- *
- * author
- * Stephan Wenger stewe@cs.tu-berlin.de
- *****************************************************************************/
- int WriteRTPPacket (RTPpacket_t *p, FILE *f)
- {
- int intime = -1;
- assert (f != NULL);
- assert (p != NULL);
- if (1 != fwrite (&p->packlen, 4, 1, f))
- return -1;
- if (1 != fwrite (&intime, 4, 1, f))
- return -1;
- if (1 != fwrite (p->packet, p->packlen, 1, f))
- return -1;
- return 0;
- }
- /*!
- *****************************************************************************
- *
- * brief
- * int RTPWriteNALU write a NALU to the RTP file
- *
- * return
- * Number of bytes written to output file
- *
- * par Side effects
- * Packet written, RTPSequenceNumber and RTPTimestamp updated
- *
- * date
- * December 13, 2002
- *
- * author
- * Stephan Wenger stewe@cs.tu-berlin.de
- *****************************************************************************/
- int WriteRTPNALU (NALU_t *n)
- {
- RTPpacket_t *p;
- byte first_byte;
- assert (f != NULL);
- assert (n != NULL);
- assert (n->len < 65000);
- first_byte = (byte)
- (n->forbidden_bit << 7 |
- n->nal_reference_idc << 5 |
- n->nal_unit_type );
- // Set RTP structure elements and alloca() memory foor the buffers
- if ((p = (RTPpacket_t *) malloc (sizeof (RTPpacket_t))) == NULL)
- no_mem_exit ("RTPWriteNALU-1");
- if ((p->packet = malloc (MAXRTPPACKETSIZE)) == NULL)
- no_mem_exit ("RTPWriteNALU-2");
- if ((p->payload = malloc (MAXRTPPACKETSIZE)) == NULL)
- no_mem_exit ("RTPWriteNALU-3");
- p->v=2;
- p->p=0;
- p->x=0;
- p->cc=0;
- p->m=(n->startcodeprefix_len==4)&1; // a long startcode of Annex B sets marker bit of RTP
- // Not exactly according to the RTP paylaod spec, but
- // good enough for now (hopefully).
- //! For error resilience work, we need the correct
- //! marker bit. Introduce a nalu->marker and set it in
- //! terminate_slice()?
- p->pt=H264PAYLOADTYPE;
- p->seq=CurrentRTPSequenceNumber++;
- p->timestamp=CurrentRTPTimestamp;
- p->ssrc=H264SSRC;
- p->paylen = 1 + n->len;
- p->payload[0] = first_byte;
- memcpy (p->payload+1, n->buf, n->len);
- // Generate complete RTP packet
- if (ComposeRTPPacket (p) < 0)
- {
- printf ("Cannot compose RTP packet, exitn");
- exit (-1);
- }
- if (WriteRTPPacket (p, f) < 0)
- {
- printf ("Cannot write %d bytes of RTP packet to outfile, exitn", p->packlen);
- exit (-1);
- }
- free (p->packet);
- free (p->payload);
- free (p);
- return (n->len * 8);
- }
- /*!
- ********************************************************************************************
- * brief
- * RTPUpdateTimestamp: patches the RTP timestamp depending on the TR
- *
- * param
- * tr: TRof the following NALUs
- *
- * return
- * none.
- *
- ********************************************************************************************
- */
- void RTPUpdateTimestamp (int tr)
- {
- int delta;
- static int oldtr = -1;
- if (oldtr == -1) // First invocation
- {
- CurrentRTPTimestamp = 0; //! This is a violation of the security req. of
- //! RTP (random timestamp), but easier to debug
- oldtr = 0;
- return;
- }
- /*! The following code assumes a wrap around of TR at 256, and
- needs to be changed as soon as this is no more true.
- The support for B frames is a bit tricky, because it is not easy to distinguish
- between a natural wrap-around of the tr, and the intentional going back of the
- tr because of a B frame. It is solved here by a heuristic means: It is assumed that
- B frames are never "older" than 10 tr ticks. Everything higher than 10 is considered
- a wrap around.
- */
- delta = tr - oldtr;
- if (delta < -10) // wrap-around
- delta+=256;
- CurrentRTPTimestamp += delta * RTP_TR_TIMESTAMP_MULT;
- oldtr = tr;
- }
- /*!
- ********************************************************************************************
- * brief
- * Opens the output file for the RTP packet stream
- *
- * param Filename
- * The filename of the file to be opened
- *
- * return
- * none. Function terminates the program in case of an error
- *
- ********************************************************************************************
- */
- void OpenRTPFile (char *Filename)
- {
- if ((f = fopen (Filename, "wb")) == NULL)
- {
- printf ("Fatal: cannot open bitstream file '%s', exit (-1)n", Filename);
- exit (-1);
- }
- }
- /*!
- ********************************************************************************************
- * brief
- * Closes the output file for the RTP packet stream
- *
- * return
- * none. Function terminates the program in case of an error
- *
- ********************************************************************************************
- */
- void CloseRTPFile (void)
- {
- fclose(f);
- }
- #if 0
- /*!
- *****************************************************************************
- *
- * brief
- * int aggregationRTPWriteBits (int marker) write the Slice header for the RTP NAL
- *
- * return
- * Number of bytes written to output file
- *
- * param marker
- * marker bit,
- *
- * par Side effects
- * Packet written, RTPSequenceNumber and RTPTimestamp updated
- *
- * date
- * September 10, 2002
- *
- * author
- * Dong Tian tian@cs.tut.fi
- *****************************************************************************/
- int aggregationRTPWriteBits (int Marker, int PacketType, int subPacketType, void * bitstream,
- int BitStreamLenInByte, FILE *out)
- {
- RTPpacket_t *p;
- int offset;
- // printf( "writing aggregation packet...n");
- assert (out != NULL);
- assert (BitStreamLenInByte < 65000);
- assert (bitstream != NULL);
- assert ((PacketType&0xf) == 4);
- // Set RTP structure elements and alloca() memory foor the buffers
- p = (RTPpacket_t *) alloca (sizeof (RTPpacket_t));
- p->packet=alloca (MAXRTPPACKETSIZE);
- p->payload=alloca (MAXRTPPACKETSIZE);
- p->v=2;
- p->p=0;
- p->x=0;
- p->cc=0;
- p->m=Marker&1;
- p->pt=H264PAYLOADTYPE;
- p->seq=CurrentRTPSequenceNumber++;
- p->timestamp=CurrentRTPTimestamp;
- p->ssrc=H264SSRC;
- offset = 0;
- p->payload[offset++] = PacketType; // This is the first byte of the compound packet
- // FIRST, write the sei message to aggregation packet, if it is available
- if ( HaveAggregationSEI() )
- {
- p->payload[offset++] = sei_message[AGGREGATION_SEI].subPacketType; // this is the first byte of the first subpacket
- *(short*)&(p->payload[offset]) = sei_message[AGGREGATION_SEI].payloadSize;
- offset += 2;
- memcpy (&p->payload[offset], sei_message[AGGREGATION_SEI].data, sei_message[AGGREGATION_SEI].payloadSize);
- offset += sei_message[AGGREGATION_SEI].payloadSize;
- clear_sei_message(AGGREGATION_SEI);
- }
- // SECOND, write other payload to the aggregation packet
- // to do ...
- // LAST, write the slice data to the aggregation packet
- p->payload[offset++] = subPacketType; // this is the first byte of the second subpacket
- *(short*)&(p->payload[offset]) = BitStreamLenInByte;
- offset += 2;
- memcpy (&p->payload[offset], bitstream, BitStreamLenInByte);
- offset += BitStreamLenInByte;
- p->paylen = offset; // 1 +3 +seiPayload.payloadSize +3 +BitStreamLenInByte
- // Now the payload is ready, we can ...
- // Generate complete RTP packet
- if (ComposeRTPPacket (p) < 0)
- {
- printf ("Cannot compose RTP packet, exitn");
- exit (-1);
- }
- if (WriteRTPPacket (p, out) < 0)
- {
- printf ("Cannot write %d bytes of RTP packet to outfile, exitn", p->packlen);
- exit (-1);
- }
- return (p->packlen);
- }
- /*!
- *****************************************************************************
- * brief
- * Determine if current packet is normal packet or compound packet (aggregation
- * packet)
- *
- * return
- * return TRUE, if it is compound packet.
- * return FALSE, otherwise.
- *
- * date
- * September 10, 2002
- *
- * author
- * Dong Tian tian@cs.tut.fi
- *****************************************************************************/
- Boolean isAggregationPacket(void)
- {
- if (HaveAggregationSEI())
- {
- return TRUE;
- }
- // Until Sept 2002, the JM will produce aggregation packet only for some SEI messages
- return FALSE;
- }
- #endif
- /*!
- *****************************************************************************
- * brief
- * Prepare the aggregation sei message.
- *
- * date
- * September 10, 2002
- *
- * author
- * Dong Tian tian@cs.tut.fi
- *****************************************************************************/
- void PrepareAggregationSEIMessage(void)
- {
- Boolean has_aggregation_sei_message = FALSE;
- clear_sei_message(AGGREGATION_SEI);
- // prepare the sei message here
- // write the spare picture sei payload to the aggregation sei message
- if (seiHasSparePicture && img->type != B_SLICE)
- {
- FinalizeSpareMBMap();
- assert(seiSparePicturePayload.data->byte_pos == seiSparePicturePayload.payloadSize);
- write_sei_message(AGGREGATION_SEI, seiSparePicturePayload.data->streamBuffer, seiSparePicturePayload.payloadSize, SEI_SPARE_PIC);
- has_aggregation_sei_message = TRUE;
- }
- // write the sub sequence information sei paylaod to the aggregation sei message
- if (seiHasSubseqInfo)
- {
- FinalizeSubseqInfo(img->layer);
- write_sei_message(AGGREGATION_SEI, seiSubseqInfo[img->layer].data->streamBuffer, seiSubseqInfo[img->layer].payloadSize, SEI_SUB_SEQ_INFO);
- ClearSubseqInfoPayload(img->layer);
- has_aggregation_sei_message = TRUE;
- }
- // write the sub sequence layer information sei paylaod to the aggregation sei message
- if (seiHasSubseqLayerInfo && img->number == 0)
- {
- FinalizeSubseqLayerInfo();
- write_sei_message(AGGREGATION_SEI, seiSubseqLayerInfo.data, seiSubseqLayerInfo.payloadSize, SEI_SUB_SEQ_LAYER_CHARACTERISTICS);
- seiHasSubseqLayerInfo = FALSE;
- has_aggregation_sei_message = TRUE;
- }
- // write the sub sequence characteristics payload to the aggregation sei message
- if (seiHasSubseqChar)
- {
- FinalizeSubseqChar();
- write_sei_message(AGGREGATION_SEI, seiSubseqChar.data->streamBuffer, seiSubseqChar.payloadSize, SEI_SUB_SEQ_CHARACTERISTICS);
- ClearSubseqCharPayload();
- has_aggregation_sei_message = TRUE;
- }
- // write the pan scan rectangle info sei playload to the aggregation sei message
- if (seiHasPanScanRectInfo)
- {
- FinalizePanScanRectInfo();
- write_sei_message(AGGREGATION_SEI, seiPanScanRectInfo.data->streamBuffer, seiPanScanRectInfo.payloadSize, SEI_PAN_SCAN_RECT);
- ClearPanScanRectInfoPayload();
- has_aggregation_sei_message = TRUE;
- }
- // write the arbitrary (unregistered) info sei playload to the aggregation sei message
- if (seiHasUser_data_unregistered_info)
- {
- FinalizeUser_data_unregistered();
- write_sei_message(AGGREGATION_SEI, seiUser_data_unregistered.data->streamBuffer, seiUser_data_unregistered.payloadSize, SEI_USER_DATA_UNREGISTERED);
- ClearUser_data_unregistered();
- has_aggregation_sei_message = TRUE;
- }
- // write the arbitrary (unregistered) info sei playload to the aggregation sei message
- if (seiHasUser_data_registered_itu_t_t35_info)
- {
- FinalizeUser_data_registered_itu_t_t35();
- write_sei_message(AGGREGATION_SEI, seiUser_data_registered_itu_t_t35.data->streamBuffer, seiUser_data_registered_itu_t_t35.payloadSize, SEI_USER_DATA_REGISTERED_ITU_T_T35);
- ClearUser_data_registered_itu_t_t35();
- has_aggregation_sei_message = TRUE;
- }
- //write RandomAccess info sei payload to the aggregation sei message
- if (seiHasRecoveryPoint_info)
- {
- FinalizeRandomAccess();
- write_sei_message(AGGREGATION_SEI, seiRecoveryPoint.data->streamBuffer, seiRecoveryPoint.payloadSize, SEI_RECOVERY_POINT);
- ClearRandomAccess();
- has_aggregation_sei_message = TRUE;
- }
- // more aggregation sei payload is written here...
- // write the scene information SEI payload
- if (seiHasSceneInformation)
- {
- FinalizeSceneInformation();
- write_sei_message(AGGREGATION_SEI, seiSceneInformation.data->streamBuffer, seiSceneInformation.payloadSize, SEI_SCENE_INFO);
- has_aggregation_sei_message = TRUE;
- }
- if (seiHasTone_mapping)
- {
- FinalizeToneMapping();
- write_sei_message(AGGREGATION_SEI, seiToneMapping.data->streamBuffer, seiToneMapping.payloadSize, SEI_TONE_MAPPING);
- ClearToneMapping();
- has_aggregation_sei_message = TRUE;
- }
- if (seiHasPostFilterHints_info)
- {
- FinalizePostFilterHints();
- write_sei_message(AGGREGATION_SEI, seiPostFilterHints.data->streamBuffer, seiPostFilterHints.payloadSize, SEI_POST_FILTER_HINTS);
- has_aggregation_sei_message = TRUE;
- }
- if (seiHasBuffering_period)
- {
- FinalizeBufferingPeriod();
- write_sei_message(AGGREGATION_SEI, seiBufferingPeriod.data->streamBuffer, seiBufferingPeriod.payloadSize, SEI_BUFFERING_PERIOD);
- has_aggregation_sei_message = TRUE;
- }
- if (seiHasPicTiming_info)
- {
- FinalizePicTiming();
- write_sei_message(AGGREGATION_SEI, seiPicTiming.data->streamBuffer, seiPicTiming.payloadSize, SEI_PIC_TIMING);
- has_aggregation_sei_message = TRUE;
- }
- // after all the sei payload is written
- if (has_aggregation_sei_message)
- finalize_sei_message(AGGREGATION_SEI);
- }
- #if 0
- /*!
- *****************************************************************************
- * begin_sub_sequence_rtp
- * brief
- * do some initialization for sub-sequence under rtp
- *
- * date
- * September 10, 2002
- *
- * author
- * Dong Tian tian@cs.tut.fi
- *****************************************************************************/
- void begin_sub_sequence_rtp(void)
- {
- if ( params->of_mode != PAR_OF_RTP || params->NumFramesInELSubSeq == 0 )
- return;
- // begin to encode the base layer subseq
- if ( IMG_NUMBER == 0 )
- {
- // printf("begin to encode the base layer subseqn");
- InitSubseqInfo(0);
- if (1)
- UpdateSubseqChar();
- }
- // begin to encode the enhanced layer subseq
- if ( IMG_NUMBER % (params->NumFramesInELSubSeq+1) == 1 )
- {
- // printf("begin to encode the enhanced layer subseqn");
- InitSubseqInfo(1); // init the sub-sequence in the enhanced layer
- // add_dependent_subseq(1);
- if (1)
- UpdateSubseqChar();
- }
- }
- /*!
- *****************************************************************************
- * end_sub_sequence_rtp
- * brief
- * do nothing
- *
- * date
- * September 10, 2002
- *
- * author
- * Dong Tian tian@cs.tut.fi
- *****************************************************************************/
- void end_sub_sequence_rtp(void)
- {
- // end of the base layer:
- if ( img->number == params->no_frames - 1 )
- {
- // printf("end of encoding the base layer subseqn");
- CloseSubseqInfo(0);
- // updateSubSequenceBox(0);
- }
- // end of the enhanced layer:
- if ( ((IMG_NUMBER%(params->NumFramesInELSubSeq+1)==0) && (params->successive_Bframe != 0) && (IMG_NUMBER>0)) || // there are B frames
- ((IMG_NUMBER%(params->NumFramesInELSubSeq+1)==params->NumFramesInELSubSeq) && (params->successive_Bframe==0)) // there are no B frames
- )
- {
- // printf("end of encoding the enhanced layer subseqn");
- CloseSubseqInfo(1);
- // add_dependent_subseq(1);
- // updateSubSequenceBox(1);
- }
- }
- #endif