예제 #1
0
int tmedia_codec_video_clamp_out_size_to_range_max(tmedia_codec_video_t *self)
{
    int ret = 0;
    if (!self) {
        TSK_DEBUG_ERROR("Invalid parameter");
        return -1;
    }
    if (tmedia_defaults_get_adapt_video_size_range_enabled()) {
        tmedia_pref_video_size_t min, max;
        if ((ret = tmedia_defaults_get_pref_video_size_range(&min, &max)) == 0) {
            unsigned width, height;
            // clip(max)
            if ((ret = tmedia_video_get_size(max, &width, &height)) == 0) {
                unsigned new_width = TSK_CLAMP(0, self->out.width, width);
                unsigned new_height = TSK_CLAMP(0, self->out.height, height);
                TSK_DEBUG_INFO("Pref. video size range defined, video size clipped (%ux%u)->(%ux%u)",
                               width, height,
                               self->out.width, self->out.height);
                self->out.width = width;
                self->out.height = height;
            }
            // no clip(min) as we cannot increase the size to more than what was negotiated without sending reINVITE
        }
    }
    return ret;
}
예제 #2
0
static int tdav_codec_mp4ves_set(tmedia_codec_t* self, const tmedia_param_t* param)
{
	tdav_codec_mp4ves_t* mp4ves = (tdav_codec_mp4ves_t*)self;
	if(!self->opened){
		TSK_DEBUG_ERROR("Codec not opened");
		return -1;
	}
	if(param->value_type == tmedia_pvt_int32){
		if(tsk_striequals(param->key, "action")){
			tmedia_codec_action_t action = (tmedia_codec_action_t)TSK_TO_INT32((uint8_t*)param->value);
			switch(action){
				case tmedia_codec_action_encode_idr:
					{
						mp4ves->encoder.force_idr = tsk_true;
						break;
					}
				case tmedia_codec_action_bw_down:
					{
						mp4ves->encoder.quality = TSK_CLAMP(1, (mp4ves->encoder.quality + 1), 31);
						mp4ves->encoder.context->global_quality = FF_QP2LAMBDA * mp4ves->encoder.quality;
						break;
					}
				case tmedia_codec_action_bw_up:
					{
						mp4ves->encoder.quality = TSK_CLAMP(1, (mp4ves->encoder.quality - 1), 31);
						mp4ves->encoder.context->global_quality = FF_QP2LAMBDA * mp4ves->encoder.quality;
						break;
					}
			}
		}
		else if(tsk_striequals(param->key, "rotation")){
			int rotation = *((int32_t*)param->value);
			if(mp4ves->encoder.rotation != rotation){
				if(self->opened){
					int ret;
					mp4ves->encoder.rotation = rotation;
					if((ret = tdav_codec_mp4ves_close_encoder(mp4ves))){
						return ret;
					}
					if((ret = tdav_codec_mp4ves_open_encoder(mp4ves))){
						return ret;
					}
				}
			}
			return 0;
		}
	}
	return -1;
}
예제 #3
0
int tdav_consumer_audio_set(tdav_consumer_audio_t* self, const tmedia_param_t* param)
{
	if(!self){
		TSK_DEBUG_ERROR("Invalid parameter");
		return -1;
	}

	if(param->plugin_type == tmedia_ppt_consumer){
		if(param->value_type == tmedia_pvt_int32){
			if(tsk_striequals(param->key, "gain")){
				int32_t gain = *((int32_t*)param->value);
				if(gain<TDAV_AUDIO_GAIN_MAX && gain>=0){
					TMEDIA_CONSUMER(self)->audio.gain = (uint8_t)gain;
					TSK_DEBUG_INFO("audio consumer gain=%u", gain);
				}
				else{
					TSK_DEBUG_ERROR("%u is invalid as gain value", gain);
					return -2;
				}
			}
			else if(tsk_striequals(param->key, "volume")){
				TMEDIA_CONSUMER(self)->audio.volume = TSK_TO_INT32((uint8_t*)param->value);
				TMEDIA_CONSUMER(self)->audio.volume = TSK_CLAMP(0, TMEDIA_CONSUMER(self)->audio.volume, 100);
			}
		}
	}

	return 0;
}
예제 #4
0
static int tdav_webrtc_denoise_set(tmedia_denoise_t* _self, const tmedia_param_t* param)
{
	tdav_webrtc_denoise_t *self = (tdav_webrtc_denoise_t *)_self;
	if(!self || !param){
		TSK_DEBUG_ERROR("Invalid parameter");
		return -1;
	}
	
	if(param->value_type == tmedia_pvt_int32){
		if(tsk_striequals(param->key, "echo-tail")){
			int32_t echo_tail = *((int32_t*)param->value);
			self->echo_tail = TSK_CLAMP(WEBRTC_MIN_ECHO_TAIL, echo_tail, WEBRTC_MAX_ECHO_TAIL);
			TSK_DEBUG_INFO("set_echo_tail (%d->%d)", echo_tail, self->echo_tail);
			return 0;
		}
	}
	return -1;
}
예제 #5
0
int tmedia_codec_plugin_register_2(const tmedia_codec_plugin_def_t* plugin, int prio)
{
    tsk_size_t index = 0, max;
    tsk_bool_t already_registered = tsk_false;
    const tmedia_codec_plugin_def_t* tmp;
    if (!plugin || tsk_strnullORempty(plugin->name) || tsk_strnullORempty(plugin->format) || (prio + 1) >= TMED_CODEC_MAX_PLUGINS) {
        TSK_DEBUG_ERROR("Invalid parameter");
        return -1;
    }

    // count codecs and found if already registered
    while (__tmedia_codec_plugins[index]) {
        if (__tmedia_codec_plugins[index] == plugin) {
            already_registered = tsk_true;
        }
        ++index;
    }

    if (index >= TMED_CODEC_MAX_PLUGINS) {
        TSK_DEBUG_ERROR("No room");
        return -1;
    }

	// clamp prio (must be done here before unregistering the plugin)
	max = tmedia_codec_plugin_registered_count(__tmedia_codec_plugins, sizeof(__tmedia_codec_plugins)/sizeof(__tmedia_codec_plugins[0]));
	prio = TSK_CLAMP(0, prio, (int)(max > 0 ? (max - 1) : 0));

    // unregister and compact
    if (already_registered) {
        if (tmedia_codec_plugin_unregister(plugin) == 0) {
            --index;
        }
    }

	

    // put current plugin at prio and old (which was at prio) at the end
    tmp = __tmedia_codec_plugins[prio];
    __tmedia_codec_plugins[index] = tmp;// put old codec add prio to the end of the list
    __tmedia_codec_plugins[prio] = plugin;

    return 0;
}
예제 #6
0
// Congestion quality metrics based
int tdav_video_jb_get_qcong(tdav_video_jb_t* self, float* q)
{
    float lm;
    if (!self || !q) {
        TSK_DEBUG_ERROR("Invalid parameter");
        return -1;
    }
    lm = (float)self->latency_max;
    if (lm <= 0.f) { // must never happen...but used as a guard against div(0)
        *q = 1.f;
    }
    else {
        // when "frames_count" is > "latency_max" q is < 0 but it'll be clipped to 0.f
        *q = 1.f - (self->frames_count / lm);
    }
    // 0.0001f instead of zero which could be interpreted as "no data available"
    // 0.0001f encoded to 1-byte in RTCP-RR-JCNG will be coded as (0.0001f * 255.f) = zero
    *q = TSK_CLAMP(0.0001f, *q, 1.f);
    return 0;
}
예제 #7
0
static int tdav_webrtc_denoise_open(tmedia_denoise_t* self, uint32_t frame_size, uint32_t sampling_rate)
{
	tdav_webrtc_denoise_t *denoiser = (tdav_webrtc_denoise_t *)self;
	int ret;

	if(!denoiser){
		TSK_DEBUG_ERROR("Invalid parameter");
		return -1;
	}

	if(denoiser->AEC_inst || 
#if HAVE_SPEEX_DSP && PREFER_SPEEX_DENOISER
		denoiser->SpeexDenoiser_proc
#else
		denoiser->NS_inst
#endif
		){
		TSK_DEBUG_ERROR("Denoiser already initialized");
		return -2;
	}
	
	denoiser->echo_tail = TSK_CLAMP(WEBRTC_MIN_ECHO_TAIL, TMEDIA_DENOISE(denoiser)->echo_tail, WEBRTC_MAX_ECHO_TAIL);
	TSK_DEBUG_INFO("echo_tail=%d", denoiser->echo_tail);
	denoiser->echo_skew = TMEDIA_DENOISE(denoiser)->echo_skew;
	denoiser->frame_size = frame_size;
	denoiser->sampling_rate = sampling_rate;
	
	//
	//	AEC instance
	//
	if((ret = TDAV_WebRtcAec_Create(&denoiser->AEC_inst))){
		TSK_DEBUG_ERROR("WebRtcAec_Create failed with error code = %d", ret);
		return ret;
	}
	if((ret = TDAV_WebRtcAec_Init(denoiser->AEC_inst, denoiser->sampling_rate, denoiser->sampling_rate))){
		TSK_DEBUG_ERROR("WebRtcAec_Init failed with error code = %d", ret);
		return ret;
	}

#if WEBRTC_AEC_AGGRESSIVE
	{	
		AecConfig aecConfig;
		aecConfig.nlpMode = kAecNlpAggressive;
		aecConfig.skewMode = kAecTrue;
		aecConfig.metricsMode = kAecFalse;
		aecConfig.delay_logging = kAecFalse;

		if((ret = WebRtcAec_set_config(denoiser->AEC_inst, aecConfig))){
			TSK_DEBUG_ERROR("WebRtcAec_set_config failed with error code = %d", ret);
		}
	}
#endif
	
	//
	//	Noise Suppression instance
	//
	if(TMEDIA_DENOISE(denoiser)->noise_supp_enabled){
#if HAVE_SPEEX_DSP && PREFER_SPEEX_DENOISER
		if((denoiser->SpeexDenoiser_proc = speex_preprocess_state_init(denoiser->frame_size, denoiser->sampling_rate))){
			int i = 1;
			speex_preprocess_ctl(denoiser->SpeexDenoiser_proc, SPEEX_PREPROCESS_SET_DENOISE, &i);
			i = TMEDIA_DENOISE(denoiser)->noise_supp_level;
			speex_preprocess_ctl(denoiser->SpeexDenoiser_proc, SPEEX_PREPROCESS_SET_NOISE_SUPPRESS, &i);
		}
#else
		if((ret = TDAV_WebRtcNs_Create(&denoiser->NS_inst))){
			TSK_DEBUG_ERROR("WebRtcNs_Create failed with error code = %d", ret);
			return ret;
		}
		if((ret = TDAV_WebRtcNs_Init(denoiser->NS_inst, denoiser->sampling_rate))){
			TSK_DEBUG_ERROR("WebRtcNs_Init failed with error code = %d", ret);
			return ret;
		}
#endif
	}

	// allocate temp buffer for record processing
	if(!(denoiser->temp_rec_out = tsk_realloc(denoiser->temp_rec_out, denoiser->frame_size * kSizeOfWord16))){
		TSK_DEBUG_ERROR("Failed to allocate new buffer");
		return -3;
	}

	TSK_DEBUG_INFO("WebRTC denoiser opened");

	return ret;
}
예제 #8
0
/* ============ Internal functions ================= */
int tdav_codec_mp4ves_open_encoder(tdav_codec_mp4ves_t* self)
{
	int ret, size;
	int32_t max_bw_kpbs;
	if(!self->encoder.codec && !(self->encoder.codec = avcodec_find_encoder(CODEC_ID_MPEG4))){
		TSK_DEBUG_ERROR("Failed to find mp4v encoder");
		return -1;
	}

	if(self->encoder.context){
		TSK_DEBUG_ERROR("Encoder already opened");
		return -1;
	}
	self->encoder.context = avcodec_alloc_context();
	avcodec_get_context_defaults(self->encoder.context);
	
	self->encoder.context->pix_fmt		= PIX_FMT_YUV420P;
	self->encoder.context->time_base.num  = 1;
	self->encoder.context->time_base.den  = TMEDIA_CODEC_VIDEO(self)->in.fps;
	self->encoder.context->width = (self->encoder.rotation == 90 || self->encoder.rotation == 270) ? TMEDIA_CODEC_VIDEO(self)->out.height : TMEDIA_CODEC_VIDEO(self)->out.width;
	self->encoder.context->height = (self->encoder.rotation == 90 || self->encoder.rotation == 270) ? TMEDIA_CODEC_VIDEO(self)->out.width : TMEDIA_CODEC_VIDEO(self)->out.height;
	self->encoder.context->mb_decision = FF_MB_DECISION_RD;
	self->encoder.context->noise_reduction = 250;
	self->encoder.context->flags |= CODEC_FLAG_QSCALE;
	self->encoder.context->global_quality = FF_QP2LAMBDA * self->encoder.quality;
	
	max_bw_kpbs = TSK_CLAMP(
		0,
		tmedia_get_video_bandwidth_kbps_2(TMEDIA_CODEC_VIDEO(self)->out.width, TMEDIA_CODEC_VIDEO(self)->out.height, TMEDIA_CODEC_VIDEO(self)->out.fps), 
		self->encoder.max_bw_kpbs
	);
	self->encoder.context->bit_rate = (max_bw_kpbs * 1024);// bps
	self->encoder.context->rtp_payload_size = MP4V_RTP_PAYLOAD_SIZE;
	self->encoder.context->opaque = tsk_null;
	self->encoder.context->profile = self->profile>>4;
	self->encoder.context->level = self->profile & 0x0F;
	self->encoder.context->gop_size = (TMEDIA_CODEC_VIDEO(self)->in.fps * MP4V_GOP_SIZE_IN_SECONDS);
	self->encoder.context->max_b_frames = 0;
	self->encoder.context->b_frame_strategy = 1;
    self->encoder.context->flags |= CODEC_FLAG_AC_PRED;

	// Picture (YUV 420)
	if(!(self->encoder.picture = avcodec_alloc_frame())){
		TSK_DEBUG_ERROR("Failed to create MP4V-ES encoder picture");
		return -2;
	}
	avcodec_get_frame_defaults(self->encoder.picture);
	
	size = avpicture_get_size(PIX_FMT_YUV420P, self->encoder.context->width, self->encoder.context->height);
	if(!(self->encoder.buffer = tsk_calloc(size, sizeof(uint8_t)))){
		TSK_DEBUG_ERROR("Failed to allocate MP4V-ES encoder buffer");
		return -2;
	}
	
	// Open encoder
	if((ret = avcodec_open(self->encoder.context, self->encoder.codec)) < 0){
		TSK_DEBUG_ERROR("Failed to open MP4V-ES encoder");
		return ret;
	}

	TSK_DEBUG_INFO("[MP4V-ES] bitrate=%d bps", self->encoder.context->bit_rate);

	return ret;
}
예제 #9
0
int tdav_codec_h264_open_encoder(tdav_codec_h264_t* self)
{
#if HAVE_FFMPEG
	int ret;
	tsk_size_t size;

	if(self->encoder.context){
		TSK_DEBUG_ERROR("Encoder already opened");
		return -1;
	}
    
#if (LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51, 35, 0))
    if((self->encoder.context = avcodec_alloc_context3(self->encoder.codec))){
        avcodec_get_context_defaults3(self->encoder.context, self->encoder.codec);
    }
#else
    if((self->encoder.context = avcodec_alloc_context())){
        avcodec_get_context_defaults(self->encoder.context);
    }
#endif
    
    if(!self->encoder.context){
        TSK_DEBUG_ERROR("Failed to allocate context");
		return -1;
    }

#if TDAV_UNDER_X86 && LIBAVCODEC_VERSION_MAJOR <= 53
	self->encoder.context->dsp_mask = (FF_MM_MMX | FF_MM_MMXEXT | FF_MM_SSE);
#endif

	self->encoder.context->pix_fmt		= PIX_FMT_YUV420P;
	self->encoder.context->time_base.num  = 1;
	self->encoder.context->time_base.den  = TMEDIA_CODEC_VIDEO(self)->out.fps;
	self->encoder.context->width = (self->encoder.rotation == 90 || self->encoder.rotation == 270) ? TMEDIA_CODEC_VIDEO(self)->out.height : TMEDIA_CODEC_VIDEO(self)->out.width;
	self->encoder.context->height = (self->encoder.rotation == 90 || self->encoder.rotation == 270) ? TMEDIA_CODEC_VIDEO(self)->out.width : TMEDIA_CODEC_VIDEO(self)->out.height;
	self->encoder.max_bw_kpbs = TSK_CLAMP(
		0,
		tmedia_get_video_bandwidth_kbps_2(TMEDIA_CODEC_VIDEO(self)->out.width, TMEDIA_CODEC_VIDEO(self)->out.height, TMEDIA_CODEC_VIDEO(self)->out.fps), 
		TMEDIA_CODEC(self)->bandwidth_max_upload
	);
	self->encoder.context->bit_rate = (self->encoder.max_bw_kpbs * 1024);// bps

	self->encoder.context->rc_min_rate = (self->encoder.context->bit_rate >> 3);
	self->encoder.context->rc_max_rate = self->encoder.context->bit_rate;

#if LIBAVCODEC_VERSION_MAJOR <= 53
	self->encoder.context->rc_lookahead = 0;
#endif
	self->encoder.context->global_quality = FF_QP2LAMBDA * self->encoder.quality;
	
#if LIBAVCODEC_VERSION_MAJOR <= 53
    self->encoder.context->partitions = X264_PART_I4X4 | X264_PART_I8X8 | X264_PART_P8X8 | X264_PART_B8X8;
#endif
    self->encoder.context->me_method = ME_UMH;
	self->encoder.context->me_range = 16;
	self->encoder.context->qmin = 10;
	self->encoder.context->qmax = 51;
#if LIBAVCODEC_VERSION_MAJOR <= 53
    self->encoder.context->mb_qmin = self->encoder.context->qmin;
	self->encoder.context->mb_qmax = self->encoder.context->qmax;
#endif
	/* METROPOLIS = G2J.COM TelePresence client. Check Issue 378: No video when calling "TANDBERG/4129 (X8.1.1)" */
#if !METROPOLIS  && 0
	self->encoder.context->flags |= CODEC_FLAG_GLOBAL_HEADER;
#endif
    self->encoder.context->flags |= CODEC_FLAG_LOW_DELAY;
	if (self->encoder.context->profile == FF_PROFILE_H264_BASELINE) {
		self->encoder.context->max_b_frames = 0;
	}

	switch(TDAV_CODEC_H264_COMMON(self)->profile){
		case profile_idc_baseline:
		default:
			self->encoder.context->profile = FF_PROFILE_H264_BASELINE;
			self->encoder.context->level = TDAV_CODEC_H264_COMMON(self)->level;
			break;
		case profile_idc_main:
			self->encoder.context->profile = FF_PROFILE_H264_MAIN;
			self->encoder.context->level = TDAV_CODEC_H264_COMMON(self)->level;
			break;
	} 
	
	/* Comment from libavcodec/libx264.c:
     * Allow x264 to be instructed through AVCodecContext about the maximum
     * size of the RTP payload. For example, this enables the production of
     * payload suitable for the H.264 RTP packetization-mode 0 i.e. single
     * NAL unit per RTP packet.
     */
	self->encoder.context->rtp_payload_size = H264_RTP_PAYLOAD_SIZE;
	self->encoder.context->opaque = tsk_null;
	self->encoder.context->gop_size = (TMEDIA_CODEC_VIDEO(self)->out.fps * TDAV_H264_GOP_SIZE_IN_SECONDS);
	
#if (LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51, 35, 0))
    if((ret = av_opt_set_int(self->encoder.context->priv_data, "slice-max-size", H264_RTP_PAYLOAD_SIZE, 0))){
	    TSK_DEBUG_ERROR("Failed to set x264 slice-max-size to %d", H264_RTP_PAYLOAD_SIZE);
	}
    if((ret = av_opt_set(self->encoder.context->priv_data, "profile", (self->encoder.context->profile == FF_PROFILE_H264_BASELINE ? "baseline" : "main"), 0))){
	    TSK_DEBUG_ERROR("Failed to set x264 profile");
	}
    if((ret = av_opt_set(self->encoder.context->priv_data, "preset", "veryfast", 0))){
	    TSK_DEBUG_ERROR("Failed to set x264 preset to veryfast");
	}
    if((ret = av_opt_set_int(self->encoder.context->priv_data, "rc-lookahead", 0, 0)) && (ret = av_opt_set_int(self->encoder.context->priv_data, "rc_lookahead", 0, 0))){
        TSK_DEBUG_ERROR("Failed to set x264 rc_lookahead=0");
    }
	if((ret = av_opt_set(self->encoder.context->priv_data, "tune", "animation+zerolatency", 0))){
	    TSK_DEBUG_ERROR("Failed to set x264 tune to zerolatency");
	}
#endif

	// Picture (YUV 420)
	if(!(self->encoder.picture = avcodec_alloc_frame())){
		TSK_DEBUG_ERROR("Failed to create encoder picture");
		return -2;
	}
	avcodec_get_frame_defaults(self->encoder.picture);
	

	size = avpicture_get_size(PIX_FMT_YUV420P, self->encoder.context->width, self->encoder.context->height);
	if(!(self->encoder.buffer = tsk_calloc(size, sizeof(uint8_t)))){
		TSK_DEBUG_ERROR("Failed to allocate encoder buffer");
		return -2;
	}

	// Open encoder
	if((ret = avcodec_open(self->encoder.context, self->encoder.codec)) < 0){
		TSK_DEBUG_ERROR("Failed to open [%s] codec", TMEDIA_CODEC(self)->plugin->desc);
		return ret;
	}
    
    self->encoder.frame_count = 0;

	TSK_DEBUG_INFO("[H.264] bitrate=%d bps", self->encoder.context->bit_rate);

	return ret;
#elif HAVE_H264_PASSTHROUGH
    self->encoder.frame_count = 0;
	return 0;
#endif

	TSK_DEBUG_ERROR("Not expected code called");
	return -1;
}
예제 #10
0
static int tdav_codec_h264_set(tmedia_codec_t* self, const tmedia_param_t* param)
{
	tdav_codec_h264_t* h264 = (tdav_codec_h264_t*)self;
	if (param->value_type == tmedia_pvt_int32) {
		if(tsk_striequals(param->key, "action")){
			tmedia_codec_action_t action = (tmedia_codec_action_t)TSK_TO_INT32((uint8_t*)param->value);
			switch(action){
				case tmedia_codec_action_encode_idr:
					{
						h264->encoder.force_idr = tsk_true;
						break;
					}
				case tmedia_codec_action_bw_down:
					{
						h264->encoder.quality = TSK_CLAMP(1, (h264->encoder.quality + 1), 31);
#if HAVE_FFMPEG
						if (h264->encoder.context) {
							h264->encoder.context->global_quality = FF_QP2LAMBDA * h264->encoder.quality;
						}
#endif
						break;
					}
				case tmedia_codec_action_bw_up:
					{
						h264->encoder.quality = TSK_CLAMP(1, (h264->encoder.quality - 1), 31);
#if HAVE_FFMPEG
						if (h264->encoder.context) {
							h264->encoder.context->global_quality = FF_QP2LAMBDA * h264->encoder.quality;
						}
#endif
						break;
					}
			}
			return 0;
		}
		else if(tsk_striequals(param->key, "bw_kbps")){
			int32_t max_bw_userdefine = self->bandwidth_max_upload;
			int32_t max_bw_new = *((int32_t*)param->value);
			if (max_bw_userdefine > 0) {
				// do not use more than what the user defined in it's configuration
				h264->encoder.max_bw_kpbs = TSK_MIN(max_bw_new, max_bw_userdefine);
			}
			else {
				h264->encoder.max_bw_kpbs = max_bw_new;
			}
			return 0;
		}
		else if(tsk_striequals(param->key, "bypass-encoding")){
			h264->encoder.passthrough = *((int32_t*)param->value) ? tsk_true : tsk_false;
			TSK_DEBUG_INFO("[H.264] bypass-encoding = %d", h264->encoder.passthrough);
			return 0;
		}
		else if(tsk_striequals(param->key, "bypass-decoding")){
			h264->decoder.passthrough = *((int32_t*)param->value) ? tsk_true : tsk_false;
			TSK_DEBUG_INFO("[H.264] bypass-decoding = %d", h264->decoder.passthrough);
			return 0;
		}
		else if(tsk_striequals(param->key, "rotation")){
			int32_t rotation = *((int32_t*)param->value);
			if(h264->encoder.rotation != rotation){
                h264->encoder.rotation = rotation;
				if (self->opened) {
					int ret;
                    if ((ret = tdav_codec_h264_close_encoder(h264, kResetRotationFalse))) {
                        return ret;
                    }
					if ((ret = tdav_codec_h264_open_encoder(h264))) {
						return ret;
					}
#if 0 // Not working
					if((ret = avcodec_close(h264->encoder.context))){
						TSK_DEBUG_ERROR("Failed to close [%s] codec", TMEDIA_CODEC(h264)->plugin->desc);
						return ret;
					}
					h264->encoder.context->width = (rotation == 90 || rotation == 270) ? TMEDIA_CODEC_VIDEO(h264)->out.height : TMEDIA_CODEC_VIDEO(h264)->out.width;
					h264->encoder.context->height = (rotation == 90 || rotation == 270) ? TMEDIA_CODEC_VIDEO(h264)->out.width : TMEDIA_CODEC_VIDEO(h264)->out.height;
					if((ret = avcodec_open(h264->encoder.context, h264->encoder.codec)) < 0){
						TSK_DEBUG_ERROR("Failed to open [%s] codec", TMEDIA_CODEC(h264)->plugin->desc);
						return ret;
					}
					h264->encoder.force_idr = tsk_true;
#endif
				}
			}
			return 0;
		}
	}
	return -1;
}
예제 #11
0
int tdav_codec_h264_open_encoder(tdav_codec_h264_t* self)
{
#if HAVE_FFMPEG
	int ret;
	tsk_size_t size;
	int32_t max_bw_kpbs;

	if(self->encoder.context){
		TSK_DEBUG_ERROR("Encoder already opened");
		return -1;
	}
    
#if (LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51, 35, 0))
    if((self->encoder.context = avcodec_alloc_context3(self->encoder.codec))){
        avcodec_get_context_defaults3(self->encoder.context, self->encoder.codec);
    }
#else
    if((self->encoder.context = avcodec_alloc_context())){
        avcodec_get_context_defaults(self->encoder.context);
    }
#endif
    
    if(!self->encoder.context){
        TSK_DEBUG_ERROR("Failed to allocate context");
		return -1;
    }

#if TDAV_UNDER_X86 && LIBAVCODEC_VERSION_MAJOR <= 53
	self->encoder.context->dsp_mask = (FF_MM_MMX | FF_MM_MMXEXT | FF_MM_SSE);
#endif

	self->encoder.context->pix_fmt		= PIX_FMT_YUV420P;
	self->encoder.context->time_base.num  = 1;
	self->encoder.context->time_base.den  = TMEDIA_CODEC_VIDEO(self)->out.fps;
	self->encoder.context->width = (self->encoder.rotation == 90 || self->encoder.rotation == 270) ? TMEDIA_CODEC_VIDEO(self)->out.height : TMEDIA_CODEC_VIDEO(self)->out.width;
	self->encoder.context->height = (self->encoder.rotation == 90 || self->encoder.rotation == 270) ? TMEDIA_CODEC_VIDEO(self)->out.width : TMEDIA_CODEC_VIDEO(self)->out.height;
	max_bw_kpbs = TSK_CLAMP(
		0,
		tmedia_get_video_bandwidth_kbps_2(TMEDIA_CODEC_VIDEO(self)->out.width, TMEDIA_CODEC_VIDEO(self)->out.height, TMEDIA_CODEC_VIDEO(self)->out.fps), 
		self->encoder.max_bw_kpbs
	);
	self->encoder.context->bit_rate = (max_bw_kpbs * 1024);// bps

	self->encoder.context->rc_min_rate = (self->encoder.context->bit_rate >> 3);
	self->encoder.context->rc_max_rate = self->encoder.context->bit_rate;

#if LIBAVCODEC_VERSION_MAJOR <= 53
	self->encoder.context->rc_lookahead = 0;
#endif
	self->encoder.context->global_quality = FF_QP2LAMBDA * self->encoder.quality;
	
	self->encoder.context->scenechange_threshold = 0;
    self->encoder.context->me_subpel_quality = 0;
#if LIBAVCODEC_VERSION_MAJOR <= 53
    self->encoder.context->partitions = X264_PART_I4X4 | X264_PART_I8X8 | X264_PART_P8X8 | X264_PART_B8X8;
#endif
    self->encoder.context->me_method = ME_EPZS;
    self->encoder.context->trellis = 0;

	self->encoder.context->me_range = 16;
	self->encoder.context->qmin = 10;
	self->encoder.context->qmax = 51;
#if LIBAVCODEC_VERSION_MAJOR <= 53
    self->encoder.context->mb_qmin = self->encoder.context->qmin;
	self->encoder.context->mb_qmax = self->encoder.context->qmax;
#endif
	self->encoder.context->qcompress = 0.6f;
	self->encoder.context->mb_decision = FF_MB_DECISION_SIMPLE;
#if LIBAVCODEC_VERSION_MAJOR <= 53
	self->encoder.context->flags2 |= CODEC_FLAG2_FASTPSKIP;
#else 
    self->encoder.context->flags2 |= CODEC_FLAG2_FAST;
#endif
	self->encoder.context->flags |= CODEC_FLAG_LOOP_FILTER;
	self->encoder.context->flags |= CODEC_FLAG_GLOBAL_HEADER;
    self->encoder.context->flags |= CODEC_FLAG_LOW_DELAY;
	self->encoder.context->max_b_frames = 0;
	self->encoder.context->b_frame_strategy = 1;
	self->encoder.context->chromaoffset = 0;

	switch(TDAV_CODEC_H264_COMMON(self)->profile){
		case profile_idc_baseline:
		default:
			self->encoder.context->profile = FF_PROFILE_H264_BASELINE;
			self->encoder.context->level = TDAV_CODEC_H264_COMMON(self)->level;
			break;
		case profile_idc_main:
			self->encoder.context->profile = FF_PROFILE_H264_MAIN;
			self->encoder.context->level = TDAV_CODEC_H264_COMMON(self)->level;
			break;
	}
	
	self->encoder.context->rtp_payload_size = H264_RTP_PAYLOAD_SIZE;
	self->encoder.context->opaque = tsk_null;
	self->encoder.context->gop_size = (TMEDIA_CODEC_VIDEO(self)->out.fps * TDAV_H264_GOP_SIZE_IN_SECONDS);
	
#if (LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51, 35, 0))
    if((ret = av_opt_set_int(self->encoder.context->priv_data, "slice-max-size", H264_RTP_PAYLOAD_SIZE, 0))){
	    TSK_DEBUG_ERROR("Failed to set x264 slice-max-size to %d", H264_RTP_PAYLOAD_SIZE);
	}
    if((ret = av_opt_set(self->encoder.context->priv_data, "profile", (self->encoder.context->profile == FF_PROFILE_H264_BASELINE ? "baseline" : "main"), 0))){
	    TSK_DEBUG_ERROR("Failed to set x264 profile");
	}
    if((ret = av_opt_set(self->encoder.context->priv_data, "preset", "veryfast", 0))){
	    TSK_DEBUG_ERROR("Failed to set x264 preset to veryfast");
	}
    if((ret = av_opt_set_int(self->encoder.context->priv_data, "rc-lookahead", 0, 0)) && (ret = av_opt_set_int(self->encoder.context->priv_data, "rc_lookahead", 0, 0))){
        TSK_DEBUG_ERROR("Failed to set x264 rc_lookahead=0");
    }
	if((ret = av_opt_set(self->encoder.context->priv_data, "tune", "animation+zerolatency", 0))){
	    TSK_DEBUG_ERROR("Failed to set x264 tune to zerolatency");
	}
#endif

	// Picture (YUV 420)
	if(!(self->encoder.picture = avcodec_alloc_frame())){
		TSK_DEBUG_ERROR("Failed to create encoder picture");
		return -2;
	}
	avcodec_get_frame_defaults(self->encoder.picture);
	

	size = avpicture_get_size(PIX_FMT_YUV420P, self->encoder.context->width, self->encoder.context->height);
	if(!(self->encoder.buffer = tsk_calloc(size, sizeof(uint8_t)))){
		TSK_DEBUG_ERROR("Failed to allocate encoder buffer");
		return -2;
	}

	// Open encoder
	if((ret = avcodec_open(self->encoder.context, self->encoder.codec)) < 0){
		TSK_DEBUG_ERROR("Failed to open [%s] codec", TMEDIA_CODEC(self)->plugin->desc);
		return ret;
	}

	TSK_DEBUG_INFO("[H.264] bitrate=%d bps", self->encoder.context->bit_rate);

	return ret;
#elif HAVE_H264_PASSTHROUGH
	return 0;
#endif

	TSK_DEBUG_ERROR("Not expected code called");
	return -1;
}