rtp_theora.c

Go to the documentation of this file.
00001 /* *
00002  * This file is part of libnemesi
00003  *
00004  * Copyright (C) 2007 by LScube team <team@streaming.polito.it>
00005  * See AUTHORS for more details
00006  *
00007  * libnemesi is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * libnemesi is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with libnemesi; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  *
00021  * */
00022 
00023 #include "rtpparser.h"
00024 #include "rtp_xiph.h"
00025 #include "rtp_utils.h"
00026 #include <math.h>
00027 
00038 typedef struct {
00039     long offset;    
00040     int pkts;       
00041     uint8_t *buf;   
00042     long len;       
00043     int id;         
00044     rtp_xiph_conf *conf;        
00045     int conf_len;
00046 } rtp_theora;
00047 
00048 static const rtpparser_info theora_served = {
00049     -1,
00050     {"theora", NULL}
00051 };
00052 
00053 static int single_parse(rtp_theora * priv, rtp_pkt * pkt, rtp_frame * fr,
00054             rtp_buff * config, rtp_ssrc * ssrc)
00055 {
00056     uint8_t * this_pkt = RTP_PKT_DATA(pkt) + priv->offset;
00057     unsigned len = nms_consume_BE2(&this_pkt);
00058 
00059     if (priv->id != RTP_XIPH_ID(pkt) &&    //not the current id
00060         //  !cfg_cache_find(priv,RTP_XIPH_ID(pkt)) || //XXX
00061         (RTP_XIPH_T(pkt) != 1)    //not a config packet
00062        ) {
00063         nms_printf(NMSML_ERR, "Id %0x unknown, expected %0x\n",
00064                    (unsigned)RTP_XIPH_ID(pkt), (unsigned)priv->id);
00065         return RTP_PARSE_ERROR;
00066     }
00067 
00068     fr->data = priv->buf = realloc(priv->buf, len);
00069     fr->len = priv->len = len;
00070 
00071     memcpy(fr->data, this_pkt, fr->len);
00072     priv->pkts--;
00073     if (priv->pkts == 0) {
00074         rtp_rm_pkt(ssrc);
00075     }
00076 
00077     if (RTP_XIPH_T(pkt) == 1)
00078         return -1; //cfg_fixup(priv, fr, config, RTP_XIPH_ID(pkt));
00079     else {
00080         config->data = priv->conf[0].conf;
00081         config->len  = priv->conf[0].len;
00082     }
00083 
00084     return 0;
00085 }
00086 
00087 static int frag_parse(rtp_theora * priv, rtp_pkt * pkt, rtp_frame * fr,
00088               rtp_buff * config, rtp_ssrc * ssrc)
00089 {
00090     int len, err = EAGAIN;
00091 
00092     switch (RTP_XIPH_F(pkt)) {
00093     case 1:
00094         priv->len = 0;
00095     case 2:
00096         len = RTP_XIPH_LEN(pkt, 4);
00097         priv->buf = realloc(priv->buf, priv->len + len);
00098         memcpy(priv->buf + priv->len, RTP_XIPH_DATA(pkt, 4), len);
00099         priv->len += len;
00100         break;
00101     case 3:
00102         len = RTP_XIPH_LEN(pkt, 4);
00103         priv->buf = realloc(priv->buf, priv->len + len);
00104         memcpy(priv->buf + priv->len, RTP_XIPH_DATA(pkt, 4), len);
00105         priv->len += len;
00106 
00107         if (priv->len > fr->len) {
00108             fr->data = realloc(fr->data, priv->len);
00109             fr->len = priv->len;
00110         }
00111         memcpy(fr->data, priv->buf, fr->len);
00112 
00113         if (RTP_XIPH_T(pkt) == 1)
00114             err = -1;//cfg_fixup(priv, fr, config, RTP_XIPH_ID(pkt));
00115         else {
00116             config->data = priv->conf[0].conf;
00117             config->len  = priv->conf[0].len;
00118             err = 0;
00119         }
00120         break;
00121     default:
00122         err = -1;
00123         break;
00124     }
00125 
00126     rtp_rm_pkt(ssrc);
00127 
00128     return err;
00129 }
00130 
00131 static int pack_parse(rtp_theora * priv, rtp_pkt * pkt, rtp_frame * fr,
00132               rtp_buff * config, rtp_ssrc * ssrc)
00133 {
00134     single_parse(priv, pkt, fr, config, ssrc);
00135     priv->offset += fr->len + 2;
00136     return 0;
00137 }
00138 
00139 static uint64_t get_v(uint8_t **cur, int *len)
00140 {
00141     uint64_t val = 0;
00142     uint8_t *cursor = *cur;
00143     int tmp = 128, i;
00144     for (i = 0; i<*len && tmp&128; i++)
00145     {
00146         tmp = *cursor++;
00147         val= (val<<7) + (tmp&127);
00148     }
00149     *cur = cursor;
00150     *len -= i;
00151     return val;
00152 }
00153 
00154 static int xiphrtp_to_mkv(rtp_theora *priv, uint8_t **value, int *size)
00155 {
00156     uint8_t *conf;
00157     rtp_xiph_conf *tmp;
00158     int i, count, offset = 1, val;
00159     int id  = nms_consume_BE3(value);
00160     int len = nms_consume_BE2(value);
00161 
00162     //XXX check len
00163 
00164     if (len) {
00165         // convert the format
00166         count = get_v(value, size);
00167         if (count != 2) {
00168             // corrupted packet?
00169             return RTP_PARSE_ERROR;
00170         }
00171         conf = malloc(len + len/255 + 64);
00172         for (i=0; i < count && size > 0 && offset < len; i++) {
00173             val = get_v(value, size);
00174             offset += nms_xiphlacing(conf + offset, val);
00175         }
00176         if (len > *size) {
00177             free(conf);
00178             return RTP_PARSE_ERROR;
00179         }
00180         conf[0] = count;
00181         memcpy(conf + offset, *value, len);
00182         *value += len;
00183         // append to the list
00184         priv->conf_len++;
00185         priv->conf = realloc(priv->conf,
00186                                priv->conf_len*sizeof(rtp_xiph_conf));
00187         tmp = priv->conf + priv->conf_len - 1;
00188         tmp->conf = conf;
00189         tmp->len = len + offset;
00190         tmp->id = id;
00191     }
00192     return 0;
00193 }
00194 
00195 
00196 static int unpack_config(rtp_theora *priv, char *value, int len)
00197 {
00198     uint8_t buff[len];
00199     uint8_t *cur = buff;
00200     int size = nms_base64_decode(buff, value, len);
00201     int count, i;
00202     if (size <= 0) return 1;
00203 
00204     count = nms_consume_BE4(&cur);
00205     size -= 4;
00206 
00207     for (i = 0; i < count && size > 0; i++) {
00208         if (xiphrtp_to_mkv(priv, &cur, &size)) return 1;
00209     }
00210 
00211     return 0;
00212 }
00213 
00214 static void cleanup (rtp_theora *priv)
00215 {
00216     int i;
00217     if (priv->buf)
00218         free(priv->buf);
00219     if (priv->conf) {
00220         for (i = 0; i < priv->conf_len; i++)
00221             if (priv->conf[i].conf)
00222                 free(priv->conf[i].conf);
00223         free(priv->conf);
00224     }
00225 
00226     free(priv);
00227 }
00228 
00229 static int theora_uninit_parser(rtp_ssrc * ssrc, unsigned pt)
00230 {
00231     rtp_theora *priv = ssrc->rtp_sess->ptdefs[pt]->priv;
00232 
00233     if (!priv) return 0;
00234 
00235     cleanup(priv);
00236 
00237     ssrc->rtp_sess->ptdefs[pt]->priv = NULL;
00238 
00239     return 0;
00240 }
00241 
00242 static int theora_init_parser(rtp_session * rtp_sess, unsigned pt)
00243 {
00244     rtp_theora *priv = calloc(1, sizeof(rtp_theora));
00245     rtp_pt_attrs *attrs = &rtp_sess->ptdefs[pt]->attrs;
00246     char value[65536];
00247     int i, err = -1;
00248     int len;
00249 
00250     if (!priv)
00251         return RTP_ERRALLOC;
00252 
00253     memset(priv, 0, sizeof(rtp_theora));
00254 
00255 // parse the sdp to get the first configuration
00256     for (i=0; i < attrs->size; i++) {
00257         if ((len = nms_get_attr_value(attrs->data[i], "configuration",
00258              value, sizeof(value)))) {
00259             err = unpack_config(priv, value, len);
00260         }
00261         // other ways are disregarded for now.
00262         if (!err) break;
00263     }
00264 
00265     if (err) {
00266         cleanup(priv);
00267         return RTP_PARSE_ERROR;
00268     }
00269 
00270     // We start with the first codebook set
00271     priv->id = priv->conf[0].id;
00272 
00273     rtp_sess->ptdefs[pt]->priv = priv;
00274 
00275     return 0;
00276 }
00277 
00283 static int theora_parse(rtp_ssrc * ssrc, rtp_frame * fr, rtp_buff * config)
00284 {
00285     rtp_pkt *pkt;
00286     size_t len;
00287 
00288     rtp_theora *priv = ssrc->rtp_sess->ptdefs[fr->pt]->priv;
00289 
00290     config->data = priv->conf[0].conf;
00291     config->len  = priv->conf[0].len;
00292 
00293     // get the current packet
00294     if (!(pkt = rtp_get_pkt(ssrc, &len)))
00295         return RTP_BUFF_EMPTY;
00296     /*fprintf(stderr, "ID: %d, Type: %d, Off: %d\n", RTP_XIPH_ID(pkt), RTP_XIPH_T(pkt), priv->offset);*/
00297     // if I don't have previous work
00298     if (!priv->pkts) {
00299 
00300         // get the number of packets stuffed in the rtp
00301         priv->pkts = RTP_XIPH_PKTS(pkt);
00302         /*fprintf(stderr, "Pkt: %d\n", priv->pkts);*/
00303         // some error checking
00304         if (priv->pkts > 0 && ( (RTP_XIPH_F(pkt)) || (RTP_XIPH_T(pkt) !=0) )) {
00305             /*fprintf(stderr, "ERRORE\n");*/
00306             return RTP_PARSE_ERROR;
00307         }
00308 
00309         if (RTP_XIPH_F(pkt))
00310             return frag_parse(priv, pkt, fr, config, ssrc);
00311 
00312         priv->offset = 4;
00313 
00314         // single packet, easy case
00315         if (priv->pkts == 1) {
00316             /*fprintf(stderr, "SINGL\n");*/
00317             return single_parse(priv, pkt, fr, config, ssrc);
00318         }
00319     }
00320     // keep parsing the current rtp packet
00321     /*fprintf(stderr, "PACK\n");*/
00322     return pack_parse(priv, pkt, fr, config, ssrc);
00323 }
00324 
00325 RTP_PARSER_FULL(theora);

Generated on Tue Feb 3 03:10:02 2009 for libnemesi by  doxygen 1.5.4