videoenc.c 31.2 KB
Newer Older
aymeric's avatar
aymeric committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#ifdef HAVE_CONFIG_H
#include "mediastreamer-config.h"
#endif

unknown's avatar
unknown committed
24
#include "ffmpeg-priv.h"
25

aymeric's avatar
aymeric committed
26 27 28
#include "mediastreamer2/msfilter.h"
#include "mediastreamer2/msvideo.h"
#include "mediastreamer2/msticker.h"
Ghislain MARY's avatar
Ghislain MARY committed
29
#include "mediastreamer2/videostarter.h"
aymeric's avatar
aymeric committed
30 31 32 33 34 35 36 37 38

#ifdef _WIN32
#include <ws2tcpip.h>
#else
#include <netinet/in.h>			/* ntohl(3) */
#endif

#include "rfc2429.h"

39 40
#define RATE_CONTROL_MARGIN 15000 /*bits/second*/

41 42
#define MS_VIDEOENC_CONF(required_bitrate, bitrate_limit, resolution, fps, cpu, qminvalue) \
	{ required_bitrate, bitrate_limit, { MS_VIDEO_SIZE_ ## resolution ## _W, MS_VIDEO_SIZE_ ## resolution ## _H }, fps, cpu, (void *)&qmin ## qminvalue }
43

aymeric's avatar
aymeric committed
44 45
static bool_t avcodec_initialized=FALSE;

46 47
static const int qmin2 = 2;
static const int qmin3 = 3;
48 49 50
#if HAVE_AVCODEC_SNOW
static const int qmin4 = 4;
#endif
51 52 53
static const int qmin5 = 5;

static const MSVideoConfiguration h263_conf_list[] = {
54 55 56 57 58
	MS_VIDEOENC_CONF( 800000, 1024000,  4CIF, 25, 2, 2),
	MS_VIDEOENC_CONF( 512000,  800000,  CIF, 25, 1, 2),
	MS_VIDEOENC_CONF( 256000,  512000,  CIF, 17, 1, 3),
	MS_VIDEOENC_CONF( 128000,  256000, QCIF, 10, 1, 3),
	MS_VIDEOENC_CONF(      0,  128000, QCIF,  5, 1, 5)
59 60 61
};

static const MSVideoConfiguration h263p_conf_list[] = {
62 63 64 65 66
	MS_VIDEOENC_CONF(800000, 1024000, 4CIF, 25, 2, 2),
	MS_VIDEOENC_CONF(512000,  800000,  CIF, 25, 1, 2),
	MS_VIDEOENC_CONF(256000,  512000,  CIF, 17, 1, 3),
	MS_VIDEOENC_CONF(128000,  256000, QCIF, 10, 1, 3),
	MS_VIDEOENC_CONF(     0,  128000, QCIF,  5, 1, 5)
67 68 69
};

static const MSVideoConfiguration mjpeg_conf_list[] = {
70 71 72 73 74 75 76
	MS_VIDEOENC_CONF(1024000, 1536000, SVGA, 25, 1, 2),
	MS_VIDEOENC_CONF( 800000, 1024000,  VGA, 25, 1, 2),
	MS_VIDEOENC_CONF( 512000,  800000,  CIF, 25, 1, 2),
	MS_VIDEOENC_CONF( 256000,  512000,  CIF, 17, 1, 3),
	MS_VIDEOENC_CONF( 170000,  256000, QVGA, 15, 1, 3),
	MS_VIDEOENC_CONF( 128000,  170000, QCIF, 10, 1, 3),
	MS_VIDEOENC_CONF(      0,  128000, QCIF,  5, 1, 5)
77 78 79
};

static const MSVideoConfiguration mpeg4_conf_list[] = {
80 81 82 83 84 85 86 87 88 89
    	MS_VIDEOENC_CONF(2048000, 2560000, SXGA_MINUS, 25, 4, 2),
	MS_VIDEOENC_CONF(2048000, 2560000, 720P, 25, 4, 2),
    	MS_VIDEOENC_CONF(1536000, 2048000,  XGA, 25, 4, 2),
	MS_VIDEOENC_CONF(1024000, 1536000, SVGA, 25, 2, 2),
	MS_VIDEOENC_CONF( 800000, 1024000,  VGA, 25, 1, 2),
	MS_VIDEOENC_CONF( 512000,  800000,  CIF, 25, 1, 2),
	MS_VIDEOENC_CONF( 256000,  512000,  CIF, 17, 1, 3),
	MS_VIDEOENC_CONF( 170000,  256000, QVGA, 15, 1, 3),
	MS_VIDEOENC_CONF( 128000,  170000, QCIF, 10, 1, 3),
	MS_VIDEOENC_CONF(      0,  128000, QCIF,  5, 1, 5)
90 91
};

92
#if HAVE_AVCODEC_SNOW
93
static const MSVideoConfiguration snow_conf_list[] = {
94 95 96 97 98 99 100 101
	MS_VIDEOENC_CONF(1024000, 1536000, SVGA, 25, 2, 2),
	MS_VIDEOENC_CONF( 800000, 1024000,  VGA, 25, 1, 2),
	MS_VIDEOENC_CONF( 512000,  800000,  CIF, 25, 1, 2),
	MS_VIDEOENC_CONF( 256000,  512000,  CIF, 17, 1, 3),
	MS_VIDEOENC_CONF( 170000,  256000, QVGA, 15, 1, 3),
	MS_VIDEOENC_CONF( 128000,  170000, QCIF, 10, 1, 3),
	MS_VIDEOENC_CONF(  64000,  128000, QCIF,  7, 1, 4),
	MS_VIDEOENC_CONF(      0,   64000, QCIF,  5, 1, 5)
102
};
103
#endif
104

105 106 107 108
#ifndef FF_I_TYPE
#define FF_I_TYPE AV_PICTURE_TYPE_I
#endif

109 110 111 112
#ifdef ENABLE_LOG_FFMPEG

void ms_ffmpeg_log_callback(void* ptr, int level, const char* fmt, va_list vl)
{
Simon Morlat's avatar
Simon Morlat committed
113
	ortp_logv(ORTP_MESSAGE,fmt,vl);
114 115 116 117
}

#endif

aymeric's avatar
aymeric committed
118 119
void ms_ffmpeg_check_init(){
	if(!avcodec_initialized){
120
#ifdef FF_API_AVCODEC_INIT
aymeric's avatar
aymeric committed
121
		avcodec_init();
122
#endif
aymeric's avatar
aymeric committed
123 124
		avcodec_register_all();
		avcodec_initialized=TRUE;
125 126 127 128
#ifdef ENABLE_LOG_FFMPEG
		av_log_set_level(AV_LOG_WARNING);
		av_log_set_callback(&ms_ffmpeg_log_callback);
#endif
aymeric's avatar
aymeric committed
129 130 131 132 133 134
	}
}

typedef struct EncState{
	AVCodecContext av_context;
	AVCodec *av_codec;
135
	AVFrame* pict;
aymeric's avatar
aymeric committed
136 137 138 139 140
	enum CodecID codec;
	mblk_t *comp_buf;
	int mtu;	/* network maximum transmission unit in bytes */
	int profile;
	int qmin;
141
	uint32_t framenum;
Ghislain MARY's avatar
Ghislain MARY committed
142
	MSVideoStarter starter;
aymeric's avatar
aymeric committed
143
	bool_t req_vfu;
144 145
	const MSVideoConfiguration *vconf_list;
	MSVideoConfiguration vconf;
aymeric's avatar
aymeric committed
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
}EncState;

static bool_t parse_video_fmtp(const char *fmtp, float *fps, MSVideoSize *vsize){
	char *tmp=ms_strdup(fmtp);
	char *semicolon;
	char *equal;
	bool_t ret=TRUE;

	ms_message("parsing %s",fmtp);
	/*extract fisrt pair */
	if ((semicolon=strchr(tmp,';'))!=NULL){
		*semicolon='\0';
	}
	if ((equal=strchr(tmp,'='))!=NULL){
		int divider;
		*equal='\0';
		if (strcasecmp(tmp,"CIF")==0){
			if (vsize->width>=MS_VIDEO_SIZE_CIF_W){
				vsize->width=MS_VIDEO_SIZE_CIF_W;
				vsize->height=MS_VIDEO_SIZE_CIF_H;
			}
		}else if (strcasecmp(tmp,"QCIF")==0){
			vsize->width=MS_VIDEO_SIZE_QCIF_W;
			vsize->height=MS_VIDEO_SIZE_QCIF_H;
		}else{
			ms_warning("unsupported video size %s",tmp);
			ret=FALSE;
173
			goto end;
aymeric's avatar
aymeric committed
174 175 176 177 178 179 180 181 182 183
		}
		divider=atoi(equal+1);
		if (divider!=0){
			float newfps=29.97/divider;
			if (*fps>newfps) *fps=newfps;
		}else{
			ms_warning("Could not find video fps");
			ret=FALSE;
		}
	}else ret=FALSE;
184 185

end:
aymeric's avatar
aymeric committed
186 187 188 189 190 191 192 193 194 195
	ms_free(tmp);
	return ret;
}

static int enc_add_fmtp(MSFilter *f,void *arg){
	EncState *s=(EncState*)f->data;
	const char *fmtp=(const char*)arg;
	char val[10];
	if (fmtp_get_value(fmtp,"profile",val,sizeof(val))){
		s->profile=atoi(val);
196
	}else parse_video_fmtp(fmtp,&s->vconf.fps,&s->vconf.vsize);
aymeric's avatar
aymeric committed
197 198 199 200 201 202 203 204 205
	return 0;
}

static int enc_req_vfu(MSFilter *f, void *unused){
	EncState *s=(EncState*)f->data;
	s->req_vfu=TRUE;
	return 0;
}

206 207 208 209 210 211 212 213 214 215 216
static const MSVideoConfiguration * get_vconf_list(EncState *s) {
	switch (s->codec) {
		case CODEC_ID_H263:
			return  &h263_conf_list[0];
		case CODEC_ID_H263P:
			return &h263p_conf_list[0];
		case CODEC_ID_MJPEG:
			return &mjpeg_conf_list[0];
		case CODEC_ID_MPEG4:
		default:
			return &mpeg4_conf_list[0];
217
#if HAVE_AVCODEC_SNOW
218 219
		case CODEC_ID_SNOW:
			return &snow_conf_list[0];
220
#endif
221 222 223
	}
}

aymeric's avatar
aymeric committed
224 225
static void enc_init(MSFilter *f, enum CodecID codec)
{
226
	EncState *s=ms_new0(EncState,1);
aymeric's avatar
aymeric committed
227 228 229
	f->data=s;
	ms_ffmpeg_check_init();
	s->profile=0;/*always default to profile 0*/
230
	s->comp_buf=NULL;
aymeric's avatar
aymeric committed
231 232 233 234
	s->mtu=ms_get_payload_max_size()-2;/*-2 for the H263 payload header*/
	s->codec=codec;
	s->qmin=2;
	s->req_vfu=FALSE;
235
	s->framenum=0;
aymeric's avatar
aymeric committed
236
	s->av_context.codec=NULL;
237
	s->vconf_list = get_vconf_list(s);
238
	s->vconf = ms_video_find_best_configuration_for_bitrate(s->vconf_list, 500000, ms_get_cpu_count());
239
	s->pict = av_frame_alloc();
aymeric's avatar
aymeric committed
240 241 242 243 244 245 246 247 248
}

static void enc_h263_init(MSFilter *f){
	enc_init(f,CODEC_ID_H263P);
}

static void enc_mpeg4_init(MSFilter *f){
	enc_init(f,CODEC_ID_MPEG4);
}
249
#if HAVE_AVCODEC_SNOW
aymeric's avatar
aymeric committed
250 251 252
static void enc_snow_init(MSFilter *f){
	enc_init(f,CODEC_ID_SNOW);
}
253
#endif
254 255 256 257
static void enc_mjpeg_init(MSFilter *f){
	enc_init(f,CODEC_ID_MJPEG);
}

aymeric's avatar
aymeric committed
258 259
static void prepare(EncState *s){
	AVCodecContext *c=&s->av_context;
Simon Morlat's avatar
Simon Morlat committed
260 261
	const int max_br_vbv=128000;

262
	avcodec_get_context_defaults3(c, NULL);
263 264 265
	if (s->codec==CODEC_ID_MJPEG)
	{
		ms_message("Codec bitrate set to %i",c->bit_rate);
266 267
		c->width = s->vconf.vsize.width;
		c->height = s->vconf.vsize.height;
268
		c->time_base.num = 1;
269 270
		c->time_base.den = (int)s->vconf.fps;
		c->gop_size=(int)s->vconf.fps*5; /*emit I frame every 5 seconds*/
271 272 273 274 275
		c->pix_fmt=PIX_FMT_YUVJ420P;
		s->comp_buf=allocb(c->bit_rate*2,0);
		return;
	}

aymeric's avatar
aymeric committed
276
	/* put codec parameters */
277
	/* in order to take in account RTP protocol overhead and avoid possible
278
	 bitrate peaks especially on low bandwidth, we make a correction on the
279 280
	 codec's target bitrate.
	*/
281
	c->bit_rate=(float)s->vconf.required_bitrate*0.92;
282 283 284
	if (c->bit_rate>RATE_CONTROL_MARGIN){
		 c->bit_rate -= RATE_CONTROL_MARGIN;
	}
285
	c->bit_rate_tolerance=s->vconf.fps>1?(float)c->bit_rate/(s->vconf.fps-1):c->bit_rate;
aymeric's avatar
aymeric committed
286

Simon Morlat's avatar
Simon Morlat committed
287 288
	/* ffmpeg vbv rate control consumes too much cpu above a certain target bitrate.
	We don't use it above max_br_vbv */
289 290
	if (
#if HAVE_AVCODEC_SNOW
291
		s->codec!=CODEC_ID_SNOW &&
292 293
#endif
		s->vconf.required_bitrate<max_br_vbv){
aymeric's avatar
aymeric committed
294
		/*snow does not like 1st pass rate control*/
295
		c->rc_max_rate=c->bit_rate;
smorlat's avatar
smorlat committed
296
		c->rc_min_rate=0;
aymeric's avatar
aymeric committed
297 298 299 300 301 302 303
		c->rc_buffer_size=c->rc_max_rate;
	}else{
		/*use qmin instead*/
		c->qmin=s->qmin;
	}

	ms_message("Codec bitrate set to %i",c->bit_rate);
304 305
	c->width = s->vconf.vsize.width;
	c->height = s->vconf.vsize.height;
aymeric's avatar
aymeric committed
306
	c->time_base.num = 1;
307 308
	c->time_base.den = (int)s->vconf.fps;
	c->gop_size=(int)s->vconf.fps*10; /*emit I frame every 10 seconds*/
aymeric's avatar
aymeric committed
309
	c->pix_fmt=PIX_FMT_YUV420P;
310
	s->comp_buf=allocb(c->bit_rate*2,0);
311
#if HAVE_AVCODEC_SNOW
aymeric's avatar
aymeric committed
312 313 314
	if (s->codec==CODEC_ID_SNOW){
		c->strict_std_compliance=-2;
	}
315
#endif
316 317
	ms_message("Codec size set to w=%i/h=%i",c->width, c->height);

aymeric's avatar
aymeric committed
318 319 320 321 322 323
}

static void prepare_h263(EncState *s){
	AVCodecContext *c=&s->av_context;
	/* we don't use the rtp_callback but use rtp_mode that forces ffmpeg to insert
	Start Codes as much as possible in the bitstream */
324 325 326
#if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0)
        c->rtp_mode = 1;
#endif
aymeric's avatar
aymeric committed
327 328 329 330
	c->rtp_payload_size = s->mtu/2;
	if (s->profile==0){
		s->codec=CODEC_ID_H263;
	}else{
331
		/*
aymeric's avatar
aymeric committed
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
		c->flags|=CODEC_FLAG_H263P_UMV;
		c->flags|=CODEC_FLAG_AC_PRED;
		c->flags|=CODEC_FLAG_H263P_SLICE_STRUCT;
		c->flags|=CODEC_FLAG_OBMC;
		c->flags|=CODEC_FLAG_AC_PRED;
		*/
		s->codec=CODEC_ID_H263P;
	}
}

static void prepare_mpeg4(EncState *s){
	AVCodecContext *c=&s->av_context;
	c->max_b_frames=0; /*don't use b frames*/
}

static void enc_uninit(MSFilter  *f){
	EncState *s=(EncState*)f->data;
349
	if (s->pict) av_frame_free(&s->pict);
aymeric's avatar
aymeric committed
350 351 352 353 354 355 356 357 358 359 360
	ms_free(s);
}

static void enc_preprocess(MSFilter *f){
	EncState *s=(EncState*)f->data;
	int error;
	prepare(s);
	if (s->codec==CODEC_ID_H263P || s->codec==CODEC_ID_H263)
		prepare_h263(s);
	else if (s->codec==CODEC_ID_MPEG4)
		prepare_mpeg4(s);
361
#if HAVE_AVCODEC_SNOW
aymeric's avatar
aymeric committed
362 363
	else if (s->codec==CODEC_ID_SNOW){
		/**/
364 365 366
	}
#endif
	else if (s->codec==CODEC_ID_MJPEG){
367
		/**/
aymeric's avatar
aymeric committed
368 369 370 371 372 373 374 375 376
	}else {
		ms_error("Unsupported codec id %i",s->codec);
		return;
	}
	s->av_codec=avcodec_find_encoder(s->codec);
	if (s->av_codec==NULL){
		ms_error("could not find encoder for codec id %i",s->codec);
		return;
	}
377
	error=avcodec_open2(&s->av_context, s->av_codec, NULL);
aymeric's avatar
aymeric committed
378 379 380 381
	if (error!=0) {
		ms_error("avcodec_open() failed: %i",error);
		return;
	}
Ghislain MARY's avatar
Ghislain MARY committed
382
	ms_video_starter_init(&s->starter);
aymeric's avatar
aymeric committed
383 384
	ms_debug("image format is %i.",s->av_context.pix_fmt);
	ms_message("qmin=%i qmax=%i",s->av_context.qmin,s->av_context.qmax);
385
	s->framenum=0;
aymeric's avatar
aymeric committed
386 387 388 389 390 391 392 393
}

static void enc_postprocess(MSFilter *f){
	EncState *s=(EncState*)f->data;
	if (s->av_context.codec!=NULL){
		avcodec_close(&s->av_context);
		s->av_context.codec=NULL;
	}
394 395 396 397
	if (s->comp_buf!=NULL)	{
		freemsg(s->comp_buf);
		s->comp_buf=NULL;
	}
aymeric's avatar
aymeric committed
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
}

static void add_rfc2190_header(mblk_t **packet, AVCodecContext *context){
	mblk_t *header;
	header = allocb(4, 0);
	memset(header->b_wptr, 0, 4);
	// assume video size is CIF or QCIF
	if (context->width == 352 && context->height == 288) header->b_wptr[1] = 0x60;
	else header->b_wptr[1] = 0x40;
	if (context->coded_frame->pict_type != FF_I_TYPE) header->b_wptr[1] |= 0x10;
	header->b_wptr += 4;
	header->b_cont = *packet;
	*packet = header;
}

smorlat's avatar
smorlat committed
413
#if 0
aymeric's avatar
aymeric committed
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
static int get_gbsc(uint8_t *psc, uint8_t *end)
{
	int len = end-psc;
	uint32_t buf;
	int i, j, k;
	k = len;
	for (i = 2; i < len-4; i++) {
		buf = *((uint32_t *)(psc+i));
		for (j = 0; j < 8; j++) {
			if (((buf >> j) & 0x00FCFFFF) == 0x00800000) {/*PSC*/
				i += 2;
				k=i;
				break;
			} else if (((buf >> j) & 0x0080FFFF) == 0x00800000) {/*GBSC*/
				i += 2;
				k = i;
				break;
			}
		}
	}
	return k;
}
smorlat's avatar
smorlat committed
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
#else
static int get_gbsc_bytealigned(uint8_t *begin, uint8_t *end){
	int i;
	int len = end - begin;
	for (i = len - 2;  /*len + length of scan window*/
	   i > 2 + 2; /*length of scan window + 2 avoidance of 1st gob or psc*/
	   i--){
		if(*(begin + i) == 0 &&
		   *(begin + i+1) == 0 &&
		   (*(begin + i+2) & 0x80) == 0x80){
		  /*ms_message("JV psc/gob found! %2x %2x %2x", *(begin + i), *(begin + i+1), *(begin + i + 2));*/
		  return i;
		}
	}
	/*ms_message("JV no psc or gob found!");*/
	return len;
}
#endif
aymeric's avatar
aymeric committed
454 455 456

static void rfc2190_generate_packets(MSFilter *f, EncState *s, mblk_t *frame, uint32_t timestamp){
	mblk_t *packet=NULL;
457

aymeric's avatar
aymeric committed
458 459
	while (frame->b_rptr<frame->b_wptr){
		packet=dupb(frame);
smorlat's avatar
smorlat committed
460 461 462
		/*frame->b_rptr=packet->b_wptr=packet->b_rptr+get_gbsc(packet->b_rptr, MIN(packet->b_rptr+s->mtu,frame->b_wptr));*/
		frame->b_rptr = packet->b_wptr =
			packet->b_rptr + get_gbsc_bytealigned(packet->b_rptr, MIN(packet->b_rptr+s->mtu,frame->b_wptr));
aymeric's avatar
aymeric committed
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
		add_rfc2190_header(&packet, &s->av_context);
		mblk_set_timestamp_info(packet,timestamp);
		ms_queue_put(f->outputs[0],packet);
	}
	/* the marker bit is set on the last packet, if any.*/
	mblk_set_marker_info(packet,TRUE);
}

static void mpeg4_fragment_and_send(MSFilter *f,EncState *s,mblk_t *frame, uint32_t timestamp){
	uint8_t *rptr;
	mblk_t *packet=NULL;
	int len;
	for (rptr=frame->b_rptr;rptr<frame->b_wptr;){
		len=MIN(s->mtu,(frame->b_wptr-rptr));
		packet=dupb(frame);
		packet->b_rptr=rptr;
		packet->b_wptr=rptr+len;
		mblk_set_timestamp_info(packet,timestamp);
		ms_queue_put(f->outputs[0],packet);
		rptr+=len;
	}
	/*set marker bit on last packet*/
	mblk_set_marker_info(packet,TRUE);
}

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){
	mblk_t *packet;
	int len=end-psc;
491 492

	packet=dupb(frame);
aymeric's avatar
aymeric committed
493 494 495 496 497 498
	packet->b_rptr=psc;
	packet->b_wptr=end;
	/*ms_message("generating packet of size %i",end-psc);*/
	rfc2429_set_P(psc,1);
	mblk_set_timestamp_info(packet,timestamp);

499

aymeric's avatar
aymeric committed
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
	if (len>s->mtu){
		/*need to slit the packet using "follow-on" packets */
		/*compute the number of packets need (rounded up)*/
		int num=(len+s->mtu-1)/s->mtu;
		int i;
		uint8_t *pos;
		/*adjust the first packet generated*/
		pos=packet->b_wptr=packet->b_rptr+s->mtu;
		ms_queue_put(f->outputs[0],packet);
		ms_debug("generating %i follow-on packets",num);
		for (i=1;i<num;++i){
			mblk_t *header;
			packet=dupb(frame);
			packet->b_rptr=pos;
			pos=packet->b_wptr=MIN(pos+s->mtu,end);
			header=allocb(2,0);
			header->b_wptr[0]=0;
			header->b_wptr[1]=0;
			header->b_wptr+=2;
			/*no P bit is set */
			header->b_cont=packet;
			packet=header;
			mblk_set_timestamp_info(packet,timestamp);
			ms_queue_put(f->outputs[0],packet);
		}
	}else ms_queue_put(f->outputs[0],packet);
	/* the marker bit is set on the last packet, if any.*/
	mblk_set_marker_info(packet,last_packet);
}

/* returns the last psc position just below packet_size */
static uint8_t *get_psc(uint8_t *begin,uint8_t *end, int packet_size){
	int i;
	uint8_t *ret=NULL;
	uint8_t *p;
	if (begin==end) return NULL;
	for(i=1,p=begin+1;p<end && i<packet_size;++i,++p){
		if (p[-1]==0 && p[0]==0){
			ret=p-1;
		}
		p++;/* to skip possible 0 after the PSC that would make a double detection */
	}
	return ret;
}

545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602

struct jpeghdr {
	//unsigned int tspec:8;   /* type-specific field */
	unsigned int off:32;    /* fragment byte offset */
	uint8_t type;            /* id of jpeg decoder params */
	uint8_t q;               /* quantization factor (or table id) */
	uint8_t width;           /* frame width in 8 pixel blocks */
	uint8_t height;          /* frame height in 8 pixel blocks */
};

struct jpeghdr_rst {
	uint16_t dri;
	unsigned int f:1;
	unsigned int l:1;
	unsigned int count:14;
};

struct jpeghdr_qtable {
	uint8_t  mbz;
	uint8_t  precision;
	uint16_t length;
};

#define RTP_JPEG_RESTART           0x40

/* Procedure SendFrame:
 *
 *  Arguments:
 *    start_seq: The sequence number for the first packet of the current
 *               frame.
 *    ts: RTP timestamp for the current frame
 *    ssrc: RTP SSRC value
 *    jpeg_data: Huffman encoded JPEG scan data
 *    len: Length of the JPEG scan data
 *    type: The value the RTP/JPEG type field should be set to
 *    typespec: The value the RTP/JPEG type-specific field should be set
 *              to
 *    width: The width in pixels of the JPEG image
 *    height: The height in pixels of the JPEG image
 *    dri: The number of MCUs between restart markers (or 0 if there
 *         are no restart markers in the data
 *    q: The Q factor of the data, to be specified using the Independent
 *       JPEG group's algorithm if 1 <= q <= 99, specified explicitly
 *       with lqt and cqt if q >= 128, or undefined otherwise.
 *    lqt: The quantization table for the luminance channel if q >= 128
 *    cqt: The quantization table for the chrominance channels if
 *         q >= 128
 *
 *  Return value:
 *    the sequence number to be sent for the first packet of the next
 *    frame.
 *
 * The following are assumed to be defined:
 *
 * PACKET_SIZE                         - The size of the outgoing packet
 * send_packet(u_int8 *data, int len)  - Sends the packet to the network
 */

603
static void mjpeg_fragment_and_send(MSFilter *f,EncState *s,mblk_t *frame, uint32_t timestamp,
604 605 606 607 608 609 610
							 uint8_t type,	uint8_t typespec, int dri,
							 uint8_t q, mblk_t *lqt, mblk_t *cqt) {
	struct jpeghdr jpghdr;
	struct jpeghdr_rst rsthdr;
	struct jpeghdr_qtable qtblhdr;
	int bytes_left = msgdsize(frame);
	int data_len;
611

612
	mblk_t *packet;
613

614 615 616 617 618 619
	/* Initialize JPEG header
	 */
	//jpghdr.tspec = typespec;
	jpghdr.off = 0;
	jpghdr.type = type | ((dri != 0) ? RTP_JPEG_RESTART : 0);
	jpghdr.q = q;
620 621
	jpghdr.width = s->vconf.vsize.width / 8;
	jpghdr.height = s->vconf.vsize.height / 8;
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671

	/* Initialize DRI header
	 */
	if (dri != 0) {
		rsthdr.dri = htons(dri);
		rsthdr.f = 1;        /* This code does not align RIs */
		rsthdr.l = 1;
		rsthdr.count = 0x3fff;
	}

	/* Initialize quantization table header
	 */
	if (q >= 128) {
		qtblhdr.mbz = 0;
		qtblhdr.precision = 0; /* This code uses 8 bit tables only */
		qtblhdr.length = htons(msgdsize(lqt)+msgdsize(cqt));  /* 2 64-byte tables */
	}

	while (bytes_left > 0) {
		packet = allocb(s->mtu, 0);

		jpghdr.off = htonl(jpghdr.off);
		memcpy(packet->b_wptr, &jpghdr, sizeof(jpghdr));
		jpghdr.off = ntohl(jpghdr.off);
		packet->b_wptr += sizeof(jpghdr);

		if (dri != 0) {
			memcpy(packet->b_wptr, &rsthdr, sizeof(rsthdr));
			packet->b_wptr += sizeof(rsthdr);
		}

		if (q >= 128 && jpghdr.off == 0) {
			memcpy(packet->b_wptr, &qtblhdr, sizeof(qtblhdr));
			packet->b_wptr += sizeof(qtblhdr);
			if (msgdsize(lqt)){
				memcpy(packet->b_wptr, lqt->b_rptr, msgdsize(lqt));
				packet->b_wptr += msgdsize(lqt);
			}
			if (msgdsize(cqt)){
				memcpy(packet->b_wptr, cqt->b_rptr, msgdsize(cqt));
				packet->b_wptr += msgdsize(cqt);
			}
		}

		data_len = s->mtu - (packet->b_wptr - packet->b_rptr);
		if (data_len >= bytes_left) {
			data_len = bytes_left;
			mblk_set_marker_info(packet,TRUE);
		}

672
		memcpy(packet->b_wptr, frame->b_rptr + jpghdr.off, data_len);
673
		packet->b_wptr=packet->b_wptr + data_len;
674

675 676 677 678 679 680 681 682 683 684
		mblk_set_timestamp_info(packet,timestamp);
		ms_queue_put(f->outputs[0],packet);

		jpghdr.off += data_len;
		bytes_left -= data_len;
	}
}

static int find_marker(uint8_t **pbuf_ptr, uint8_t *buf_end){

685 686 687 688 689 690 691 692 693 694 695 696 697 698 699
	uint8_t *buf_ptr;
	unsigned int v, v2;
	int val;

	buf_ptr = *pbuf_ptr;
	while (buf_ptr < buf_end) {
		v = *buf_ptr++;
		v2 = *buf_ptr;
		if ((v == 0xff) && (v2 >= 0xc0) && (v2 <= 0xfe) && buf_ptr < buf_end) {
			val = *buf_ptr++;
			*pbuf_ptr = buf_ptr;
			return val;
		}
	}
	val = -1;
700 701 702
	return val;
}

703
static mblk_t *skip_jpeg_headers(mblk_t *full_frame, mblk_t **lqt, mblk_t **cqt){
704 705
	int err;
	uint8_t *pbuf_ptr=full_frame->b_rptr;
706
	uint8_t *buf_end=full_frame->b_wptr;
707

Simon Morlat's avatar
Simon Morlat committed
708
	ms_message("image size: %li)", (long)(buf_end-pbuf_ptr));
709 710 711 712 713 714 715

	*lqt=NULL;
	*cqt=NULL;

	err = find_marker(&pbuf_ptr, buf_end);
	while (err!=-1)
	{
Simon Morlat's avatar
Simon Morlat committed
716
		ms_message("marker found: %x (offset from beginning %li)", err, (long)(pbuf_ptr-full_frame->b_rptr));
717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747
		if (err==0xdb)
		{
			/* copy DQT table */
			int len = ntohs(*(uint16_t*)(pbuf_ptr));
			if (*lqt==NULL)
			{
				mblk_t *_lqt = allocb(len-3, 0);
				memcpy(_lqt->b_rptr, pbuf_ptr+3, len-3);
				_lqt->b_wptr += len-3;
				*lqt = _lqt;
				//*cqt = dupb(*lqt);
			}
			else
			{
				mblk_t *_cqt = allocb(len-3, 0);
				memcpy(_cqt->b_rptr, pbuf_ptr+3, len-3);
				_cqt->b_wptr += len-3;
				*cqt = _cqt;
			}
		}
		if (err==0xda)
		{
			uint16_t *bistream=(uint16_t *)pbuf_ptr;
			uint16_t len = ntohs(*bistream);
			full_frame->b_rptr = pbuf_ptr+len;
		}
		err = find_marker(&pbuf_ptr, buf_end);
	}
	return full_frame;
}

aymeric's avatar
aymeric committed
748 749 750 751
static void split_and_send(MSFilter *f, EncState *s, mblk_t *frame){
	uint8_t *lastpsc;
	uint8_t *psc;
	uint32_t timestamp=f->ticker->time*90LL;
752

753
	if (s->codec==CODEC_ID_MPEG4
754 755 756 757
#if HAVE_AVCODEC_SNOW
	|| s->codec==CODEC_ID_SNOW
#endif
	)
aymeric's avatar
aymeric committed
758 759 760 761
	{
		mpeg4_fragment_and_send(f,s,frame,timestamp);
		return;
	}
762 763 764 765 766 767 768 769 770 771 772 773 774 775
	else if (s->codec==CODEC_ID_MJPEG)
	{
		mblk_t *lqt=NULL;
		mblk_t *cqt=NULL;
		skip_jpeg_headers(frame, &lqt, &cqt);
		mjpeg_fragment_and_send(f,s,frame,timestamp,
								1, /* 420? */
								0,
								0, /* dri ?*/
								255, /* q */
								lqt,
								cqt);
		return;
	}
aymeric's avatar
aymeric committed
776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797

	ms_debug("processing frame of size %i",frame->b_wptr-frame->b_rptr);
	if (f->desc->id==MS_H263_ENC_ID){
		lastpsc=frame->b_rptr;
		while(1){
			psc=get_psc(lastpsc+2,frame->b_wptr,s->mtu);
			if (psc!=NULL){
				rfc4629_generate_follow_on_packets(f,s,frame,timestamp,lastpsc,psc,FALSE);
				lastpsc=psc;
			}else break;
		}
		/* send the end of frame */
		rfc4629_generate_follow_on_packets(f,s,frame, timestamp,lastpsc,frame->b_wptr,TRUE);
	}else if (f->desc->id==MS_H263_OLD_ENC_ID){
		rfc2190_generate_packets(f,s,frame,timestamp);
	}else{
		ms_fatal("Ca va tres mal.");
	}
}

static void process_frame(MSFilter *f, mblk_t *inm){
	EncState *s=(EncState*)f->data;
798

aymeric's avatar
aymeric committed
799
	AVCodecContext *c=&s->av_context;
800
	int error,got_packet;
aymeric's avatar
aymeric committed
801 802
	mblk_t *comp_buf=s->comp_buf;
	int comp_buf_sz=comp_buf->b_datap->db_lim-comp_buf->b_datap->db_base;
803
	YuvBuf yuv;
804 805
	struct AVPacket packet;
	memset(&packet, 0, sizeof(packet));
806

807
	ms_yuv_buf_init_from_mblk(&yuv, inm);
aymeric's avatar
aymeric committed
808
	/* convert image if necessary */
809
	av_frame_unref(s->pict);
810 811
	avpicture_fill((AVPicture*)s->pict,yuv.planes[0],c->pix_fmt,c->width,c->height);

aymeric's avatar
aymeric committed
812
	/* timestamp used by ffmpeg, unset here */
813
	s->pict->pts=AV_NOPTS_VALUE;
Ghislain MARY's avatar
Ghislain MARY committed
814 815

	if (ms_video_starter_need_i_frame (&s->starter, f->ticker->time)){
816 817 818
		/*sends an I frame at 2 seconds and 4 seconds after the beginning of the call*/
		s->req_vfu=TRUE;
	}
aymeric's avatar
aymeric committed
819
	if (s->req_vfu){
820
		s->pict->pict_type=FF_I_TYPE;
aymeric's avatar
aymeric committed
821 822 823
		s->req_vfu=FALSE;
	}
	comp_buf->b_rptr=comp_buf->b_wptr=comp_buf->b_datap->db_base;
824
#if HAVE_AVCODEC_SNOW
aymeric's avatar
aymeric committed
825 826
	if (s->codec==CODEC_ID_SNOW){
		//prepend picture size
827
		uint32_t header=((s->vconf.vsize.width&0xffff)<<16) | (s->vconf.vsize.height&0xffff);
aymeric's avatar
aymeric committed
828 829 830 831
		*(uint32_t*)comp_buf->b_wptr=htonl(header);
		comp_buf->b_wptr+=4;
		comp_buf_sz-=4;
	}
832
#endif
833 834
	packet.data=comp_buf->b_wptr;
	packet.size=comp_buf_sz;
835
	error=avcodec_encode_video2(c, &packet, s->pict, &got_packet);
836

837 838
	if (error<0) ms_warning("ms_AVencoder_process: error %i.",error);
	else if (got_packet){
839
		s->framenum++;
840
		if (s->framenum==1){
Ghislain MARY's avatar
Ghislain MARY committed
841
			ms_video_starter_first_frame(&s->starter, f->ticker->time);
842
		}
aymeric's avatar
aymeric committed
843 844 845
		if (c->coded_frame->pict_type==FF_I_TYPE){
			ms_message("Emitting I-frame");
		}
846
		comp_buf->b_wptr+=packet.size;
aymeric's avatar
aymeric committed
847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866
		split_and_send(f,s,comp_buf);
	}
	freemsg(inm);
}

static void enc_process(MSFilter *f){
	mblk_t *inm;
	EncState *s=(EncState*)f->data;
	if (s->av_context.codec==NULL) {
		ms_queue_flush(f->inputs[0]);
		return;
	}
	ms_filter_lock(f);
	while((inm=ms_queue_get(f->inputs[0]))!=0){
		process_frame(f,inm);
	}
	ms_filter_unlock(f);
}


867 868 869
static int enc_set_configuration(MSFilter *f, void *data) {
	EncState *s = (EncState *)f->data;
	const MSVideoConfiguration *vconf = (const MSVideoConfiguration *)data;
870
	if (vconf != &s->vconf) memcpy(&s->vconf, vconf, sizeof(MSVideoConfiguration));
871

872 873
	if (s->vconf.required_bitrate > s->vconf.bitrate_limit)
		s->vconf.required_bitrate = s->vconf.bitrate_limit;
874 875
	if (s->av_context.codec != NULL) {
		/* When we are processing, apply new settings immediately */
876 877 878 879 880 881
		ms_filter_lock(f);
		enc_postprocess(f);
		enc_preprocess(f);
		ms_filter_unlock(f);
		return 0;
	}
882 883 884 885

	if (vconf->extra != NULL) {
		s->qmin = *((int *)vconf->extra);
	}
886 887 888 889 890
	ms_message("Video configuration set: bitrate=%dbits/s, fps=%f, vsize=%dx%d for encoder [%p]", s->vconf.required_bitrate
																								, s->vconf.fps
																								, s->vconf.vsize.width
																								, s->vconf.vsize.height
																								, f);
891 892 893
	return 0;
}

894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910
static int enc_set_fps(MSFilter *f, void *arg){
	EncState *s=(EncState*)f->data;
	s->vconf.fps=*(float*)arg;
	enc_set_configuration(f, &s->vconf);
	return 0;
}

static int enc_get_fps(MSFilter *f, void *arg){
	EncState *s=(EncState*)f->data;
	*(float*)arg=s->vconf.fps;
	return 0;
}

static int enc_set_vsize(MSFilter *f, void *arg) {
	MSVideoConfiguration best_vconf;
	MSVideoSize *vs = (MSVideoSize *)arg;
	EncState *s=(EncState*)f->data;
911
	best_vconf = ms_video_find_best_configuration_for_size(s->vconf_list, *vs, ms_get_cpu_count());
912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934
	s->vconf.vsize = *vs;
	s->vconf.fps = best_vconf.fps;
	s->vconf.bitrate_limit = best_vconf.bitrate_limit;
	enc_set_configuration(f, &s->vconf);
	return 0;
}

static int enc_get_vsize(MSFilter *f,void *arg){
	EncState *s=(EncState*)f->data;
	*(MSVideoSize*)arg=s->vconf.vsize;
	return 0;
}

static int enc_set_mtu(MSFilter *f,void *arg){
	EncState *s=(EncState*)f->data;
	s->mtu=*(int*)arg;
	return 0;
}

static int enc_get_br(MSFilter *f, void *arg){
	EncState *s=(EncState*)f->data;
	*(int*)arg=s->vconf.required_bitrate;
	return 0;
935 936 937 938 939
}

static int enc_set_br(MSFilter *f, void *arg) {
	EncState *s = (EncState *)f->data;
	int br = *(int *)arg;
940 941 942
	if (s->av_context.codec != NULL) {
		/* Encoding is already ongoing, do not change video size, only bitrate. */
		s->vconf.required_bitrate = br;
943
		enc_set_configuration(f, &s->vconf);
944
	} else {
945
		MSVideoConfiguration best_vconf = ms_video_find_best_configuration_for_bitrate(s->vconf_list, br, ms_get_cpu_count());
946
		enc_set_configuration(f, &best_vconf);
aymeric's avatar
aymeric committed
947
	}
948 949 950 951 952 953
	return 0;
}

static int enc_get_configuration_list(MSFilter *f, void *data) {
	EncState *s = (EncState *)f->data;
	const MSVideoConfiguration **vconf_list = (const MSVideoConfiguration **)data;
954
	*vconf_list = s->vconf_list;
aymeric's avatar
aymeric committed
955 956 957 958
	return 0;
}


959 960 961 962 963 964 965 966 967 968 969 970 971 972
static MSFilterMethod methods[] = {
	{ MS_FILTER_SET_FPS,                       enc_set_fps                },
	{ MS_FILTER_GET_FPS,                       enc_get_fps                },
	{ MS_FILTER_SET_VIDEO_SIZE,                enc_set_vsize              },
	{ MS_FILTER_GET_VIDEO_SIZE,                enc_get_vsize              },
	{ MS_FILTER_ADD_FMTP,                      enc_add_fmtp               },
	{ MS_FILTER_SET_BITRATE,                   enc_set_br                 },
	{ MS_FILTER_GET_BITRATE,                   enc_get_br                 },
	{ MS_FILTER_SET_MTU,                       enc_set_mtu                },
	{ MS_FILTER_REQ_VFU,                       enc_req_vfu                },
	{ MS_VIDEO_ENCODER_REQ_VFU,                enc_req_vfu                },
	{ MS_VIDEO_ENCODER_GET_CONFIGURATION_LIST, enc_get_configuration_list },
	{ MS_VIDEO_ENCODER_SET_CONFIGURATION,      enc_set_configuration      },
	{ 0,                                       NULL                       }
aymeric's avatar
aymeric committed
973 974 975 976 977 978 979
};

#ifdef _MSC_VER

MSFilterDesc ms_h263_enc_desc={
	MS_H263_ENC_ID,
	"MSH263Enc",
980
	N_("A video H.263 encoder using ffmpeg library."),
aymeric's avatar
aymeric committed
981 982 983 984 985 986 987 988 989 990 991 992 993 994 995
	MS_FILTER_ENCODER,
	"H263-1998",
	1, /*MS_YUV420P is assumed on this input */
	1,
	enc_h263_init,
	enc_preprocess,
	enc_process,
	enc_postprocess,
	enc_uninit,
	methods
};

MSFilterDesc ms_h263_old_enc_desc={
	MS_H263_OLD_ENC_ID,
	"MSH263OldEnc",
996
	N_("A video H.263 encoder using ffmpeg library. It is compliant with old RFC2190 spec."),
aymeric's avatar
aymeric committed
997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011
	MS_FILTER_ENCODER,
	"H263",
	1, /*MS_YUV420P is assumed on this input */
	1,
	enc_h263_init,
	enc_preprocess,
	enc_process,
	enc_postprocess,
	enc_uninit,
	methods
};

MSFilterDesc ms_mpeg4_enc_desc={
	MS_MPEG4_ENC_ID,
	"MSMpeg4Enc",
1012
	N_("A video MPEG4 encoder using ffmpeg library."),
aymeric's avatar
aymeric committed
1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
	MS_FILTER_ENCODER,
	"MP4V-ES",
	1, /*MS_YUV420P is assumed on this input */
	1,
	enc_mpeg4_init,
	enc_preprocess,
	enc_process,
	enc_postprocess,
	enc_uninit,
	methods
};
1024
#if HAVE_AVCODEC_SNOW
aymeric's avatar
aymeric committed
1025 1026 1027
MSFilterDesc ms_snow_enc_desc={
	MS_SNOW_ENC_ID,
	"MSSnowEnc",
1028
	N_("A video snow encoder using ffmpeg library."),
aymeric's avatar
aymeric committed
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039
	MS_FILTER_ENCODER,
	"x-snow",
	1, /*MS_YUV420P is assumed on this input */
	1,
	enc_snow_init,
	enc_preprocess,
	enc_process,
	enc_postprocess,
	enc_uninit,
	methods
};
1040
#endif
1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
MSFilterDesc ms_mjpeg_enc_desc={
	MS_JPEG_ENC_ID,
	"MSJpegEnc",
	N_("A RTP/MJPEG encoder using ffmpeg library."),
	MS_FILTER_ENCODER,
	"JPEG",
	1, /*MS_YUV420P is assumed on this input */
	1,
	enc_mjpeg_init,
	enc_preprocess,
	enc_process,
	enc_postprocess,
	enc_uninit,
	methods
};

aymeric's avatar
aymeric committed
1057 1058 1059 1060 1061
#else

MSFilterDesc ms_h263_enc_desc={
	.id=MS_H263_ENC_ID,
	.name="MSH263Enc",
1062
	.text=N_("A video H.263 encoder using ffmpeg library."),
aymeric's avatar
aymeric committed
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077
	.category=MS_FILTER_ENCODER,
	.enc_fmt="H263-1998",
	.ninputs=1, /*MS_YUV420P is assumed on this input */
	.noutputs=1,
	.init=enc_h263_init,
	.preprocess=enc_preprocess,
	.process=enc_process,
	.postprocess=enc_postprocess,
	.uninit=enc_uninit,
	.methods=methods
};

MSFilterDesc ms_h263_old_enc_desc={
	.id=MS_H263_OLD_ENC_ID,
	.name="MSH263Enc",
1078
	.text=N_("A video H.263 encoder using ffmpeg library, compliant with old RFC2190 spec."),
aymeric's avatar
aymeric committed
1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093
	.category=MS_FILTER_ENCODER,
	.enc_fmt="H263",
	.ninputs=1, /*MS_YUV420P is assumed on this input */
	.noutputs=1,
	.init=enc_h263_init,
	.preprocess=enc_preprocess,
	.process=enc_process,
	.postprocess=enc_postprocess,
	.uninit=enc_uninit,
	.methods=methods
};

MSFilterDesc ms_mpeg4_enc_desc={
	.id=MS_MPEG4_ENC_ID,
	.name="MSMpeg4Enc",
1094
	.text=N_("A video MPEG4 encoder using ffmpeg library."),
aymeric's avatar
aymeric committed
1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
	.category=MS_FILTER_ENCODER,
	.enc_fmt="MP4V-ES",
	.ninputs=1, /*MS_YUV420P is assumed on this input */
	.noutputs=1,
	.init=enc_mpeg4_init,
	.preprocess=enc_preprocess,
	.process=enc_process,
	.postprocess=enc_postprocess,
	.uninit=enc_uninit,
	.methods=methods
};
1106
#if HAVE_AVCODEC_SNOW
aymeric's avatar
aymeric committed
1107 1108 1109
MSFilterDesc ms_snow_enc_desc={
	.id=MS_SNOW_ENC_ID,
	.name="MSSnowEnc",
1110
	.text=N_("The snow codec is royalty-free and is open-source. \n"
1111
		"It uses innovative techniques that makes it one of most promising video "
aymeric's avatar
aymeric committed
1112
		"codec. It is implemented within the ffmpeg project.\n"
1113
		"However it is under development, quite unstable and compatibility with other versions "
1114
		"cannot be guaranteed."),
aymeric's avatar
aymeric committed
1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125
	.category=MS_FILTER_ENCODER,
	.enc_fmt="x-snow",
	.ninputs=1, /*MS_YUV420P is assumed on this input */
	.noutputs=1,
	.init=enc_snow_init,
	.preprocess=enc_preprocess,
	.process=enc_process,
	.postprocess=enc_postprocess,
	.uninit=enc_uninit,
	.methods=methods
};
1126
#endif
1127
MSFilterDesc ms_mjpeg_enc_desc={
1128
	.id=MS_JPEG_ENC_ID,
1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142
	.name="MSMJpegEnc",
	.text=N_("A MJPEG encoder using ffmpeg library."),
	.category=MS_FILTER_ENCODER,
	.enc_fmt="JPEG",
	.ninputs=1, /*MS_YUV420P is assumed on this input */
	.noutputs=1,
	.init=enc_mjpeg_init,
	.preprocess=enc_preprocess,
	.process=enc_process,
	.postprocess=enc_postprocess,
	.uninit=enc_uninit,
	.methods=methods
};

aymeric's avatar
aymeric committed
1143 1144
#endif

Simon Morlat's avatar
Simon Morlat committed
1145
void __register_ffmpeg_encoders_if_possible(MSFactory *obj){
1146 1147
	ms_ffmpeg_check_init();
	if (avcodec_find_encoder(CODEC_ID_MPEG4))
Simon Morlat's avatar
Simon Morlat committed
1148
		ms_factory_register_filter(obj,&ms_mpeg4_enc_desc);
1149
	if (avcodec_find_encoder(CODEC_ID_H263)){
Simon Morlat's avatar
Simon Morlat committed
1150 1151
		ms_factory_register_filter(obj,&ms_h263_enc_desc);
		ms_factory_register_filter(obj,&ms_h263_old_enc_desc);
1152
	}
1153
#if HAVE_AVCODEC_SNOW
1154
	if (avcodec_find_encoder(CODEC_ID_SNOW))
Simon Morlat's avatar
Simon Morlat committed
1155
		ms_factory_register_filter(obj,&ms_snow_enc_desc);
1156
#endif
1157 1158
	if (avcodec_find_encoder(CODEC_ID_MJPEG))
	{
Simon Morlat's avatar
Simon Morlat committed
1159
		ms_factory_register_filter(obj,&ms_mjpeg_enc_desc);
1160
	}
1161 1162
}