/*
 *			GPAC - Multimedia Framework C SDK
 *
 *			Authors: Jean Le Feuvre
 *			Copyright (c) Telecom ParisTech 2000-2012
 *					All rights reserved
 *
 *  This file is part of GPAC / Stream Management sub-project
 *
 *  GPAC is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  GPAC 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 Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */



#ifndef _GF_MEDIA_OBJECT_H_
#define _GF_MEDIA_OBJECT_H_

#ifdef __cplusplus
extern "C" {
#endif

/*!
 *	\file <gpac/mediaobject.h>
 *	\brief Interface between compositor and decoding engine for media data access.
 */
	
/*!
 *\addtogroup mobj_grp MediaObject
 *\ingroup playback_grp
 *\brief Interface between compositor and decoding engine for media data access.
 *
 *This section documents the API betwwen the compositor of GPAC and the decoding engine (terminal)
 *	@{
 */
	
#include <gpac/scenegraph_vrml.h>
#include <gpac/modules/codec.h>


/*
		Media Object

  opaque handler for all natural media objects (audio, video, image) so that compositor and systems engine
are not too tied up.
	NOTE: the media object location relies on the node parent graph (this is to deal with namespaces in OD framework)
therefore it is the task of the media management app to setup clear links between the scene graph and its ressources
(but this is not mandatory, cf URLs in VRML )

	TODO - add interface for shape coding positioning in mediaObject and in the decoder API
*/

typedef struct _mediaobj GF_MediaObject;

/*locate media object related to the given node - url designes the object to find - returns NULL if
URL cannot be handled - note that until the mediaObject.isInit member is true, the media object is not valid
(and could actually never be) */
GF_MediaObject *gf_mo_register(GF_Node *node, MFURL *url, Bool lock_timelines, Bool force_new_res);
/*unregister the node from the media object*/
void gf_mo_unregister(GF_Node *node, GF_MediaObject *mo);

/*opens media object*/
void gf_mo_play(GF_MediaObject *mo, Double clipBegin, Double clipEnd, Bool can_loop);
/*stops media object - video memory is not reset, last frame is kept*/
Bool gf_mo_stop(GF_MediaObject *mo);
/*restarts media object - shall be used for all looping media instead of stop/play for mediaControl
to restart appropriated objects*/
void gf_mo_restart(GF_MediaObject *mo);

void gf_mo_pause(GF_MediaObject *mo);
void gf_mo_resume(GF_MediaObject *mo);

/*
	Note on mediaControl: mediaControl is the media management app responsability, therefore
is hidden from the rendering app. Since MediaControl overrides default settings of the node (speed and loop)
you must use the gf_mo_get_speed and gf_mo_get_loop in order to know whether the related field applies or not
*/

/*set speed of media - speed is not always applied, depending on media control settings.
NOTE: audio pitching is the responsability of the rendering app*/
void gf_mo_set_speed(GF_MediaObject *mo, Fixed speed);
/*returns current speed of media - in_speed is the speed of the media as set in the node (MovieTexture,
AudioClip and AudioSource) - the return value is the real speed of the media as overloaded by mediaControl if any*/
Fixed gf_mo_get_speed(GF_MediaObject *mo, Fixed in_speed);
/*returns looping flag of media - in_loop is the looping flag of the media as set in the node (MovieTexture,
AudioClip) - the return value is the real loop flag of the media as overloaded by mediaControl if any*/
Bool gf_mo_get_loop(GF_MediaObject *mo, Bool in_loop);
/*returns media object duration*/
Double gf_mo_get_duration(GF_MediaObject *mo);
/*returns whether the object should be deactivated (stop) or not - this checks object status as well as
mediaControl status */
Bool gf_mo_should_deactivate(GF_MediaObject *mo);
/*checks whether the target object is changed - you MUST use this in order to detect url changes*/
Bool gf_mo_url_changed(GF_MediaObject *mo, MFURL *url);

/*checks whether the target object is changed - you MUST use this in order to detect url changes*/
Bool gf_mo_is_raw_memory(GF_MediaObject *mo);
GF_Err gf_mo_get_raw_image_planes(GF_MediaObject *mo, u8 **pY_or_RGB, u8 **pU, u8 **pV, u32 *stride_luma_rgb, u32 *stride_chroma);


/*returns min frame duration for his object or 0 if unknown*/
u32 gf_mo_get_min_frame_dur(GF_MediaObject *mo);

typedef enum
{
	//never resync the content of the decoded media buffer (used fo audio)
	//if clock is paused do not fetch
	GF_MO_FETCH = 0,
	//always resync the content of the decoded media buffer to the current time (used for video)
	GF_MO_FETCH_RESYNC,
	//never resync the content of the decoded media buffer (used fo audio)
	//if clock is paused,  do fetch (used for audio extraction)
	GF_MO_FETCH_PAUSED
} GF_MOFetchMode;

/*fetch media data

*/
char *gf_mo_fetch_data(GF_MediaObject *mo, GF_MOFetchMode resync, u32 upload_time_ms, Bool *eos, u32 *timestamp, u32 *size, s32 *ms_until_pres, s32 *ms_until_next, GF_MediaDecoderFrame **outFrame);

/*release given amount of media data - nb_bytes is used for audio  - drop_mode can take the following values:
-1: do not drop
0: do not force drop: the unlocked frame it will be dropped based on object time (typically video)
1: force drop : the unlocked frame will be dropped if all bytes are consumed (typically audio)
2: the frame will be stated as a discraded frame
*/
void gf_mo_release_data(GF_MediaObject *mo, u32 nb_bytes, s32 drop_mode);
/*get media time*/
void gf_mo_get_media_time(GF_MediaObject *mo, u32 *media_time, u32 *media_dur);
/*get object clock*/
void gf_mo_get_object_time(GF_MediaObject *mo, u32 *obj_time);
/*returns mute flag of media - if muted the media shouldn't be displayed*/
Bool gf_mo_is_muted(GF_MediaObject *mo);
/*returns end of stream state*/
Bool gf_mo_is_done(GF_MediaObject *mo);
/*resyncs clock - only audio objects are allowed to use this*/
void gf_mo_adjust_clock(GF_MediaObject *mo, s32 ms_drift);

u32 gf_mo_get_last_frame_time(GF_MediaObject *mo);

Bool gf_mo_get_visual_info(GF_MediaObject *mo, u32 *width, u32 *height, u32 *stride, u32 *pixel_ar, u32 *pixelFormat, Bool *is_flipped);

void gf_mo_get_nb_views(GF_MediaObject *mo, int * nb_views);

void gf_mo_get_nb_layers(GF_MediaObject *mo, int * nb_layers);

Bool gf_mo_get_audio_info(GF_MediaObject *mo, u32 *sample_rate, u32 *bits_per_sample, u32 *num_channels, u32 *channel_config);

Fixed gf_mo_get_current_speed(GF_MediaObject *mo);

/*checks if the service associated withthis object has an audio stream
returns 0 if no audio is associated, 1 if there is an audio object associated, 2 if the service is not yet ready (not connected)*/
u32 gf_mo_has_audio(GF_MediaObject *mo);

/*checks if the service associated withthis object has an audio stream*/
Bool gf_mo_is_private_media(GF_MediaObject *mo);

/*set destination window for harware codecs directly outputing to video out - returns 1 if video size has changed*/
Bool gf_mo_set_position(GF_MediaObject *mo, GF_Window *src, GF_Window *dst);

s32 gf_mo_get_clock_drift(GF_MediaObject *mo);

enum
{
	/*this is set to 0 by the OD manager whenever a change occur in the media (w/h change, SR change, etc)
	as a hint for the compositor*/
	GF_MO_IS_INIT = (1<<1),
	/*used by animation stream to remove TEXT from display upon delete and URL change*/
	GF_MO_DISPLAY_REMOVE = (1<<2),
};

u32 gf_mo_get_flags(GF_MediaObject *mo);
void gf_mo_set_flag(GF_MediaObject *mo, u32 flag, Bool set_on);

/*loads a new resource as indicated in the xlink:href attribute of the node. If this points to a fragment
of the current document, returns NULL. This will automatically trigger a play request on the resource*/
GF_MediaObject *gf_mo_load_xlink_resource(GF_Node *node, Bool primary_resource, Double clipBegin, Double clipEnd);
void gf_mo_unload_xlink_resource(GF_Node *node, GF_MediaObject *mo);
/*returns scene graph associated with a scene/document object, or NULL if wrong type or not loaded*/
GF_SceneGraph *gf_mo_get_scenegraph(GF_MediaObject *mo);


typedef struct
{
	u32 vr_type;
	s32 srd_x;
	s32 srd_y;
	s32 srd_w;
	s32 srd_h;
	
	s32 srd_min_x;
	s32 srd_min_y;
	s32 srd_max_x;
	s32 srd_max_y;
	
	u32 scene_width;
	u32 scene_height;

	Bool is_tiled_srd;
} GF_MediaObjectVRInfo;

//get SRD and VR info for this object. Returns FALSE if no VR and no SRD info
Bool gf_mo_get_srd_info(GF_MediaObject *mo, GF_MediaObjectVRInfo *vr_info);

/*sets quality degradation hint for this media object  - quality_rank is between 0 (max quality) and 100 (worst quality)*/
void gf_mo_hint_quality_degradation(GF_MediaObject *mo, u32 quality_degradation);

/*sets visible rectangle for the object - only used in 360 videos for now*/
void gf_mo_hint_visible_rect(GF_MediaObject *mo, u32 min_x, u32 max_x, u32 min_y, u32 max_y);

#include <gpac/scenegraph_svg.h>
void gf_mo_del(GF_MediaObject *mo);

GF_DOMEventTarget  *gf_mo_event_target_add_node(GF_MediaObject *mo, GF_Node *n);
GF_Err              gf_mo_event_target_remove(GF_MediaObject *mo, GF_DOMEventTarget *target);
GF_Err              gf_mo_event_target_remove_by_node(GF_MediaObject *mo, GF_Node *node);
GF_Err              gf_mo_event_target_remove_by_index(GF_MediaObject *mo, u32 i);
GF_DOMEventTarget  *gf_mo_event_target_get(GF_MediaObject *mo, u32 i);
void                gf_mo_event_target_reset(GF_MediaObject *mo);
u32                 gf_mo_event_target_count(GF_MediaObject *mo);
s32                 gf_mo_event_target_find_by_node(GF_MediaObject *mo, GF_Node *node);
GF_Node            *gf_mo_event_target_enum_node(GF_MediaObject *mo, u32 *i);

GF_Node            *gf_event_target_get_node(GF_DOMEventTarget *target);

/*! @} */

#ifdef __cplusplus
}
#endif


#endif	/*_GF_MEDIA_OBJECT_H_*/


