400 lines
12 KiB
C++
Executable File
400 lines
12 KiB
C++
Executable File
/*
|
|
* Copyright (c) 2008-2016 Allwinner Technology Co. Ltd.
|
|
* All rights reserved.
|
|
*
|
|
* File : subtitleUtils.cpp
|
|
* Description : subtitle util function, including charset convert
|
|
* History :
|
|
* Author : AL3
|
|
* Date : 2015/05/05
|
|
* Comment : create first version
|
|
*
|
|
*/
|
|
|
|
#include "subtitleUtils.h"
|
|
#include "media/mediaplayerinfo.h"
|
|
#include "unicode/ucnv.h"
|
|
#include "unicode/ustring.h"
|
|
#include "cdx_log.h"
|
|
|
|
namespace android {
|
|
|
|
//* the CHARSET_XXX strings is defined in "av/include/media/mediaplayerinfo.h",
|
|
//* and it should be the same as strings defined in "base/media/java/android/media/MediaPlayer.java"
|
|
const char* strTextCodecFormats[] =
|
|
{
|
|
CHARSET_UNKNOWN ,
|
|
CHARSET_BIG5 ,
|
|
CHARSET_BIG5_HKSCS ,
|
|
CHARSET_BOCU_1 ,
|
|
CHARSET_CESU_8 ,
|
|
CHARSET_CP864 ,
|
|
CHARSET_EUC_JP ,
|
|
CHARSET_EUC_KR ,
|
|
CHARSET_GB18030 ,
|
|
CHARSET_GBK ,
|
|
CHARSET_HZ_GB_2312 ,
|
|
CHARSET_ISO_2022_CN ,
|
|
CHARSET_ISO_2022_CN_EXT ,
|
|
CHARSET_ISO_2022_JP ,
|
|
CHARSET_ISO_2022_KR ,
|
|
CHARSET_ISO_8859_1 ,
|
|
CHARSET_ISO_8859_10 ,
|
|
CHARSET_ISO_8859_13 ,
|
|
CHARSET_ISO_8859_14 ,
|
|
CHARSET_ISO_8859_15 ,
|
|
CHARSET_ISO_8859_16 ,
|
|
CHARSET_ISO_8859_2 ,
|
|
CHARSET_ISO_8859_3 ,
|
|
CHARSET_ISO_8859_4 ,
|
|
CHARSET_ISO_8859_5 ,
|
|
CHARSET_ISO_8859_6 ,
|
|
CHARSET_ISO_8859_7 ,
|
|
CHARSET_ISO_8859_8 ,
|
|
CHARSET_ISO_8859_9 ,
|
|
CHARSET_KOI8_R ,
|
|
CHARSET_KOI8_U ,
|
|
CHARSET_MACINTOSH ,
|
|
CHARSET_SCSU ,
|
|
CHARSET_SHIFT_JIS ,
|
|
CHARSET_TIS_620 ,
|
|
CHARSET_US_ASCII ,
|
|
CHARSET_UTF_16 ,
|
|
CHARSET_UTF_16BE ,
|
|
CHARSET_UTF_16LE ,
|
|
CHARSET_UTF_32 ,
|
|
CHARSET_UTF_32BE ,
|
|
CHARSET_UTF_32LE ,
|
|
CHARSET_UTF_7 ,
|
|
CHARSET_UTF_8 ,
|
|
CHARSET_WINDOWS_1250 ,
|
|
CHARSET_WINDOWS_1251 ,
|
|
CHARSET_WINDOWS_1252 ,
|
|
CHARSET_WINDOWS_1253 ,
|
|
CHARSET_WINDOWS_1254 ,
|
|
CHARSET_WINDOWS_1255 ,
|
|
CHARSET_WINDOWS_1256 ,
|
|
CHARSET_WINDOWS_1257 ,
|
|
CHARSET_WINDOWS_1258 ,
|
|
CHARSET_X_DOCOMO_SHIFT_JIS_2007 ,
|
|
CHARSET_X_GSM_03_38_2000 ,
|
|
CHARSET_X_IBM_1383_P110_1999 ,
|
|
CHARSET_X_IMAP_MAILBOX_NAME ,
|
|
CHARSET_X_ISCII_BE ,
|
|
CHARSET_X_ISCII_DE ,
|
|
CHARSET_X_ISCII_GU ,
|
|
CHARSET_X_ISCII_KA ,
|
|
CHARSET_X_ISCII_MA ,
|
|
CHARSET_X_ISCII_OR ,
|
|
CHARSET_X_ISCII_PA ,
|
|
CHARSET_X_ISCII_TA ,
|
|
CHARSET_X_ISCII_TE ,
|
|
CHARSET_X_ISO_8859_11_2001 ,
|
|
CHARSET_X_JAVAUNICODE ,
|
|
CHARSET_X_KDDI_SHIFT_JIS_2007 ,
|
|
CHARSET_X_MAC_CYRILLIC ,
|
|
CHARSET_X_SOFTBANK_SHIFT_JIS_2007 ,
|
|
CHARSET_X_UNICODEBIG ,
|
|
CHARSET_X_UTF_16LE_BOM ,
|
|
CHARSET_X_UTF16_OPPOSITEENDIAN ,
|
|
CHARSET_X_UTF16_PLATFORMENDIAN ,
|
|
CHARSET_X_UTF32_OPPOSITEENDIAN ,
|
|
CHARSET_X_UTF32_PLATFORMENDIAN ,
|
|
NULL
|
|
};
|
|
|
|
|
|
static int SubtitleUtilsConvertUnicode(char* pOutBuf,
|
|
int nOutBufSize,
|
|
SubtitleItem* pSubItem,
|
|
const char* pDefaultTextFormatName)
|
|
{
|
|
const char *pInBuf = pSubItem->pText;
|
|
ESubtitleTextFormat eInputTextFormat = pSubItem->eTextFormat;
|
|
int len = pSubItem->nTextLength;
|
|
|
|
int charset;
|
|
const char* enc;;
|
|
unsigned int subTextLen;
|
|
UErrorCode status;
|
|
UConverter* conv;
|
|
UConverter* utf8Conv;
|
|
const char* src;
|
|
int targetLength;
|
|
char* target;
|
|
|
|
//*if subtitle decoder know charset,use it ,or use app's setting.
|
|
switch(eInputTextFormat)
|
|
{
|
|
case SUBTITLE_TEXT_FORMAT_UTF8:
|
|
enc = CHARSET_UTF_8;
|
|
break;
|
|
|
|
case SUBTITLE_TEXT_FORMAT_GB2312:
|
|
enc = CHARSET_HZ_GB_2312;
|
|
break;
|
|
|
|
case SUBTITLE_TEXT_FORMAT_UTF16LE:
|
|
enc = CHARSET_UTF_16LE;
|
|
break;
|
|
|
|
case SUBTITLE_TEXT_FORMAT_UTF16BE:
|
|
enc = CHARSET_UTF_16BE;
|
|
break;
|
|
|
|
case SUBTITLE_TEXT_FORMAT_UTF32LE:
|
|
enc = CHARSET_UTF_32LE;
|
|
break;
|
|
|
|
case SUBTITLE_TEXT_FORMAT_UTF32BE:
|
|
enc = CHARSET_UTF_32BE;
|
|
break;
|
|
|
|
case SUBTITLE_TEXT_FORMAT_BIG5:
|
|
enc = CHARSET_BIG5;
|
|
break;
|
|
|
|
case SUBTITLE_TEXT_FORMAT_GBK:
|
|
enc = CHARSET_GBK;
|
|
break;
|
|
|
|
case SUBTITLE_TEXT_FORMAT_ANSI: //can not match,set to "UTF-8"
|
|
enc = CHARSET_UTF_8;
|
|
break;
|
|
|
|
default:
|
|
enc = pDefaultTextFormatName;
|
|
break;
|
|
}
|
|
|
|
status = U_ZERO_ERROR;
|
|
|
|
conv = ucnv_open(enc, &status);
|
|
if(U_FAILURE(status))
|
|
{
|
|
logw("could not create UConverter for %s\n", enc);
|
|
memset(pOutBuf, 0, nOutBufSize);
|
|
return -1;
|
|
}
|
|
|
|
utf8Conv = ucnv_open("UTF-8", &status);
|
|
if (U_FAILURE(status))
|
|
{
|
|
logw("could not create UConverter for UTF-8\n");
|
|
memset(pOutBuf, 0, nOutBufSize);
|
|
ucnv_close(conv);
|
|
return -1;
|
|
}
|
|
|
|
//*first we need to untangle the utf8 and convert it back to the original bytes
|
|
// since we are reducing the length of the string, we can do this in place
|
|
src = pInBuf;
|
|
targetLength = len * 3 + 1;
|
|
|
|
//*now convert from native encoding to UTF-8
|
|
if(targetLength > nOutBufSize)
|
|
targetLength = nOutBufSize;
|
|
|
|
memset(pOutBuf, 0, nOutBufSize);
|
|
target = &pOutBuf[0];
|
|
|
|
ucnv_convertEx(utf8Conv,
|
|
conv,
|
|
&target,
|
|
(const char*)target + targetLength,
|
|
&src,
|
|
(const char*)src + len,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
true,
|
|
true,
|
|
&status);
|
|
|
|
if (U_FAILURE(status))
|
|
{
|
|
logw("ucnv_convertEx failed: %d\n", status);
|
|
memset(pOutBuf, 0, nOutBufSize);
|
|
}
|
|
|
|
subTextLen = target - (char*)pOutBuf;
|
|
logv("CedarXTimedText::convertUniCode src = %s, target = %s\n, subTextLen = %d",
|
|
pInBuf, pOutBuf, subTextLen);
|
|
|
|
ucnv_close(conv);
|
|
ucnv_close(utf8Conv);
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
// Store the timing and text sample in a Parcel.
|
|
// The Parcel will be sent to MediaPlayer.java through event, and will be
|
|
// parsed in TimedText.java.
|
|
int SubtitleUtilsFillTextSubtitleToParcel(Parcel* parcelDst,
|
|
SubtitleItem* pSubItem,
|
|
int nSubtitleID,
|
|
const char* strDefaultTextFormatName,
|
|
int* mIsFistItem)
|
|
{
|
|
int nFontStyleIdx;
|
|
int nSubStyleFlag;
|
|
unsigned int nTextLen;
|
|
int nPts;
|
|
|
|
#define MAX_OUTPUT_TEXT_SIZE (1024)
|
|
char strOutText[MAX_OUTPUT_TEXT_SIZE];
|
|
|
|
SubtitleUtilsConvertUnicode(strOutText,
|
|
MAX_OUTPUT_TEXT_SIZE,
|
|
pSubItem,
|
|
strDefaultTextFormatName);
|
|
|
|
nFontStyleIdx = 0;
|
|
nSubStyleFlag = 0;
|
|
nTextLen = strlen((char*)strOutText);
|
|
|
|
parcelDst->writeInt32(KEY_LOCAL_SETTING);
|
|
parcelDst->writeInt32(KEY_START_TIME);
|
|
//* pts in unit of us, write out pts in unit of ms.
|
|
parcelDst->writeInt32((int)(pSubItem->nPts/1000));
|
|
|
|
parcelDst->writeInt32(KEY_STRUCT_TEXT);
|
|
parcelDst->writeInt32(nTextLen); //* write the size of the text sample
|
|
parcelDst->writeInt32(nTextLen); //* write the text sample as a byte array
|
|
parcelDst->write((char*)strOutText, nTextLen);
|
|
|
|
//*set subtitleID
|
|
parcelDst->writeInt32(KEY_SUBTITLE_ID);
|
|
parcelDst->writeInt32(nSubtitleID);
|
|
|
|
if(pSubItem->eAlignment != 0)
|
|
{
|
|
parcelDst->writeInt32(KEY_STRUCT_AWEXTEND_SUBDISPPOS);
|
|
//*write text subtitle's position area.
|
|
parcelDst->writeInt32(pSubItem->eAlignment);
|
|
|
|
parcelDst->writeInt32(KEY_STRUCT_AWEXTEND_SCREENRECT);
|
|
//*write text subtitle's whole screen rect.
|
|
parcelDst->writeInt32(0);
|
|
parcelDst->writeInt32(0);
|
|
parcelDst->writeInt32(pSubItem->nReferenceVideoHeight);
|
|
parcelDst->writeInt32(pSubItem->nReferenceVideoWidth);
|
|
|
|
if(*mIsFistItem == 1)
|
|
{
|
|
parcelDst->writeInt32(KEY_STRUCT_TEXT_POS);
|
|
//*write text subtitle's position Rect.
|
|
parcelDst->writeInt32(pSubItem->nStartY);
|
|
parcelDst->writeInt32(pSubItem->nStartX);
|
|
parcelDst->writeInt32(pSubItem->nEndY);
|
|
parcelDst->writeInt32(pSubItem->nEndX);
|
|
*mIsFistItem = 0;
|
|
}
|
|
}
|
|
|
|
if(pSubItem->nFontSize!=0 && pSubItem->nPrimaryColor!=0)
|
|
{
|
|
//*convert strFontName,bBold,bItalic,bUnderlined
|
|
if(!strcmp(pSubItem->strFontName, SUBTITLE_FONT_NAME_EPILOG))
|
|
nFontStyleIdx = 0;
|
|
else if(!strcmp(pSubItem->strFontName, SUBTITLE_FONT_NAME_VERDANA))
|
|
nFontStyleIdx = 1;
|
|
else if(!strcmp(pSubItem->strFontName, SUBTITLE_FONT_NAME_GEORGIA))
|
|
nFontStyleIdx = 2;
|
|
else if(!strcmp(pSubItem->strFontName, SUBTITLE_FONT_NAME_ARIAL))
|
|
nFontStyleIdx = 3;
|
|
else if(!strcmp(pSubItem->strFontName, SUBTITLE_FONT_NAME_TIMES_NEW_ROMAN))
|
|
nFontStyleIdx = 4;
|
|
else
|
|
nFontStyleIdx = -1;
|
|
|
|
//* In the absence of any bits set in flags, the text
|
|
//* is plain. Otherwise, 1: bold, 2: italic, 4: underline
|
|
if(pSubItem->bBold)
|
|
nSubStyleFlag |= 1<<0;
|
|
if(pSubItem->bItalic)
|
|
nSubStyleFlag |= 1<<1;
|
|
if(pSubItem->bUnderlined)
|
|
nSubStyleFlag |= 1<<2;
|
|
|
|
parcelDst->writeInt32(KEY_STRUCT_STYLE_LIST);
|
|
parcelDst->writeInt32(KEY_FONT_ID);
|
|
parcelDst->writeInt32(nFontStyleIdx);
|
|
parcelDst->writeInt32(KEY_FONT_SIZE);
|
|
parcelDst->writeInt32((int)pSubItem->nFontSize);
|
|
parcelDst->writeInt32(KEY_TEXT_COLOR_RGBA);
|
|
parcelDst->writeInt32((int)pSubItem->nPrimaryColor);
|
|
parcelDst->writeInt32(KEY_STYLE_FLAGS);
|
|
parcelDst->writeInt32(nSubStyleFlag);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Store the timing and text sample in a Parcel.
|
|
// The Parcel will be sent to MediaPlayer.java through event, and will be
|
|
// parsed in TimedText.java.
|
|
int SubtitleUtilsFillBitmapSubtitleToParcel(Parcel* parcelDst,
|
|
SubtitleItem* pSubItem, int nSubtitleID)
|
|
{
|
|
int nBufSize;
|
|
|
|
parcelDst->writeInt32(KEY_LOCAL_SETTING);
|
|
parcelDst->writeInt32(KEY_START_TIME);
|
|
//* pts in unit of us, write out pts in unit of ms.
|
|
parcelDst->writeInt32((int)(pSubItem->nPts/1000));
|
|
|
|
parcelDst->writeInt32(KEY_STRUCT_AWEXTEND_BMP);
|
|
//* write the pixel format of bmp subtitle
|
|
parcelDst->writeInt32(KEY_STRUCT_AWEXTEND_PIXEL_FORMAT);
|
|
#if 0
|
|
parcelDst->writeInt32(pSubItem->ePixelFormat); //* 0: ARGB, 1: YUV, defined in sdecoder.h
|
|
//* but currently only support ARGB.
|
|
#else
|
|
//* application only support PIXEL_FORMAT_RGBA_8888 pixel format, this value will be ignored
|
|
//* at frameworks/base/media/java/android/media/TimeText.java::parseParcel().
|
|
//* so we write zero here.
|
|
if(pSubItem->ePixelFormat != SUBTITLE_PIXEL_FORMAT_ARGB)
|
|
{
|
|
loge("subtitle pixel format is not ARGB, can not handle.");
|
|
abort();
|
|
}
|
|
parcelDst->writeInt32(0);
|
|
#endif
|
|
|
|
//* write the width of bmp subtitle
|
|
parcelDst->writeInt32(KEY_STRUCT_AWEXTEND_PICWIDTH);
|
|
parcelDst->writeInt32(pSubItem->nBitmapWidth);
|
|
|
|
//* write the height of bmp subtitle
|
|
parcelDst->writeInt32(KEY_STRUCT_AWEXTEND_PICHEIGHT);
|
|
parcelDst->writeInt32(pSubItem->nBitmapHeight);
|
|
|
|
//* write the reference video width of bmp subtitle
|
|
parcelDst->writeInt32(KEY_STRUCT_AWEXTEND_REFERENCE_VIDEO_WIDTH);
|
|
parcelDst->writeInt32(pSubItem->nReferenceVideoWidth);
|
|
|
|
//* write the reference video height of bmp subtitle
|
|
parcelDst->writeInt32(KEY_STRUCT_AWEXTEND_REFERENCE_VIDEO_HEIGHT);
|
|
parcelDst->writeInt32(pSubItem->nReferenceVideoHeight);
|
|
|
|
//* write the size of the text sample, we only process PIXEL_FORMAT_RGBA_8888 format currently.
|
|
nBufSize = pSubItem->nBitmapWidth*pSubItem->nBitmapHeight*4;
|
|
parcelDst->writeInt32(nBufSize);
|
|
|
|
//* write the argb buffer as an int32_t array
|
|
parcelDst->writeInt32(nBufSize/4);
|
|
parcelDst->write(pSubItem->pBitmapData, nBufSize);
|
|
|
|
//* set subtitleID
|
|
parcelDst->writeInt32(KEY_SUBTITLE_ID);
|
|
parcelDst->writeInt32(nSubtitleID);
|
|
|
|
return 0;
|
|
}
|
|
|
|
};
|