/**
* Copyright(c) 2011 Sunmedia Technologies - All Rights Reserved.
*
* @file
*
* @brief this file describes subtitle descriptor parsing and supports
* the interface of subtitle module.
*/
#include <sys/ioctl.h>
#include <ctype.h>
#include "gl_types.h"
#include "gl_mutex.h"
#include "al_basictypes.h"
#include "al_subtitle.h"
#ifdef CONFIG_SUPPORT_TTX
#include "ai_teletext.h"
#endif
#include "ai_debug_config.h"
#include "mid_sub_dtv_interface.h"
#include "drv_dtv_external.h"
#include "drv_dtv_common.h"
#include "mid_siutil_dvb.h"
#include "kmf_ioctl.h"
#include "drv_tuner_external.h"
#include "ap_extern.h"
#include "pvrparser.h"
#include "mid_tspl_util.h"
#include "mid_tspl_parser.h"
#ifdef CONFIG_SUPPORT_MHEG5
#include "mid_mheg5.h"
#include "app_iso639.h"
#include "app_data_setting.h"
#endif

#if SUB_DBG_FLAG
	#define SUBTITLE_DEBUG_MESSAGE(fmt, arg...) \
	do { \
		UMFDBG(0,"[Debug]%s: %d Line ", __FUNCTION__, __LINE__); \
		UMFDBG(0,fmt, ##arg); \
	} while(0)
#else
	#define SUBTITLE_DEBUG_MESSAGE(fmt,arg...);
#endif

#if SUB_ERROR_FLAG
	#define SUBTITLE_ERROR_MESSAGE(fmt, arg...) \
	do { \
		UMFDBG(0,"[Error]%s: %d Line ", __FUNCTION__, __LINE__); \
		UMFDBG(0,fmt, ##arg); \
	} while(0)
#else
	#define SUBTITLE_ERROR_MESSAGE(fmt, arg...);
#endif

#define SUBTITLE_MUTEX_LOCK()	{ if(g_pstSubtitleMutex) {GL_MutexLock(g_pstSubtitleMutex);}}
#define SUBTITLE_MUTEX_UNLOCK()	{ if(g_pstSubtitleMutex) {GL_MutexUnlock(g_pstSubtitleMutex);}}

#define MAX_SUBTITLE_NUM				(32) /**< maximal descriptor number for a stream */
#define DESCR_SUBTITLING				0x59	/**< tag of subtitling_descriptor*/

static GL_Mutex_t g_pstSubtitleMutex = NULL;
static al_bool g_bSubtitleInitFlag = al_false;
static AL_Subtitle_Desc_Info_t stSubtitleDescInfo[MAX_SUBTITLE_NUM];
static AL_Subtitle_Desc_Info_t stCurSubtitleDescInfo;
#ifdef CONFIG_SUPPORT_PVR
static al_uint32 Subtitlecurindex = 0;
#endif
static AL_Subtitle_Type_t stSubtitleType = AL_SUBTITLE_TYPE_MAX;
static al_uint32 SubtitleNum = 0;
static al_bool g_bSubtitleStartFlag = al_false;
static al_int32 SubChanHdl = INVALID_HANDLE;

static void _AI_Subtitle_StartRing(al_uint16 Pid)
{
	DMIOC_RINGCFG_PARAM stRingParam;
	memset(&stRingParam, 0, sizeof(DMIOC_RINGCFG_PARAM));
	stRingParam.retval = INVALID_HANDLE;
	stRingParam.DemuxUnit = 0;
	stRingParam.StreamType = DTV_Subtitle;
	stRingParam.RingType = TS_DEMUX_TYPE_PES_SP;
	stRingParam.PID = Pid;
	stRingParam.Queue_ID = NULL;
	ioctl(dtvdev, DTV_IOCTL_RingConfig, &stRingParam);
	DMIOC_SETRING_PARAM stSetParam;
	memset(&stSetParam, 0, sizeof(DMIOC_SETRING_PARAM));
	stSetParam.bEnable = TRUE;
	SubChanHdl = stRingParam.retval;
	stSetParam.Config_idx = stRingParam.retval;
	ioctl(dtvdev, DTV_IOCTL_SetRing, &stSetParam);
}

static al_void _AI_Subtitle_StopRing(al_int32 ChanHdl)
{
	DMIOC_SETRING_PARAM stSetParam;
	memset(&stSetParam, 0, sizeof(DMIOC_SETRING_PARAM));
	stSetParam.bEnable = FALSE;
	stSetParam.Config_idx = ChanHdl;
	ioctl(dtvdev, DTV_IOCTL_SetRing, &stSetParam);
}

/**
* @brief subtitle init function.
*
* This api is used to create mutex for protecting the shared resource and so on.
*
* @param al_void.
*
* @return AL_SUCCESS if initialization is successful, AL_FAILURE otherwise.
*/
AL_Return_t AI_Subtitle_Init(al_void)
{
	GL_Status_t ret = GL_FAILURE;

	if(g_bSubtitleInitFlag)
	{
		SUBTITLE_DEBUG_MESSAGE("Subtitle has been inited!\n");
		return AL_SUCCESS;
	}

	ret = GL_MutexCreate("SubtitleMutex",&g_pstSubtitleMutex);

	if (ret != GL_SUCCESS)
	{
		SUBTITLE_ERROR_MESSAGE("Error %d: %s call GL_SemaphoreCreate for mutex failed!\n", ret, __FUNCTION__);
		goto SUBTITLE_INIT_FAILED;
	}

	g_bSubtitleInitFlag = al_true;

	return AL_SUCCESS;

SUBTITLE_INIT_FAILED:

	if(g_pstSubtitleMutex)
	{
		GL_MutexDelete(g_pstSubtitleMutex);
	}

	g_bSubtitleInitFlag = al_false;

	return AL_FAILURE;
}

/**
* @brief subtitle uninit function.
*
* This api is used to delete mutex for protecting the shared resource and so on.
*
* @param al_void.
*
* @return AL_SUCCESS if uninitialization is successful, AL_FAILURE otherwise.
*/
AL_Return_t AI_Subtitle_Uninit(al_void)
{
	SUBTITLE_MUTEX_LOCK();
	if (g_bSubtitleInitFlag)
	{
		if(g_pstSubtitleMutex)
		{
			GL_MutexDelete(g_pstSubtitleMutex);
			g_pstSubtitleMutex = NULL;
		}
		g_bSubtitleInitFlag = al_false;
	}
	SUBTITLE_MUTEX_UNLOCK();
	return AL_SUCCESS;
}

/**
* @brief subtitle start function.
*
* If the subtitle type is dvb subtitle, the function will start dvb subtitle function that
* creates decoder task and display task. The subtitle page id and pid will be set middleware
* layer. The subtitle data will be gotten to subtitle buffer by openning channel with
* pid, and the decoder task will parse data. Then display task will start to display subtitle
* on the screen.
* If the subtitle type is teletext subtitle, the function will start teletext function that
* creates decoder task and render task. The subtitle page and magazine number and
* pid will be set middleware layer. The teletext data will be gotten to teletext buffer by
* openning channel with pid, and the decode task will parse data with page and magazine
* number. Then render task will start ti display teletext subtitle on the screen.
*
* @param Index user selects subtitle number on the subtitle menu, and using index, the special
* subtitle descriptor information will be gotten from subtitle descriptor buffer.
*
* @param SubtitleType subtitle type.
*
* @return AL_SUCCESS if starting is successful, AL_FAILURE otherwise.
*/
AL_Return_t AL_Subtitle_Start(al_int Index, AL_Subtitle_Type_t SubtitleType)
{
	SUBTITLE_DEBUG_MESSAGE("\n=======AL_Subtitle_Start start!!!!!!!!\n");
	int ret = 0;

	SUBTITLE_MUTEX_LOCK();
#if defined(CONFIG_SUPPORT_MHEG5_HD) && defined(CONFIG_SUPPORT_MHEG5_ICS)
	if (MHEG5_ICS_IsRunning())
	{
#ifdef CONFIG_USE_PROPRIETARY_MHEG5
		if ((al_uint32)Index < SubtitleNum)
		{
			extern APP_SETTING_Feature_t g_stFeatureData;

			UINT8* APP_Language_GetISO639ByIndx(UINT8 Index, APP_Data_LangNameType_e LANType);

			UINT8 *primarySubtitle = APP_Language_GetISO639ByIndx(g_stFeatureData.PreferredSubtitle1st, APP_DATA_LANG_TYPE_SUBTITLE);
			primarySubtitle = primarySubtitle ? primarySubtitle : APP_Language_GetISO639_2ByIndx(g_stFeatureData.PreferredSubtitle1st, APP_DATA_LANG_TYPE_SUBTITLE);
			
			if (primarySubtitle != NULL &&  strcasecmp((char *)stSubtitleDescInfo[Index].Language, (char *)primarySubtitle) != 0)
			{
				primarySubtitle = stSubtitleDescInfo[Index].Language;
			}
			
			UINT8 *secondarySubtitle = NULL;
#ifdef SUPPORT_2ND_PREFER_SUBTITLE
			secondarySubtitle = APP_Language_GetISO639ByIndx(g_stFeatureData.PreferredSubtitle2nd, APP_DATA_LANG_TYPE_SUBTITLE);
			secondarySubtitle = secondarySubtitle ? secondarySubtitle : APP_Language_GetISO639_2ByIndx(g_stFeatureData.PreferredSubtitle2nd, APP_DATA_LANG_TYPE_SUBTITLE);			
#endif
			MHEG5_ICS_SetPrefSubtLang((char*)primarySubtitle, (char*)secondarySubtitle);
		}
#endif
		SUBTITLE_MUTEX_UNLOCK();
		return AL_SUCCESS;
	}
#endif
	if(g_bSubtitleStartFlag == al_true)
	{
		SUBTITLE_DEBUG_MESSAGE("Subtitle has started!\n");
		SUBTITLE_MUTEX_UNLOCK();
		return AL_SUCCESS;
	}
	if(SubtitleType == AL_SUBTITLE_TYPE_DVB_SUBTITLE)
	{
		if ((al_uint32)Index < SubtitleNum)
		{
#ifdef CONFIG_SUPPORT_PVR
			if(MID_TSPLParser_GetThreadState())
			{
				al_uint32 u32PEState = MID_TSPL_MODE_MAX;
				MID_TSPLParser_GetPlayState(&u32PEState, NULL);
				if((u32PEState==MID_TSPL_MODE_PLAY)||(u32PEState==MID_TSPL_MODE_PAUSE)
				   ||(u32PEState==MID_TSPL_MODE_FB)||(u32PEState==MID_TSPL_MODE_FF)
				   ||(u32PEState==MID_TSPL_MODE_SF)||(u32PEState==MID_TSPL_MODE_SB))
				{
				    MID_TSPLParser_SetSubtitleStream(TRUE,stSubtitleDescInfo[Index].id);
				    Subtitlecurindex = Index;
				}
				else
				{
					SUBTITLE_MUTEX_UNLOCK();
					SUBTITLE_ERROR_MESSAGE("set subtitle id error!\n");
					return AL_FAILURE;
				}
			}
			else
#endif
			{
				_AI_Subtitle_StartRing(stSubtitleDescInfo[Index].Pid);
				ret = mid_sub_dtv_open((int)stSubtitleDescInfo[Index].CompositionPageId, (int)stSubtitleDescInfo[Index].AncillaryPageId, 0);
				if(ret == 0)
				{
					SUBTITLE_ERROR_MESSAGE("Dvb Subtitle don't start!\n");
					SUBTITLE_MUTEX_UNLOCK();
					return AL_FAILURE;
				}
				memcpy(&stCurSubtitleDescInfo, &stSubtitleDescInfo[Index], sizeof(AL_Subtitle_Desc_Info_t));
			}
		}
	}
#ifdef CONFIG_SUPPORT_TTX
	else if(SubtitleType == AL_SUBTITLE_TYPE_TTX_SUBTITLE)
	{
		if (AI_TTX_StartSubtitle(Index) == AL_FAILURE)
		{
			SUBTITLE_ERROR_MESSAGE("TTX Subtitle don't start!\n");
			SUBTITLE_MUTEX_UNLOCK();
			return AL_FAILURE;
		}
	}
#endif
	else
	{
		SUBTITLE_ERROR_MESSAGE("invalid Subtitle type!\n");
		SUBTITLE_MUTEX_UNLOCK();
		return AL_FAILURE;
	}

	g_bSubtitleStartFlag = al_true;

	stSubtitleType = SubtitleType;

	SUBTITLE_MUTEX_UNLOCK();
	SUBTITLE_DEBUG_MESSAGE("\n=======AL_Subtitle_Start start success!!!!!!!!\n");

	return AL_SUCCESS;

}

/**
* @brief subtitle stop function.
*
* If the subtitle type is dvb subtitle, the function will delete decoder task and display task
* free the subtitle buffer.
* If the subtitle type is teletext subtitle, the function will suspend teletext decoder thread
* and delete render task.
*
* @param al_void.
*
* @return AL_SUCCESS if stoping is successful, AL_FAILURE otherwise.
*/
AL_Return_t AL_Subtitle_Stop(al_void)
{
	SUBTITLE_MUTEX_LOCK();
#if defined(CONFIG_SUPPORT_MHEG5_HD) && defined(CONFIG_SUPPORT_MHEG5_ICS)
	if (MHEG5_ICS_IsRunning())
	{
		SUBTITLE_MUTEX_UNLOCK();
		return AL_SUCCESS;
	}
#endif

	if(g_bSubtitleStartFlag == al_false)
	{
		SUBTITLE_DEBUG_MESSAGE("Subtitle has stopped!\n");
		SUBTITLE_MUTEX_UNLOCK();
		return AL_SUCCESS;
	}
	if (stSubtitleType == AL_SUBTITLE_TYPE_DVB_SUBTITLE)
	{
#ifdef CONFIG_SUPPORT_PVR
        if(MID_TSPLParser_GetThreadState())
        {
            MID_TSPLParser_SetSubtitleStream(FALSE,stSubtitleDescInfo[Subtitlecurindex].id);
        }
        else
#endif
        {
            mid_sub_dtv_close();
			memset(&stCurSubtitleDescInfo, 0xff, sizeof(AL_Subtitle_Desc_Info_t));
			if(SubChanHdl != INVALID_HANDLE)
			{
            	_AI_Subtitle_StopRing(SubChanHdl);
				SubChanHdl = INVALID_HANDLE;
			}
        }
	}
#ifdef CONFIG_SUPPORT_TTX
	else if (stSubtitleType == AL_SUBTITLE_TYPE_TTX_SUBTITLE)
	{
		if (AI_TTX_StopSubtitle() == AL_FAILURE)
		{
			SUBTITLE_ERROR_MESSAGE("TTX Subtitle don't stop!\n");
			SUBTITLE_MUTEX_UNLOCK();
			return AL_FAILURE;
		}
	}
#endif
	else
	{
		SUBTITLE_ERROR_MESSAGE("invalid Subtitle type!\n");
		SUBTITLE_MUTEX_UNLOCK();
		return AL_FAILURE;
	}

	g_bSubtitleStartFlag = al_false;

	stSubtitleType = AL_SUBTITLE_TYPE_MAX;

	SUBTITLE_MUTEX_UNLOCK();

	return AL_SUCCESS;
}

/**
* @brief subtitle reset function.
*
* The buffer that stores subtitle descriptor information is static buffer, so
* it needs be reset with following initialization or a programe change.
*
* @param al_void.
*
* @return AL_SUCCESS if reseting is successful, AL_FAILURE otherwise.
*/
AL_Return_t AL_Subtitle_Reset(al_void)
{
	SUBTITLE_MUTEX_LOCK();

	SubtitleNum = 0;

	memset(&stSubtitleDescInfo, 0xff, sizeof(AL_Subtitle_Desc_Info_t) * MAX_SUBTITLE_NUM);

	SUBTITLE_MUTEX_UNLOCK();

	return AL_SUCCESS;
}


/**
* @brief subtitle restart function.
*
* Stop and restart subtitle if the selected subtitle is different from the one which is playing.
*
* @param Index user selects subtitle number on the subtitle menu, and using index, the special
* subtitle descriptor information will be gotten from subtitle descriptor buffer.
*
* @param SubtitleType subtitle type.
*
* @return AL_SUCCESS if starting is successful, AL_FAILURE otherwise.
*/
AL_Return_t AL_Subtitle_Restart(al_int Index, AL_Subtitle_Type_t SubtitleType)
{
	if(SubtitleType == AL_SUBTITLE_TYPE_DVB_SUBTITLE)
	{
#ifdef CONFIG_SUPPORT_PVR
		if(MID_TSPLParser_GetThreadState())
		{
			AL_Subtitle_Stop();
			AL_Subtitle_Start(Index, SubtitleType);
			return AL_SUCCESS;
		}
#endif
	
		SUBTITLE_MUTEX_LOCK();

		if(memcmp(&stSubtitleDescInfo[Index], &stCurSubtitleDescInfo, sizeof(AL_Subtitle_Desc_Info_t)) == 0) // the same as current subtitle, ignore it
		{
			SUBTITLE_MUTEX_UNLOCK();
			return AL_SUCCESS;
		}

		SUBTITLE_MUTEX_UNLOCK();

		AL_Subtitle_Stop();
		return AL_Subtitle_Start(Index, SubtitleType);
	}
#ifdef CONFIG_SUPPORT_TTX
	else if(SubtitleType == AL_SUBTITLE_TYPE_TTX_SUBTITLE)
	{
		AL_Subtitle_Stop();
		return AL_Subtitle_Start(Index, SubtitleType);
	}
#endif

	return AL_FAILURE;
}

/**
* @brief the function can get the valid subtitle descriptor total number.
*
* Before the subtitle module starts to work, it needs get the subtitle descpritor
* total number. if the total number is more than 0, the subtitle module will start
* to work. otherwise stop to work.
*
* @param *GetTotalNum get the dvb subtitle total number.
*
* @return AL_SUCCESS if getting total number is successful, AL_FAILURE otherwise.
*/
AL_Return_t AL_Subtitle_GetTotalNum(al_uint32 *GetTotalNum)
{
	if(GetTotalNum == al_null)
	{
		return AL_FAILURE;
	}
	SUBTITLE_MUTEX_LOCK();

	*GetTotalNum = SubtitleNum;

	if (*GetTotalNum <= 0)
	{
		//SUBTITLE_DEBUG_MESSAGE("Get invalid subtitle number!\n");
		SUBTITLE_MUTEX_UNLOCK();
		return AL_FAILURE;
	}

	SUBTITLE_MUTEX_UNLOCK();

	return AL_SUCCESS;

}

/**
* @brief the function can get the parsed subtitle descriptor information.
*
* After creating the subtitle menu with pressing subtitle key, the subtitle menu
* with all subtitle types will be shown on the screen. So when displayed information
* is inited, the parsed subtitle descriptor information will be gotten.
*
* @note Index value is less than the total subtitle descriptor number.
*
* @param Index using the index can get special subtitle descriptor information from
* the buffer.
*
* @param *SubtitleDescInfo it will store the gotten subtitle descriptor information.
*
* @return AL_SUCCESS if getting subtitle descriptor information is successful,
* AL_FAILURE otherwise.
*/
AL_Return_t AL_Subtitle_GetDescInfo(al_int Index, AL_Subtitle_Desc_Info_t *SubtitleDescInfo)
{
	if((SubtitleDescInfo == al_null) || (Index < 0))
	{
		return AL_FAILURE;
	}
	SUBTITLE_MUTEX_LOCK();

	if ((al_uint32)Index <= SubtitleNum)
	{
		memcpy(SubtitleDescInfo, &stSubtitleDescInfo[Index], sizeof(AL_Subtitle_Desc_Info_t));
		SUBTITLE_MUTEX_UNLOCK();
		return AL_SUCCESS;
	}

	SUBTITLE_MUTEX_UNLOCK();

	return AL_FAILURE;
}

/**
* @brief the function can get the subtitle start status.
*
* @param* None.
*
* @return AL_SUCCESS if getting subtitle start flag is true,
* AL_FAILURE otherwise.
*/
AL_Return_t AL_Subtitle_GetStartFlag(void)
{
	if (g_bSubtitleStartFlag)
	{
		return AL_SUCCESS;
	}
	return AL_FAILURE;
}

/**
* @brief the function can set subtitle display window freezed or not.
*
* After the video is freezed with pressing freeze key, if the subtitle is
* displaying on the screen, the subtitle needs be freezed. Else the
* video isn't freezed with pressing freeze key again,  if the subtitle is
* displaying on the screen, the subtitle needn't be freezed.
*
* @param FreezeStatus if freeze is true, the subtitle needs be freezed.
* Else if freeze is false, the subtitle needn't be freezed.
*
* @return AL_SUCCESS if setting freeze is successful,
* AL_FAILURE otherwise.
*/
AL_Return_t AL_Subtitle_SetFreeze(al_bool FreezeStatus)
{
	SUBTITLE_MUTEX_LOCK();

	if (stSubtitleType == AL_SUBTITLE_TYPE_MAX)
	{
		SUBTITLE_ERROR_MESSAGE("invalid subtitle type!\n");
		SUBTITLE_MUTEX_UNLOCK();
		return AL_FAILURE;
	}
	else if (stSubtitleType == AL_SUBTITLE_TYPE_DVB_SUBTITLE)
	{
		mid_sub_dtv_pause(FreezeStatus);
	}
#ifdef CONFIG_SUPPORT_TTX
	else
	{
		AI_TTX_SetSubtitleFreeze(FreezeStatus);
	}
#endif
	SUBTITLE_MUTEX_UNLOCK();

	return AL_SUCCESS;
}

/**
* @brief the function can get file ts subtitle information from pe module
*
* when play recorded file, if need to display subtitle on the screen, the file ts
*subtitle information need to be gotten from pe module.
*
* @param al_void.
*
* @return AL_SUCCESS if getting file ts subtitle information is successful,
* AL_FAILURE otherwise.
*/
#ifdef CONFIG_SUPPORT_PVR
AL_Return_t AL_Subtitle_GetFileTsSubInfo(al_void)
{
	al_int Ret;
	al_uint32 Subtitle_Num = 0;
    al_int subtitle_id;
	al_uint8 i;
    TS_SUB_PG_t Subtitle_Program_Info;

	SUBTITLE_MUTEX_LOCK();

    MID_TSPLParser_GetTotalSubtitleStreamCount(&Subtitle_Num);
    for (i = 0; i < Subtitle_Num; i++)
    {
        memset(&Subtitle_Program_Info, 0x0, sizeof(TS_SUB_PG_t));
        subtitle_id = MID_TSPL_PVR_GetSubtitleID(i);
        Ret = MID_TSPLParser_GetSubtitleAttribute(i,&Subtitle_Program_Info);
        if (Ret != 0)
        {
            continue;
        }
		if((Subtitle_Program_Info.type == TS_SUBTITLE_SUB) && (SubtitleNum < MAX_SUBTITLE_NUM))
		{
            stSubtitleDescInfo[SubtitleNum].id = subtitle_id;
            stSubtitleDescInfo[SubtitleNum].Pid = Subtitle_Program_Info.pid;
			stSubtitleDescInfo[SubtitleNum].Type = Subtitle_Program_Info.sub.subtitling_type;
			stSubtitleDescInfo[SubtitleNum].CompositionPageId = Subtitle_Program_Info.sub.composition_page_id;
			stSubtitleDescInfo[SubtitleNum].AncillaryPageId = Subtitle_Program_Info.sub.ancillary_page_id;
			memcpy(stSubtitleDescInfo[SubtitleNum].Language, Subtitle_Program_Info.sub.ISO_639_language_code,
				sizeof(al_uint8)*LANG_CODE_SIZE);
			SubtitleNum++;
		}
#ifdef CONFIG_SUPPORT_TTX
		if(Subtitle_Program_Info.type == TS_SUBTITLE_TTX)
		{
			AL_TTX_Desc_Info_t TTXSubInfo;
			memset(&TTXSubInfo, 0xff, sizeof(AL_TTX_Desc_Info_t));
			if((Subtitle_Program_Info.ttx.teletext_type == 0x02)//teletext subtitle page
				|| (Subtitle_Program_Info.ttx.teletext_type == 0x05))//teletext subtitle page for hearing impaired people
			{
				TTXSubInfo.id = subtitle_id;
				TTXSubInfo.Pid = Subtitle_Program_Info.pid;
				TTXSubInfo.Type = Subtitle_Program_Info.ttx.teletext_type;
				TTXSubInfo.MagazineNum = Subtitle_Program_Info.ttx.teletext_magazine_number;
				if(TTXSubInfo.MagazineNum == 0)
				{
					TTXSubInfo.MagazineNum = 8;
				}
				TTXSubInfo.PageNum = Subtitle_Program_Info.ttx.teletext_page_number;
				memcpy(TTXSubInfo.Language, Subtitle_Program_Info.ttx.ISO_639_language_code,
					sizeof(al_uint8)*LANG_CODE_SIZE);
				AI_TTX_GetFileTsSubInfo(TTXSubInfo);
			}
		}
#endif
    }
	SUBTITLE_MUTEX_UNLOCK();
    return AL_SUCCESS;
}
#endif

/**
* @brief the function can parse subtitle descriptor in PMT.
*
* After parsing PMT, PSI listener will start to work. When the stream
* type is private data of PES packet, and the descriptor type is subtitle
* descriptor, the subtitle descriptor will be parsing. When parsing the
* subtitle descriptor, the information: subtitle pid, subtitle language,
* subtitle type, composition page id and ancillary page id will be
* stored to subtitle buffer.
*
* @param *Data subtitle descpriptor data.
*
* @param DataLen the number of bytes of descriptors.
*
* @param Pid subtitle pid.
*
* @return AL_SUCCESS if parsing subtitle descriptor is successful,
* AL_FAILURE otherwise .
*/
AL_Return_t AL_Subtitle_ParseDesc(al_uint8 *Data, al_uint16 DataLen, al_uint16 Pid)
{
	al_uint8 u8DescTag = 0;
	al_uint8 u8DescLen = 0;
	al_uint8 u8DescPos = 0;
	al_uint16 u16Pos = 0;
	al_bool bRedundantFlag = al_false;
	al_uint32 i;
	AL_Subtitle_Desc_Info_t SubtitleDescInfo;

	if(Data == al_null)
	{
		return AL_FAILURE;
	}
	SUBTITLE_MUTEX_LOCK();
	while (u16Pos < DataLen && SubtitleNum < MAX_SUBTITLE_NUM)
	{
		u8DescTag = Data[u16Pos++];
		u8DescLen = Data[u16Pos++];
		if (u8DescTag == DESCR_SUBTITLING)
		{
			u8DescPos = 0;
			while (u8DescPos + 8 <= u8DescLen && SubtitleNum < MAX_SUBTITLE_NUM)
			{
				memset(&SubtitleDescInfo, 0, sizeof(AL_Subtitle_Desc_Info_t));
				/**< get subtitle descriptor pid */
				SubtitleDescInfo.Pid = Pid;
				/**< get subtitle descriptor language. If the gotten language code is lower char code,
				lower char code will be transformed to upper char code */
				memcpy(SubtitleDescInfo.Language, Data + u16Pos + u8DescPos, sizeof(al_uint8)*LANG_CODE_SIZE);
				SubtitleDescInfo.Language[0] = toupper(SubtitleDescInfo.Language[0]);
				SubtitleDescInfo.Language[1] = toupper(SubtitleDescInfo.Language[1]);
				SubtitleDescInfo.Language[2] = toupper(SubtitleDescInfo.Language[2]);

				u8DescPos += 3;
				/**< get subtitle type */
				SubtitleDescInfo.Type = Data[u16Pos + u8DescPos];

				u8DescPos++;
				/**< get subtitle composition page id */
				SubtitleDescInfo.CompositionPageId =
					Data[u16Pos + u8DescPos] << 8 | Data[u16Pos + u8DescPos + 1];

				u8DescPos += 2;
				
				/**< get subtitle ancillary page id */
				SubtitleDescInfo.AncillaryPageId =
					Data[u16Pos + u8DescPos] << 8 | Data[u16Pos + u8DescPos + 1];

				u8DescPos += 2;

				/**< check redundant content */
				bRedundantFlag = al_false;

				for (i=0; i<SubtitleNum; i++)
				{
					if(memcmp(&stSubtitleDescInfo[i], &SubtitleDescInfo, sizeof(AL_Subtitle_Desc_Info_t)) == 0)
					{
						bRedundantFlag = al_true;
						break;
					}
				}
				if (bRedundantFlag == al_false)
				{
					memcpy(&stSubtitleDescInfo[SubtitleNum], &SubtitleDescInfo, sizeof(AL_Subtitle_Desc_Info_t));
					SubtitleNum++;
				}
			}
		}
		u16Pos += u8DescLen;
	}

	SUBTITLE_MUTEX_UNLOCK();

	return AL_SUCCESS;
}

