Commit 05360396 authored by Ghislain MARY's avatar Ghislain MARY
Browse files

Add API to get list of video encoder configurations and to set the video...

Add API to get list of video encoder configurations and to set the video encoder configuration to use.
parent c2fd01b7
......@@ -196,6 +196,10 @@ typedef enum _MSRecorderState MSRecorderState;
/* request a video-fast-update (=I frame for H263,MP4V-ES) to a video encoder*/
#define MS_VIDEO_ENCODER_REQ_VFU \
MS_FILTER_METHOD_NO_ARG(MSFilterVideoEncoderInterface, 1)
#define MS_VIDEO_ENCODER_GET_CONFIGURATION_LIST \
MS_FILTER_METHOD(MSFilterVideoEncoderInterface, 2, const MSVideoConfiguration **)
#define MS_VIDEO_ENCODER_SET_CONFIGURATION \
MS_FILTER_METHOD(MSFilterVideoEncoderInterface, 3, const MSVideoConfiguration *)
/** Interface definitions for audio capture */
/* Start numbering from the end for hacks */
......
......@@ -136,6 +136,23 @@ typedef struct MSRect{
int x,y,w,h;
} MSRect;
/**
* Structure describing a video configuration to be able to define a video size, a FPS
* and some other parameters according to the desired bitrate.
*/
struct _MSVideoConfiguration {
int bitrate; /**< The minimum bitrate required for the video configuration to be used. */
MSVideoSize vsize; /**< The video size that is used when using this video configuration. */
float fps; /**< The FPS that is used when using this video configuration. */
void *extra; /**< A pointer to some extra parameters that may be used by the encoder when using this video configuration. */
};
/**
* Definition of the MSVideoConfiguration type.
* @see struct _MSVideoConfiguration
*/
typedef struct _MSVideoConfiguration MSVideoConfiguration;
#define MS_VIDEO_SIZE_UNKNOWN (MSVideoSize){ MS_VIDEO_SIZE_UNKNOWN_W, MS_VIDEO_SIZE_UNKNOWN_H }
#define MS_VIDEO_SIZE_CIF (MSVideoSize){MS_VIDEO_SIZE_CIF_W,MS_VIDEO_SIZE_CIF_H}
......
......@@ -37,8 +37,64 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define RATE_CONTROL_MARGIN 15000 /*bits/second*/
#define MS_VIDEOENC_CONF(bitrate, resolution, fps, qminvalue) \
{ bitrate, MS_VIDEO_SIZE_ ## resolution, fps, (void *)&qmin ## qminvalue }
static bool_t avcodec_initialized=FALSE;
static const int qmin2 = 2;
static const int qmin3 = 3;
static const int qmin4 = 4;
static const int qmin5 = 5;
static const MSVideoConfiguration h263_conf_list[] = {
MS_VIDEOENC_CONF(1024000, SVGA, 25, 2),
MS_VIDEOENC_CONF( 800000, VGA, 25, 2),
MS_VIDEOENC_CONF( 512000, CIF, 25, 2),
MS_VIDEOENC_CONF( 256000, CIF, 17, 3),
MS_VIDEOENC_CONF( 128000, QCIF, 10, 3),
MS_VIDEOENC_CONF( 0, QCIF, 5, 5)
};
static const MSVideoConfiguration h263p_conf_list[] = {
MS_VIDEOENC_CONF(800000, 4CIF, 25, 2),
MS_VIDEOENC_CONF(512000, CIF, 25, 2),
MS_VIDEOENC_CONF(256000, CIF, 17, 3),
MS_VIDEOENC_CONF(128000, QCIF, 10, 3),
MS_VIDEOENC_CONF( 0, QCIF, 5, 5)
};
static const MSVideoConfiguration mjpeg_conf_list[] = {
MS_VIDEOENC_CONF(1024000, SVGA, 25, 2),
MS_VIDEOENC_CONF( 800000, VGA, 25, 2),
MS_VIDEOENC_CONF( 512000, CIF, 25, 2),
MS_VIDEOENC_CONF( 256000, CIF, 17, 3),
MS_VIDEOENC_CONF( 170000, QVGA, 15, 3),
MS_VIDEOENC_CONF( 128000, QCIF, 10, 3),
MS_VIDEOENC_CONF( 0, QCIF, 5, 5)
};
static const MSVideoConfiguration mpeg4_conf_list[] = {
MS_VIDEOENC_CONF(1024000, SVGA, 25, 2),
MS_VIDEOENC_CONF( 800000, VGA, 25, 2),
MS_VIDEOENC_CONF( 512000, CIF, 25, 2),
MS_VIDEOENC_CONF( 256000, CIF, 17, 3),
MS_VIDEOENC_CONF( 170000, QVGA, 15, 3),
MS_VIDEOENC_CONF( 128000, QCIF, 10, 3),
MS_VIDEOENC_CONF( 0, QCIF, 5, 5)
};
static const MSVideoConfiguration snow_conf_list[] = {
MS_VIDEOENC_CONF(1024000, SVGA, 25, 2),
MS_VIDEOENC_CONF( 800000, VGA, 25, 2),
MS_VIDEOENC_CONF( 512000, CIF, 25, 2),
MS_VIDEOENC_CONF( 256000, CIF, 17, 3),
MS_VIDEOENC_CONF( 170000, QVGA, 15, 3),
MS_VIDEOENC_CONF( 128000, QCIF, 10, 3),
MS_VIDEOENC_CONF( 64000, QCIF, 7, 4),
MS_VIDEOENC_CONF( 0, QCIF, 5, 5)
};
#ifndef FF_I_TYPE
#define FF_I_TYPE AV_PICTURE_TYPE_I
#endif
......@@ -835,82 +891,87 @@ static int enc_get_br(MSFilter *f, void *arg){
return 0;
}
static int enc_set_br(MSFilter *f, void *arg){
EncState *s=(EncState*)f->data;
bool_t snow=s->codec==CODEC_ID_SNOW;
s->maxbr=*(int*)arg;
if (s->av_context.codec!=NULL){
/*when we are processing, apply new settings immediately*/
static int enc_set_configuration(MSFilter *f, void *data) {
EncState *s = (EncState *)f->data;
const MSVideoConfiguration *vconf = (const MSVideoConfiguration *)data;
s->maxbr = vconf->bitrate;
if (s->av_context.codec != NULL) {
/* When we are processing, apply new settings immediately */
ms_filter_lock(f);
enc_postprocess(f);
enc_preprocess(f);
ms_filter_unlock(f);
return 0;
}
if (s->maxbr>=1024000 && s->codec!=CODEC_ID_H263P){
if (s->codec!=CODEC_ID_H263P){
s->vsize.width = MS_VIDEO_SIZE_SVGA_W;
s->vsize.height = MS_VIDEO_SIZE_SVGA_H;
}else{
s->vsize.width = MS_VIDEO_SIZE_4CIF_W;
s->vsize.height = MS_VIDEO_SIZE_4CIF_H;
}
s->fps=25;
}else if (s->maxbr>=800000 ){
if (s->codec!=CODEC_ID_H263P){
s->vsize.width = MS_VIDEO_SIZE_VGA_W;
s->vsize.height = MS_VIDEO_SIZE_VGA_H;
}else{
s->vsize.width = MS_VIDEO_SIZE_4CIF_W;
s->vsize.height = MS_VIDEO_SIZE_4CIF_H;
s->vsize = vconf->vsize;
s->fps = vconf->fps;
if (vconf->extra != NULL) {
s->qmin = *((int *)vconf->extra);
}
ms_message("Video configuration set: bitrate=%dbits/s, fps=%f, vsize=%dx%d", s->maxbr, s->fps, s->vsize.width, s->vsize.height);
return 0;
}
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];
case CODEC_ID_SNOW:
return &snow_conf_list[0];
}
}
static int enc_set_br(MSFilter *f, void *arg) {
EncState *s = (EncState *)f->data;
int br = *(int *)arg;
const MSVideoConfiguration *current_vconf = get_vconf_list(s);
const MSVideoConfiguration *closer_to_best_vconf = NULL;
MSVideoConfiguration best_vconf;
while (closer_to_best_vconf == NULL) {
if ((br >= current_vconf->bitrate) || (current_vconf->bitrate == 0)) {
closer_to_best_vconf = current_vconf;
} else {
current_vconf++;
}
s->fps=25;
}else if (s->maxbr>=512000){
s->vsize.width=MS_VIDEO_SIZE_CIF_W;
s->vsize.height=MS_VIDEO_SIZE_CIF_H;
s->fps=25;
}else if (s->maxbr>=256000){
s->vsize.width=MS_VIDEO_SIZE_CIF_W;
s->vsize.height=MS_VIDEO_SIZE_CIF_H;
s->fps=17;
s->qmin=3;
}else if (s->maxbr>=170000 && s->codec!=CODEC_ID_H263P && s->codec!=CODEC_ID_H263){
s->vsize.width=MS_VIDEO_SIZE_QVGA_W;
s->vsize.height=MS_VIDEO_SIZE_QVGA_H;
s->fps=15;
s->qmin=3;
}else if (s->maxbr>=128000){
s->vsize.width=MS_VIDEO_SIZE_QCIF_W;
s->vsize.height=MS_VIDEO_SIZE_QCIF_H;
s->fps=10;
s->qmin=3;
}else if (s->maxbr>=64000){
s->vsize.width=MS_VIDEO_SIZE_QCIF_W;
s->vsize.height=MS_VIDEO_SIZE_QCIF_H;
s->fps=snow ? 7 : 5;
s->qmin=snow ? 4 : 5;
}else{
s->vsize.width=MS_VIDEO_SIZE_QCIF_W;
s->vsize.height=MS_VIDEO_SIZE_QCIF_H;
s->fps=5;
s->qmin=5;
}
memcpy(&best_vconf, closer_to_best_vconf, sizeof(best_vconf));
best_vconf.bitrate = br;
enc_set_configuration(f, &best_vconf);
return 0;
}
static int enc_get_configuration_list(MSFilter *f, void *data) {
EncState *s = (EncState *)f->data;
const MSVideoConfiguration **vconf_list = (const MSVideoConfiguration **)data;
*vconf_list = get_vconf_list(s);
return 0;
}
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 },
{ 0 , NULL }
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 }
};
#ifdef _MSC_VER
......
......@@ -38,6 +38,25 @@
#undef FRAGMENT_ON_PARTITIONS
#define MS_VP8_CONF(bitrate, resolution, fps) \
{ bitrate, MS_VIDEO_SIZE_ ## resolution, fps, NULL }
static const MSVideoConfiguration vp8_conf_list[] = {
#ifdef __arm__
MS_VP8_CONF(300000, VGA, 12),
MS_VP8_CONF( 0, QVGA, 12)
#else
MS_VP8_CONF(1024000, VGA, 25),
MS_VP8_CONF( 350000, VGA, 15),
MS_VP8_CONF( 200000, CIF, 15),
MS_VP8_CONF( 150000, QVGA, 15),
MS_VP8_CONF( 100000, QVGA, 10),
MS_VP8_CONF( 64000, QCIF, 12),
MS_VP8_CONF( 0, QCIF, 5)
#endif
};
/* the goal of this small object is to tell when to send I frames at startup:
at 2 and 4 seconds*/
typedef struct VideoStarter{
......@@ -280,59 +299,44 @@ static int enc_get_br(MSFilter *f, void*data){
return 0;
}
static int enc_set_br(MSFilter *f, void*data){
int br=*(int*)data;
EncState *s=(EncState*)f->data;
s->bitrate=br;
s->cfg.rc_target_bitrate = ((float)s->bitrate)*0.92/1024.0; //0.9=take into account IP/UDP/RTP overhead, in average.
if (s->ready){
static int enc_set_configuration(MSFilter *f, void *data) {
EncState *s = (EncState *)f->data;
const MSVideoConfiguration *vconf = (const MSVideoConfiguration *)data;
s->bitrate = vconf->bitrate;
s->cfg.rc_target_bitrate = ((float)s->bitrate) * 0.92 / 1024.0; //0.9=take into account IP/UDP/RTP overhead, in average.
if (s->ready) {
ms_filter_lock(f);
enc_postprocess(f);
enc_preprocess(f);
ms_filter_unlock(f);
return 0;
}
if (br>=1024000){
s->width = MS_VIDEO_SIZE_VGA_W;
s->height = MS_VIDEO_SIZE_VGA_H;
s->fps=25;
}else if (br>=350000){
s->width = MS_VIDEO_SIZE_VGA_W;
s->height = MS_VIDEO_SIZE_VGA_H;
s->fps=15;
} else if (br>=200000){
s->width = MS_VIDEO_SIZE_CIF_W;
s->height = MS_VIDEO_SIZE_CIF_H;
s->fps=15;
}else if (br>=150000){
s->width=MS_VIDEO_SIZE_QVGA_W;
s->height=MS_VIDEO_SIZE_QVGA_H;
s->fps=15;
}else if (br>=100000){
s->width=MS_VIDEO_SIZE_QVGA_W;
s->height=MS_VIDEO_SIZE_QVGA_H;
s->fps=10;
}else if (br>=64000){
s->width=MS_VIDEO_SIZE_QCIF_W;
s->height=MS_VIDEO_SIZE_QCIF_H;
s->fps=12;
}else{
s->width=MS_VIDEO_SIZE_QCIF_W;
s->height=MS_VIDEO_SIZE_QCIF_H;
s->fps=5;
}
#ifdef __arm__
if (br >= 300000) {
s->width = MS_VIDEO_SIZE_VGA_W;
s->height = MS_VIDEO_SIZE_VGA_H;
} else {
s->width=MS_VIDEO_SIZE_QVGA_W;
s->height=MS_VIDEO_SIZE_QVGA_H;
s->width = vconf->vsize.width;
s->height = vconf->vsize.height;
s->fps = vconf->fps;
ms_message("Video configuration set: bitrate=%dbits/s, fps=%f, vsize=%dx%d", s->bitrate, s->fps, s->width, s->height);
return 0;
}
static int enc_set_br(MSFilter *f, void*data) {
int br = *(int *)data;
const MSVideoConfiguration *current_vconf = &vp8_conf_list[0];
const MSVideoConfiguration *closer_to_best_vconf = NULL;
MSVideoConfiguration best_vconf;
while (closer_to_best_vconf == NULL) {
if ((br >= current_vconf->bitrate) || (current_vconf->bitrate == 0)) {
closer_to_best_vconf = current_vconf;
} else {
current_vconf++;
}
}
s->fps=12;
#endif
ms_message("bitrate requested...: %d (%d x %d)\n", br, s->width, s->height);
memcpy(&best_vconf, closer_to_best_vconf, sizeof(best_vconf));
best_vconf.bitrate = br;
enc_set_configuration(f, &best_vconf);
return 0;
}
......@@ -348,18 +352,27 @@ static int enc_req_vfu(MSFilter *f, void *unused){
return 0;
}
static MSFilterMethod enc_methods[]={
{ MS_FILTER_SET_VIDEO_SIZE, enc_set_vsize },
{ MS_FILTER_SET_FPS, enc_set_fps },
{ MS_FILTER_GET_VIDEO_SIZE, enc_get_vsize },
{ MS_FILTER_GET_FPS, enc_get_fps },
{ MS_FILTER_ADD_ATTR, enc_add_attr },
{ 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 },
{ 0 , NULL }
static int enc_get_configuration_list(MSFilter *f, void *data) {
const MSVideoConfiguration **vconf_list = (const MSVideoConfiguration **)data;
MS_UNUSED(f);
*vconf_list = &vp8_conf_list[0];
return 0;
}
static MSFilterMethod enc_methods[] = {
{ MS_FILTER_SET_VIDEO_SIZE, enc_set_vsize },
{ MS_FILTER_SET_FPS, enc_set_fps },
{ MS_FILTER_GET_VIDEO_SIZE, enc_get_vsize },
{ MS_FILTER_GET_FPS, enc_get_fps },
{ MS_FILTER_ADD_ATTR, enc_add_attr },
{ 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 }
};
#ifdef _MSC_VER
......
......@@ -316,6 +316,24 @@ static void configure_video_source(VideoStream *stream){
}
}
static MSVideoConfiguration find_best_video_configuration(const MSVideoConfiguration *vconf_list, int bitrate) {
const MSVideoConfiguration *current_vconf = vconf_list;
const MSVideoConfiguration *closer_to_best_vconf = NULL;
MSVideoConfiguration best_vconf;
while (closer_to_best_vconf == NULL) {
if ((bitrate >= current_vconf->bitrate) || (current_vconf->bitrate == 0)) {
closer_to_best_vconf = current_vconf;
} else {
current_vconf++;
}
}
memcpy(&best_vconf, closer_to_best_vconf, sizeof(best_vconf));
best_vconf.bitrate = bitrate;
return best_vconf;
}
int video_stream_start (VideoStream *stream, RtpProfile *profile, const char *rem_rtp_ip, int rem_rtp_port,
const char *rem_rtcp_ip, int rem_rtcp_port, int payload, int jitt_comp, MSWebCam *cam){
PayloadType *pt;
......@@ -377,8 +395,15 @@ int video_stream_start (VideoStream *stream, RtpProfile *profile, const char *re
}
if (pt->normal_bitrate>0){
MSVideoConfiguration *vconf_list = NULL;
ms_message("Limiting bitrate of video encoder to %i bits/s",pt->normal_bitrate);
ms_filter_call_method(stream->ms.encoder,MS_FILTER_SET_BITRATE,&pt->normal_bitrate);
ms_filter_call_method(stream->ms.encoder, MS_VIDEO_ENCODER_GET_CONFIGURATION_LIST, &vconf_list);
if (vconf_list != NULL) {
MSVideoConfiguration vconf = find_best_video_configuration(vconf_list, pt->normal_bitrate);
ms_filter_call_method(stream->ms.encoder, MS_VIDEO_ENCODER_SET_CONFIGURATION, &vconf);
} else {
ms_filter_call_method(stream->ms.encoder, MS_FILTER_SET_BITRATE, &pt->normal_bitrate);
}
}
if (pt->send_fmtp){
ms_filter_call_method(stream->ms.encoder,MS_FILTER_ADD_FMTP,pt->send_fmtp);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment