source: mediastreamer2/linphone/mediastreamer2/src/theora.c @ 436:4b242e98916e

Last change on this file since 436:4b242e98916e was 205:f65852271c00, checked in by smorlat <smorlat@…>, 4 years ago

internationalization of mediastreamer2 (thanks to Petr Pisar)

git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@208 3f6dc0c8-ddfe-455d-9043-3cd528dc4637

File size: 14.2 KB
Line 
1/*
2mediastreamer2 library - modular sound and video processing and streaming
3Copyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)
4
5This program is free software; you can redistribute it and/or
6modify it under the terms of the GNU General Public License
7as published by the Free Software Foundation; either version 2
8of the License, or (at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18*/
19
20#include "mediastreamer2/msfilter.h"
21#include "mediastreamer2/msticker.h"
22#include "mediastreamer2/msvideo.h"
23
24#include <theora/theora.h>
25
26typedef struct EncState{
27        theora_state tstate;
28        theora_info tinfo;
29        yuv_buffer yuv;
30        mblk_t *packed_conf;
31        uint64_t start_time;
32        uint64_t conf_time;
33        unsigned int mtu;
34} EncState;
35
36static void enc_init(MSFilter *f){
37        EncState *s=(EncState *)ms_new(EncState,1);
38        theora_info_init(&s->tinfo);
39        s->tinfo.width=MS_VIDEO_SIZE_CIF_W;
40        s->tinfo.height=MS_VIDEO_SIZE_CIF_H;
41        s->tinfo.frame_width=MS_VIDEO_SIZE_CIF_W;
42        s->tinfo.frame_height=MS_VIDEO_SIZE_CIF_H;
43        s->tinfo.offset_x=0;
44        s->tinfo.offset_y=0;
45        s->tinfo.target_bitrate=500000;
46        s->tinfo.pixelformat=OC_PF_420;
47        s->tinfo.fps_numerator=15;
48        s->tinfo.fps_denominator=1;
49        s->tinfo.aspect_numerator=1;
50        s->tinfo.aspect_denominator=1;
51        s->tinfo.colorspace=OC_CS_UNSPECIFIED;
52        s->tinfo.dropframes_p=0;
53        s->tinfo.quick_p=1;
54        s->tinfo.quality=63;
55        s->tinfo.keyframe_auto_p=1;
56        s->tinfo.keyframe_frequency=64;
57        s->tinfo.keyframe_frequency_force=64;
58        s->tinfo.keyframe_data_target_bitrate=s->tinfo.target_bitrate*1.2;
59        s->tinfo.keyframe_auto_threshold=80;
60        s->tinfo.keyframe_mindistance=8;
61        s->tinfo.noise_sensitivity=1;
62        s->packed_conf=NULL;
63        s->start_time=0;
64        s->conf_time=0;
65        s->mtu=ms_get_payload_max_size()-6;
66        f->data=s;
67}
68
69static void enc_uninit(MSFilter *f){
70        EncState *s=(EncState*)f->data;
71        theora_info_clear(&s->tinfo);
72        ms_free(s);
73}
74
75static int enc_set_vsize(MSFilter *f, void*data){
76        MSVideoSize *vs=(MSVideoSize*)data;
77        EncState *s=(EncState*)f->data;
78        s->tinfo.width=vs->width;
79        s->tinfo.height=vs->height;
80        s->tinfo.frame_width=vs->width;
81        s->tinfo.frame_height=vs->height;
82        return 0;
83}
84
85static int enc_get_vsize(MSFilter *f, void *data){
86        EncState *s=(EncState*)f->data;
87        MSVideoSize *vs=(MSVideoSize*)data;
88        vs->width=s->tinfo.width;
89        vs->height=s->tinfo.height;
90        return 0;
91}
92
93static int enc_add_attr(MSFilter *f, void*data){
94        /*const char *attr=(const char*)data;
95        EncState *s=(EncState*)f->data;*/
96        return 0;
97}
98
99static int enc_set_fps(MSFilter *f, void *data){
100        float *fps=(float*)data;
101        EncState *s=(EncState*)f->data;
102        s->tinfo.fps_numerator=*fps;
103        s->tinfo.keyframe_frequency=(*fps)*5;
104        s->tinfo.keyframe_frequency_force=(*fps)*5;
105        return 0;
106}
107
108static int enc_get_fps(MSFilter *f, void *data){
109        EncState *s=(EncState*)f->data;
110        float *fps=(float*)data;
111        *fps=s->tinfo.fps_numerator;
112        return 0;
113}
114
115static int enc_set_br(MSFilter *f, void*data){
116        int br=*(int*)data;
117        EncState *s=(EncState*)f->data;
118        MSVideoSize vsize;
119        float fps;
120        float codecbr=(float)br;
121        vsize.width=s->tinfo.width;
122        vsize.height=s->tinfo.height;
123        fps=s->tinfo.fps_numerator;
124        s->tinfo.target_bitrate=codecbr*0.8;
125        s->tinfo.keyframe_data_target_bitrate=codecbr;
126        /*those default settings would need to be affined*/
127        if (br>=1024000){
128                vsize.width = MS_VIDEO_SIZE_4CIF_W;
129                vsize.height = MS_VIDEO_SIZE_4CIF_H;
130                s->tinfo.quality=32;
131                fps=15;
132        }else if (br>=512000){
133                vsize.width = MS_VIDEO_SIZE_CIF_W;
134                vsize.height = MS_VIDEO_SIZE_CIF_H;
135                s->tinfo.quality=32;
136                fps=15;
137        }else if (br>=256000){
138                vsize.width = MS_VIDEO_SIZE_CIF_W;
139                vsize.height = MS_VIDEO_SIZE_CIF_H;
140                s->tinfo.quality=5;
141                fps=12;
142        }else if(br>=128000){
143                vsize.width=MS_VIDEO_SIZE_QCIF_W;
144                vsize.height=MS_VIDEO_SIZE_QCIF_H;
145                s->tinfo.quality=20;
146                fps=10;
147        }else if(br>=64000){
148                vsize.width=MS_VIDEO_SIZE_QCIF_W;
149                vsize.height=MS_VIDEO_SIZE_QCIF_H;
150                s->tinfo.quality=7;
151                fps=7;
152        }
153        enc_set_vsize(f,&vsize);
154        enc_set_fps(f,&fps);
155        return 0;
156}
157
158static int enc_set_mtu(MSFilter *f, void*data){
159        EncState *s=(EncState*)f->data;
160        s->mtu=*(int*)data;
161        return 0;
162}
163
164#define THEORA_RAW_DATA 0
165#define THEORA_PACKED_CONF 1
166#define THEORA_COMMENT 2
167#define THEORA_RESERVED 3
168
169#define NOT_FRAGMENTED 0
170#define START_FRAGMENT 1
171#define CONT_FRAGMENT 2
172#define END_FRAGMENT 3
173
174
175static inline void payload_header_set(uint8_t *buf, uint32_t ident, uint8_t ft, uint8_t tdt, uint8_t pkts){
176        uint32_t tmp;
177        tmp=((ident&0xFFFFFF)<<8) | ((ft&0x3)<<6) | ((tdt&0x3)<<4) | (pkts&0xf);
178        *((uint32_t*)buf)=htonl(tmp);
179}
180
181static inline uint32_t payload_header_get_ident(uint8_t *buf){
182        uint32_t *tmp=(uint32_t*)buf;
183        return (ntohl(*tmp)>>8) & 0xFFFFFF;
184}
185
186static inline uint32_t payload_header_get_tdt(uint8_t *buf){
187        uint32_t *tmp=(uint32_t*)buf;
188        return ((ntohl(*tmp))>>4) & 0x3;
189}
190
191static inline uint32_t payload_header_get_ft(uint8_t *buf){
192        uint32_t *tmp=(uint32_t*)buf;
193        return ((ntohl(*tmp))>>6) & 0x3;
194}
195
196static inline uint32_t payload_header_get_pkts(uint8_t *buf){
197        uint32_t *tmp=(uint32_t*)buf;
198        return ntohl(*tmp) & 0xf;
199}
200
201static int create_packed_conf(EncState *s){
202        ogg_packet p;
203        theora_state *tstate=&s->tstate;
204        mblk_t *h,*t;
205        if (theora_encode_header(tstate,&p)!=0){
206                ms_error("theora_encode_header() error.");
207                return -1;
208        }
209        h=allocb(p.bytes,0);
210        memcpy(h->b_wptr,p.packet,p.bytes);
211        h->b_wptr+=p.bytes;
212        if (theora_encode_tables(tstate,&p)!=0){
213                ms_error("theora_encode_tables error.");
214                freemsg(h);
215                return -1;
216        }
217        t=allocb(p.bytes,0);
218        memcpy(t->b_wptr,p.packet,p.bytes);
219        t->b_wptr+=p.bytes;
220        h->b_cont=t;
221        msgpullup(h,-1);
222        s->packed_conf=h;
223        return 0;
224}
225
226static void enc_preprocess(MSFilter *f){
227        EncState *s=(EncState*)f->data;
228        int err;
229        if ((err=theora_encode_init(&s->tstate,&s->tinfo))!=0){
230                ms_error("error in theora_encode_init() : %i !",err);
231        }
232        s->yuv.y_width=s->tinfo.width;
233        s->yuv.y_height=s->tinfo.height;
234        s->yuv.y_stride=s->tinfo.width;
235        s->yuv.uv_width=s->tinfo.width/2;
236        s->yuv.uv_height=s->tinfo.height/2;
237        s->yuv.uv_stride=s->tinfo.width/2;
238        create_packed_conf(s);
239        s->conf_time=0;
240        s->start_time=f->ticker->time;
241}
242
243static void enc_postprocess(MSFilter *f){
244        EncState *s=(EncState*)f->data;
245        theora_clear(&s->tstate);
246       
247        //If preprocess is called after postprocess,
248        //then we loose all info...
249        //theora_info_clear(&s->tinfo);
250       
251        if (s->packed_conf) {
252                freemsg(s->packed_conf);
253                s->packed_conf=NULL;
254        }
255}
256
257static void enc_fill_yuv(yuv_buffer *yuv, mblk_t *im){
258        yuv->y=(uint8_t*)im->b_rptr;
259        yuv->u=(uint8_t*)im->b_rptr+(yuv->y_stride*yuv->y_height);
260        yuv->v=(uint8_t*)yuv->u+(yuv->uv_stride*yuv->uv_height);
261}
262
263
264static void packetize_and_send(MSFilter *f, EncState *s, mblk_t *om, uint32_t timestamp, uint8_t tdt){
265        mblk_t *packet;
266        mblk_t *h;
267        int npackets=0;
268        static const int ident=0xdede;
269        while(om!=NULL){
270                if (om->b_wptr-om->b_rptr>=s->mtu){
271                        packet=dupb(om);
272                        packet->b_wptr=packet->b_rptr+s->mtu;
273                        om->b_rptr=packet->b_wptr;
274                }else {
275                        packet=om;
276                        om=NULL;
277                }
278                ++npackets;
279                h=allocb(6,0);
280                if (npackets==1){
281                        if (om==NULL)
282                                payload_header_set(h->b_wptr,ident,NOT_FRAGMENTED,tdt,1);
283                        else
284                                payload_header_set(h->b_wptr,ident,START_FRAGMENT,tdt,1);
285                }else{
286                        if (om==NULL)
287                                payload_header_set(h->b_wptr,ident,END_FRAGMENT,tdt,1);
288                        else
289                                payload_header_set(h->b_wptr,ident,CONT_FRAGMENT,tdt,1);
290                }
291                h->b_wptr+=4;
292                *((uint16_t*)h->b_wptr)=htons(msgdsize(packet));
293                h->b_wptr+=2;
294                h->b_cont=packet;
295                mblk_set_timestamp_info(h,timestamp);
296                ms_debug("sending theora frame of size %i",msgdsize(h));
297                ms_queue_put(f->outputs[0],h);
298        }
299}
300
301bool_t need_send_conf(EncState *s, uint64_t elapsed){
302#ifdef AMD_HACK
303        if (elapsed<5000 && elapsed>=s->conf_time){
304                s->conf_time+=500;
305                return TRUE;
306        }
307#else
308        /*send immediately then 10 seconds later */
309        if ( (elapsed<1000 && s->conf_time==0)
310                || (elapsed>10000 && s->conf_time==1)){
311                s->conf_time++;
312                return TRUE;
313        }
314#endif
315        return FALSE;
316}
317
318static void enc_process(MSFilter *f){
319        mblk_t *im,*om;
320        ogg_packet op;
321        EncState *s=(EncState*)f->data;
322        uint64_t timems=f->ticker->time;
323        uint32_t timestamp=timems*90;
324        uint64_t elapsed=timems-s->start_time;
325        while((im=ms_queue_get(f->inputs[0]))!=NULL){
326                /*for the firsts frames only send theora packed conf*/
327                om=NULL;
328
329                if (need_send_conf(s,elapsed)){
330                        if (s->packed_conf) {
331                                om=dupmsg(s->packed_conf);
332                                ms_message("sending theora packed conf (%i bytes)",msgdsize(om));
333                                packetize_and_send(f,s,om,timestamp,THEORA_PACKED_CONF);
334                        }else {
335                                ms_error("No packed conf to send.");
336                        }
337                }else{
338                        enc_fill_yuv(&s->yuv,im);
339                        ms_debug("subtmitting yuv frame to theora encoder...");
340                        if (theora_encode_YUVin(&s->tstate,&s->yuv)!=0){
341                                ms_error("theora_encode_YUVin error.");
342                        }else{
343                                if (theora_encode_packetout(&s->tstate,0,&op)==1){
344                                        ms_debug("Got theora coded frame");
345                                        om=allocb(op.bytes,0);
346                                        memcpy(om->b_wptr,op.packet,op.bytes);
347                                        om->b_wptr+=op.bytes;
348                                        packetize_and_send(f,s,om,timestamp,THEORA_RAW_DATA);
349                                }
350                        }
351                }
352                freemsg(im);
353        }
354}
355
356static MSFilterMethod enc_methods[]={
357        {       MS_FILTER_SET_VIDEO_SIZE, enc_set_vsize },
358        {       MS_FILTER_SET_FPS,      enc_set_fps     },
359        {       MS_FILTER_GET_VIDEO_SIZE, enc_get_vsize },
360        {       MS_FILTER_GET_FPS,      enc_get_fps     },
361        {       MS_FILTER_ADD_ATTR, enc_add_attr        },
362        {       MS_FILTER_SET_BITRATE, enc_set_br       },
363        {       MS_FILTER_SET_MTU, enc_set_mtu  },
364        {       0                       , NULL }
365};
366
367#ifdef _MSC_VER
368
369MSFilterDesc ms_theora_enc_desc={
370        MS_THEORA_ENC_ID,
371        "MSTheoraEnc",
372        N_("The theora video encoder from xiph.org"),
373        MS_FILTER_ENCODER,
374        "theora",
375        1,
376        1,
377        enc_init,
378        enc_preprocess,
379        enc_process,
380        enc_postprocess,
381        enc_uninit,
382        enc_methods
383};
384
385#else
386
387MSFilterDesc ms_theora_enc_desc={
388        .id=MS_THEORA_ENC_ID,
389        .name="MSTheoraEnc",
390        .text=N_("The open-source and royalty-free 'theora' video codec from xiph.org"),
391        .category=MS_FILTER_ENCODER,
392        .enc_fmt="theora",
393        .ninputs=1,
394        .noutputs=1,
395        .init=enc_init,
396        .preprocess=enc_preprocess,
397        .process=enc_process,
398        .postprocess=enc_postprocess,
399        .uninit=enc_uninit,
400        .methods=enc_methods
401};
402
403#endif
404
405MS_FILTER_DESC_EXPORT(ms_theora_enc_desc)
406
407typedef struct DecState{
408        theora_state tstate;
409        theora_info tinfo;
410        mblk_t *yuv;
411        mblk_t *curframe;
412        bool_t ready;
413}DecState;
414
415static void dec_init(MSFilter *f){
416        DecState *s=(DecState *)ms_new(DecState,1);
417        s->ready=FALSE;
418        theora_info_init(&s->tinfo);
419        s->yuv=NULL;
420        s->curframe=NULL;
421        f->data=s;
422}
423
424static void dec_uninit(MSFilter *f){
425        DecState *s=(DecState*)f->data;
426        if (s->yuv!=NULL) freemsg(s->yuv);
427        if (s->curframe!=NULL) freemsg(s->curframe);
428        theora_info_clear(&s->tinfo);
429        ms_free(s);
430}
431
432static bool_t dec_init_theora(DecState *s, ogg_packet *op){
433        theora_comment tcom;
434        static const int ident_packet_size=42; 
435        theora_comment_init(&tcom);
436        tcom.vendor="dummy";
437        op->b_o_s=1;
438        if (theora_decode_header(&s->tinfo,&tcom,op)==0){
439                op->packet+=ident_packet_size;
440                op->bytes-=ident_packet_size;
441                /*recall once to decode tables*/
442                if (theora_decode_header(&s->tinfo,&tcom,op)==0){
443                        if (theora_decode_init(&s->tstate,&s->tinfo)==0){
444                                ms_debug("theora decoder ready, pixfmt=%i",
445                                        s->tinfo.pixelformat);
446                                return TRUE;   
447                        }
448                }else{
449                        ms_warning("error decoding theora tables");
450                }
451        }else{
452                ms_warning("error decoding theora header");
453        }
454        return FALSE;
455}
456/* remove payload header and agregates fragmented packets */
457static mblk_t *dec_unpacketize(MSFilter *f, DecState *s, mblk_t *im, int *tdt){
458        uint8_t ft;
459        *tdt=payload_header_get_tdt((uint8_t*)im->b_rptr);
460        ft=payload_header_get_ft((uint8_t*)im->b_rptr);
461        im->b_rptr+=6;
462       
463        if (ft==NOT_FRAGMENTED) return im;
464        if (ft==START_FRAGMENT){
465                if (s->curframe!=NULL)
466                        freemsg(s->curframe);
467                s->curframe=im;
468        }else if (ft==CONT_FRAGMENT){
469                if (s->curframe!=NULL)
470                        concatb(s->curframe,im);
471                else
472                        freemsg(im);
473        }else{/*end fragment*/
474                if (s->curframe!=NULL){
475                        mblk_t *ret;
476                        concatb(s->curframe,im);
477                        msgpullup(s->curframe,-1);
478                        ret=s->curframe;
479                        s->curframe=NULL;
480                        return ret;
481                }else
482                        freemsg(im);
483        }
484        return NULL;
485}
486
487static void dec_process_frame(MSFilter *f, DecState *s, ogg_packet *op){
488        yuv_buffer yuv;
489        if (theora_decode_packetin(&s->tstate,op)==0){
490                if (theora_decode_YUVout(&s->tstate,&yuv)==0){
491                        mblk_t *om;
492                        int i;
493                        int ylen=yuv.y_width*yuv.y_height;
494                        int uvlen=yuv.uv_width*yuv.uv_height;
495                        ms_debug("Got yuv buffer from theora decoder");
496                        if (s->yuv==NULL){
497                                int len=(ylen)+(2*uvlen);
498                                s->yuv=allocb(len,0);
499                        }
500                        om=dupb(s->yuv);
501                        for(i=0;i<yuv.y_height;++i){
502                                memcpy(om->b_wptr,yuv.y+yuv.y_stride*i,yuv.y_width);
503                                om->b_wptr+=yuv.y_width;
504                        }
505                        for(i=0;i<yuv.uv_height;++i){
506                                memcpy(om->b_wptr,yuv.u+yuv.uv_stride*i,yuv.uv_width);
507                                om->b_wptr+=yuv.uv_width;
508                        }
509                        for(i=0;i<yuv.uv_height;++i){
510                                memcpy(om->b_wptr,yuv.v+yuv.uv_stride*i,yuv.uv_width);
511                                om->b_wptr+=yuv.uv_width;
512                        }
513                        ms_queue_put(f->outputs[0],om);
514                }
515        }else{
516                ms_warning("theora decoding error");
517        }
518}
519
520static void dec_process(MSFilter *f){
521        mblk_t *im;
522        mblk_t *m;
523        ogg_packet op;
524        int tdt;
525        DecState *s=(DecState*)f->data;
526        while( (im=ms_queue_get(f->inputs[0]))!=0) {
527                m=dec_unpacketize(f,s,im,&tdt);
528                if (m!=NULL){
529                        /* now in im we have only the theora data*/
530                        op.packet=(uint8_t*)m->b_rptr;
531                        op.bytes=m->b_wptr-m->b_rptr;
532                        op.b_o_s=0;
533                        op.e_o_s=0;
534                        op.granulepos=0;
535                        op.packetno=0;
536                        if (tdt!=THEORA_RAW_DATA) /*packed conf*/ {
537                                if (!s->ready){
538                                        if (dec_init_theora(s,&op))
539                                                s->ready=TRUE;
540                                }
541                        }else{
542                                if (s->ready){
543                                        dec_process_frame(f,s,&op);
544                                }else{
545                                        ms_warning("skipping theora packet because decoder was not initialized yet with theora header and tables");
546                                }
547                        }
548                        freemsg(m);
549                }
550        }
551}
552
553#ifdef _MSC_VER
554
555MSFilterDesc ms_theora_dec_desc={
556        MS_THEORA_DEC_ID,
557        "MSTheoraDec",
558        N_("The theora video decoder from xiph.org"),
559        MS_FILTER_DECODER,
560        "theora",
561        1,
562        1,
563        dec_init,
564        NULL,
565        dec_process,
566        NULL,
567        dec_uninit,
568        NULL
569};
570
571#else
572
573MSFilterDesc ms_theora_dec_desc={
574        .id=MS_THEORA_DEC_ID,
575        .name="MSTheoraDec",
576        .text=N_("The theora video decoder from xiph.org"),
577        .category=MS_FILTER_DECODER,
578        .enc_fmt="theora",
579        .ninputs=1,
580        .noutputs=1,
581        .init=dec_init,
582        .process=dec_process,
583        .uninit=dec_uninit
584};
585
586#endif
587MS_FILTER_DESC_EXPORT(ms_theora_dec_desc)
Note: See TracBrowser for help on using the repository browser.