/*
 *			GPAC - Multimedia Framework C SDK
 *
 *			Authors: Cyril Concolato
 *			Copyright (c) Telecom ParisTech 2013-2019
 *					All rights reserved
 *
 *  This file is part of GPAC / HTML Media Element header
 *
 *  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_HTMLMEDIA_H_
#define _GF_HTMLMEDIA_H_

#ifdef __cplusplus
extern "C" {
#endif


/*!
\file <gpac/html5_media.h>
\brief Scene graph extensions for HTML5 media.
 */
	
/*!
\defgroup html5_grp HTML5
\ingroup scene_grp
\brief HTML5 extensions of the scene graph.
*/

/*!
\addtogroup html5media_grp HTML5 media
\ingroup html5_grp
\brief Scene graph extensions for HTML5 media.

This section documents the scene graph extensions used for HTML5 media (video).

@{
 */

#include <gpac/internal/scenegraph_dev.h>

/*base SVG type*/
#include <gpac/nodes_svg.h>
/*dom events*/
#include <gpac/events.h>
/*dom text event*/
#include <gpac/utf.h>

#include <gpac/download.h>
#include <gpac/network.h>
#include <gpac/xml.h>
#include <gpac/internal/compositor_dev.h>

#ifdef GPAC_ENABLE_HTML5_MEDIA

typedef struct
{
	u32 nb_inst;
	/* Basic classes */
	JSClassDef  arrayBufferClass;

	/*HTML Media classes*/
	JSClassDef  htmlVideoElementClass;
	JSClassDef  htmlAudioElementClass;
	JSClassDef  htmlSourceElementClass;
	JSClassDef  htmlTrackElementClass;
	JSClassDef  htmlMediaElementClass;
	JSClassDef  mediaControllerClass;
	JSClassDef  audioTrackListClass;
	JSClassDef  audioTrackClass;
	JSClassDef  videoTrackListClass;
	JSClassDef  videoTrackClass;
	JSClassDef  textTrackListClass;
	JSClassDef  textTrackClass;
	JSClassDef  textTrackCueListClass;
	JSClassDef  textTrackCueClass;
	JSClassDef  timeRangesClass;
	JSClassDef  trackEventClass;
	JSClassDef  mediaErrorClass;

	/* Media Source Extensions */
	JSClassDef  mediaSourceClass;
	JSClassDef  sourceBufferClass;
	JSClassDef  sourceBufferListClass;
	JSClassDef  URLClass;

	/* Media Capture */
	JSClassDef  mediaStreamClass;
	JSClassDef  localMediaStreamClass;
	JSClassDef  mediaStreamTrackClass;
	JSClassDef  mediaStreamTrackListClass;
	JSClassDef  navigatorUserMediaClass;
	JSClassDef  navigatorUserMediaErrorClass;
} GF_HTML_MediaRuntime;

/************************************************************
 *
 *  HTML 5 Media Element
 *  http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#media-element
 *
 *************************************************************/

typedef enum
{
	MEDIA_ERR_ABORTED           = 1,
	MEDIA_ERR_NETWORK           = 2,
	MEDIA_ERR_DECODE            = 3,
	MEDIA_ERR_SRC_NOT_SUPPORTED = 4
} GF_HTML_MediaErrorCode;

typedef enum
{
	NETWORK_EMPTY               = 0,
	NETWORK_IDLE                = 1,
	NETWORK_LOADING             = 2,
	NETWORK_NO_SOURCE           = 3
} GF_HTML_NetworkState;

typedef enum
{
	HAVE_NOTHING                = 0,
	HAVE_METADATA               = 1,
	HAVE_CURRENT_DATA           = 2,
	HAVE_FUTURE_DATA            = 3,
	HAVE_ENOUGH_DATA            = 4
} GF_HTML_MediaReadyState;

typedef struct
{
	/* JavaScript context associated to this object */
	JSContext               *c;
	/* JavaScript counterpart */
	JSObject                *_this;

	GF_HTML_MediaErrorCode   code;
} GF_HTML_MediaError;

typedef struct _timerange
{
	/* JavaScript context associated to this object */
	JSContext               *c;
	/* JavaScript counterpart */
	JSObject                *_this;

	GF_List                 *times;
	u32						timescale;
} GF_HTML_MediaTimeRanges;

typedef enum {
	HTML_MEDIA_TRACK_TYPE_UNKNOWN = 0,
	HTML_MEDIA_TRACK_TYPE_AUDIO = 1,
	HTML_MEDIA_TRACK_TYPE_VIDEO = 2,
	HTML_MEDIA_TRACK_TYPE_TEXT  = 3
} GF_HTML_TrackType;

#define BASE_HTML_TRACK     \
    /* JavaScript context associated to this object */\
    JSContext               *c;\
    /* JavaScript counterpart */\
    JSObject                *_this;\
    /* GPAC-specific properties */\
    u32                     bin_id;    /* track id */\
    void *            channel;   /* channel object used by the terminal */\
    GF_ObjectDescriptor     *od;       /* MPEG-4 Object descriptor for this track */\
    GF_List                 *buffer;   /* List of MSE Packets */\
    u32						packet_index;   /* index of MSE Packets*/\
    GF_Mutex                *buffer_mutex;\
    Bool                    last_dts_set; \
    u64						last_dts; /* MSE  last decode timestamp (in timescale units)*/ \
    u32						last_dur; /* MSE  last frame duration (in timescale units)*/ \
    Bool                    highest_pts_set; \
    u64						highest_pts; /* MSE highest presentation timestamp (in timescale units)*/ \
    Bool                    needs_rap; /* MSE  need random access point flag */ \
    u32                     timescale; /* used by time stamps in MSE Packets */ \
    s64                     timestampOffset; /* MSE SourceBuffer value (in timescale units) */ \
    /* standard HTML properties */ \
    GF_HTML_TrackType        type;\
    char                    *id;\
    char                    *kind;\
    char                    *label;\
    char                    *language;\
    char                    *mime; \
    Bool                    enabled_or_selected;

typedef struct
{
	BASE_HTML_TRACK
} GF_HTML_Track;

typedef struct
{
	BASE_HTML_TRACK
	JSFunction				*oncuechange;
	char                    *inBandMetadataTrackDispatchType;
	//GF_HTMLTextTrackMode    mode;
	//GF_HTMLTextTrackCueList cues;
	//GF_HTMLTextTrackCueList activeCues;
} GF_HTML_TextTrack;

#define BASE_HTML_TRACK_LIST     \
    /* JavaScript context associated to this object */\
    JSContext               *c;\
    /* JavaScript counterpart */\
    JSObject                *_this;\
    GF_List                 *tracks; \
	jsval					onchange; \
	jsval					onaddtrack; \
	jsval					onremovetrack; \
    u32                     selected_index;

typedef struct
{
	BASE_HTML_TRACK_LIST
} GF_HTML_TrackList;

typedef enum
{
	MEDIA_CONTROLLER_WAITING = 0,
	MEDIA_CONTROLLER_PLAYING = 1,
	MEDIA_CONTROLLER_ENDED   = 2
} GF_HTML_MediaControllerPlaybackState;

typedef struct
{
	/* JavaScript context associated to this object */
	JSContext               *c;
	/* JavaScript counterpart */
	JSObject                *_this;

	GF_HTML_MediaTimeRanges  *buffered;
	GF_HTML_MediaTimeRanges  *seekable;
	GF_HTML_MediaTimeRanges  *played;
	Bool                    paused;
	GF_HTML_MediaControllerPlaybackState playbackState;
	double                  defaultPlaybackRate;

	/* list of media elements using this media controller */
	GF_List                 *media_elements;
} GF_HTML_MediaController;

typedef struct
{
	/* JavaScript context associated to this object */
	JSContext               *c;
	/* JavaScript counterpart */
	JSObject                *_this;

	/* The audio or video node */
	GF_Node                 *node;

	/* error state */
	GF_HTML_MediaError       error;

	/* src: not stored in this structure,
	        using the value stored in the node ( see HTML 5 "must reflect the content of the attribute")*/
	/* currentSrc: the actual source used for the video (src attribute on video, audio or source elements) */
	char                    *currentSrc;
	/* crossOrigin: "must reflect the content of the attribute of the same name", use the node */
	/* networkState: retrieved dynamically from GPAC Service */
	/* preload: "must reflect the content of the attribute of the same name", use the node */
	GF_HTML_MediaTimeRanges  *buffered;
	/* ready state */
	/* readyState: retrieved from GPAC Media Object dynamically */
	Bool                    seeking;

	/* playback state */
	/* currentTime: retrieved from GPAC Media Object */
	/* duration: retrieved from GPAC Media Object */
	char                    *startDate;
	Bool                    paused;
	double                  defaultPlaybackRate;
	GF_HTML_MediaTimeRanges  *played;
	GF_HTML_MediaTimeRanges  *seekable;
	/* ended: retrieved from the state of GPAC Media Object */
	/* autoplay: "must reflect the content of the attribute of the same name", use the node */
	/* loop: "must reflect the content of the attribute of the same name", use the node */

	/* media controller*/
	/* mediaGroup: "must reflect the content of the attribute of the same name", use the node */
	GF_HTML_MediaController  *controller;

	/* controls*/
	/* controls: "must reflect the content of the attribute of the same name", use the node */
	/* volume: retrieved from GPAC Audio Input in GPAC Media Object */
	/* muted: retrieved from GPAC media object */
	/* defaultMuted: "must reflect the content of the attribute of with the name" muted */

	/* tracks*/
	GF_HTML_TrackList        audioTracks;
	GF_HTML_TrackList        videoTracks;
	GF_HTML_TrackList        textTracks;

	GF_DOMEventTarget		 *evt_target;
} GF_HTML_MediaElement;

typedef struct
{
	/* JavaScript context used to create the JavaScript object below */
	JSContext               *c;

	/* JavaScript counterpart for this object*/
	JSObject                *_this;

	char    *data;
	u32     length;
	char    *url;
	Bool	is_init;
	GF_Blob blob;
	/* used to do proper garbage collection between JS and Terminal */
	u32     reference_count;
} GF_HTML_ArrayBuffer;

/*
 * TimeRanges
 */
GF_HTML_MediaTimeRanges *gf_html_timeranges_new(u32 timescale);
GF_Err gf_html_timeranges_add_start(GF_HTML_MediaTimeRanges *timeranges, u64 start);
GF_Err gf_html_timeranges_add_end(GF_HTML_MediaTimeRanges *timeranges, u64 end);
void	gf_html_timeranges_reset(GF_HTML_MediaTimeRanges *range);
void	gf_html_timeranges_del(GF_HTML_MediaTimeRanges *range);
GF_HTML_MediaTimeRanges *gf_html_timeranges_intersection(GF_HTML_MediaTimeRanges *a, GF_HTML_MediaTimeRanges *b);
GF_HTML_MediaTimeRanges *gf_html_timeranges_union(GF_HTML_MediaTimeRanges *a, GF_HTML_MediaTimeRanges *b);

/*
 * HTML5 TrackList
 */
GF_HTML_Track *html_media_add_new_track_to_list(GF_HTML_TrackList *tracklist,
        GF_HTML_TrackType type, const char *mime, Bool enable_or_selected,
        const char *id, const char *kind, const char *label, const char *lang);
Bool html_media_tracklist_has_track(GF_HTML_TrackList *tracklist, const char *id);
GF_HTML_Track *html_media_tracklist_get_track(GF_HTML_TrackList *tracklist, const char *id);
void gf_html_tracklist_del(GF_HTML_TrackList *tlist);

/*
 * HTML5 Tracks
 */
GF_HTML_Track *gf_html_media_track_new(GF_HTML_TrackType type, const char *mime, Bool enable_or_selected,
                                       const char *id, const char *kind, const char *label, const char *lang);
void gf_html_track_del(GF_HTML_Track *track);

/*
 * HTML5 Media Element
 */
GF_HTML_MediaElement *gf_html_media_element_new(GF_Node *media_node, GF_HTML_MediaController *mc);
void gf_html_media_element_del(GF_HTML_MediaElement *me);

void html_media_element_js_init(JSContext *c, JSObject *new_obj, GF_Node *n);

/*
 * HTML5 Media Controller
 */
GF_HTML_MediaController *gf_html_media_controller_new();
void gf_html_media_controller_del(GF_HTML_MediaController *mc);

/*
 * HTML5 Array Buffer
 */
GF_HTML_ArrayBuffer *gf_arraybuffer_new(u8 *data, u32 length);
JSObject *gf_arraybuffer_js_new(JSContext *c, u8 *data, u32 length, JSObject *parent);
void gf_arraybuffer_del(GF_HTML_ArrayBuffer *buffer, Bool del_js);


#endif //GPAC_ENABLE_HTML5_MEDIA

/*! @} */

#ifdef __cplusplus
}
#endif

#endif	// _GF_HTMLMEDIA_H_
