source: mediastreamer2/plugins/msx264/src/msx264.c @ 872:8338349821ee

Last change on this file since 872:8338349821ee was 872:8338349821ee, checked in by Simon Morlat <simon.morlat@…>, 3 years ago

force stream to be baseline with lastest x264 deliveries.

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