www.pudn.com > JM86.rar > rtp.c, change:2004-09-16,size:12371b


/********************************************************************** 
 * Software Copyright Licensing Disclaimer 
 * 
 * This software module was originally developed by contributors to the 
 * course of the development of ISO/IEC 14496-10 for reference purposes 
 * and its performance may not have been optimized.  This software 
 * module is an implementation of one or more tools as specified by 
 * ISO/IEC 14496-10.  ISO/IEC gives users free license to this software 
 * module or modifications thereof. Those intending to use this software 
 * module in products are advised that its use may infringe existing 
 * patents.  ISO/IEC have no liability for use of this software module 
 * or modifications thereof.  The original contributors retain full 
 * rights to modify and use the code for their own purposes, and to 
 * assign or donate the code to third-parties. 
 * 
 * This copyright notice must be included in all copies or derivative 
 * works.  Copyright (c) ISO/IEC 2004. 
 **********************************************************************/ 
 
/*! 
 ************************************************************************ 
 * \file  rtp.c 
 * 
 * \brief 
 *    Network Adaptation layer for RTP packets 
 * 
 * \author 
 *    Main contributors (see contributors.h for copyright, address and affiliation details) 
 *    - Stephan Wenger   <stewe@cs.tu-berlin.de> 
 ************************************************************************ 
 */ 
 
 
/*! 
 
  A quick guide to the basics of the RTP decoder implementation 
 
  This module contains the RTP packetization, de-packetization, and the 
  handling of Parameter Sets, see VCEG-N52 and accompanying documents. 
  Note: Compound packets are not yet implemented! 
 
  The interface between every NAL (including the RTP NAL) and the VCL is 
  based on Slices.  The slice data structure on which the VCL is working 
  is defined in the type Slice (in defines.h).  This type contains the 
  various fields of the slice header and a partition array, which itself 
  contains the data partitions the slice consists of.  When data 
  partitioning is not used, then the whole slice bit string is stored 
  in partition #0.  When individual partitions are missing, this is 
  indicated by the size of the bit strings in the partition array. 
  A complete missing slice (e.g. if a Full Slice packet was lost) is 
  indicated in a similar way.   
   
  part of the slice structure is the error indication (ei-flag).  The 
  Ei-flag is set in such cases in which at least one partition of a slice 
  is damaged or missing.When data partitioning is used, it can happen that 
  one partition does not contain any symbols but the ei_flag is cleared, 
  which indicates the intentional missing of symbols of that partition. 
  A typical example for this behaviour is the Intra Slice, which does not 
  have symnbols in its type C partition. 
 
  The VCL requests new data to work on through the call of readSliceRTP(). 
  This function calls the main state machine of this module in ReadRTPpaacket(). 
 
  ReadRTPpacket assumes, when called, that in an error free environment 
  a complete slice, consisting of one Full Slice RTP packet, or three Partition 
  packets of types A, B, C with consecutive sequence numbers, can be read. 
  It first interprets any trailing SUPP and Parameter Update (Header) packets. 
  Then it reads one video data packet.  Two cases have to be distinguished: 
 
  1. Type A, or Full Slice packet 
  In this case, the PictureID and the macroblock mumbers are used to 
  identify the potential loss of a slice.  A slice is lost, when the 
  StartMB of the newly read slice header is not equal to the current 
  state of the decoder 
    1.1 Loss detected 
      In this case the last packet is unread (fseek back), and a dummy slice 
      containing the missing macroblocks is conveyed to the VCL.  At the next  
      call of the NAL, the same packet is read again, but this time no packet  
      loss is detected by the above algorithm, 
    1.2. No loss 
      In this case it is checked whether a Full Slice packet or a type A data 
      partition was read 
        1.2.1 Full Slice 
          The Full Slice packet is conveyed to the NAL 
        1.2.2 Type A Partition 
          The function RTPReadDataPartitionedSlice() is called, which collects 
          the remaining type B, C partitions and handles them appropriately. 
 
  Paraneter Update Packets (aka Header packets) are in an SDP-like syntax 
  and are interpreted by a simple parser in the function  
  RTPInterpretParameterSetPacket()  
 
  Each Slice header contaions the information on which parameter set to be used. 
  The function RTPSetImgInp() copies the information of the relevant parameter 
  set in the VCL's global variables img-> and inp->  IMPORTANT: any changes 
  in the semantics of the img-> and inp-> structure members must be represented 
  in this function as well! 
 
  A note to the stream-buffer data structure: The stream buffer always contains 
  only the contents of the partition in question, and not the slice/partition 
  header.  Decoding has to start at bitoffset 0 (UVLC) or bytreoffset 0 (CABAC). 
 
  The remaining functions should be self-explanatory. 
   
*/ 
 
#include "contributors.h" 
 
#include <assert.h> 
#include <stdlib.h> 
#include <math.h> 
#include <string.h> 
#include <ctype.h> 
 
#include "global.h" 
#include "errorconcealment.h" 
#include "rtp.h" 
#include "fmo.h" 
#include "sei.h" 
#include "memalloc.h" 
 
 
FILE *bits; 
 
int RTPReadPacket (RTPpacket_t *p, FILE *bits); 
 
/*! 
 ************************************************************************ 
 * \brief 
 *    Opens the bit stream file named fn 
 * \return 
 *    none 
 ************************************************************************ 
 */ 
void OpenRTPFile (char *fn) 
{ 
  if (NULL == (bits=fopen(fn, "rb"))) 
  { 
    snprintf (errortext, ET_SIZE, "Cannot open RTP file '%s'", input->infile); 
    error(errortext,500); 
  } 
} 
 
 
/*! 
 ************************************************************************ 
 * \brief 
 *    Closes the bit stream file 
 ************************************************************************ 
 */ 
void CloseRTPFile() 
{ 
  fclose (bits); 
} 
 
 
/*! 
 ************************************************************************ 
 * \brief 
 *    Fills nalu->buf and nalu->len with the payload of an RTP packet.   
 *    Other fields in nalu-> remain uninitialized (will be taken care of  
 *    by NALUtoRBSP. 
 * 
 * \return 
 *     4 in case of ok (for compatibility with GetAnnexbNALU) 
 *     0 if there is nothing any more to read (EOF) 
 *    -1 in case of any error 
 * 
 ************************************************************************ 
 */ 
 
int GetRTPNALU (NALU_t *nalu) 
{ 
  RTPpacket_t *p; 
  int ret; 
 
  if ((p=malloc (sizeof (RTPpacket_t)))== NULL) 
    no_mem_exit ("GetRTPNALU-1"); 
  if ((p->packet=malloc (MAXRTPPACKETSIZE))== NULL) 
    no_mem_exit ("GetRTPNALU-2"); 
  if ((p->payload=malloc (MAXRTPPACKETSIZE))== NULL) 
    no_mem_exit ("GetRTPNALU-3"); 
 
  ret = RTPReadPacket (p, bits); 
  nalu->forbidden_bit = 1; 
  nalu->len = 0; 
   
  if (ret < 0) 
    return -1; 
  if (ret == 0) 
    return 0; 
 
  assert (p->paylen < nalu->max_size); 
 
  nalu->len = p->paylen; 
  memcpy (nalu->buf, p->payload, p->paylen); 
  nalu->forbidden_bit = (nalu->buf[0]>>7) & 1; 
  nalu->nal_reference_idc = (nalu->buf[0]>>5) & 3; 
  nalu->nal_unit_type = (nalu->buf[0]) & 0x1f; 
 
  free (p->payload); 
  free (p->packet); 
  free (p);  
//  printf ("Got an RTP NALU, len %d, first byte %x\n", nalu->len, nalu->buf[0]); 
  return nalu->len; 
} 
 
 
 
/*! 
 ***************************************************************************** 
 * 
 * \brief  
 *    DecomposeRTPpacket interprets the RTP packet and writes the various 
 *    structure members of the RTPpacket_t structure 
 * 
 * \return 
 *    0 in case of success 
 *    negative error code in case of failure 
 * 
 * \param p 
 *    Caller is responsible to allocate enough memory for the generated payload 
 *    in parameter->payload. Typically a malloc of paclen-12 bytes is sufficient 
 * 
 * \par Side effects 
 *    none 
 * 
 * \date 
 *    30 Spetember 2001 
 * 
 * \author 
 *    Stephan Wenger   stewe@cs.tu-berlin.de 
 *****************************************************************************/ 
 
int DecomposeRTPpacket (RTPpacket_t *p) 
 
{ 
  // consistency check  
  assert (p->packlen < 65536 - 28);  // IP, UDP headers 
  assert (p->packlen >= 12);         // at least a complete RTP header 
  assert (p->payload != NULL); 
  assert (p->packet != NULL); 
 
  // Extract header information 
 
  p->v  = p->packet[0] & 0x3; 
  p->p  = (p->packet[0] & 0x4) >> 2; 
  p->x  = (p->packet[0] & 0x8) >> 3; 
  p->cc = (p->packet[0] & 0xf0) >> 4; 
 
  p->m  = p->packet[1] & 0x1; 
  p->pt = (p->packet[1] & 0xfe) >> 1; 
 
  p->seq = p->packet[2] | (p->packet[3] << 8); 
 
  memcpy (&p->timestamp, &p->packet[4], 4);// change to shifts for unified byte sex 
  memcpy (&p->ssrc, &p->packet[8], 4);// change to shifts for unified byte sex 
 
  // header consistency checks 
  if (     (p->v != 2) 
        || (p->p != 0) 
        || (p->x != 0) 
        || (p->cc != 0) ) 
  { 
    printf ("DecomposeRTPpacket, RTP header consistency problem, header follows\n"); 
    DumpRTPHeader (p); 
    return -1; 
  } 
  p->paylen = p->packlen-12; 
  memcpy (p->payload, &p->packet[12], p->paylen); 
  return 0; 
} 
 
/*! 
 ***************************************************************************** 
 * 
 * \brief  
 *    DumpRTPHeader is a debug tool that dumps a human-readable interpretation 
 *    of the RTP header 
 * 
 * \return 
 *    n.a. 
 * \param p 
 *    the RTP packet to be dumped, after DecompositeRTPpacket() 
 * 
 * \par Side effects 
 *    Debug output to stdout 
 * 
 * \date 
 *    30 Spetember 2001 
 * 
 * \author 
 *    Stephan Wenger   stewe@cs.tu-berlin.de 
 *****************************************************************************/ 
 
void DumpRTPHeader (RTPpacket_t *p) 
 
{ 
  int i; 
  for (i=0; i< 30; i++) 
    printf ("%02x ", p->packet[i]); 
  printf ("Version (V): %d\n", p->v); 
  printf ("Padding (P): %d\n", p->p); 
  printf ("Extension (X): %d\n", p->x); 
  printf ("CSRC count (CC): %d\n", p->cc); 
  printf ("Marker bit (M): %d\n", p->m); 
  printf ("Payload Type (PT): %d\n", p->pt); 
  printf ("Sequence Number: %d\n", p->seq); 
  printf ("Timestamp: %d\n", p->timestamp); 
  printf ("SSRC: %d\n", p->ssrc); 
} 
 
 
/*! 
 ***************************************************************************** 
 * 
 * \brief  
 *    RTPReadPacket reads one packet from file 
 * 
 * \return 
 *    0: EOF 
 *    negative: error 
 *    positive: size of RTP packet in bytes 
 * 
 * \param p 
 *    packet data structure, with memory for p->packet allocated 
 * 
 * \param bits 
 *    target file 
 * 
 * \par Side effects: 
 *   - File pointer in bits moved 
 *   - p->xxx filled by reading and Decomposepacket() 
 * 
 * \date 
 *    04 November, 2001 
 * 
 * \author 
 *    Stephan Wenger, stewe@cs.tu-berlin.de 
 *****************************************************************************/ 
 
int RTPReadPacket (RTPpacket_t *p, FILE *bits) 
{ 
  int Filepos, intime; 
 
  assert (p != NULL); 
  assert (p->packet != NULL); 
  assert (p->payload != NULL); 
 
  Filepos = ftell (bits); 
  if (4 != fread (&p->packlen,1, 4, bits)) 
    { 
      return 0; 
    } 
     
  if (4 != fread (&intime, 1, 4, bits)) 
    { 
      fseek (bits, Filepos, SEEK_SET); 
      printf ("RTPReadPacket: File corruption, could not read Timestamp, exit\n"); 
      exit (-1); 
    } 
 
  assert (p->packlen < MAXRTPPACKETSIZE); 
 
  if (p->packlen != fread (p->packet, 1, p->packlen, bits)) 
    { 
      printf ("RTPReadPacket: File corruption, could not read %d bytes\n", p->packlen); 
      exit (-1);    // EOF inidication 
    } 
 
  if (DecomposeRTPpacket (p) < 0) 
    { 
      // this should never happen, hence exit() is ok.  We probably do not want to attempt 
      // to decode a packet that obviously wasn't generated by RTP 
      printf ("Errors reported by DecomposePacket(), exit\n"); 
      exit (-700); 
    } 
    assert (p->pt == H26LPAYLOADTYPE); 
    assert (p->ssrc == 0x12345678); 
  return p->packlen; 
}