2 mediastreamer2 x264 plugin
3 Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org)
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #include "mediastreamer2/msfilter.h"
21 #include "mediastreamer2/msticker.h"
22 #include "mediastreamer2/msvideo.h"
23 #include "mediastreamer2/rfc3984.h"
29 #ifdef HAVE_LIBAVCODEC_AVCODEC_H
30 #include <libavcodec/avcodec.h>
31 #include <libswscale/swscale.h>
33 #include <ffmpeg/avcodec.h>
34 #include <ffmpeg/swscale.h>
37 #define REMOVE_PREVENTING_BYTES 1
39 typedef struct _EncData{
46 Rfc3984Context packer;
48 bool_t generate_keyframe;
52 static void enc_init(MSFilter *f){
53 EncData *d=ms_new(EncData,1);
56 d->vsize=MS_VIDEO_SIZE_CIF;
58 d->keyframe_int=10; /*10 seconds */
61 d->generate_keyframe=FALSE;
65 static void enc_uninit(MSFilter *f){
66 EncData *d=(EncData*)f->data;
70 static void enc_preprocess(MSFilter *f){
71 EncData *d=(EncData*)f->data;
74 rfc3984_init(&d->packer);
75 rfc3984_set_mode(&d->packer,d->mode);
76 rfc3984_enable_stap_a(&d->packer,FALSE);
78 x264_param_default(¶ms);
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;
85 params.i_slice_max_size=ms_get_payload_max_size()-100; /*-100 security margin*/
86 /*params.i_level_idc=30;*/
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 ?*/
97 params.i_keyint_max = (int)d->fps*d->keyframe_int;
98 params.i_keyint_min = (int)d->fps;
100 params.b_repeat_headers=1;
101 params.b_cabac=0;//disable cabac to be baseline
102 params.i_bframe=0;/*no B frames*/
103 d->enc=x264_encoder_open(¶ms);
104 if (d->enc==NULL) ms_error("Fail to create x264 encoder.");
108 static void x264_nals_to_msgb(x264_nal_t *xnals, int num_nals, MSQueue * nalus){
112 for (i=0;i<num_nals;++i){
113 m=allocb(xnals[i].i_payload+10,0);
115 memcpy(m->b_wptr,xnals[i].p_payload+4,xnals[i].i_payload-4);
116 m->b_wptr+=xnals[i].i_payload-4;
117 if (xnals[i].i_type==7) {
118 ms_message("A SPS is being sent.");
119 }else if (xnals[i].i_type==8) {
120 ms_message("A PPS is being sent.");
122 ms_queue_put(nalus,m);
126 static void enc_process(MSFilter *f){
127 EncData *d=(EncData*)f->data;
128 uint32_t ts=f->ticker->time*90LL;
132 ms_queue_init(&nalus);
133 while((im=ms_queue_get(f->inputs[0]))!=NULL){
134 if (yuv_buf_init_from_mblk(&pic,im)==0){
136 x264_picture_t oxpic;
137 x264_nal_t *xnals=NULL;
140 /*send I frame 2 seconds and 4 seconds after the beginning */
141 if (d->framenum==(int)d->fps*2 || d->framenum==(int)d->fps*4)
142 d->generate_keyframe=TRUE;
144 if (d->generate_keyframe){
145 xpic.i_type=X264_TYPE_IDR;
146 d->generate_keyframe=FALSE;
147 }else xpic.i_type=X264_TYPE_AUTO;
149 xpic.i_pts=d->framenum;
151 xpic.img.i_csp=X264_CSP_I420;
153 xpic.img.i_stride[0]=pic.strides[0];
154 xpic.img.i_stride[1]=pic.strides[1];
155 xpic.img.i_stride[2]=pic.strides[2];
156 xpic.img.i_stride[3]=0;
157 xpic.img.plane[0]=pic.planes[0];
158 xpic.img.plane[1]=pic.planes[1];
159 xpic.img.plane[2]=pic.planes[2];
161 if (x264_encoder_encode(d->enc,&xnals,&num_nals,&xpic,&oxpic)>=0){
162 x264_nals_to_msgb(xnals,num_nals,&nalus);
163 rfc3984_pack(&d->packer,&nalus,f->outputs[0],ts);
166 ms_error("x264_encoder_encode() error.");
173 static void enc_postprocess(MSFilter *f){
174 EncData *d=(EncData*)f->data;
175 rfc3984_uninit(&d->packer);
177 x264_encoder_close(d->enc);
182 static int enc_set_br(MSFilter *f, void *arg){
183 EncData *d=(EncData*)f->data;
184 d->bitrate=*(int*)arg;
186 if (d->bitrate>=1024000){
187 d->vsize=MS_VIDEO_SIZE_VGA;
189 }else if (d->bitrate>=512000){
190 d->vsize=MS_VIDEO_SIZE_VGA;
192 }else if (d->bitrate>=384000){
193 d->vsize=MS_VIDEO_SIZE_CIF;
195 }else if (d->bitrate>=256000){
196 d->vsize=MS_VIDEO_SIZE_CIF;
198 }else if (d->bitrate>=128000){
199 d->vsize=MS_VIDEO_SIZE_CIF;
201 }else if (d->bitrate>=64000){
202 d->vsize=MS_VIDEO_SIZE_CIF;
204 }else if (d->bitrate>=32000){
205 d->vsize=MS_VIDEO_SIZE_QCIF;
208 d->vsize=MS_VIDEO_SIZE_QCIF;
211 ms_message("bitrate set to %i",d->bitrate);
215 static int enc_set_fps(MSFilter *f, void *arg){
216 EncData *d=(EncData*)f->data;
221 static int enc_get_fps(MSFilter *f, void *arg){
222 EncData *d=(EncData*)f->data;
227 static int enc_get_vsize(MSFilter *f, void *arg){
228 EncData *d=(EncData*)f->data;
229 *(MSVideoSize*)arg=d->vsize;
233 static int enc_set_vsize(MSFilter *f, void *arg){
234 EncData *d=(EncData*)f->data;
235 d->vsize=*(MSVideoSize*)arg;
239 static int enc_add_fmtp(MSFilter *f, void *arg){
240 EncData *d=(EncData*)f->data;
241 const char *fmtp=(const char *)arg;
243 if (fmtp_get_value(fmtp,"packetization-mode",value,sizeof(value))){
245 ms_message("packetization-mode set to %i",d->mode);
250 static int enc_req_vfu(MSFilter *f, void *arg){
251 EncData *d=(EncData*)f->data;
252 d->generate_keyframe=TRUE;
257 static MSFilterMethod enc_methods[]={
258 { MS_FILTER_SET_FPS , enc_set_fps },
259 { MS_FILTER_SET_BITRATE , enc_set_br },
260 { MS_FILTER_GET_FPS , enc_get_fps },
261 { MS_FILTER_GET_VIDEO_SIZE, enc_get_vsize },
262 { MS_FILTER_SET_VIDEO_SIZE, enc_set_vsize },
263 { MS_FILTER_ADD_FMTP , enc_add_fmtp },
264 { MS_FILTER_REQ_VFU , enc_req_vfu },
268 static MSFilterDesc x264_enc_desc={
269 .id=MS_FILTER_PLUGIN_ID,
271 .text="A H264 encoder based on x264 project (with multislicing enabled)",
272 .category=MS_FILTER_ENCODER,
277 .preprocess=enc_preprocess,
278 .process=enc_process,
279 .postprocess=enc_postprocess,
284 typedef struct _DecData{
287 Rfc3984Context unpacker;
289 struct SwsContext *sws_ctx;
290 AVCodecContext av_context;
291 unsigned int packet_num;
296 static void ffmpeg_init(){
297 static bool_t done=FALSE;
300 avcodec_register_all();
305 static void dec_open(DecData *d){
308 codec=avcodec_find_decoder(CODEC_ID_H264);
309 if (codec==NULL) ms_fatal("Could not find H264 decoder in ffmpeg.");
310 avcodec_get_context_defaults(&d->av_context);
311 error=avcodec_open(&d->av_context,codec);
313 ms_fatal("avcodec_open() failed.");
317 static void dec_init(MSFilter *f){
318 DecData *d=(DecData*)ms_new(DecData,1);
324 rfc3984_init(&d->unpacker);
329 d->bitstream_size=65536;
330 d->bitstream=ms_malloc0(d->bitstream_size);
334 static void dec_reinit(DecData *d){
335 avcodec_close(&d->av_context);
339 static void dec_uninit(MSFilter *f){
340 DecData *d=(DecData*)f->data;
341 rfc3984_uninit(&d->unpacker);
342 avcodec_close(&d->av_context);
343 if (d->yuv_msg) freemsg(d->yuv_msg);
344 if (d->sps) freemsg(d->sps);
345 if (d->pps) freemsg(d->pps);
346 ms_free(d->bitstream);
350 static mblk_t *get_as_yuvmsg(MSFilter *f, DecData *s, AVFrame *orig){
351 AVCodecContext *ctx=&s->av_context;
353 if (s->outbuf.w!=ctx->width || s->outbuf.h!=ctx->height){
354 if (s->sws_ctx!=NULL){
355 sws_freeContext(s->sws_ctx);
360 ms_message("Getting yuv picture of %ix%i",ctx->width,ctx->height);
361 s->yuv_msg=yuv_buf_alloc(&s->outbuf,ctx->width,ctx->height);
362 s->outbuf.w=ctx->width;
363 s->outbuf.h=ctx->height;
364 s->sws_ctx=sws_getContext(ctx->width,ctx->height,ctx->pix_fmt,
365 ctx->width,ctx->height,PIX_FMT_YUV420P,SWS_FAST_BILINEAR,
368 if (sws_scale(s->sws_ctx,orig->data,orig->linesize, 0,
369 ctx->height, s->outbuf.planes, s->outbuf.strides)<0){
370 ms_error("%s: error in sws_scale().",f->desc->name);
372 return dupmsg(s->yuv_msg);
375 static void update_sps(DecData *d, mblk_t *sps){
381 static void update_pps(DecData *d, mblk_t *pps){
384 if (pps) d->pps=dupb(pps);
388 static bool_t check_sps_pps_change(DecData *d, mblk_t *sps, mblk_t *pps){
389 bool_t ret1=FALSE,ret2=FALSE;
392 ret1=(msgdsize(sps)!=msgdsize(d->sps)) || (memcmp(d->sps->b_rptr,sps->b_rptr,msgdsize(sps))!=0);
395 ms_message("SPS changed !");
400 ms_message("Receiving first SPS");
405 ret2=(msgdsize(pps)!=msgdsize(d->pps)) || (memcmp(d->pps->b_rptr,pps->b_rptr,msgdsize(pps))!=0);
408 ms_message("PPS changed ! %i,%i",msgdsize(pps),msgdsize(d->pps));
412 ms_message("Receiving first PPS");
418 static void enlarge_bitstream(DecData *d, int new_size){
419 d->bitstream_size=new_size;
420 d->bitstream=ms_realloc(d->bitstream,d->bitstream_size);
423 static int nalusToFrame(DecData *d, MSQueue *naluq, bool_t *new_sps_pps){
425 uint8_t *dst=d->bitstream,*src,*end;
427 bool_t start_picture=TRUE;
430 end=d->bitstream+d->bitstream_size;
431 while((im=ms_queue_get(naluq))!=NULL){
433 nal_len=im->b_wptr-src;
434 if (dst+nal_len+100>end){
435 int pos=dst-d->bitstream;
436 enlarge_bitstream(d, d->bitstream_size+nal_len+100);
437 dst=d->bitstream+pos;
438 end=d->bitstream+d->bitstream_size;
440 nalu_type=(*src) & ((1<<5)-1);
442 *new_sps_pps=check_sps_pps_change(d,im,NULL) || *new_sps_pps;
444 *new_sps_pps=check_sps_pps_change(d,NULL,im) || *new_sps_pps;
445 if (start_picture || nalu_type==7/*SPS*/ || nalu_type==8/*PPS*/ ){
449 /*prepend nal marker*/
454 while(src<(im->b_wptr-3)){
455 if (src[0]==0 && src[1]==0 && src[2]<3){
468 return dst-d->bitstream;
471 static void dec_process(MSFilter *f){
472 DecData *d=(DecData*)f->data;
476 ms_queue_init(&nalus);
477 while((im=ms_queue_get(f->inputs[0]))!=NULL){
478 /*push the sps/pps given in sprop-parameter-sets if any*/
479 if (d->packet_num==0 && d->sps && d->pps){
480 mblk_set_timestamp_info(d->sps,mblk_get_timestamp_info(im));
481 mblk_set_timestamp_info(d->pps,mblk_get_timestamp_info(im));
482 rfc3984_unpack(&d->unpacker,d->sps,&nalus);
483 rfc3984_unpack(&d->unpacker,d->pps,&nalus);
487 rfc3984_unpack(&d->unpacker,im,&nalus);
488 if (!ms_queue_empty(&nalus)){
491 bool_t need_reinit=FALSE;
493 size=nalusToFrame(d,&nalus,&need_reinit);
497 end=d->bitstream+size;
502 avcodec_get_frame_defaults(&orig);
503 av_init_packet(&pkt);
506 len=avcodec_decode_video2(&d->av_context,&orig,&got_picture,&pkt);
508 ms_warning("ms_AVdecoder_process: error %i.",len);
512 ms_queue_put(f->outputs[0],get_as_yuvmsg(f,d,&orig));
521 static int dec_add_fmtp(MSFilter *f, void *arg){
522 DecData *d=(DecData*)f->data;
523 const char *fmtp=(const char *)arg;
525 if (fmtp_get_value(fmtp,"sprop-parameter-sets",value,sizeof(value))){
526 char * b64_sps=value;
527 char * b64_pps=strchr(value,',');
531 ms_message("Got sprop-parameter-sets : sps=%s , pps=%s",b64_sps,b64_pps);
532 d->sps=allocb(sizeof(value),0);
533 d->sps->b_wptr+=b64_decode(b64_sps,strlen(b64_sps),d->sps->b_wptr,sizeof(value));
534 d->pps=allocb(sizeof(value),0);
535 d->pps->b_wptr+=b64_decode(b64_pps,strlen(b64_pps),d->pps->b_wptr,sizeof(value));
541 static MSFilterMethod h264_dec_methods[]={
542 { MS_FILTER_ADD_FMTP , dec_add_fmtp },
546 static MSFilterDesc h264_dec_desc={
547 .id=MS_FILTER_PLUGIN_ID,
549 .text="A H264 decoder based on ffmpeg project.",
550 .category=MS_FILTER_DECODER,
555 .process=dec_process,
557 .methods=h264_dec_methods
560 void libmsx264_init(void){
561 ms_filter_register(&x264_enc_desc);
562 ms_filter_register(&h264_dec_desc);