2 mediastreamer2 library - modular sound and video processing and streaming
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.
21 #include "mediastreamer-config.h"
24 #ifdef HAVE_LIBAVCODEC_AVCODEC_H
25 #include <libavcodec/avcodec.h>
27 #include <ffmpeg/avcodec.h>
30 #include "mediastreamer2/msfilter.h"
31 #include "mediastreamer2/msvideo.h"
32 #include "mediastreamer2/msticker.h"
37 #include <netinet/in.h> /* ntohl(3) */
42 static bool_t avcodec_initialized=FALSE;
44 #ifdef ENABLE_LOG_FFMPEG
46 void ms_ffmpeg_log_callback(void* ptr, int level, const char* fmt, va_list vl)
48 static char message[8192];
50 vsnprintf(message, sizeof message, fmt, vl);
56 void ms_ffmpeg_check_init(){
57 if(!avcodec_initialized){
59 avcodec_register_all();
60 avcodec_initialized=TRUE;
61 #ifdef ENABLE_LOG_FFMPEG
62 av_log_set_level(AV_LOG_WARNING);
63 av_log_set_callback(&ms_ffmpeg_log_callback);
68 typedef struct EncState{
69 AVCodecContext av_context;
74 int mtu; /* network maximum transmission unit in bytes */
83 static int enc_set_fps(MSFilter *f, void *arg){
84 EncState *s=(EncState*)f->data;
89 static int enc_get_fps(MSFilter *f, void *arg){
90 EncState *s=(EncState*)f->data;
95 static int enc_set_vsize(MSFilter *f,void *arg){
96 EncState *s=(EncState*)f->data;
97 s->vsize=*(MSVideoSize*)arg;
101 static int enc_get_vsize(MSFilter *f,void *arg){
102 EncState *s=(EncState*)f->data;
103 *(MSVideoSize*)arg=s->vsize;
107 static int enc_set_mtu(MSFilter *f,void *arg){
108 EncState *s=(EncState*)f->data;
113 static bool_t parse_video_fmtp(const char *fmtp, float *fps, MSVideoSize *vsize){
114 char *tmp=ms_strdup(fmtp);
119 ms_message("parsing %s",fmtp);
120 /*extract fisrt pair */
121 if ((semicolon=strchr(tmp,';'))!=NULL){
124 if ((equal=strchr(tmp,'='))!=NULL){
127 if (strcasecmp(tmp,"CIF")==0){
128 if (vsize->width>=MS_VIDEO_SIZE_CIF_W){
129 vsize->width=MS_VIDEO_SIZE_CIF_W;
130 vsize->height=MS_VIDEO_SIZE_CIF_H;
132 }else if (strcasecmp(tmp,"QCIF")==0){
133 vsize->width=MS_VIDEO_SIZE_QCIF_W;
134 vsize->height=MS_VIDEO_SIZE_QCIF_H;
136 ms_warning("unsupported video size %s",tmp);
139 divider=atoi(equal+1);
141 float newfps=29.97/divider;
142 if (*fps>newfps) *fps=newfps;
144 ms_warning("Could not find video fps");
152 static int enc_add_fmtp(MSFilter *f,void *arg){
153 EncState *s=(EncState*)f->data;
154 const char *fmtp=(const char*)arg;
156 if (fmtp_get_value(fmtp,"profile",val,sizeof(val))){
157 s->profile=atoi(val);
158 }else parse_video_fmtp(fmtp,&s->fps,&s->vsize);
162 static int enc_req_vfu(MSFilter *f, void *unused){
163 EncState *s=(EncState*)f->data;
168 static void enc_init(MSFilter *f, enum CodecID codec)
170 EncState *s=(EncState *)ms_new(EncState,1);
172 ms_ffmpeg_check_init();
173 s->profile=0;/*always default to profile 0*/
176 s->mtu=ms_get_payload_max_size()-2;/*-2 for the H263 payload header*/
179 s->vsize.width=MS_VIDEO_SIZE_CIF_W;
180 s->vsize.height=MS_VIDEO_SIZE_CIF_H;
184 s->av_context.codec=NULL;
187 static void enc_h263_init(MSFilter *f){
188 enc_init(f,CODEC_ID_H263P);
191 static void enc_mpeg4_init(MSFilter *f){
192 enc_init(f,CODEC_ID_MPEG4);
195 static void enc_snow_init(MSFilter *f){
196 enc_init(f,CODEC_ID_SNOW);
199 static void enc_mjpeg_init(MSFilter *f){
200 enc_init(f,CODEC_ID_MJPEG);
203 static void prepare(EncState *s){
204 AVCodecContext *c=&s->av_context;
205 avcodec_get_context_defaults(c);
206 if (s->codec==CODEC_ID_MJPEG)
208 ms_message("Codec bitrate set to %i",c->bit_rate);
209 c->width = s->vsize.width;
210 c->height = s->vsize.height;
211 c->time_base.num = 1;
212 c->time_base.den = (int)s->fps;
213 c->gop_size=(int)s->fps*5; /*emit I frame every 5 seconds*/
214 c->pix_fmt=PIX_FMT_YUVJ420P;
215 s->comp_buf=allocb(c->bit_rate*2,0);
219 /* put codec parameters */
220 c->bit_rate=(float)s->maxbr*0.7;
221 c->bit_rate_tolerance=s->fps!=1?(float)c->bit_rate/(s->fps-1):c->bit_rate;
223 if (s->codec!=CODEC_ID_SNOW && s->maxbr<256000){
224 /*snow does not like 1st pass rate control*/
225 /*and rate control eats too much cpu with CIF high fps pictures*/
226 c->rc_max_rate=(float)s->maxbr*0.8;
228 c->rc_buffer_size=c->rc_max_rate;
234 ms_message("Codec bitrate set to %i",c->bit_rate);
235 c->width = s->vsize.width;
236 c->height = s->vsize.height;
237 c->time_base.num = 1;
238 c->time_base.den = (int)s->fps;
239 c->gop_size=(int)s->fps*5; /*emit I frame every 5 seconds*/
240 c->pix_fmt=PIX_FMT_YUV420P;
241 s->comp_buf=allocb(c->bit_rate*2,0);
242 if (s->codec==CODEC_ID_SNOW){
243 c->strict_std_compliance=-2;
248 static void prepare_h263(EncState *s){
249 AVCodecContext *c=&s->av_context;
250 /* we don't use the rtp_callback but use rtp_mode that forces ffmpeg to insert
251 Start Codes as much as possible in the bitstream */
252 #if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0)
255 c->rtp_payload_size = s->mtu/2;
257 s->codec=CODEC_ID_H263;
259 c->flags|=CODEC_FLAG_H263P_UMV;
260 c->flags|=CODEC_FLAG_AC_PRED;
261 c->flags|=CODEC_FLAG_H263P_SLICE_STRUCT;
263 c->flags|=CODEC_FLAG_OBMC;
264 c->flags|=CODEC_FLAG_AC_PRED;
266 s->codec=CODEC_ID_H263P;
270 static void prepare_mpeg4(EncState *s){
271 AVCodecContext *c=&s->av_context;
272 c->max_b_frames=0; /*don't use b frames*/
273 c->flags|=CODEC_FLAG_AC_PRED;
274 c->flags|=CODEC_FLAG_H263P_UMV;
275 /*c->flags|=CODEC_FLAG_QPEL;*/ /*don't enable this one: this forces profile_level to advanced simple profile */
276 c->flags|=CODEC_FLAG_4MV;
277 c->flags|=CODEC_FLAG_GMC;
278 c->flags|=CODEC_FLAG_LOOP_FILTER;
279 c->flags|=CODEC_FLAG_H263P_SLICE_STRUCT;
282 static void enc_uninit(MSFilter *f){
283 EncState *s=(EncState*)f->data;
287 static void enc_set_rc(EncState *s, AVCodecContext *c){
288 int factor=c->width/MS_VIDEO_SIZE_QCIF_W;
290 c->bit_rate=400; /* this value makes around 100kbit/s at QCIF=2 */
291 c->rc_max_rate=c->bit_rate+1;
292 c->rc_buffer_size=20000*factor; /* food recipe */
296 static void enc_preprocess(MSFilter *f){
297 EncState *s=(EncState*)f->data;
300 if (s->codec==CODEC_ID_H263P || s->codec==CODEC_ID_H263)
302 else if (s->codec==CODEC_ID_MPEG4)
304 else if (s->codec==CODEC_ID_SNOW){
306 }else if (s->codec==CODEC_ID_MJPEG){
309 ms_error("Unsupported codec id %i",s->codec);
312 s->av_codec=avcodec_find_encoder(s->codec);
313 if (s->av_codec==NULL){
314 ms_error("could not find encoder for codec id %i",s->codec);
317 error=avcodec_open(&s->av_context, s->av_codec);
319 ms_error("avcodec_open() failed: %i",error);
322 ms_debug("image format is %i.",s->av_context.pix_fmt);
323 ms_message("qmin=%i qmax=%i",s->av_context.qmin,s->av_context.qmax);
326 static void enc_postprocess(MSFilter *f){
327 EncState *s=(EncState*)f->data;
328 if (s->av_context.codec!=NULL){
329 avcodec_close(&s->av_context);
330 s->av_context.codec=NULL;
332 if (s->comp_buf!=NULL) {
333 freemsg(s->comp_buf);
338 static void add_rfc2190_header(mblk_t **packet, AVCodecContext *context){
340 header = allocb(4, 0);
341 memset(header->b_wptr, 0, 4);
342 // assume video size is CIF or QCIF
343 if (context->width == 352 && context->height == 288) header->b_wptr[1] = 0x60;
344 else header->b_wptr[1] = 0x40;
345 if (context->coded_frame->pict_type != FF_I_TYPE) header->b_wptr[1] |= 0x10;
347 header->b_cont = *packet;
352 static int get_gbsc(uint8_t *psc, uint8_t *end)
358 for (i = 2; i < len-4; i++) {
359 buf = *((uint32_t *)(psc+i));
360 for (j = 0; j < 8; j++) {
361 if (((buf >> j) & 0x00FCFFFF) == 0x00800000) {/*PSC*/
365 } else if (((buf >> j) & 0x0080FFFF) == 0x00800000) {/*GBSC*/
375 static int get_gbsc_bytealigned(uint8_t *begin, uint8_t *end){
377 int len = end - begin;
378 for (i = len - 2; /*len + length of scan window*/
379 i > 2 + 2; /*length of scan window + 2 avoidance of 1st gob or psc*/
381 if(*(begin + i) == 0 &&
382 *(begin + i+1) == 0 &&
383 (*(begin + i+2) & 0x80) == 0x80){
384 /*ms_message("JV psc/gob found! %2x %2x %2x", *(begin + i), *(begin + i+1), *(begin + i + 2));*/
388 /*ms_message("JV no psc or gob found!");*/
393 static void rfc2190_generate_packets(MSFilter *f, EncState *s, mblk_t *frame, uint32_t timestamp){
396 while (frame->b_rptr<frame->b_wptr){
398 /*frame->b_rptr=packet->b_wptr=packet->b_rptr+get_gbsc(packet->b_rptr, MIN(packet->b_rptr+s->mtu,frame->b_wptr));*/
399 frame->b_rptr = packet->b_wptr =
400 packet->b_rptr + get_gbsc_bytealigned(packet->b_rptr, MIN(packet->b_rptr+s->mtu,frame->b_wptr));
401 add_rfc2190_header(&packet, &s->av_context);
402 mblk_set_timestamp_info(packet,timestamp);
403 ms_queue_put(f->outputs[0],packet);
405 /* the marker bit is set on the last packet, if any.*/
406 mblk_set_marker_info(packet,TRUE);
409 static void mpeg4_fragment_and_send(MSFilter *f,EncState *s,mblk_t *frame, uint32_t timestamp){
413 for (rptr=frame->b_rptr;rptr<frame->b_wptr;){
414 len=MIN(s->mtu,(frame->b_wptr-rptr));
417 packet->b_wptr=rptr+len;
418 mblk_set_timestamp_info(packet,timestamp);
419 ms_queue_put(f->outputs[0],packet);
422 /*set marker bit on last packet*/
423 mblk_set_marker_info(packet,TRUE);
426 static void rfc4629_generate_follow_on_packets(MSFilter *f, EncState *s, mblk_t *frame, uint32_t timestamp, uint8_t *psc, uint8_t *end, bool_t last_packet){
433 /*ms_message("generating packet of size %i",end-psc);*/
434 rfc2429_set_P(psc,1);
435 mblk_set_timestamp_info(packet,timestamp);
439 /*need to slit the packet using "follow-on" packets */
440 /*compute the number of packets need (rounded up)*/
441 int num=(len+s->mtu-1)/s->mtu;
444 /*adjust the first packet generated*/
445 pos=packet->b_wptr=packet->b_rptr+s->mtu;
446 ms_queue_put(f->outputs[0],packet);
447 ms_debug("generating %i follow-on packets",num);
452 pos=packet->b_wptr=MIN(pos+s->mtu,end);
458 header->b_cont=packet;
460 mblk_set_timestamp_info(packet,timestamp);
461 ms_queue_put(f->outputs[0],packet);
463 }else ms_queue_put(f->outputs[0],packet);
464 /* the marker bit is set on the last packet, if any.*/
465 mblk_set_marker_info(packet,last_packet);
468 /* returns the last psc position just below packet_size */
469 static uint8_t *get_psc(uint8_t *begin,uint8_t *end, int packet_size){
473 if (begin==end) return NULL;
474 for(i=1,p=begin+1;p<end && i<packet_size;++i,++p){
475 if (p[-1]==0 && p[0]==0){
478 p++;/* to skip possible 0 after the PSC that would make a double detection */
485 //unsigned int tspec:8; /* type-specific field */
486 unsigned int off:32; /* fragment byte offset */
487 uint8_t type; /* id of jpeg decoder params */
488 uint8_t q; /* quantization factor (or table id) */
489 uint8_t width; /* frame width in 8 pixel blocks */
490 uint8_t height; /* frame height in 8 pixel blocks */
497 unsigned int count:14;
500 struct jpeghdr_qtable {
506 #define RTP_JPEG_RESTART 0x40
508 /* Procedure SendFrame:
511 * start_seq: The sequence number for the first packet of the current
513 * ts: RTP timestamp for the current frame
514 * ssrc: RTP SSRC value
515 * jpeg_data: Huffman encoded JPEG scan data
516 * len: Length of the JPEG scan data
517 * type: The value the RTP/JPEG type field should be set to
518 * typespec: The value the RTP/JPEG type-specific field should be set
520 * width: The width in pixels of the JPEG image
521 * height: The height in pixels of the JPEG image
522 * dri: The number of MCUs between restart markers (or 0 if there
523 * are no restart markers in the data
524 * q: The Q factor of the data, to be specified using the Independent
525 * JPEG group's algorithm if 1 <= q <= 99, specified explicitly
526 * with lqt and cqt if q >= 128, or undefined otherwise.
527 * lqt: The quantization table for the luminance channel if q >= 128
528 * cqt: The quantization table for the chrominance channels if
532 * the sequence number to be sent for the first packet of the next
535 * The following are assumed to be defined:
537 * PACKET_SIZE - The size of the outgoing packet
538 * send_packet(u_int8 *data, int len) - Sends the packet to the network
541 static void mjpeg_fragment_and_send(MSFilter *f,EncState *s,mblk_t *frame, uint32_t timestamp,
542 uint8_t type, uint8_t typespec, int dri,
543 uint8_t q, mblk_t *lqt, mblk_t *cqt) {
544 struct jpeghdr jpghdr;
545 struct jpeghdr_rst rsthdr;
546 struct jpeghdr_qtable qtblhdr;
547 int bytes_left = msgdsize(frame);
552 /* Initialize JPEG header
554 //jpghdr.tspec = typespec;
556 jpghdr.type = type | ((dri != 0) ? RTP_JPEG_RESTART : 0);
558 jpghdr.width = s->vsize.width / 8;
559 jpghdr.height = s->vsize.height / 8;
561 /* Initialize DRI header
564 rsthdr.dri = htons(dri);
565 rsthdr.f = 1; /* This code does not align RIs */
567 rsthdr.count = 0x3fff;
570 /* Initialize quantization table header
574 qtblhdr.precision = 0; /* This code uses 8 bit tables only */
575 qtblhdr.length = htons(msgdsize(lqt)+msgdsize(cqt)); /* 2 64-byte tables */
578 while (bytes_left > 0) {
579 packet = allocb(s->mtu, 0);
581 jpghdr.off = htonl(jpghdr.off);
582 memcpy(packet->b_wptr, &jpghdr, sizeof(jpghdr));
583 jpghdr.off = ntohl(jpghdr.off);
584 packet->b_wptr += sizeof(jpghdr);
587 memcpy(packet->b_wptr, &rsthdr, sizeof(rsthdr));
588 packet->b_wptr += sizeof(rsthdr);
591 if (q >= 128 && jpghdr.off == 0) {
592 memcpy(packet->b_wptr, &qtblhdr, sizeof(qtblhdr));
593 packet->b_wptr += sizeof(qtblhdr);
595 memcpy(packet->b_wptr, lqt->b_rptr, msgdsize(lqt));
596 packet->b_wptr += msgdsize(lqt);
599 memcpy(packet->b_wptr, cqt->b_rptr, msgdsize(cqt));
600 packet->b_wptr += msgdsize(cqt);
604 data_len = s->mtu - (packet->b_wptr - packet->b_rptr);
605 if (data_len >= bytes_left) {
606 data_len = bytes_left;
607 mblk_set_marker_info(packet,TRUE);
610 memcpy(packet->b_wptr, frame->b_rptr + jpghdr.off, data_len);
611 packet->b_wptr=packet->b_wptr + data_len;
613 mblk_set_timestamp_info(packet,timestamp);
614 ms_queue_put(f->outputs[0],packet);
616 jpghdr.off += data_len;
617 bytes_left -= data_len;
621 static int find_marker(uint8_t **pbuf_ptr, uint8_t *buf_end){
628 while (buf_ptr < buf_end) {
631 if ((v == 0xff) && (v2 >= 0xc0) && (v2 <= 0xfe) && buf_ptr < buf_end) {
641 static mblk_t *skip_jpeg_headers(mblk_t *full_frame, mblk_t **lqt, mblk_t **cqt){
643 uint8_t *pbuf_ptr=full_frame->b_rptr;
644 uint8_t *buf_end=full_frame->b_wptr;
646 ms_message("image size: %i)", buf_end-pbuf_ptr);
651 err = find_marker(&pbuf_ptr, buf_end);
654 ms_message("marker found: %x (offset from beginning%i)", err, pbuf_ptr-full_frame->b_rptr);
658 int len = ntohs(*(uint16_t*)(pbuf_ptr));
661 mblk_t *_lqt = allocb(len-3, 0);
662 memcpy(_lqt->b_rptr, pbuf_ptr+3, len-3);
663 _lqt->b_wptr += len-3;
669 mblk_t *_cqt = allocb(len-3, 0);
670 memcpy(_cqt->b_rptr, pbuf_ptr+3, len-3);
671 _cqt->b_wptr += len-3;
677 uint16_t *bistream=(uint16_t *)pbuf_ptr;
678 uint16_t len = ntohs(*bistream);
679 full_frame->b_rptr = pbuf_ptr+len;
681 err = find_marker(&pbuf_ptr, buf_end);
686 static void split_and_send(MSFilter *f, EncState *s, mblk_t *frame){
689 uint32_t timestamp=f->ticker->time*90LL;
691 if (s->codec==CODEC_ID_MPEG4 || s->codec==CODEC_ID_SNOW)
693 mpeg4_fragment_and_send(f,s,frame,timestamp);
696 else if (s->codec==CODEC_ID_MJPEG)
700 skip_jpeg_headers(frame, &lqt, &cqt);
701 mjpeg_fragment_and_send(f,s,frame,timestamp,
711 ms_debug("processing frame of size %i",frame->b_wptr-frame->b_rptr);
712 if (f->desc->id==MS_H263_ENC_ID){
713 lastpsc=frame->b_rptr;
715 psc=get_psc(lastpsc+2,frame->b_wptr,s->mtu);
717 rfc4629_generate_follow_on_packets(f,s,frame,timestamp,lastpsc,psc,FALSE);
721 /* send the end of frame */
722 rfc4629_generate_follow_on_packets(f,s,frame, timestamp,lastpsc,frame->b_wptr,TRUE);
723 }else if (f->desc->id==MS_H263_OLD_ENC_ID){
724 rfc2190_generate_packets(f,s,frame,timestamp);
726 ms_fatal("Ca va tres mal.");
730 static void process_frame(MSFilter *f, mblk_t *inm){
731 EncState *s=(EncState*)f->data;
733 AVCodecContext *c=&s->av_context;
735 mblk_t *comp_buf=s->comp_buf;
736 int comp_buf_sz=comp_buf->b_datap->db_lim-comp_buf->b_datap->db_base;
738 /* convert image if necessary */
739 avcodec_get_frame_defaults(&pict);
740 avpicture_fill((AVPicture*)&pict,(uint8_t*)inm->b_rptr,c->pix_fmt,c->width,c->height);
742 /* timestamp used by ffmpeg, unset here */
743 pict.pts=AV_NOPTS_VALUE;
745 if (s->framenum==(int)(s->fps*2.0) || s->framenum==(int)(s->fps*4.0)){
746 /*sends an I frame at 2 seconds and 4 seconds after the beginning of the call*/
750 pict.pict_type=FF_I_TYPE;
753 comp_buf->b_rptr=comp_buf->b_wptr=comp_buf->b_datap->db_base;
754 if (s->codec==CODEC_ID_SNOW){
755 //prepend picture size
756 uint32_t header=((s->vsize.width&0xffff)<<16) | (s->vsize.height&0xffff);
757 *(uint32_t*)comp_buf->b_wptr=htonl(header);
761 error=avcodec_encode_video(c, (uint8_t*)comp_buf->b_wptr,comp_buf_sz, &pict);
762 if (error<=0) ms_warning("ms_AVencoder_process: error %i.",error);
765 if (c->coded_frame->pict_type==FF_I_TYPE){
766 ms_message("Emitting I-frame");
768 comp_buf->b_wptr+=error;
769 split_and_send(f,s,comp_buf);
774 static void enc_process(MSFilter *f){
776 EncState *s=(EncState*)f->data;
777 if (s->av_context.codec==NULL) {
778 ms_queue_flush(f->inputs[0]);
782 while((inm=ms_queue_get(f->inputs[0]))!=0){
783 process_frame(f,inm);
789 static int enc_get_br(MSFilter *f, void *arg){
790 EncState *s=(EncState*)f->data;
795 static int enc_set_br(MSFilter *f, void *arg){
796 EncState *s=(EncState*)f->data;
797 bool_t snow=s->codec==CODEC_ID_SNOW;
799 if (s->maxbr>=1024000 && s->codec!=CODEC_ID_H263P){
800 s->vsize.width = MS_VIDEO_SIZE_SVGA_W;
801 s->vsize.height = MS_VIDEO_SIZE_SVGA_H;
803 }else if (s->maxbr>=800000 && s->codec!=CODEC_ID_H263P){
804 s->vsize.width = MS_VIDEO_SIZE_VGA_W;
805 s->vsize.height = MS_VIDEO_SIZE_VGA_H;
807 }else if (s->maxbr>=512000){
808 s->vsize.width=MS_VIDEO_SIZE_CIF_W;
809 s->vsize.height=MS_VIDEO_SIZE_CIF_H;
811 }else if (s->maxbr>=256000){
812 s->vsize.width=MS_VIDEO_SIZE_CIF_W;
813 s->vsize.height=MS_VIDEO_SIZE_CIF_H;
816 }else if (s->maxbr>=128000){
817 s->vsize.width=MS_VIDEO_SIZE_QCIF_W;
818 s->vsize.height=MS_VIDEO_SIZE_QCIF_H;
821 }else if (s->maxbr>=64000){
822 s->vsize.width=MS_VIDEO_SIZE_QCIF_W;
823 s->vsize.height=MS_VIDEO_SIZE_QCIF_H;
825 s->qmin=snow ? 4 : 5;
827 s->vsize.width=MS_VIDEO_SIZE_QCIF_W;
828 s->vsize.height=MS_VIDEO_SIZE_QCIF_H;
832 if (s->av_context.codec!=NULL){
833 /*apply new settings dynamically*/
843 static MSFilterMethod methods[]={
844 { MS_FILTER_SET_FPS , enc_set_fps },
845 { MS_FILTER_GET_FPS , enc_get_fps },
846 { MS_FILTER_SET_VIDEO_SIZE , enc_set_vsize },
847 { MS_FILTER_GET_VIDEO_SIZE , enc_get_vsize },
848 { MS_FILTER_ADD_FMTP , enc_add_fmtp },
849 { MS_FILTER_SET_BITRATE , enc_set_br },
850 { MS_FILTER_GET_BITRATE , enc_get_br },
851 { MS_FILTER_SET_MTU , enc_set_mtu },
852 { MS_FILTER_REQ_VFU , enc_req_vfu },
858 MSFilterDesc ms_h263_enc_desc={
861 N_("A video H.263 encoder using ffmpeg library."),
864 1, /*MS_YUV420P is assumed on this input */
874 MSFilterDesc ms_h263_old_enc_desc={
877 N_("A video H.263 encoder using ffmpeg library. It is compliant with old RFC2190 spec."),
880 1, /*MS_YUV420P is assumed on this input */
890 MSFilterDesc ms_mpeg4_enc_desc={
893 N_("A video MPEG4 encoder using ffmpeg library."),
896 1, /*MS_YUV420P is assumed on this input */
906 MSFilterDesc ms_snow_enc_desc={
909 N_("A video snow encoder using ffmpeg library."),
912 1, /*MS_YUV420P is assumed on this input */
922 MSFilterDesc ms_mjpeg_enc_desc={
925 N_("A RTP/MJPEG encoder using ffmpeg library."),
928 1, /*MS_YUV420P is assumed on this input */
940 MSFilterDesc ms_h263_enc_desc={
943 .text=N_("A video H.263 encoder using ffmpeg library."),
944 .category=MS_FILTER_ENCODER,
945 .enc_fmt="H263-1998",
946 .ninputs=1, /*MS_YUV420P is assumed on this input */
949 .preprocess=enc_preprocess,
950 .process=enc_process,
951 .postprocess=enc_postprocess,
956 MSFilterDesc ms_h263_old_enc_desc={
957 .id=MS_H263_OLD_ENC_ID,
959 .text=N_("A video H.263 encoder using ffmpeg library, compliant with old RFC2190 spec."),
960 .category=MS_FILTER_ENCODER,
962 .ninputs=1, /*MS_YUV420P is assumed on this input */
965 .preprocess=enc_preprocess,
966 .process=enc_process,
967 .postprocess=enc_postprocess,
972 MSFilterDesc ms_mpeg4_enc_desc={
975 .text=N_("A video MPEG4 encoder using ffmpeg library."),
976 .category=MS_FILTER_ENCODER,
978 .ninputs=1, /*MS_YUV420P is assumed on this input */
980 .init=enc_mpeg4_init,
981 .preprocess=enc_preprocess,
982 .process=enc_process,
983 .postprocess=enc_postprocess,
988 MSFilterDesc ms_snow_enc_desc={
991 .text=N_("The snow codec is royalty-free and is open-source. \n"
992 "It uses innovative techniques that makes it one of most promising video "
993 "codec. It is implemented within the ffmpeg project.\n"
994 "However it is under development, quite unstable and compatibility with other versions "
995 "cannot be guaranteed."),
996 .category=MS_FILTER_ENCODER,
998 .ninputs=1, /*MS_YUV420P is assumed on this input */
1000 .init=enc_snow_init,
1001 .preprocess=enc_preprocess,
1002 .process=enc_process,
1003 .postprocess=enc_postprocess,
1008 MSFilterDesc ms_mjpeg_enc_desc={
1011 .text=N_("A MJPEG encoder using ffmpeg library."),
1012 .category=MS_FILTER_ENCODER,
1014 .ninputs=1, /*MS_YUV420P is assumed on this input */
1016 .init=enc_mjpeg_init,
1017 .preprocess=enc_preprocess,
1018 .process=enc_process,
1019 .postprocess=enc_postprocess,
1026 void __register_ffmpeg_encoders_if_possible(void){
1027 ms_ffmpeg_check_init();
1028 if (avcodec_find_encoder(CODEC_ID_MPEG4))
1029 ms_filter_register(&ms_mpeg4_enc_desc);
1030 if (avcodec_find_encoder(CODEC_ID_H263)){
1031 ms_filter_register(&ms_h263_enc_desc);
1032 ms_filter_register(&ms_h263_old_enc_desc);
1034 if (avcodec_find_encoder(CODEC_ID_SNOW))
1035 ms_filter_register(&ms_snow_enc_desc);
1036 if (avcodec_find_encoder(CODEC_ID_MJPEG))
1038 ms_filter_register(&ms_mjpeg_enc_desc);