Beispiel #1
0
GF_Err MPD_ChannelGetSLP(GF_InputService *plug, LPNETCHANNEL channel, char **out_data_ptr, u32 *out_data_size, GF_SLHeader *out_sl_hdr, Bool *sl_compressed, GF_Err *out_reception_status, Bool *is_new_data)
{
    GF_MPD_In *mpdin = (GF_MPD_In*) plug->priv;
	GF_InputService *segment_ifce = MPD_GetInputServiceForChannel(mpdin, channel);
    if (!plug || !plug->priv || !segment_ifce) return GF_SERVICE_ERROR;
    return segment_ifce->ChannelGetSLP(segment_ifce, channel, out_data_ptr, out_data_size, out_sl_hdr, sl_compressed, out_reception_status, is_new_data);
}
Beispiel #2
0
GF_Err MPD_ChannelReleaseSLP(GF_InputService *plug, LPNETCHANNEL channel)
{
    GF_MPD_In *mpdin = (GF_MPD_In*) plug->priv;
	GF_InputService *segment_ifce = MPD_GetInputServiceForChannel(mpdin, channel);
    if (!plug || !plug->priv || !segment_ifce) return GF_SERVICE_ERROR;
    return segment_ifce->ChannelReleaseSLP(segment_ifce, channel);
}
Beispiel #3
0
GF_Err MPD_ConnectChannel(GF_InputService *plug, LPNETCHANNEL channel, const char *url, Bool upstream)
{
    GF_MPD_In *mpdin = (GF_MPD_In*) plug->priv;
	GF_InputService *segment_ifce = MPD_GetInputServiceForChannel(mpdin, channel);
    if (!plug || !plug->priv || !segment_ifce) return GF_SERVICE_ERROR;
    GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD_IN] Received Channel Connection (%p) request from terminal for %s\n", channel, url));
	return segment_ifce->ConnectChannel(segment_ifce, channel, url, upstream);
}
Beispiel #4
0
GF_Err MPD_DisconnectChannel(GF_InputService *plug, LPNETCHANNEL channel)
{
    GF_MPD_In *mpdin = (GF_MPD_In*) plug->priv;
	GF_InputService *segment_ifce = MPD_GetInputServiceForChannel(mpdin, channel);
    if (!plug || !plug->priv || !segment_ifce) return GF_SERVICE_ERROR;
    GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD_IN] Received Disconnect channel (%p) request from terminal \n", channel));

	return segment_ifce->DisconnectChannel(segment_ifce, channel);
}
Beispiel #5
0
s32 MPD_GetGroupIndexForChannel(GF_MPD_In *mpdin, LPNETCHANNEL channel)
{
	u32 i;
	GF_InputService *ifce = MPD_GetInputServiceForChannel(mpdin, channel);
	if (!ifce) return -1;

	for (i=0; i<gf_dash_get_group_count(mpdin->dash); i++) {
		GF_MPDGroup *group = gf_dash_get_group_udta(mpdin->dash, i);
		if (!group) continue;
		if (group->segment_ifce == ifce) return i;
	}
	return -1;
}
Beispiel #6
0
GF_Err MPD_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com)
{
	s32 idx;
    GF_Err e;
    GF_MPD_In *mpdin = (GF_MPD_In*) plug->priv;
	GF_InputService *segment_ifce = NULL;

	if (!plug || !plug->priv || !com ) return GF_SERVICE_ERROR;

	segment_ifce = MPD_GetInputServiceForChannel(mpdin, com->base.on_channel);

	switch (com->command_type) {
    case GF_NET_SERVICE_INFO:
    {
        GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD_IN] Received Info command from terminal on Service (%p)\n", mpdin->service));

		e = GF_OK;
		if (segment_ifce) {
			/* defer to the real input service */
			e = segment_ifce->ServiceCommand(segment_ifce, com);
		}

		if (e!= GF_OK || !com->info.name || 2 > strlen(com->info.name)) {
			gf_dash_get_info(mpdin->dash, &com->info.name, &com->info.comment);
        }
        return GF_OK;
    }
	/*we could get it from MPD*/
    case GF_NET_SERVICE_HAS_AUDIO:
        GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD_IN] Received Has Audio command from terminal on Service (%p)\n", mpdin->service));
		if (segment_ifce) {
	        /* defer to the real input service */
		    return segment_ifce->ServiceCommand(segment_ifce, com);
		}
        return GF_NOT_SUPPORTED;

	case GF_NET_SERVICE_HAS_FORCED_VIDEO_SIZE:
		com->par.width = mpdin->use_max_res ? mpdin->width : 0;
		com->par.height = mpdin->use_max_res ? mpdin->height : 0;
        return GF_OK;

	case GF_NET_SERVICE_QUALITY_SWITCH:
		gf_dash_switch_quality(mpdin->dash, com->switch_quality.up, mpdin->immediate_switch);
        return GF_OK;
	}
	/*not supported*/
	if (!com->base.on_channel) return GF_NOT_SUPPORTED;

	segment_ifce = MPD_GetInputServiceForChannel(mpdin, com->base.on_channel);
	if (!segment_ifce) return GF_NOT_SUPPORTED;

	switch (com->command_type) {
    case GF_NET_CHAN_INTERACTIVE:
        /* we are interactive (that's the whole point of MPD) */
        return GF_OK;

	/*we should get it from MPD minBufferTime*/
	case GF_NET_CHAN_BUFFER:
        return segment_ifce->ServiceCommand(segment_ifce, com);
        break;

	case GF_NET_CHAN_DURATION:
		/* Ignore the duration given by the input service and use the one given in the MPD
		   Note: the duration of the initial segment will be 0 anyway (in MP4).*/
		com->duration.duration = gf_dash_get_duration(mpdin->dash);
		return GF_OK;

	case GF_NET_CHAN_PLAY:
		/*don't seek if this command is the first PLAY request of objects declared by the subservice*/
		if (!com->play.initial_broadcast_play) {
			GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD_IN] Received Play command from terminal on channel %p on Service (%p)\n", com->base.on_channel, mpdin->service));

			if (!gf_dash_in_period_setup(mpdin->dash) && !com->play.dash_segment_switch && ! mpdin->in_seek) {
				Bool skip_seek;

				mpdin->in_seek = 1;

				/*if start range request is the same as previous one, don't process it
				- this happens at period switch when new objects are declared*/
				skip_seek = (mpdin->previous_start_range==com->play.start_range) ? 1 : 0;
				mpdin->previous_start_range = com->play.start_range;

				gf_dash_seek(mpdin->dash, com->play.start_range);
			}
			/*For MPEG-2 TS or formats not using Init Seg: since objects are declared and started once the first
			segment is playing, we will stay in playback_start_range!=-1 until next segment (because we won't have a query_next),
			which will prevent seeking until then ... we force a reset of playback_start_range to allow seeking asap*/
			else if (mpdin->in_seek && (com->play.start_range==0)) {
//				mpdin->in_seek = 0;
			}
			else if (gf_dash_in_period_setup(mpdin->dash) && (com->play.start_range==0)) {
				com->play.start_range = gf_dash_get_playback_start_range(mpdin->dash);
			}

			idx = MPD_GetGroupIndexForChannel(mpdin, com->play.on_channel);
			if (idx>=0) {
				gf_dash_set_group_done(mpdin->dash, idx, 0);
				com->play.dash_segment_switch = gf_dash_group_segment_switch_forced(mpdin->dash, idx);
			}

			/*don't forward commands, we are killing the service anyway ...*/
			if (gf_dash_get_period_switch_status(mpdin->dash) ) return GF_OK;
		}

		return segment_ifce->ServiceCommand(segment_ifce, com);

	case GF_NET_CHAN_STOP:
	{
		s32 idx = MPD_GetGroupIndexForChannel(mpdin, com->play.on_channel);
		if (idx>=0) {
			gf_dash_set_group_done(mpdin->dash, (u32) idx, 1);
		}
	}
		return segment_ifce->ServiceCommand(segment_ifce, com);

	/*we could get it from MPD*/
	case GF_NET_CHAN_GET_PIXEL_AR:
        /* defer to the real input service */
        return segment_ifce->ServiceCommand(segment_ifce, com);

	case GF_NET_CHAN_SET_SPEED:
        return segment_ifce->ServiceCommand(segment_ifce, com);

    default:
        return segment_ifce->ServiceCommand(segment_ifce, com);
    }
}
Beispiel #7
0
GF_Err MPD_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com)
{
	s32 idx;
	GF_Err e;
	GF_MPD_In *mpdin = (GF_MPD_In*) plug->priv;
	GF_InputService *segment_ifce = NULL;

	if (!plug || !plug->priv || !com ) return GF_SERVICE_ERROR;

	segment_ifce = MPD_GetInputServiceForChannel(mpdin, com->base.on_channel);

	switch (com->command_type) {
	case GF_NET_SERVICE_INFO:
	{
		s32 idx;
		GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD_IN] Received Info command from terminal on Service (%p)\n", mpdin->service));

		e = GF_OK;
		if (segment_ifce) {
			/* defer to the real input service */
			e = segment_ifce->ServiceCommand(segment_ifce, com);
		}

		if (e!= GF_OK || !com->info.name || 2 > strlen(com->info.name)) {
			gf_dash_get_info(mpdin->dash, &com->info.name, &com->info.comment);
		}
		idx = MPD_GetGroupIndexForChannel(mpdin, com->play.on_channel);
		if (idx>=0) {
			//gather role and co
			if (!com->info.role) {
				gf_dash_group_enum_descriptor(mpdin->dash, idx, GF_MPD_DESC_ROLE, 0, NULL, NULL, &com->info.role);
			}
			if (!com->info.accessibility) {
				gf_dash_group_enum_descriptor(mpdin->dash, idx, GF_MPD_DESC_ACCESSIBILITY, 0, NULL, NULL, &com->info.accessibility);
			}
			if (!com->info.rating) {
				gf_dash_group_enum_descriptor(mpdin->dash, idx, GF_MPD_DESC_RATING, 0, NULL, NULL, &com->info.rating);
			}
		}
		return GF_OK;
	}
	/*we could get it from MPD*/
	case GF_NET_SERVICE_HAS_AUDIO:
	case GF_NET_SERVICE_FLUSH_DATA:
		if (segment_ifce) {
			/* defer to the real input service */
			return segment_ifce->ServiceCommand(segment_ifce, com);
		}
		return GF_NOT_SUPPORTED;

	case GF_NET_SERVICE_HAS_FORCED_VIDEO_SIZE:
		com->par.width = mpdin->use_max_res ? mpdin->width : 0;
		com->par.height = mpdin->use_max_res ? mpdin->height : 0;
		return GF_OK;

	case GF_NET_SERVICE_QUALITY_SWITCH:
		if (com->switch_quality.set_auto) {
			gf_dash_set_automatic_switching(mpdin->dash, 1);
		} else if (com->base.on_channel) {
			segment_ifce = MPD_GetInputServiceForChannel(mpdin, com->base.on_channel);
			if (!segment_ifce) return GF_NOT_SUPPORTED;
			idx = MPD_GetGroupIndexForChannel(mpdin, com->play.on_channel);
			if (idx < 0) return GF_BAD_PARAM;

			gf_dash_set_automatic_switching(mpdin->dash, 0);
			gf_dash_group_select_quality(mpdin->dash, idx, com->switch_quality.ID);
		} else {
			gf_dash_switch_quality(mpdin->dash, com->switch_quality.up, mpdin->immediate_switch);
		}
		return GF_OK;

	case GF_NET_GET_TIMESHIFT:
		com->timeshift.time = gf_dash_get_timeshift_buffer_pos(mpdin->dash);
		return GF_OK;

	default:
		break;
	}
	/*not supported*/
	if (!com->base.on_channel) return GF_NOT_SUPPORTED;

	segment_ifce = MPD_GetInputServiceForChannel(mpdin, com->base.on_channel);
	if (!segment_ifce) return GF_NOT_SUPPORTED;

	switch (com->command_type) {
	case GF_NET_CHAN_INTERACTIVE:
		/* TODO - we are interactive if not live without timeshift */
		return GF_OK;

	case GF_NET_GET_STATS:
	{
		idx = MPD_GetGroupIndexForChannel(mpdin, com->base.on_channel);
		if (idx < 0) return GF_BAD_PARAM;
		com->net_stats.bw_down = 8 * gf_dash_group_get_download_rate(mpdin->dash, idx);
	}
	return GF_OK;

	case GF_NET_SERVICE_QUALITY_QUERY:
	{
		GF_DASHQualityInfo qinfo;
		GF_Err e;
		u32 count;
		idx = MPD_GetGroupIndexForChannel(mpdin, com->quality_query.on_channel);
		if (idx < 0) return GF_BAD_PARAM;
		count = gf_dash_group_get_num_qualities(mpdin->dash, idx);
		if (!com->quality_query.index) {
			com->quality_query.index = count;
			return GF_OK;
		}
		if (com->quality_query.index>count) return GF_BAD_PARAM;

		e = gf_dash_group_get_quality_info(mpdin->dash, idx, com->quality_query.index-1, &qinfo);
		if (e) return e;

		com->quality_query.bandwidth = qinfo.bandwidth;
		com->quality_query.ID = qinfo.ID;
		com->quality_query.mime = qinfo.mime;
		com->quality_query.codec = qinfo.codec;
		com->quality_query.width = qinfo.width;
		com->quality_query.height = qinfo.height;
		com->quality_query.interlaced = qinfo.interlaced;
		if (qinfo.fps_den) {
			com->quality_query.fps = qinfo.fps_num;
			com->quality_query.fps /= qinfo.fps_den;
		}
		com->quality_query.par_num = qinfo.par_num;
		com->quality_query.par_den = qinfo.par_den;
		com->quality_query.sample_rate = qinfo.sample_rate;
		com->quality_query.nb_channels = qinfo.nb_channels;
		com->quality_query.disabled = qinfo.disabled;
		com->quality_query.is_selected = qinfo.is_selected;
		com->quality_query.automatic = gf_dash_get_automatic_switching(mpdin->dash);
		return GF_OK;
	}

	break;

	case GF_NET_CHAN_BUFFER:
		/*get it from MPD minBufferTime - if not in low latency mode, indicate the value given in MPD (not possible to fetch segments earlier) - to be more precise we should get the min segment duration for this group*/
		if (!mpdin->use_low_latency && (mpdin->buffer_mode>=MPDIN_BUFFER_MIN) ) {
			u32 max = gf_dash_get_min_buffer_time(mpdin->dash);
			if (max>com->buffer.max)
				com->buffer.max = max;

			if (! gf_dash_is_dynamic_mpd(mpdin->dash)) {
				com->buffer.min = 1;
			}
		}
		return GF_OK;

	case GF_NET_CHAN_DURATION:
		com->duration.duration = gf_dash_get_duration(mpdin->dash);
		idx = MPD_GetGroupIndexForChannel(mpdin, com->play.on_channel);
		if (idx >= 0) {
			com->duration.time_shift_buffer = gf_dash_group_get_time_shift_buffer_depth(mpdin->dash, idx);
		}
		return GF_OK;

	case GF_NET_CHAN_PLAY:

		idx = MPD_GetGroupIndexForChannel(mpdin, com->play.on_channel);
		if (idx < 0) return GF_BAD_PARAM;

		//adjust play range from media timestamps to MPD time
		if (com->play.timestamp_based) {
			u32 timescale;
			u64 pto;
			Double offset;
			GF_MPDGroup *group = gf_dash_get_group_udta(mpdin->dash, idx);

			if (com->play.timestamp_based==1) {
				gf_dash_group_get_presentation_time_offset(mpdin->dash, idx, &pto, &timescale);
				offset = (Double) pto;
				offset /= timescale;
				com->play.start_range -= offset;
				if (com->play.start_range < 0) com->play.start_range = 0;
			}

			group->is_timestamp_based = 1;
			group->pto_setup = 0;
			mpdin->media_start_range = com->play.start_range;
		} else {
			GF_MPDGroup *group = gf_dash_get_group_udta(mpdin->dash, idx);
			group->is_timestamp_based = 0;
			group->pto_setup = 0;
			if (com->play.start_range<0) com->play.start_range = 0;
		}

		//we cannot handle seek request outside of a period being setup, this messes up our internal service setup
		//we postpone the seek and will request it later on ...
		if (gf_dash_in_period_setup(mpdin->dash)) {
			u64 p_end = gf_dash_get_period_duration(mpdin->dash);
			if (p_end) {
				p_end += gf_dash_get_period_start(mpdin->dash);
				if (p_end<1000*com->play.start_range) {
					mpdin->seek_request = com->play.start_range;
					return GF_OK;
				}
			}
		}


		gf_dash_set_speed(mpdin->dash, com->play.speed);

		/*don't seek if this command is the first PLAY request of objects declared by the subservice*/
		if (! mpdin->in_seek && (!com->play.initial_broadcast_play || (com->play.start_range>2.0) ) ) {
			Bool skip_seek;
			GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD_IN] Received Play command from terminal on channel %p on Service (%p)\n", com->base.on_channel, mpdin->service));

			mpdin->in_seek = 1;

			/*if start range request is the same as previous one, don't process it
			- this happens at period switch when new objects are declared*/
			skip_seek = 0;
			if (com->play.initial_broadcast_play && (mpdin->previous_start_range==com->play.start_range))
				skip_seek = 1;

			mpdin->previous_start_range = com->play.start_range;

			if (!skip_seek) {
				if (com->play.end_range<=0) {
					u32 ms = (u32) ( 1000 * (-com->play.end_range) );
					if (ms<1000) ms = 0;
					gf_dash_set_timeshift(mpdin->dash, ms);
				}
				gf_dash_seek(mpdin->dash, com->play.start_range);

				//we have issued a seek request, mark the group as seeking
				if (mpdin->in_seek) {
					//group->in_seek = 1;
				}
				//and check if current segment playback should be aborted
				com->play.dash_segment_switch = gf_dash_group_segment_switch_forced(mpdin->dash, idx);
			}

			//to remove once we manage to keep the service alive
			/*don't forward commands if a switch of period is to be scheduled, we are killing the service anyway ...*/
			if (gf_dash_get_period_switch_status(mpdin->dash) ) return GF_OK;
		}

		gf_dash_group_select(mpdin->dash, idx, GF_TRUE);
		gf_dash_set_group_done(mpdin->dash, (u32) idx, 0);

		//adjust start range from MPD time to media time
		{
			u64 pto;
			u32 timescale;
			com->play.start_range = gf_dash_group_get_start_range(mpdin->dash, idx);
			gf_dash_group_get_presentation_time_offset(mpdin->dash, idx, &pto, &timescale);
			com->play.start_range += ((Double)pto ) / timescale;
		}

		return segment_ifce->ServiceCommand(segment_ifce, com);

	case GF_NET_CHAN_STOP:
	{
		s32 idx = MPD_GetGroupIndexForChannel(mpdin, com->play.on_channel);
		if (idx>=0) {
			gf_dash_set_group_done(mpdin->dash, (u32) idx, 1);
		}
		mpdin->previous_start_range = -1;
	}
	return segment_ifce->ServiceCommand(segment_ifce, com);

	/*we could get it from MPD*/
	case GF_NET_CHAN_GET_PIXEL_AR:
		/* defer to the real input service */
		return segment_ifce->ServiceCommand(segment_ifce, com);

	case GF_NET_CHAN_SET_SPEED:
		gf_dash_set_speed(mpdin->dash, com->play.speed);
		return segment_ifce->ServiceCommand(segment_ifce, com);

	default:
		return segment_ifce->ServiceCommand(segment_ifce, com);
	}
}