/*
 *			GPAC - MPEG-4 Systems C Development Kit
 *
 *			Copyright (c) Jean Le Feuvre 2000-2005 
 *					All rights reserved
 *
 *  This file is part of GPAC / Authoring Tools sub-project
 *
 *  GPAC is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU 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 General Public License for more details.
 *   
 *  You should have received a copy of the GNU General Public License
 *  along with GNU Make; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
 *
 */


#ifndef _M4_AUTHOR_DEV_H_
#define _M4_AUTHOR_DEV_H_

#include <gpac/m4_author.h>

/*since 0.2.2, we use zlib for xmt/x3d reading to handle gz files*/
#include <zlib.h>


/*extremely crude xml parsing helper
	All string returns are maintained by parser and shall not be freed by user.
	The string returned are pointers to internal buffers, hence their content will liokely change 
	at each operations. You shall therefore copy their value if you need them later on
*/


#define XML_LINE_SIZE	8000
typedef struct 
{
	/*gz input file*/
	gzFile gz_in;
	/*eof*/
	Bool done;
	/*current line parsed (mainly used for error reports)*/
	u32 line;
	/*0: UTF-8, 1: UTF-16 BE, 2: UTF-16 LE. String input is always converted back to utf8*/
	u32 unicode_type;
	/*line buffer - needs refinement, cannot handle attribute values with size over XMT_LINE_SIZE (except string
	where space is used as a line-break...)*/
	char line_buffer[XML_LINE_SIZE];
	/*name buffer for elements and attributes*/
	char name_buffer[1000];
	/*dynamic buffer for attribute values*/
	char *value_buffer;
	u32 att_buf_size;
	/*line size and current position*/
	s32 line_size, current_pos;
	/*absolute line start position in file (needed for hard seeking in xmt-a)*/
	s32 line_start_pos;
	/*text parsing mode (text with markers), avoids getting rid of \n & co*/
	Bool text_parsing;

	/*file size and pos for user notif*/
	u32 file_size, file_pos;
	/*if set notifies current progress*/
	void (*OnProgress)(void *cbck, u32 done, u32 tot);
	void *cbk;
} XMLParser;

/*inits parser with given local file (handles gzip) - checks UTF8/16*/
M4Err xml_init_parser(XMLParser *parser, const char *fileName);
/*reset parser (closes file and destroy value buffer)*/
void xml_reset_parser(XMLParser *parser);
/*get next element name*/
char *xml_get_element(XMLParser *parser);
/*returns 1 if given element is done*/
Bool xml_element_done(XMLParser *parser, char *name);
/*skip given element*/
void xml_skip_element(XMLParser *parser, char *name);
/*skip element attributes*/
void xml_skip_attributes(XMLParser *parser);
/*returns 1 if element has attributes*/
Bool xml_has_attributes(XMLParser *parser);
/*returns next attribute name*/
char *xml_get_attribute(XMLParser *parser);
/*returns attribute value*/
char *xml_get_attribute_value(XMLParser *parser);
/*translate input string, removing all special XML encoding. Returned string shall be freed by caller*/
char *xml_translate_xml_string(char *str);
/*checks if next line should be loaded - is not needed except when seeking file outside the parser routines*/
void xml_check_line(XMLParser *parser);
/*sets text mode on/off*/
void xml_set_text_mode(XMLParser *parser, Bool text_mode);

/*loads text between elements if any (returns 1) or retruns 0 if no text.
Text data is stored in attribute value buffer*/
Bool xml_load_text(XMLParser *parser);
/*fetches CSS-attribute {name : Val} in the same way as attribute (eg returns Name and stores Val in attribute value buffer)*/
char *xml_get_css(XMLParser *parser);


M4Err import_message(M4TrackImporter *import, M4Err e, char *format, ...);
void import_progress(M4TrackImporter *import, u32 cur_samp, u32 count);


/*
		RTP -> SL packetization tool
	You should ONLY modify the SLHeader while packetizing, all the rest is private
	to the tool.
	Also note that AU start/end is automatically updated, therefore you should only
	set CTS-DTS-OCR-sequenceNumber (which is automatically incremented when spliting a payload)
	-padding-idle infos
	SL flags are computed on the fly, but you may wish to modify them in case of 
	packet drop/... at the encoder side

*/
typedef struct _rtpbuilder
{
	/*input packet sl header cfg. modify oly if needed*/
	SLHeader sl_header;

	/*
	
		PRIVATE _ DO NOT TOUCH
	*/
	
	/*RTP payload type (RFC type, NOT the RTP hdr payT)*/
	u32 rtp_payt;
	/*packetization flags*/
	u32 flags;
	/*Path MTU size without 12-bytes RTP header*/
	u32 Path_MTU;
	/*max packet duration in RTP TS*/
	u32 max_ptime;

	/*payload type of RTP packets - only one payload type can be used in GPAC*/
	u8 PayloadType;

	/*RTP header of current packet*/
	RTPHeader rtp_header;

	/*RTP packet handling callbacks*/
	void (*OnNewPacket)(void *cbk_obj, RTPHeader *header);
	void (*OnPacketDone)(void *cbk_obj, RTPHeader *header);
	void (*OnDataReference)(void *cbk_obj, u32 payload_size, u32 offset_from_orig);
	void (*OnData)(void *cbk_obj, char *data, u32 data_size, Bool is_header);
	void *cbk_obj;
	
	/*rest of struct is for MPEG-4 Generic hinting */
	/*SL to RTP map*/
	RTPSLMap slMap;
	/*SL conf and state*/
	SLConfigDescriptor sl_config;

	/*set to 1 if firstSL in RTP packet*/
	Bool first_sl_in_rtp;
	Bool has_AU_header;
	/*current info writers*/
	BitStream *pck_hdr, *payload;

	/*AU SN of last au*/
	u32 last_au_sn;

	/*info for the current packet*/
	u32 auh_size, bytesInPacket;

	/*ISMACryp info*/
	Bool force_flush, is_encrypted;
	u64 IV, first_AU_IV;
	char *key_indicator;

	/*AVC non-IDR flag: set if all NAL in current packet are non-IDR (disposable)*/
	Bool avc_non_idr;
} M4RTPBuilder;

/*packetization routines*/
M4Err M4RTP_ProcessMPEG4(M4RTPBuilder *builder, char *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize);
M4Err M4RTP_ProcessH263(M4RTPBuilder *builder, char *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize);
M4Err M4RTP_ProcessAMR(M4RTPBuilder *builder, char *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize);
M4Err M4RTP_ProcessMPEG12(M4RTPBuilder *builder, char *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize);
M4Err M4RTP_ProcessText(M4RTPBuilder *builder, char *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize, u32 duration, u8 descIndex);
M4Err M4RTP_ProcessAVC(M4RTPBuilder *builder, char *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize);
M4Err M4RTP_ProcessQCELP(M4RTPBuilder *builder, char *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize);
M4Err M4RTP_ProcessEVRC_SMV(M4RTPBuilder *builder, char *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize);
M4Err M4RTP_ProcessLATM(M4RTPBuilder *builder, char *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize); 

/*RTP track hinter*/
typedef struct _tagM4RTPHinter
{
	M4File *file;
	/*IDs are kept for mp4 hint sample building*/
	u32 TrackNum, TrackID, HintTrack, HintID;
	/*current Hint sample and associated RTP time*/
	u32 HintSample, RTPTime;

	/*track has composition time offset*/
	Bool has_ctts;
	/*remember if first SL packet in RTP packet is RAP*/
	u8 SampleIsRAP;
	u32 base_offset_in_sample;
	u32 OrigTimeScale;
	/*rtp builder*/
	LPM4RTPBUILDER rtp_p;

	void (*OnProgress)(void *cbk_obj, u32 done, u32 total);
	void *cbk_obj;

	u32 bandwidth, nb_chan;

	/*NALU size for H264/AVC*/
	u32 avc_nalu_size;

	/*stats*/
	u32 TotalSample, CurrentSample;
} M4TrackHinterRTP;



M4Err M4SM_LoaderInit_BT(M4ContextLoader *load);
void M4SM_LoaderDone_BT(M4ContextLoader *load);
M4Err M4SM_LoaderRun_BT(M4ContextLoader *load);

M4Err M4SM_LoaderInit_XMT(M4ContextLoader *load);
void M4SM_LoaderDone_XMT(M4ContextLoader *load);
M4Err M4SM_LoaderRun_XMT(M4ContextLoader *load);

M4Err M4SM_LoaderInit_MP4(M4ContextLoader *load);
void M4SM_LoaderDone_MP4(M4ContextLoader *load);
M4Err M4SM_LoaderRun_MP4(M4ContextLoader *load);

M4Err M4SM_LoaderInit_SWF(M4ContextLoader *load);
void M4SM_LoaderDone_SWF(M4ContextLoader *load);
M4Err M4SM_LoaderRun_SWF(M4ContextLoader *load);


#define AVC_NALU_NON_IDR_SLICE 0x1
#define AVC_NALU_DP_A_SLICE 0x2
#define AVC_NALU_DP_B_SLICE 0x3
#define AVC_NALU_DP_C_SLICE 0x4
#define AVC_NALU_IDR_SLICE 0x5
#define AVC_NALU_SEI 0x6
#define AVC_NALU_SEQ_PARAM 0x7
#define AVC_NALU_PIC_PARAM 0x8
#define AVC_NALU_ACCESS_UNIT 0x9
#define AVC_NALU_END_OF_SEQ 0xa
#define AVC_NALU_END_OF_STREAM 0xb
#define AVC_NALU_FILLER_DATA 0xc

#define AVC_TYPE_P 0
#define AVC_TYPE_B 1
#define AVC_TYPE_I 2
#define AVC_TYPE_SP 3
#define AVC_TYPE_SI 4
#define AVC_TYPE2_P 5
#define AVC_TYPE2_B 6
#define AVC_TYPE2_I 7
#define AVC_TYPE2_SP 8
#define AVC_TYPE2_SI 9

/*returns 0 if not a start code, or size of start code (3 or 4 bytes). If start code, bitstream
is positionned AFTER start code*/
u32 AVC_IsStartCode(BitStream *bs);
/*returns size of chunk between current and next startcode (excluding startcode sizes), 0 if no more startcodes (eos)*/
u32 AVC_NextStartCode(BitStream *bs);
/*returns NAL unit type - bitstream must be sync'ed!!*/
u8 AVC_NALUType(BitStream *bs);
/*slice NALU*/
Bool AVC_NALUIsSlice(u8 type);


typedef struct
{
    s32 profile_idc;
    s32 level_idc;
    s32 prof_compat;
    s32 log2_max_frame_num;
    u32 poc_type, poc_cycle_length;
    s32 log2_max_poc_lsb;
    s32 delta_pic_order_always_zero_flag;
	s32 offset_for_non_ref_pic, offset_for_top_to_bottom_field;
	Bool frame_mbs_only_flag;

    s16 offset_for_ref_frame[256];

    s32 timing_info_present_flag;
    u32 num_units_in_tick;
    u32 time_scale;
    s32 fixed_frame_rate_flag;

	u32 width, height;
	/*used to discard repeated SPSs - 0: not parsed, 1 parsed, 2 sent*/
	u32 status;
} AVC_SPS;

typedef struct 
{
    s32 sps_id;
    s32 pic_order_present;      /* pic_order_present_flag*/
    s32 redundant_pic_cnt_present; /* redundant_pic_cnt_present_flag */
    int slice_group_count;      /* num_slice_groups_minus1 + 1*/
	/*used to discard repeated SPSs - 0: not parsed, 1 parsed, 2 sent*/
	u32 status;
} AVC_PPS;

typedef struct
{
	u8 nal_ref_idc, nal_unit_type, field_pic_flag, bottom_field_flag;
	u32 frame_num, idr_pic_id, poc_lsb, slice_type;
	s32 delta_poc_bottom;
	s32 delta_poc[2];
	s32 redundant_pic_cnt;

	s32 poc;
	u32 poc_msb, poc_msb_prev, poc_lsb_prev, frame_num_prev;
	s32 frame_num_offset, frame_num_offset_prev;

	AVC_SPS *sps;
	AVC_PPS *pps;
} AVCSliceInfo;


typedef struct 
{
	u32 frame_cnt;
	u8 exact_match_flag;
	u8 broken_link_flag;
	u8 changing_slice_group_idc;
	u8 valid;
} AVCSeiRecoveryPoint;


typedef struct 
{
	AVCSeiRecoveryPoint recovery_point;
	/*to be eventually completed by other sei*/

} AVCSei;

typedef struct
{
	AVC_SPS sps[32];
	AVC_PPS pps[255];

	AVCSliceInfo s_info;
	AVCSei sei;
} AVCState;

/*return sps ID or -1 if error*/
s32 AVC_ReadSeqInfo(BitStream *bs, AVCState *avc);
/*return pps ID or -1 if error*/
s32 AVC_ReadPictParamSet(BitStream *bs, AVCState *avc);
/*is slice a RAP*/
Bool AVC_SliceIsIDR(AVCState *avc);
/*parses NALU, updates avc state and returns:
	1 if NALU part of new frame
	0 if NALU part of prev frame
	-1 if bitstream error
*/
s32 AVC_ParseNALU(BitStream *bs, u32 nal_hdr, AVCState *avc);
/*remove SEI messages not allowed in MP4*/
u32 AVC_ReformatSEI_NALU(char *buffer, u32 nal_size, AVCState *avc);

#endif

