source: mediastreamer2/plugins/msx264/src/msx264.c @ 1440:aae76607396a

Last change on this file since 1440:aae76607396a was 1440:aae76607396a, checked in by laurent@…, 16 months ago

update x264

File size: 9.9 KB
Line 
1/*
2mediastreamer2 x264 plugin
3Copyright (C) 2006-2010 Belledonne Communications SARL (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#ifdef _MSC_VER
26#include <stdint.h>
27#endif
28
29#include <x264.h>
30
31#ifndef VERSION
32#define VERSION "1.4.1"
33#endif
34
35
36#define RC_MARGIN 10000 /*bits per sec*/
37
38
39#define SPECIAL_HIGHRES_BUILD_CRF 28
40
41/* the goal of this small object is to tell when to send I frames at startup:
42at 2 and 4 seconds*/
43typedef struct VideoStarter{
44        uint64_t next_time;
45        int i_frame_count;
46}VideoStarter;
47
48static void video_starter_init(VideoStarter *vs){
49        vs->next_time=0;
50        vs->i_frame_count=0;
51}
52
53static void video_starter_first_frame(VideoStarter *vs, uint64_t curtime){
54        vs->next_time=curtime+2000;
55}
56
57static bool_t video_starter_need_i_frame(VideoStarter *vs, uint64_t curtime){
58        if (vs->next_time==0) return FALSE;
59        if (curtime>=vs->next_time){
60                vs->i_frame_count++;
61                if (vs->i_frame_count==1){
62                        vs->next_time+=2000;
63                }else{
64                        vs->next_time=0;
65                }
66                return TRUE;
67        }
68        return FALSE;
69}
70
71typedef struct _EncData{
72        x264_t *enc;
73        x264_param_t params;
74        MSVideoSize vsize;
75        int bitrate;
76        float fps;
77        int mode;
78        uint64_t framenum;
79        Rfc3984Context *packer;
80        int keyframe_int;
81        VideoStarter starter;
82        bool_t generate_keyframe;
83}EncData;
84
85
86static void enc_init(MSFilter *f){
87        EncData *d=ms_new(EncData,1);
88        d->enc=NULL;
89    MS_VIDEO_SIZE_ASSIGN(d->vsize,CIF);
90        d->bitrate=384000;
91        d->fps=30;
92        d->keyframe_int=10; /*10 seconds */
93        d->mode=0;
94        d->framenum=0;
95        d->generate_keyframe=FALSE;
96        d->packer=NULL;
97        f->data=d;
98}
99
100static void enc_uninit(MSFilter *f){
101        EncData *d=(EncData*)f->data;
102        ms_free(d);
103}
104
105static void apply_bitrate(MSFilter *f, int target_bitrate){
106        EncData *d=(EncData*)f->data;
107        x264_param_t *params=&d->params;
108        float bitrate;
109
110        d->bitrate=target_bitrate;
111        bitrate=(float)d->bitrate*0.92;
112        if (bitrate>RC_MARGIN)
113                bitrate-=RC_MARGIN;
114       
115        params->rc.i_rc_method = X264_RC_ABR;
116        params->rc.i_bitrate=(int)(bitrate/1000);
117        params->rc.f_rate_tolerance=0.1;
118        params->rc.i_vbv_max_bitrate=(int) ((bitrate+RC_MARGIN/2)/1000);
119        params->rc.i_vbv_buffer_size=params->rc.i_vbv_max_bitrate;
120        params->rc.f_vbv_buffer_init=0.5;
121}
122
123static void enc_preprocess(MSFilter *f){
124        EncData *d=(EncData*)f->data;
125        x264_param_t *params=&d->params;
126       
127        d->packer=rfc3984_new();
128        rfc3984_set_mode(d->packer,d->mode);
129        rfc3984_enable_stap_a(d->packer,FALSE);
130#ifdef __arm__ 
131        if (x264_param_default_preset(params,"superfast"/*"ultrafast"*/,"zerolatency")) { 
132#else
133                x264_param_default(params); {
134#endif
135                ms_error("Cannot apply default x264 configuration");
136        };
137       
138        params->i_threads=1;
139        params->i_sync_lookahead=0;
140        params->i_width=d->vsize.width;
141        params->i_height=d->vsize.height;
142        params->i_fps_num=(int)d->fps;
143        params->i_fps_den=1;
144        params->i_slice_max_size=ms_get_payload_max_size()-100; /*-100 security margin*/
145        params->i_level_idc=13;
146       
147        apply_bitrate(f,d->bitrate);
148
149        params->rc.i_lookahead=0;
150        /*enable this by config ?*/
151        /*
152         params.i_keyint_max = (int)d->fps*d->keyframe_int;
153         params.i_keyint_min = (int)d->fps;
154         */
155        params->b_repeat_headers=1;
156        params->b_annexb=0;
157       
158        //these parameters must be set so that our stream is baseline
159        params->analyse.b_transform_8x8 = 0;
160        params->b_cabac = 0;
161        params->i_cqm_preset = X264_CQM_FLAT;
162        params->i_bframe = 0;
163        params->analyse.i_weighted_pred = X264_WEIGHTP_NONE;
164        d->enc=x264_encoder_open(params);
165        if (d->enc==NULL) ms_error("Fail to create x264 encoder.");
166        d->framenum=0;
167        video_starter_init(&d->starter);
168}
169
170
171static void x264_nals_to_msgb(x264_nal_t *xnals, int num_nals, MSQueue * nalus){
172        int i;
173        mblk_t *m;
174        /*int bytes;*/
175        for (i=0;i<num_nals;++i){
176                m=allocb(xnals[i].i_payload+10,0);
177               
178                memcpy(m->b_wptr,xnals[i].p_payload+4,xnals[i].i_payload-4);
179                m->b_wptr+=xnals[i].i_payload-4;
180                if (xnals[i].i_type==7) {
181                        ms_message("A SPS is being sent.");
182                }else if (xnals[i].i_type==8) {
183                        ms_message("A PPS is being sent.");
184                }
185                ms_queue_put(nalus,m);
186        }
187}
188
189static void enc_process(MSFilter *f){
190        EncData *d=(EncData*)f->data;
191        uint32_t ts=f->ticker->time*90LL;
192        mblk_t *im;
193        MSPicture pic;
194        MSQueue nalus;
195        ms_queue_init(&nalus);
196        while((im=ms_queue_get(f->inputs[0]))!=NULL){
197                if (ms_yuv_buf_init_from_mblk(&pic,im)==0){
198                        x264_picture_t xpic;
199                        x264_picture_t oxpic;
200                        x264_nal_t *xnals=NULL;
201                        int num_nals=0;
202
203                        memset(&xpic, 0, sizeof(xpic));
204                        memset(&oxpic, 0, sizeof(oxpic));
205
206                        /*send I frame 2 seconds and 4 seconds after the beginning */
207                        if (video_starter_need_i_frame(&d->starter,f->ticker->time))
208                                d->generate_keyframe=TRUE;
209
210                        if (d->generate_keyframe){
211                                xpic.i_type=X264_TYPE_IDR;
212                                d->generate_keyframe=FALSE;
213                        }else xpic.i_type=X264_TYPE_AUTO;
214                        xpic.i_qpplus1=0;
215                        xpic.i_pts=d->framenum;
216                        xpic.param=NULL;
217                        xpic.img.i_csp=X264_CSP_I420;
218                        xpic.img.i_plane=3;
219                        xpic.img.i_stride[0]=pic.strides[0];
220                        xpic.img.i_stride[1]=pic.strides[1];
221                        xpic.img.i_stride[2]=pic.strides[2];
222                        xpic.img.i_stride[3]=0;
223                        xpic.img.plane[0]=pic.planes[0];
224                        xpic.img.plane[1]=pic.planes[1];
225                        xpic.img.plane[2]=pic.planes[2];
226                        xpic.img.plane[3]=0;
227           
228                        if (x264_encoder_encode(d->enc,&xnals,&num_nals,&xpic,&oxpic)>=0){
229                                x264_nals_to_msgb(xnals,num_nals,&nalus);
230                                /*if (num_nals == 0)    ms_message("Delayed frames info: current=%d max=%d\n",
231                                        x264_encoder_delayed_frames(d->enc),
232                                        x264_encoder_maximum_delayed_frames(d->enc));
233                                */
234                                rfc3984_pack(d->packer,&nalus,f->outputs[0],ts);
235                                d->framenum++;
236                                if (d->framenum==0)
237                                        video_starter_first_frame(&d->starter,f->ticker->time);
238                        }else{
239                                ms_error("x264_encoder_encode() error.");
240                        }
241                }
242                freemsg(im);
243        }
244}
245
246static void enc_postprocess(MSFilter *f){
247        EncData *d=(EncData*)f->data;
248        rfc3984_destroy(d->packer);
249        d->packer=NULL;
250        if (d->enc!=NULL){
251                x264_encoder_close(d->enc);
252                d->enc=NULL;
253        }
254}
255
256static int enc_get_br(MSFilter *f, void*arg){
257        EncData *d=(EncData*)f->data;
258        *(int*)arg=d->bitrate;
259        return 0;
260}
261
262static int enc_set_br(MSFilter *f, void *arg){
263        EncData *d=(EncData*)f->data;
264        d->bitrate=*(int*)arg;
265
266        if (d->enc){
267                ms_filter_lock(f);
268                apply_bitrate(f,d->bitrate);
269                if (x264_encoder_reconfig(d->enc,&d->params)!=0){
270                        ms_error("x264_encoder_reconfig() failed.");
271                }
272                ms_filter_unlock(f);
273                return 0;
274        }
275       
276        if (d->bitrate>=1024000){
277                d->vsize.width = MS_VIDEO_SIZE_SVGA_W;
278                d->vsize.height = MS_VIDEO_SIZE_SVGA_H;
279                d->fps=25;
280        }else if (d->bitrate>=512000){
281                d->vsize.width = MS_VIDEO_SIZE_VGA_W;
282                d->vsize.height = MS_VIDEO_SIZE_VGA_H;
283                d->fps=25;
284        } else if (d->bitrate>=256000){
285                d->vsize.width = MS_VIDEO_SIZE_VGA_W;
286                d->vsize.height = MS_VIDEO_SIZE_VGA_H;
287                d->fps=15;
288        }else if (d->bitrate>=170000){
289                d->vsize.width=MS_VIDEO_SIZE_QVGA_W;
290                d->vsize.height=MS_VIDEO_SIZE_QVGA_H;
291                d->fps=15;
292        }else if (d->bitrate>=128000){
293                d->vsize.width=MS_VIDEO_SIZE_QCIF_W;
294                d->vsize.height=MS_VIDEO_SIZE_QCIF_H;
295                d->fps=10;
296        }else if (d->bitrate>=64000){
297                d->vsize.width=MS_VIDEO_SIZE_QCIF_W;
298                d->vsize.height=MS_VIDEO_SIZE_QCIF_H;
299                d->fps=7;
300        }else{
301                d->vsize.width=MS_VIDEO_SIZE_QCIF_W;
302                d->vsize.height=MS_VIDEO_SIZE_QCIF_H;
303                d->fps=5;
304        }
305
306#if defined (ANDROID) || TARGET_OS_IPHONE==1
307        d->vsize.width=MS_VIDEO_SIZE_QVGA_W;
308        d->vsize.height=MS_VIDEO_SIZE_QVGA_H;
309        d->fps=12;
310
311#endif
312       
313        ms_message("bitrate requested...: %d (%d x %d)\n", d->bitrate, d->vsize.width, d->vsize.height);
314        return 0;
315}
316
317static int enc_set_fps(MSFilter *f, void *arg){
318        EncData *d=(EncData*)f->data;
319        d->fps=*(float*)arg;
320        return 0;
321}
322
323static int enc_get_fps(MSFilter *f, void *arg){
324        EncData *d=(EncData*)f->data;
325        *(float*)arg=d->fps;
326        return 0;
327}
328
329static int enc_get_vsize(MSFilter *f, void *arg){
330        EncData *d=(EncData*)f->data;
331        *(MSVideoSize*)arg=d->vsize;
332        return 0;
333}
334
335static int enc_set_vsize(MSFilter *f, void *arg){
336        EncData *d=(EncData*)f->data;
337
338        d->vsize=*(MSVideoSize*)arg;
339
340        return 0;
341}
342
343static int enc_add_fmtp(MSFilter *f, void *arg){
344        EncData *d=(EncData*)f->data;
345        const char *fmtp=(const char *)arg;
346        char value[12];
347        if (fmtp_get_value(fmtp,"packetization-mode",value,sizeof(value))){
348                d->mode=atoi(value);
349                ms_message("packetization-mode set to %i",d->mode);
350        }
351        return 0;
352}
353
354static int enc_req_vfu(MSFilter *f, void *arg){
355        EncData *d=(EncData*)f->data;
356        d->generate_keyframe=TRUE;
357        return 0;
358}
359
360
361static MSFilterMethod enc_methods[]={
362        {       MS_FILTER_SET_FPS       ,       enc_set_fps     },
363        {       MS_FILTER_SET_BITRATE   ,       enc_set_br      },
364        {       MS_FILTER_GET_BITRATE   ,       enc_get_br      },
365        {       MS_FILTER_GET_FPS       ,       enc_get_fps     },
366        {       MS_FILTER_GET_VIDEO_SIZE,       enc_get_vsize   },
367        {       MS_FILTER_SET_VIDEO_SIZE,       enc_set_vsize   },
368        {       MS_FILTER_ADD_FMTP      ,       enc_add_fmtp    },
369        {       MS_FILTER_REQ_VFU       ,       enc_req_vfu     },
370        {       0       ,                       NULL            }
371};
372
373#ifndef _MSC_VER
374
375static MSFilterDesc x264_enc_desc={
376        .id=MS_FILTER_PLUGIN_ID,
377        .name="MSX264Enc",
378        .text="A H264 encoder based on x264 project",
379        .category=MS_FILTER_ENCODER,
380        .enc_fmt="H264",
381        .ninputs=1,
382        .noutputs=1,
383        .init=enc_init,
384        .preprocess=enc_preprocess,
385        .process=enc_process,
386        .postprocess=enc_postprocess,
387        .uninit=enc_uninit,
388        .methods=enc_methods
389};
390
391#else
392
393static MSFilterDesc x264_enc_desc={
394        MS_FILTER_PLUGIN_ID,
395        "MSX264Enc",
396        "A H264 encoder based on x264 project",
397        MS_FILTER_ENCODER,
398        "H264",
399        1,
400        1,
401        enc_init,
402        enc_preprocess,
403        enc_process,
404        enc_postprocess,
405        enc_uninit,
406        enc_methods
407};
408
409#endif
410
411MS2_PUBLIC void libmsx264_init(void){
412        ms_filter_register(&x264_enc_desc);
413        ms_message("ms264-" VERSION " plugin registered.");
414}
415
Note: See TracBrowser for help on using the repository browser.