source: mediastreamer2/linphone/mediastreamer2/plugins/msx264/src/msx264.c @ 47:1b1df357b1fe

Last change on this file since 47:1b1df357b1fe was 47:1b1df357b1fe, checked in by aymeric <aymeric@…>, 5 years ago

back to VGA for maximum

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

File size: 12.9 KB
Line 
1/*
2mediastreamer2 x264 plugin
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#include "mediastreamer2/rfc3984.h"
24
25#include "ortp/b64.h"
26
27#include <x264.h>
28
29#ifdef HAVE_LIBAVCODEC_AVCODEC_H
30#include <libavcodec/avcodec.h>
31#include <libswscale/swscale.h>
32#else
33#include <ffmpeg/avcodec.h>
34#include <ffmpeg/swscale.h>
35#endif
36
37#define REMOVE_PREVENTING_BYTES 1
38
39typedef struct _EncData{
40        x264_t *enc;
41        MSVideoSize vsize;
42        int bitrate;
43        float fps;
44        int mode;
45        uint64_t framenum;
46        Rfc3984Context packer;
47        bool_t generate_keyframe;
48}EncData;
49
50
51static void enc_init(MSFilter *f){
52        EncData *d=ms_new(EncData,1);
53        d->enc=NULL;
54        d->bitrate=384000;
55        d->vsize=MS_VIDEO_SIZE_CIF;
56        d->fps=30;
57        d->mode=0;
58        d->framenum=0;
59        d->generate_keyframe=FALSE;
60        f->data=d;
61}
62
63static void enc_uninit(MSFilter *f){
64        EncData *d=(EncData*)f->data;
65        ms_free(d);
66}
67
68static void enc_preprocess(MSFilter *f){
69        EncData *d=(EncData*)f->data;
70        x264_param_t params;
71        rfc3984_init(&d->packer);
72        rfc3984_set_mode(&d->packer,d->mode);
73        rfc3984_enable_stap_a(&d->packer,FALSE);
74        x264_param_default(&params);
75        params.i_width=d->vsize.width;
76        params.i_height=d->vsize.height;
77        params.i_fps_num=(int)d->fps;
78        params.i_fps_den=1;
79#ifdef HACKED_X264
80        ms_message("Lucky guy, you have a hacked x264 lib that allows multislicing !");
81        params.slice_size_threshold=ms_get_payload_max_size()-100; /*-100 security margin*/
82#endif
83        /*params.i_level_idc=10;*/
84        params.rc.i_rc_method = X264_RC_ABR;
85        params.rc.i_bitrate=(int)( ( ((float)d->bitrate)*0.8)/1000.0);
86        params.rc.f_rate_tolerance=0.1;
87        params.rc.i_vbv_max_bitrate=(int) (((float)d->bitrate)*0.9/1000.0);
88        params.rc.i_vbv_buffer_size=params.rc.i_vbv_max_bitrate;
89        params.rc.f_vbv_buffer_init=0.5;
90        params.b_repeat_headers=1;
91        params.b_cabac=0;//disable cabac to be baseline
92        params.i_bframe=0;/*no B frames*/
93        d->enc=x264_encoder_open(&params);
94        if (d->enc==NULL) ms_error("Fail to create x264 encoder.");
95        d->framenum=0;
96}
97
98static void x264_nals_to_msgb(x264_nal_t *xnals, int num_nals, MSQueue * nalus){
99        int i;
100        mblk_t *m;
101        /*int bytes;*/
102        for (i=0;i<num_nals;++i){
103                m=allocb(xnals[i].i_payload+10,0);
104                /*
105                x264_nal_encode(m->b_wptr, &bytes, 0, &xnals[i] );
106                m->b_wptr+=bytes;
107                */
108                *m->b_wptr=( 0x00 << 7 ) | ( xnals[i].i_ref_idc << 5 ) | xnals[i].i_type;
109                m->b_wptr++;
110                memcpy(m->b_wptr,xnals[i].p_payload,xnals[i].i_payload);
111                m->b_wptr+=xnals[i].i_payload;
112                if (xnals[i].i_type==7) {
113                        ms_message("A SPS is being sent.");
114                }else if (xnals[i].i_type==8) {
115                        ms_message("A PPS is being sent.");
116                }
117                ms_queue_put(nalus,m);
118        }
119}
120
121static void enc_process(MSFilter *f){
122        EncData *d=(EncData*)f->data;
123        uint32_t ts=f->ticker->time*90LL;
124        mblk_t *im;
125        MSPicture pic;
126        MSQueue nalus;
127        ms_queue_init(&nalus);
128        while((im=ms_queue_get(f->inputs[0]))!=NULL){
129                if (yuv_buf_init_from_mblk(&pic,im)==0){
130                        x264_picture_t xpic;
131                        x264_picture_t oxpic;
132                        x264_nal_t *xnals=NULL;
133                        int num_nals=0;
134
135                        if (d->generate_keyframe){
136                                xpic.i_type=X264_TYPE_IDR;
137                                d->generate_keyframe=FALSE;
138                        }else xpic.i_type=X264_TYPE_AUTO;
139                        xpic.i_qpplus1=0;
140                        xpic.i_pts=d->framenum;
141                        xpic.img.i_csp=X264_CSP_I420;
142                        xpic.img.i_plane=3;
143                        xpic.img.i_stride[0]=pic.strides[0];
144                        xpic.img.i_stride[1]=pic.strides[1];
145                        xpic.img.i_stride[2]=pic.strides[2];
146                        xpic.img.i_stride[3]=0;
147                        xpic.img.plane[0]=pic.planes[0];
148                        xpic.img.plane[1]=pic.planes[1];
149                        xpic.img.plane[2]=pic.planes[2];
150                        xpic.img.plane[3]=0;
151                        if (x264_encoder_encode(d->enc,&xnals,&num_nals,&xpic,&oxpic)==0){
152                                x264_nals_to_msgb(xnals,num_nals,&nalus);
153                                rfc3984_pack(&d->packer,&nalus,f->outputs[0],ts);
154                                d->framenum++;
155                        }else{
156                                ms_error("x264_encoder_encode() error.");
157                        }
158                }
159                freemsg(im);
160        }
161}
162
163static void enc_postprocess(MSFilter *f){
164        EncData *d=(EncData*)f->data;
165        rfc3984_uninit(&d->packer);
166        if (d->enc!=NULL){
167                x264_encoder_close(d->enc);
168                d->enc=NULL;
169        }
170}
171
172static int enc_set_br(MSFilter *f, void *arg){
173        EncData *d=(EncData*)f->data;
174        d->bitrate=*(int*)arg;
175
176        if (d->bitrate>=1024000){
177          d->vsize=MS_VIDEO_SIZE_VGA;
178          d->fps=15;
179        }else if (d->bitrate>=384000){
180          d->vsize=MS_VIDEO_SIZE_CIF;
181          d->fps=30;
182        }else if (d->bitrate>=256000){
183                d->vsize=MS_VIDEO_SIZE_CIF;
184                d->fps=15;
185        }else if (d->bitrate>=128000){
186                d->vsize=MS_VIDEO_SIZE_CIF;
187                d->fps=15;
188        }else if (d->bitrate>=64000){
189                d->vsize=MS_VIDEO_SIZE_CIF;
190                d->fps=10;
191        }else if (d->bitrate>=32000){
192                d->vsize=MS_VIDEO_SIZE_QCIF;
193                d->fps=10;
194        }else{
195                d->vsize=MS_VIDEO_SIZE_QCIF;
196                d->fps=5;
197        }
198        ms_message("bitrate set to %i",d->bitrate);
199        return 0;
200}
201
202static int enc_set_fps(MSFilter *f, void *arg){
203        EncData *d=(EncData*)f->data;
204        d->fps=*(float*)arg;
205        return 0;
206}
207
208static int enc_get_fps(MSFilter *f, void *arg){
209        EncData *d=(EncData*)f->data;
210        *(float*)arg=d->fps;
211        return 0;
212}
213
214static int enc_get_vsize(MSFilter *f, void *arg){
215        EncData *d=(EncData*)f->data;
216        *(MSVideoSize*)arg=d->vsize;
217        return 0;
218}
219
220static int enc_add_fmtp(MSFilter *f, void *arg){
221        EncData *d=(EncData*)f->data;
222        const char *fmtp=(const char *)arg;
223        char value[12];
224        if (fmtp_get_value(fmtp,"packetization-mode",value,sizeof(value))){
225                d->mode=atoi(value);
226                ms_message("packetization-mode set to %i",d->mode);
227        }
228        return 0;
229}
230
231static int enc_req_vfu(MSFilter *f, void *arg){
232        EncData *d=(EncData*)f->data;
233        d->generate_keyframe=TRUE;
234        return 0;
235}
236
237
238static MSFilterMethod enc_methods[]={
239        {       MS_FILTER_SET_FPS       ,       enc_set_fps     },
240        {       MS_FILTER_SET_BITRATE   ,       enc_set_br      },
241        {       MS_FILTER_GET_FPS       ,       enc_get_fps     },
242        {       MS_FILTER_GET_VIDEO_SIZE,       enc_get_vsize   },
243        {       MS_FILTER_ADD_FMTP      ,       enc_add_fmtp    },
244        {       MS_FILTER_REQ_VFU       ,       enc_req_vfu     },
245        {       0       ,                       NULL            }
246};
247
248static MSFilterDesc x264_enc_desc={
249        .id=MS_FILTER_PLUGIN_ID,
250        .name="MSX264Enc",
251        .text="A H264 encoder based on x264 project.",
252        .category=MS_FILTER_ENCODER,
253        .enc_fmt="H264",
254        .ninputs=1,
255        .noutputs=1,
256        .init=enc_init,
257        .preprocess=enc_preprocess,
258        .process=enc_process,
259        .postprocess=enc_postprocess,
260        .uninit=enc_uninit,
261        .methods=enc_methods
262};
263
264typedef struct _DecData{
265        mblk_t *yuv_msg;
266        mblk_t *sps,*pps;
267        Rfc3984Context unpacker;
268        MSPicture outbuf;
269        struct SwsContext *sws_ctx;
270        AVCodecContext av_context;
271        unsigned int packet_num;
272        uint8_t bitstream[65000];
273}DecData;
274
275static void ffmpeg_init(){
276        static bool_t done=FALSE;
277        if (!done){
278                avcodec_init();
279                avcodec_register_all();
280                done=TRUE;
281        }
282}
283
284static void dec_open(DecData *d){
285        AVCodec *codec;
286        int error;
287        codec=avcodec_find_decoder(CODEC_ID_H264);
288        if (codec==NULL) ms_fatal("Could not find H264 decoder in ffmpeg.");
289        avcodec_get_context_defaults(&d->av_context);
290        error=avcodec_open(&d->av_context,codec);
291        if (error!=0){
292                ms_fatal("avcodec_open() failed.");
293        }
294}
295
296static void dec_init(MSFilter *f){
297        DecData *d=(DecData*)ms_new(DecData,1);
298        ffmpeg_init();
299        d->yuv_msg=NULL;
300        d->sps=NULL;
301        d->pps=NULL;
302        d->sws_ctx=NULL;
303        rfc3984_init(&d->unpacker);
304        d->packet_num=0;
305        dec_open(d);
306        d->outbuf.w=0;
307        d->outbuf.h=0;
308        f->data=d;
309}
310
311static void dec_reinit(DecData *d){
312        avcodec_close(&d->av_context);
313        dec_open(d);
314}
315
316static void dec_uninit(MSFilter *f){
317        DecData *d=(DecData*)f->data;
318        rfc3984_uninit(&d->unpacker);
319        avcodec_close(&d->av_context);
320        if (d->yuv_msg) freemsg(d->yuv_msg);
321        if (d->sps) freemsg(d->sps);
322        if (d->pps) freemsg(d->pps);
323        ms_free(d);
324}
325
326static mblk_t *get_as_yuvmsg(MSFilter *f, DecData *s, AVFrame *orig){
327        AVCodecContext *ctx=&s->av_context;
328
329        if (s->outbuf.w!=ctx->width || s->outbuf.h!=ctx->height){
330                if (s->sws_ctx!=NULL){
331                        sws_freeContext(s->sws_ctx);
332                        s->sws_ctx=NULL;
333                        freemsg(s->yuv_msg);
334                        s->yuv_msg=NULL;
335                }
336                ms_message("Getting yuv picture of %ix%i",ctx->width,ctx->height);
337                s->yuv_msg=yuv_buf_alloc(&s->outbuf,ctx->width,ctx->height);
338                s->outbuf.w=ctx->width;
339                s->outbuf.h=ctx->height;
340                s->sws_ctx=sws_getContext(ctx->width,ctx->height,ctx->pix_fmt,
341                        ctx->width,ctx->height,PIX_FMT_YUV420P,SWS_FAST_BILINEAR,
342                        NULL, NULL, NULL);
343        }
344        if (sws_scale(s->sws_ctx,orig->data,orig->linesize, 0,
345                                        ctx->height, s->outbuf.planes, s->outbuf.strides)<0){
346                ms_error("%s: error in sws_scale().",f->desc->name);
347        }
348        return dupmsg(s->yuv_msg);
349}
350
351static void update_sps(DecData *d, mblk_t *sps){
352        if (d->sps)
353                freemsg(d->sps);
354        d->sps=dupb(sps);
355}
356
357static void update_pps(DecData *d, mblk_t *pps){
358        if (d->pps)
359                freemsg(d->pps);
360        d->pps=dupb(pps);
361}
362
363static bool_t check_sps_pps_change(DecData *d, mblk_t *sps, mblk_t *pps){
364        bool_t ret1=FALSE,ret2=FALSE;
365        if (d->sps){
366                if (sps){
367                        ret1=(msgdsize(sps)!=msgdsize(d->sps)) || (memcmp(d->sps->b_rptr,sps->b_rptr,msgdsize(sps))!=0);
368                        if (ret1) {
369                                update_sps(d,sps);
370                                ms_message("SPS changed !");
371                        }
372                }
373        }else if (sps) {
374                ms_message("Receiving first SPS");
375                update_sps(d,sps);
376        }
377        if (d->pps){
378                if (pps){
379                        ret2=(msgdsize(pps)!=msgdsize(d->pps)) || (memcmp(d->pps->b_rptr,pps->b_rptr,msgdsize(pps))!=0);
380                        if (ret2) {
381                                update_sps(d,pps);
382                                ms_message("PPS changed ! %i,%i",msgdsize(pps),msgdsize(d->pps));
383                        }
384                }
385        }else if (pps) {
386                ms_message("Receiving first PPS");
387                update_pps(d,pps);
388        }
389        return ret1 || ret2;
390}
391
392static int nalusToFrame(DecData *d, MSQueue *naluq, uint8_t *bitstream, int size, bool_t *new_sps_pps){
393        mblk_t *im;
394        uint8_t *dst=bitstream,*src;
395        bool_t start_picture=TRUE;
396        uint8_t nalu_type;
397        *new_sps_pps=FALSE;
398        while((im=ms_queue_get(naluq))!=NULL){
399                src=im->b_rptr;
400                nalu_type=(*src) & ((1<<5)-1);
401                if (nalu_type==7)
402                        *new_sps_pps=check_sps_pps_change(d,im,NULL) || *new_sps_pps;
403                if (nalu_type==8)
404                        *new_sps_pps=check_sps_pps_change(d,NULL,im) || *new_sps_pps;
405                if (start_picture || nalu_type==7/*SPS*/ || nalu_type==8/*PPS*/ ){
406                        *dst++=0;
407                        start_picture=FALSE;
408                }
409                /*prepend nal marker*/
410                *dst++=0;
411                *dst++=0;
412                *dst++=1;
413                *dst++=*src++;
414                while(src<(im->b_wptr-3)){
415#ifdef REMOVE_PREVENTING_BYTES
416                        if (src[0]==0 && src[1]==0 && src[2]<=3){
417                                *dst++=0;
418                                *dst++=0;
419                                *dst++=3;
420                                src+=2;
421                        }
422#endif
423                        *dst++=*src++;
424                }
425                *dst++=*src++;
426                *dst++=*src++;
427                *dst++=*src++;
428                freemsg(im);
429        }
430        return dst-bitstream;
431}
432
433static void dec_process(MSFilter *f){
434        DecData *d=(DecData*)f->data;
435        mblk_t *im;
436        MSQueue nalus;
437        AVFrame orig;
438        ms_queue_init(&nalus);
439        while((im=ms_queue_get(f->inputs[0]))!=NULL){
440                /*push the sps/pps given in sprop-parameter-sets if any*/
441                if (d->packet_num==0 && d->sps && d->pps){
442                        mblk_set_timestamp_info(d->sps,mblk_get_timestamp_info(im));
443                        mblk_set_timestamp_info(d->pps,mblk_get_timestamp_info(im));
444                        rfc3984_unpack(&d->unpacker,d->sps,&nalus);
445                        rfc3984_unpack(&d->unpacker,d->pps,&nalus);
446                        d->sps=NULL;
447                        d->pps=NULL;
448                }
449                rfc3984_unpack(&d->unpacker,im,&nalus);
450                if (!ms_queue_empty(&nalus)){
451                        int size;
452                        uint8_t *p,*end;
453                        bool_t need_reinit=FALSE;
454
455                        size=nalusToFrame(d,&nalus,d->bitstream,sizeof(d->bitstream),&need_reinit);
456                        if (need_reinit)
457                                dec_reinit(d);
458                        p=d->bitstream;
459                        end=d->bitstream+size;
460                        while (end-p>0) {
461                                int len;
462                                int got_picture=0;
463                                avcodec_get_frame_defaults(&orig);
464                                len=avcodec_decode_video(&d->av_context,&orig,&got_picture,p,end-p);
465                                if (len<=0) {
466                                        ms_warning("ms_AVdecoder_process: error %i.",len);
467                                        break;
468                                }
469                                if (got_picture) {
470                                        ms_queue_put(f->outputs[0],get_as_yuvmsg(f,d,&orig));
471                                }
472                                p+=len;
473                        }
474                }
475                d->packet_num++;
476        }
477}
478
479static int dec_add_fmtp(MSFilter *f, void *arg){
480        DecData *d=(DecData*)f->data;
481        const char *fmtp=(const char *)arg;
482        char value[256];
483        if (fmtp_get_value(fmtp,"sprop-parameter-sets",value,sizeof(value))){
484                char * b64_sps=value;
485                char * b64_pps=strchr(value,',');
486                if (b64_pps){
487                        *b64_pps='\0';
488                        ++b64_pps;
489                        ms_message("Got sprop-parameter-sets : sps=%s , pps=%s",b64_sps,b64_pps);
490                        d->sps=allocb(sizeof(value),0);
491                        d->sps->b_wptr+=b64_decode(b64_sps,strlen(b64_sps),d->sps->b_wptr,sizeof(value));
492                        d->pps=allocb(sizeof(value),0);
493                        d->pps->b_wptr+=b64_decode(b64_pps,strlen(b64_pps),d->pps->b_wptr,sizeof(value));
494                }
495        }
496        return 0;
497}
498
499static MSFilterMethod  h264_dec_methods[]={
500        {       MS_FILTER_ADD_FMTP      ,       dec_add_fmtp    },
501        {       0                       ,       NULL    }
502};
503
504static MSFilterDesc h264_dec_desc={
505        .id=MS_FILTER_PLUGIN_ID,
506        .name="MSH264Dec",
507        .text="A H264 decoder based on ffmpeg project.",
508        .category=MS_FILTER_DECODER,
509        .enc_fmt="H264",
510        .ninputs=1,
511        .noutputs=1,
512        .init=dec_init,
513        .process=dec_process,
514        .uninit=dec_uninit,
515        .methods=h264_dec_methods
516};
517
518void libmsx264_init(void){
519        ms_filter_register(&x264_enc_desc);
520        ms_filter_register(&h264_dec_desc);
521}
Note: See TracBrowser for help on using the repository browser.