linphone-developers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Linphone-developers] H263 RTP packet assembling


From: Uwe Zipf
Subject: Re: [Linphone-developers] H263 RTP packet assembling
Date: Thu, 24 Nov 2005 14:37:28 +0100
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040803

Simon Morlat wrote:
Hello,

Thank you for your interesting report.
I discovered the problem of incorrect support recently.
I've finally clean all that so that now linphone only supports H263-1998 with rfc2429 and a dynamic payload type. H263 with rfc2190 is unsupported.
I also added correctly the marker bit for end of video frames.
You can use cvs code to test those last improvements. (I'm interested in your feedback).

I have seen it shortly after I posted my message here...
I will try.
Does anyone knew some other software that uses H263-1998 to test for
compatibility?

RFC2190 is more complex to support than RFC2429. I'm currently reading it, I'll see if I can finally add support for it in linphone. Thanks for the code you submitted, it will help me.

Meantime I got it to work with the Windows Messenger and H263.
I had a look on MythPhone, a plugin for MythTV. There the H.263 data ist simply
split into packets with a size smaller then the MTU. The splitting is done only
by size not on special points in the data (GOBs).
I altered Linphone to do it the same way, done some small changes to
payloadheader construction and it finally worked.

It's a hack, but maybe helpful if you want to add H263 support.


msavencoder.c
=============

static void ms_AVencoder_rtp_callback (AVCodecContext *ctx, void *data, int 
size, int packet_number)
{
  //MX UZi
  MSAVEncoder *r = MS_AVENCODER(ctx->opaque);
  MSQueue *outq = r->q_outputs[0];
  MSMessage *outm;
  guint32 *p = (guint32 *) data;
  gint gob_num = (ntohl(*p) >> 10) & 0x1f;
  gchar *dat = (gchar *)data;
  static guint32 tr = 0; //Static to have it when needed for splitting into 
multiple
  static guint32 sz = 0; //packets (a hack that works for one video connection
                         //         only, must be stored elsewhere for more)

  if(gob_num == 0)
  {
    /* Get relevant framedata and memorize it for later use */
    /* Get the "temporal reference" from the H.263 frameheader. */
    tr = ((dat[2] & 0x03) * 64) + ((dat[3] & 0xfc) / 4);
    /* Get the Imgesize from the H.263 frameheader. */
    sz = (dat[4] >> 2) & 0x07;
  }
  else
  {
    /* The memorized values from the frame start will be used */
  }
  /* Set the H.263 Payload Header (RFC 2190)*/
  /* Get 4 more byte for it */
  outm = ms_message_new(size+4);
  /* Construct payload header.
     Set videosize and the temporal reference to that of the frame */
  ((guint32 *)outm->data)[0] = ntohl((sz << 21) | (tr & 0x000000ff));
  /* Append the data after the payload header */
  memcpy(&(outm->data[4]),data,size);
  ms_queue_put(outq, outm);
  //MX End
}


rtpsession.c
============

#define IP_MAX_MTU 1500 /* Standard MTU */
#define IP_MTU 1290 /* Some space left free for encapsulating stuff */
#define UDP_HEADER_SIZE 28
#define H263_RFC2190_A_HEADER_SIZE 4 /* Size of payloadheader mode A */
/* Space for H.263 Data including payloadheader */
#define H263SPACE (IP_MTU - RTP_FIXED_HEADER_SIZE - UDP_HEADER_SIZE)

/* Commented out the "const" because the buffer is altered */
gint
rtp_session_send_with_ts (RtpSession * session, /*const*/ gchar * buffer, gint 
len,
        guint32 userts)
{
  mblk_t *m;
  int err;

  int start; /* Start of data for actual packet */
  int pktlen; /* Length of data for actual packet */
  gchar payloadheader[4]; /* The payloadheader for the frame */
  int res; /* Result of sending the packet */

  if(session->payload_type == 34) /* For H.263 Sessions only */
  {
    /* Save the frameheader to use in all packets */
    memcpy(payloadheader,buffer,4);
    start = 0;
    len -= 4; /* Don't count the header as data to send */
    err = 0;
    while(len > 0)
    {
      /* Set payloadheader */
      memcpy(&buffer[start],payloadheader,4);
      pktlen = len + H263_RFC2190_A_HEADER_SIZE;
      if(pktlen > H263SPACE) pktlen = H263SPACE;
      #ifdef USE_SENDMSG
        m = rtp_session_create_packet_with_data(session,&buffer[start],pktlen,N
      #else
        m = rtp_session_create_packet(session,RTP_FIXED_HEADER_SIZE,&buffer[sta
      #endif
      pktlen -= H263_RFC2190_A_HEADER_SIZE;
      start += pktlen;
      len -= pktlen;
      if(len < 1) /* This is the last part of the frame so... */
      {
        /* ...set the marker bit (I have seen there is a function to
           do this) */
        ((rtp_header_t*)m->b_rptr)->markbit = 1;
      }
      res = rtp_session_sendm_with_ts(session,m,userts);
      /* Return if send failed */
      if(res < 0) return res;
      err += res;
    }
  }
  else /* Not H.263 */
  {
#ifdef USE_SENDMSG
    m=rtp_session_create_packet_with_data(session,(gchar*)buffer,len,NULL);
#else
    m = rtp_session_create_packet(session,RTP_FIXED_HEADER_SIZE,(gchar*)buffer,
#endif
    err=rtp_session_sendm_with_ts(session,m,userts);
  }
  //MX End
  return err;
}



msavdecoder.c
=============

/* Bitmasks to select bits of a byte from high or low side */
static unsigned char lbitmasks[] = 
{0x00,0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f,0xff};
static unsigned char hbitmasks[] = 
{0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff};

void ms_AVdecoder_process(MSAVDecoder *r)
{
  AVFrame orig;
  AVFrame transformed;
  MSQueue *inq,*outq;
  MSMessage *inm,*outm;
  gint error;
  gint got_picture;
  gint len;
  unsigned char *data;
  AVCodecContext *ctx=&r->av_context;
  gint gob_num;

  gint frame_start; /* If this is the start of a frame? */
  gint sbit; /* Value of the sbit */
  unsigned char tmp; /* Temporal byte */

  inq=r->q_inputs[0];
  outq=r->q_outputs[0];

  /* get a picture from the input queue */
  inm=ms_queue_get(inq);
  g_return_if_fail(inm!=NULL);
  if (inm->size > 0)
  {
    guint32 *p = inm->data;

    if (!r->av_opened){
      error=avcodec_open(&r->av_context, r->av_codec);
      if (error!=0) g_warning("avcodec_open() failed: %i",error);
      else r->av_opened=1;
    }

    /* Look for entire framestartcode instead of only the GOB number.
       Should be more secure. */
    //gob_num = (ntohl(*p) >> 10) & 0x1f;
    /* A frame start implies a GOB number of zero */
    frame_start = (ntohl(p[1]) >> 10) == 32;
    sbit = (ntohl(p[0]) >> 27) & 0x07;

//    ms_trace("gob %i, size %i", gob_num, inm->size);
    ms_trace("ms_AVdecoder_process: received %08x %08x", ntohl(p[0]), 
ntohl(p[1]));

    /* remove H.263 Payload Header */
    /* This is for H.263+, whe use H.263 */
    //p[0] = htonl( ntohl(p[0]) & 0x0000ffff );

//    if (gob_num == 0){
    if(frame_start) {
      if (r->skip_gob == 0)
      {
        unsigned char *data = r->buf_compressed;
ms_trace("ms_AVdecoder_process: decoding %08x %08x %08x", ntohl(((unsigned int *)data)[0]), ntohl(((unsigned int *)data)[1]), ntohl(((unsigned int *)data)[2]));
        while (r->buf_size > 0) {
          
len=avcodec_decode_video(&r->av_context,&orig,&got_picture,data,r->buf_size 
/*inm->size*/);
          if (len<0) {
            ms_warning("ms_AVdecoder_process: error %i.",len);
            break;
          }
          if (got_picture) {
            ms_trace("ms_AVdecoder_process: got_picture: width=%i height=%i 
fmt=%i",
                ctx->width,ctx->height,ctx->pix_fmt);
            /* set the image in the wanted format */
            outm=ms_message_alloc();
            if (r->obufwrap==NULL){
              
r->obufwrap=ms_buffer_new(avpicture_get_size(r->output_pix_fmt,ctx->width,ctx->height));
              r->obufwrap->ref_count++;
            }
            ms_message_set_buf(outm,r->obufwrap);
            
avpicture_fill(&transformed,outm->data,r->output_pix_fmt,ctx->width,ctx->height);
            img_convert(&transformed, r->output_pix_fmt,
                &orig,ctx->pix_fmt,ctx->width,ctx->height);
            ms_queue_put(outq,outm);
          }
          r->buf_size -= len;
          data += len;
        }
      }
      else {
      r->skip_gob = 0;
      }
      /* Cut off the payloadheader when copying the data */
      memcpy(r->buf_compressed, &(inm->data[4]), inm->size - 4);
      r->buf_size = inm->size - 4;
    }
    else {
      /* Reassemble splitted Byte.
         (This works if sbit and ebit make up a whole byte together) */
      if(sbit != 0)
      {
        tmp = (unsigned char)(r->buf_compressed[r->buf_size-1]) & 
hbitmasks[sbit];
        tmp |= (((unsigned char *)inm->data)[4] & lbitmasks[8-sbit]);
        r->buf_compressed[r->buf_size-1] = tmp;
        memcpy(r->buf_compressed + r->buf_size, &(inm->data[5]), inm->size - 5);
        r->buf_size += inm->size - 5;
      }
      else
      {
        memcpy(r->buf_compressed + r->buf_size, &(inm->data[4]), inm->size - 4);
        r->buf_size += inm->size - 4;
      }
    }
  }
    ms_message_destroy(inm);
}


Uwe




reply via email to

[Prev in Thread] Current Thread [Next in Thread]