[Top][All Lists]
[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