bitratedriver.c 13.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
mediastreamer2 library - modular sound and video processing and streaming

 * Copyright (C) 2011  Belledonne Communications, Grenoble, France

	 Author: 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.
 */

#include "mediastreamer2/bitratecontrol.h"

25
static const int max_ptime=100;
jehan's avatar
jehan committed
26
static const int min_ptime=10;
27 28

int ms_bitrate_driver_execute_action(MSBitrateDriver *obj, const MSRateControlAction *action){
29
	if (obj->desc->execute_action)
30
		return obj->desc->execute_action(obj,action);
31
	else ms_error("Driver does not implement execute_action");
32 33 34 35 36 37
	return -1;
}

MSBitrateDriver * ms_bitrate_driver_ref(MSBitrateDriver *obj){
	obj->refcnt++;
	return obj;
38 39
}

40 41 42 43 44 45 46
void ms_bitrate_driver_unref(MSBitrateDriver *obj){
	obj->refcnt--;
	if (obj->refcnt<=0){
		if (obj->desc->uninit)
			obj->desc->uninit(obj);
		ms_free(obj);
	}
47 48 49 50
}

struct _MSAudioBitrateDriver{
	MSBitrateDriver parent;
51
	RtpSession *session;
Simon Morlat's avatar
Simon Morlat committed
52
	MSFilter *encoder;
53 54 55 56
	int min_ptime;
	int nom_bitrate;
	int cur_ptime;
	int cur_bitrate;
57
	int encoder_caps;
58 59 60 61
};

typedef struct _MSAudioBitrateDriver MSAudioBitrateDriver;

jehan's avatar
jehan committed
62
static int apply_ptime(MSAudioBitrateDriver *obj,int target_ptime){
63
	char tmp[64];
Simon Morlat's avatar
Simon Morlat committed
64 65
	int result=-1;
	if (target_ptime < min_ptime || target_ptime>max_ptime) {
66
		ms_error("MSAudioBitrateDriver [%p]: cannot apply ptime value [%i] on [%p] because out of range [%i..%i]",obj,target_ptime,obj,min_ptime,max_ptime);
jehan's avatar
jehan committed
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
		return -1;
	}

	if (ms_filter_has_method(obj->encoder,MS_AUDIO_ENCODER_SET_PTIME)) {
		result = ms_filter_call_method(obj->encoder,MS_AUDIO_ENCODER_SET_PTIME,&target_ptime);
	} else {
		/*legacy*/
		snprintf(tmp,sizeof(tmp),"ptime=%i",target_ptime);
		result = ms_filter_call_method(obj->encoder,MS_FILTER_ADD_FMTP,tmp);
	}

	if (ms_filter_has_method(obj->encoder,MS_AUDIO_ENCODER_GET_PTIME)) {
		ms_filter_call_method(obj->encoder,MS_AUDIO_ENCODER_GET_PTIME,&obj->cur_ptime);
	} else {
		/*legacy*/
		if (result==0) {
			obj->cur_ptime=target_ptime;
		} /*else ptime remain unchanged*/
	}
	if (result == 0) {
87
		ms_message("MSAudioBitrateDriver [%p]: ptime is now [%i ms]",obj,obj->cur_ptime);
jehan's avatar
jehan committed
88
	} else {
89
		ms_message("MSAudioBitrateDriver [%p]: cannot move ptime from [%i ms] to [%i ms]",obj,obj->cur_ptime,target_ptime);
jehan's avatar
jehan committed
90 91
	}
	return result;
92 93
}

94 95
static int inc_ptime(MSAudioBitrateDriver *obj){
	return apply_ptime(obj,obj->cur_ptime+obj->min_ptime);
jehan's avatar
jehan committed
96 97
}

98 99
static int dec_ptime(MSAudioBitrateDriver *obj){
	return apply_ptime(obj,obj->cur_ptime-obj->min_ptime);
100 101
}

102 103 104
static int audio_bitrate_driver_execute_action(MSBitrateDriver *objbase, const MSRateControlAction *action){
	MSAudioBitrateDriver *obj=(MSAudioBitrateDriver*)objbase;
	ms_message("MSAudioBitrateDriver: executing action of type %s, value=%i",ms_rate_control_action_type_name(action->type),action->value);
Simon Morlat's avatar
Simon Morlat committed
105 106 107 108

	if (obj->nom_bitrate==0){
		ms_filter_call_method(obj->encoder,MS_FILTER_GET_BITRATE,&obj->nom_bitrate);
		if (obj->nom_bitrate==0){
109
			ms_warning("MSAudioBitrateDriver: Not doing bitrate control on audio encoder, it does not seem to support that. Controlling ptime only.");
Simon Morlat's avatar
Simon Morlat committed
110
			obj->nom_bitrate=-1;
111
		}else
112
			obj->cur_bitrate=obj->nom_bitrate;
Simon Morlat's avatar
Simon Morlat committed
113
	}
jehan's avatar
jehan committed
114
	if (obj->cur_ptime==0 || ms_filter_has_method(obj->encoder,MS_AUDIO_ENCODER_GET_PTIME)){ /*always sync current ptime if possible*/
115 116 117 118 119 120
		ms_filter_call_method(obj->encoder,MS_AUDIO_ENCODER_GET_PTIME,&obj->cur_ptime);
		if (obj->cur_ptime==0){
			ms_warning("MSAudioBitrateDriver: encoder %s does not implement MS_AUDIO_ENCODER_GET_PTIME. Consider to implement this method for better accuracy of rate control.",obj->encoder->desc->name);
			obj->cur_ptime=obj->min_ptime;
		}
	}
Simon Morlat's avatar
Simon Morlat committed
121

122
	if (action->type==MSRateControlActionDecreaseBitrate){
123
		
Simon Morlat's avatar
Simon Morlat committed
124
		/*reducing bitrate of the codec isn't sufficient. Increasing ptime is much more efficient*/
125
		if ((obj->encoder_caps & MS_AUDIO_ENCODER_CAP_AUTO_PTIME) || inc_ptime(obj)){
126 127 128 129 130
			if (obj->nom_bitrate>0){
				int cur_br=0;
				int new_br;

				/*if max ptime is reached, then try to reduce the codec bitrate if possible */
131

132 133 134 135
				if (ms_filter_call_method(obj->encoder,MS_FILTER_GET_BITRATE,&cur_br)!=0){
					ms_message("MSAudioBitrateDriver: GET_BITRATE failed");
					return 0;
				}
136
				obj->cur_bitrate=cur_br;
137
				new_br=cur_br-((cur_br*action->value)/100);
138 139

				ms_message("MSAudioBitrateDriver: Attempting to reduce audio bitrate from %i to %i",cur_br,new_br);
140 141
				if (ms_filter_call_method(obj->encoder,MS_FILTER_SET_BITRATE,&new_br)!=0){
					ms_message("MSAudioBitrateDriver: SET_BITRATE failed, incrementing ptime");
142
					return inc_ptime(obj);
143 144
				} else {
					rtp_session_set_target_upload_bandwidth(obj->session, new_br);
145 146 147 148 149
				}
				new_br=0;
				ms_filter_call_method(obj->encoder,MS_FILTER_GET_BITRATE,&new_br);
				ms_message("MSAudioBitrateDriver: bitrate actually set to %i",new_br);
				obj->cur_bitrate=new_br;
Simon Morlat's avatar
Simon Morlat committed
150
			}
151 152
		}
	}else if (action->type==MSRateControlActionDecreasePacketRate){
153
		return inc_ptime(obj);
154
	}else if (action->type==MSRateControlActionIncreaseQuality){
155
		int ret=0;
156 157 158 159
		if (!(obj->encoder_caps & MS_AUDIO_ENCODER_CAP_AUTO_PTIME)){
			if (obj->cur_ptime>obj->min_ptime){
				ret=dec_ptime(obj);
			}
160
		}
161
		if (obj->nom_bitrate>0){
162 163 164 165 166 167 168 169 170 171 172 173 174 175
			int cur_bitrate=0;
			if (ms_filter_call_method(obj->encoder,MS_FILTER_GET_BITRATE,&cur_bitrate)==0){
				if (cur_bitrate > 0  && cur_bitrate<obj->nom_bitrate){
					obj->cur_bitrate=(obj->cur_bitrate*140)/100;
					if (obj->cur_bitrate>= obj->nom_bitrate) {
						obj->cur_bitrate=obj->nom_bitrate;
						ret=-1;/*we reached the nominal value*/
					}
					ms_message("MSAudioBitrateDriver: increasing bitrate of codec to %i",obj->cur_bitrate);
					if (ms_filter_call_method(obj->encoder,MS_FILTER_SET_BITRATE,&obj->cur_bitrate)!=0){
						ms_message("MSAudioBitrateDriver: could not set codec bitrate to %i",obj->cur_bitrate);
					}else {
						rtp_session_set_target_upload_bandwidth(obj->session, obj->cur_bitrate);
					}
176
				}
177 178
			}else ms_warning("MSAudioBitrateDriver: MS_FILTER_GET_BITRATE failed.");
		}
179
		return ret;
180 181 182 183 184 185
	}
	return 0;
}

static void audio_bitrate_driver_uninit(MSBitrateDriver *objbase){
	//MSAudioBitrateDriver *obj=(MSBitrateDriver*)objbase;
186

187 188 189 190 191 192 193 194
}

static MSBitrateDriverDesc audio_bitrate_driver={
	audio_bitrate_driver_execute_action,
	audio_bitrate_driver_uninit
};


195
MSBitrateDriver *ms_audio_bitrate_driver_new(RtpSession *session, MSFilter *encoder){
196
	MSAudioBitrateDriver *obj=ms_new0(MSAudioBitrateDriver,1);
197
	obj->parent.desc=&audio_bitrate_driver;
198
	obj->session = session;
199
	obj->encoder=encoder;
200 201
	obj->min_ptime=20;
	obj->cur_ptime=0;
202
	obj->cur_bitrate=obj->nom_bitrate=0;
203 204
	if (ms_filter_has_method(obj->encoder, MS_AUDIO_ENCODER_GET_CAPABILITIES))
			ms_filter_call_method(obj->encoder, MS_AUDIO_ENCODER_GET_CAPABILITIES, &obj->encoder_caps);
205
	return (MSBitrateDriver*)obj;
206
}
207 208 209 210 211 212

static const int min_video_bitrate=64000;

typedef struct _MSAVBitrateDriver{
	MSBitrateDriver parent;
	MSBitrateDriver *audio_driver;
213
	RtpSession *vsession;
214 215 216 217 218 219 220
	MSFilter *venc;
	int nom_bitrate;
	int cur_bitrate;
}MSAVBitrateDriver;

static int dec_video_bitrate(MSAVBitrateDriver *obj, const MSRateControlAction *action){
	int new_br;
221

222
	ms_filter_call_method(obj->venc,MS_FILTER_GET_BITRATE,&obj->cur_bitrate);
223
	new_br=(int)(((float)obj->cur_bitrate)*(100.0f-(float)action->value)/100.0f);
224 225 226 227
	if (new_br<min_video_bitrate){
		ms_message("MSAVBitrateDriver: reaching low bound.");
		new_br=min_video_bitrate;
	}
228 229 230 231 232 233
	if (new_br!=obj->cur_bitrate){
		ms_message("MSAVBitrateDriver: targeting %i bps for video encoder.",new_br);
		ms_filter_call_method(obj->venc,MS_FILTER_SET_BITRATE,&new_br);
		rtp_session_set_target_upload_bandwidth(obj->vsession, new_br);
		obj->cur_bitrate=new_br;
	}
234 235 236 237 238 239
	return new_br==min_video_bitrate ? -1 : 0;
}

static int inc_video_bitrate(MSAVBitrateDriver *obj, const MSRateControlAction *action){
	int newbr;
	int ret=0;
240

241
	if (obj->cur_bitrate==0) return -1; /*current  bitrate was not known*/
242
	newbr=(int)((float)obj->cur_bitrate*(1.0f+((float)action->value/100.0f)));
243 244 245 246
	if (newbr>obj->nom_bitrate){
		newbr=obj->nom_bitrate;
		ret=-1;
	}
247 248 249 250 251 252
	if (newbr!=obj->cur_bitrate){
		obj->cur_bitrate=newbr;
		ms_message("MSAVBitrateDriver: increasing bitrate to %i bps for video encoder.",obj->cur_bitrate);
		ms_filter_call_method(obj->venc,MS_FILTER_SET_BITRATE,&obj->cur_bitrate);
		rtp_session_set_target_upload_bandwidth(obj->vsession, obj->cur_bitrate);
	}
253
	return ret;
254 255 256 257 258
}

static int av_driver_execute_action(MSBitrateDriver *objbase, const MSRateControlAction *action){
	MSAVBitrateDriver *obj=(MSAVBitrateDriver*)objbase;
	int ret=0;
259 260 261 262 263 264 265
	if (obj->nom_bitrate==0){
		ms_filter_call_method(obj->venc,MS_FILTER_GET_BITRATE,&obj->nom_bitrate);
		if (obj->nom_bitrate==0){
			ms_warning("MSAVBitrateDriver: Not doing adaptive rate control on video encoder, it does not seem to support that.");
			return -1;
		}
	}
266

267 268 269 270 271 272 273 274 275 276
	switch(action->type){
		case MSRateControlActionDecreaseBitrate:
			ret=dec_video_bitrate(obj,action);
		break;
		case MSRateControlActionDecreasePacketRate:
			if (obj->audio_driver){
				ret=ms_bitrate_driver_execute_action(obj->audio_driver,action);
			}
		break;
		case MSRateControlActionIncreaseQuality:
277
			ret=inc_video_bitrate(obj,action);
278 279 280 281 282 283 284 285 286 287 288
		break;
		case MSRateControlActionDoNothing:
		break;
	}
	return ret;
}

static void av_bitrate_driver_uninit(MSBitrateDriver *objbase){
	MSAVBitrateDriver *obj=(MSAVBitrateDriver*)objbase;
	if (obj->audio_driver)
		ms_bitrate_driver_unref(obj->audio_driver);
289

290 291 292 293 294 295 296
}

static MSBitrateDriverDesc av_bitrate_driver={
	av_driver_execute_action,
	av_bitrate_driver_uninit
};

297
MSBitrateDriver *ms_av_bitrate_driver_new(RtpSession *asession, MSFilter *aenc, RtpSession *vsession, MSFilter *venc){
298 299
	MSAVBitrateDriver *obj=ms_new0(MSAVBitrateDriver,1);
	obj->parent.desc=&av_bitrate_driver;
300 301
	obj->audio_driver=((asession != NULL) && (aenc!=NULL)) ? ms_bitrate_driver_ref(ms_audio_bitrate_driver_new(asession, aenc)) : NULL;
	obj->vsession = vsession;
302
	obj->venc=venc;
303

304 305 306 307
	return (MSBitrateDriver*)obj;
}


308 309 310 311 312 313 314 315 316 317 318

typedef struct _MSBandwidthBitrateDriver{
	MSBitrateDriver parent;
	MSBitrateDriver *audio_driver;
	RtpSession *vsession;
	MSFilter *venc;
	int nom_bitrate;
	int cur_bitrate;
}MSBandwidthBitrateDriver;

static int bandwidth_change_ptime(MSAudioBitrateDriver *obj, int percent){
319
	return apply_ptime(obj,(int)(obj->min_ptime + (max_ptime - obj->min_ptime) * percent / 100.f));
320 321
}

322
static int bandwidth_change_video_bitrate(MSBandwidthBitrateDriver *obj, const MSRateControlAction *action){
323
	int newbr;
324
	int oldbr;
325
	int ret=0;
326 327
	bool_t decrease = (action->type == MSRateControlActionDecreaseBitrate);
	int bound= (decrease) ? min_video_bitrate : obj->nom_bitrate;
328 329 330 331 332 333

	ms_filter_call_method(obj->venc,MS_FILTER_GET_BITRATE,&obj->cur_bitrate);
	if (obj->cur_bitrate==0){
		ms_message("MSBandwidthBitrateDriver: current bitrate was not known.");
		return -1; /*current  bitrate was not known*/
	}
334
	newbr = (int)((float)obj->cur_bitrate*(100.0f+(decrease?-1:1)*(float)action->value)/100.0f);
335 336 337
	if ((decrease&&newbr<bound) || (!decrease&&newbr>bound)){
		if (obj->cur_bitrate==bound){
			ms_message("MSBandwidthBitrateDriver: bitrate already reached %s limit %d b/s.", (decrease)?"min":"max",bound);
338 339
			return -1;
		}
340
		newbr=bound;
341
	}
342
	oldbr=obj->cur_bitrate;
343
	obj->cur_bitrate=newbr;
Gautier Pelloux-Prayer's avatar
Gautier Pelloux-Prayer committed
344
	rtp_session_set_target_upload_bandwidth(obj->vsession, obj->cur_bitrate);
345
	ms_filter_call_method(obj->venc,MS_FILTER_SET_BITRATE,&obj->cur_bitrate);
346 347 348
	ms_filter_call_method(obj->venc,MS_FILTER_GET_BITRATE,&newbr);

	ms_message("MSBandwidthBitrateDriver: changing bitrate from %i to %i bps for video encoder.",oldbr,newbr);
349 350 351 352 353 354
	return ret;
}

static int bandwidth_driver_execute_action(MSBitrateDriver *objbase, const MSRateControlAction *action){
	MSBandwidthBitrateDriver *obj=(MSBandwidthBitrateDriver*)objbase;
	int ret=0;
355
	if (obj->nom_bitrate==0&&obj->venc){
356 357 358 359 360 361 362
		ms_filter_call_method(obj->venc,MS_FILTER_GET_BITRATE,&obj->nom_bitrate);
		if (obj->nom_bitrate==0){
			ms_warning("MSBandwidthBitrateDriver: Not doing adaptive rate control on video encoder, it does not seem to support that.");
			return -1;
		}
	}

363 364 365
	if (!obj->venc){
		ret=1;
	}
366 367
	switch(action->type){
		case MSRateControlActionDecreaseBitrate:
368
			if (obj->venc){
369
				ret=bandwidth_change_video_bitrate(obj,action);
370
			}
371 372 373
			if (ret!=0 && obj->audio_driver){
				ret=ms_bitrate_driver_execute_action(obj->audio_driver,action);
			}
374 375 376 377 378
		break;
		case MSRateControlActionDecreasePacketRate:
			if (obj->audio_driver){
				ret=bandwidth_change_ptime((MSAudioBitrateDriver*) obj->audio_driver, 100);
			}else{
379
				ret=1;
380 381 382
			}
		break;
		case MSRateControlActionIncreaseQuality:
383
			if (obj->venc){
384
				ret=bandwidth_change_video_bitrate(obj,action);
385
			}
386 387
			if (ret!=0 && obj->audio_driver){
				ret=ms_bitrate_driver_execute_action(obj->audio_driver,action);
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
			}
		break;
		case MSRateControlActionDoNothing:
		break;
	}
	ms_message("MSBandwidthBitrateDriver: Action %s %s", ms_rate_control_action_type_name(action->type), ret == 0 ? "succeeded" : "failed");
	return ret;
}

static void bandwidth_bitrate_driver_uninit(MSBitrateDriver *objbase){
}

static MSBitrateDriverDesc bandwidth_bitrate_driver={
	bandwidth_driver_execute_action,
	bandwidth_bitrate_driver_uninit
};

MSBitrateDriver *ms_bandwidth_bitrate_driver_new(RtpSession *asession, MSFilter *aenc, RtpSession *vsession, MSFilter *venc){
	MSBandwidthBitrateDriver *obj=ms_new0(MSBandwidthBitrateDriver,1);
	obj->parent.desc=&bandwidth_bitrate_driver;
	obj->vsession = vsession;
	obj->audio_driver=(aenc!=NULL) ? ms_bitrate_driver_ref(ms_audio_bitrate_driver_new(asession,aenc)) : NULL;
	obj->venc=venc;

	return (MSBitrateDriver*)obj;
}