⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtp.c

📁 本源码是H.26L标准的Visual C++源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
***********************************************************************
* COPYRIGHT AND WARRANTY INFORMATION
*
* Copyright 2001, International Telecommunications Union, Geneva
*
* DISCLAIMER OF WARRANTY
*
* These software programs are available to the user without any
* license fee or royalty on an "as is" basis. The ITU disclaims
* any and all warranties, whether express, implied, or
* statutory, including any implied warranties of merchantability
* or of fitness for a particular purpose.  In no event shall the
* contributor or the ITU be liable for any incidental, punitive, or
* consequential damages of any kind whatsoever arising from the
* use of these programs.
*
* This disclaimer of warranty extends to the user of these programs
* and user's customers, employees, agents, transferees, successors,
* and assigns.
*
* The ITU does not represent or warrant that the programs furnished
* hereunder are free of infringement of any third-party patents.
* Commercial implementations of ITU-T Recommendations, including
* shareware, may be subject to royalty fees to patent holders.
* Information regarding the ITU-T patent policy is available from
* the ITU Web site at http://www.itu.int.
*
* THIS IS NOT A GRANT OF PATENT RIGHTS - SEE THE ITU-T PATENT POLICY.
************************************************************************
*/

/*!
 ************************************************************************
 * \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 <malloc.h>
#include <math.h>
#include <string.h>
#include <ctype.h>

#include "global.h"
#include "elements.h"
#include "bitsbuf.h"
#include "rtp.h"

extern void tracebits(const char *trace_str,  int len,  int info,int value1,
    int value2) ;

extern FILE *bits;
#define MAX_PARAMETER_STRINGLEN 1000

static int CurrentParameterSet = -1;

typedef struct
{
  int FramesToBeEncoded;
  int FrameSkip;
  char SequenceFileName[MAX_PARAMETER_STRINGLEN];
  int NumberBFrames;
} InfoSet_t;

static InfoSet_t InfoSet;

ParameterSet_t ParSet[RTP_MAX_PARAMETER_SET];

//! The following two variables are used to calculate the size of a lost slice.
//! The NAL conveyes this "lost" slice to the VCL with the ei_flag set in order
//! to trigger concealment

static int LastPicID;       //! PicID of the last packet (current state of the decoder 
                            //! before reading the next packet      
static int ExpectedMBNr;    //! MB Nr of the last decoded MB


/*!
 ************************************************************************
 * \brief
 *    read all Partitions of one Slice from RTP packets
 * \return
 *    SOS if this is not a new frame                                    \n
 *    SOP if this is a new frame                                        \n
 *    EOS if end of sequence reached
 ************************************************************************
 */
int readSliceRTP (struct img_par *img, struct inp_par *inp)
{
  Slice *currSlice = img->currentSlice;
  int PartitionMask;

  assert (currSlice != NULL);

  PartitionMask = ReadRTPPacket (img, inp, bits);
/*
{
int i;
for (i=0; i<25; i++)
printf ("%02x ", currSlice->partArr[0].bitstream->streamBuffer[i]);
printf ("\n");
for (i=0; i<25; i++)
printf ("%02x ", currSlice->partArr[1].bitstream->streamBuffer[i]);
printf ("\n");
for (i=0; i<25; i++)
printf ("%02x ", currSlice->partArr[2].bitstream->streamBuffer[i]);
printf ("\n");
}
*/
  if(PartitionMask == -4711)
    return EOS;

  if(currSlice->start_mb_nr != 0)
    return SOS;
  else
    return SOP;
}

  
/*!
 ************************************************************************
 * \brief
 *    read all partitions of one slice from RTP packet stream, also handle
 *    any Parameter Update packets and SuUPP-Packets
 * \return
 *    -1 for EOF                                              \n
 *    Partition-Bitmask otherwise:
 *    Partition Bitmask: 0x1: Full Slice, 0x2: type A, 0x4: Type B 
 *                       0x8: Type C
 ************************************************************************
 */
int ReadRTPPacket (struct img_par *img, struct inp_par *inp, FILE *bits)
{
  Slice *currSlice = img->currentSlice;
  DecodingEnvironmentPtr dep;
  byte *buf;
  int i=0, dt=0;
  unsigned int last_mb=0, picid=0;
  int eiflag=1;
  static int first=1;
  RTPpacket_t *p, *nextp;
  RTPSliceHeader_t *sh, *nextsh;
  int DoUnread = 0;
  int MBDataIndex;
  int PartitionMask = 0;
  int done = 0;
  int err, back=0;
  int intime=0;
  int ei_flag;
  static int last_pframe=0, bframe_to_code=0;
  int b_interval;
  static unsigned int old_seq=0;
  int FirstMacroblockInSlice;

  assert (currSlice != NULL);
  assert (bits != 0);

  if (first)
  {
    currSlice->max_part_nr = MAX_PART_NR;   // Just to get a start
    ExpectedMBNr = 0;
    LastPicID = -1;
  }


  // Tenporal storage for this function only

  p=alloca (sizeof (RTPpacket_t));      // the RTP packet
  p->packet=alloca (MAXRTPPACKETSIZE);
  p->payload=alloca (MAXRTPPAYLOADLEN);
  nextp=alloca (sizeof (RTPpacket_t));  
  sh=alloca(sizeof (RTPSliceHeader_t));
  sh->RMPNIbuffer=NULL;
  sh->MMCObuffer=NULL;

  nextsh=alloca(sizeof (RTPSliceHeader_t));
  nextsh->RMPNIbuffer=NULL;
  nextsh->MMCObuffer=NULL;

  ExpectedMBNr = img->current_mb_nr;
  LastPicID = img->tr;

  done = 0;
  do  
  {
//    Filepos = ftell (bits);             // to be able to go back one packet
      
    if (RTPReadPacket (p, bits) < 0)    // Read and decompose
      return -4711;

    switch (p->payload[0] & 0xf)
    {
    case 0:       // Full Slice packet
    case 1:       // Partition type A packet
      done = 1;
      break;
 
    case 2:       // Partition B
    case 3:       // Partition C
      // Do nothing.  this results in discarding the unexpected Partition B, C
      // packet, which will later be concealed "automatically", because when
      // interpreting the next Partition A or full slice packet a range of
      // lost blocks is found which will be concealed in the usual manner.
      //
      // If anyonme comes up with an idea how to use coefficients without the
      // header information then this code has to be changed
      printf ("ReadRTPPacket(): found unexpected Partition %c packet, skipping\n", p->payload[0]&0xf==2?'B':'C');
      break;
    case 4:
      //! Compound packets may be handled here, but I (StW) would personally prefer and
      //! recommend to handle them externally, by a pre-processor tool.  For now,
      //! compounds lead to exit()
      printf ("Compound packets not yet implemented, exit\n");
      exit (-700);
      break;
    case 5:
      //! Add implementation of SUPP packets here
      printf ("SUPP packets not yet implemented, skipped\n");
      break;
    case 6:
      printf ("Found header packet\n");

      if ((err = RTPInterpretParameterSetPacket (&p->payload[1], p->paylen-1)) < 0)
      {
        printf ("RTPInterpretParameterSetPacket returns error %d\n", err);
      }
      break;
    default:
      printf ("Undefined packet type %d found, skipped\n", p->payload[0] & 0xf);
      assert (0==1);
      break;
    }
  } while (!done);

  // Here, all the non-video data packets and lonely type B, C partitions
  // are handled.  Now work on the expected type A and full slice packets

  assert ((p->payload[0] & 0xf) < 2);

  if ((p->payload[0] & 0xf) == 0)       // Full Slice packet
  {
    currSlice->ei_flag = 0;
    MBDataIndex = 1;                    // Skip First Byte
    MBDataIndex += RTPInterpretSliceHeader (&p->payload[1], p->paylen-1, 0, sh);
  }
  else                                  // Partition A packet
  {
    currSlice->ei_flag = 0;
    MBDataIndex = 1;                    // Skip First Byte
    MBDataIndex += RTPInterpretSliceHeader (&p->payload[1], p->paylen-1, 1, sh);
  }


  FirstMacroblockInSlice = sh->FirstMBInSliceY * (img->width/16) + 
                               sh->FirstMBInSliceX;   //! assumes picture sizes divisble by 16
  // The purpose of the following if cascade is to check for a lost
  // segment  of macroblocks.  if such a segment is found, a dummy slice
  // without content, but with ei_flag set is generated in order to trigger
  // concealment.
  if(first)
  {
    bframe_to_code = InfoSet.NumberBFrames+1;
  }

  if (LastPicID == sh->PictureID)   // we are in the same picture
  {
    first = FALSE;
    if (ExpectedMBNr == FirstMacroblockInSlice)
    {
      currSlice->partArr[0].bitstream->ei_flag = 0;    // everything seems to be ok.
    }
    else
    {
      if (FirstMacroblockInSlice == 0)
      {
        assert ("weird! PicID wrap around?  Should not happen\n");
      }
      else
      {
        //printf ("SLICE LOSS 1: Slice loss at PicID %d, macoblocks %d to %d\n",LastPicID, ExpectedMBNr, FirstMacroblockInSlice-1);
        back=p->packlen+8;
        fseek (bits, -back, SEEK_CUR);    

        //FirstMacroblockInSlice = (img->width*img->height)/(16*16);
        currSlice->ei_flag = 1;
        currSlice->dp_mode = PAR_DP_1;
        currSlice->start_mb_nr = ExpectedMBNr;
        //! just the same slice we just read!
        currSlice->next_header = RTPGetFollowingSliceHeader (img, nextp, nextsh); 
        assert (currSlice->start_mb_nr == img->current_mb_nr); 
#if _ERROR_CONCEALMENT_
        currSlice->last_mb_nr = FirstMacroblockInSlice-1;
#else
        currSlice->last_mb_nr = FirstMacroblockInSlice;
#endif
        currSlice->partArr[0].bitstream->bitstream_length=0;
        currSlice->partArr[0].bitstream->read_len=0;
        currSlice->partArr[0].bitstream->code_len=0;
        currSlice->partArr[0].bitstream->ei_flag=1;
          
        img->tr = currSlice->picture_id = LastPicID;
         
        return 0;
      }
    }
  }
  else      // we are in a different picture
  {
    b_interval = (int)((float)(InfoSet.FrameSkip +1)/(float)(InfoSet.NumberBFrames +1) + 0.49999);
    if (ExpectedMBNr == 0)    // the old picture was finished
    {
      if (((last_pframe + InfoSet.FrameSkip +1)%256) == sh->PictureID && 
           (bframe_to_code > InfoSet.NumberBFrames) && !first) //! we received a new P-Frame and coded all B-Frames
      {
        //! This P-Frame is the one we expected but maybe parts of it are lost!
        if(InfoSet.NumberBFrames)
        {
          last_pframe = sh->PictureID-(InfoSet.FrameSkip +1);
          if(last_pframe < 0)
            last_pframe += 256;
          bframe_to_code = 1;
        }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -