// // Copyright 2010 The Android Open Source Project // // The Display dispatcher. // //#define LOG_NDEBUG 0 #define LOG_TAG "subtitleNativeDisplay" #include "log.h" #include "cdx_config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif #include "unicode/ucnv.h" #include "unicode/ustring.h" #ifdef __cplusplus } #endif #include "subtitleNativeDisplay.h" #include "ui/DisplayInfo.h" #include "native_window.h" #include "SkDevice.h" #include "sdecoder.h" #include #include #include #define BASELAYER 8 //5, 3, higher number layer is on topper. #define TOPBASELAYER 8 //5, 3 #define BOTTOMBASELAYER 8 #define LAYER_MULTIPLIER 10000 #define LAYER_OFFSET 1000 #define TRANSPARENT_COLOR 0x00050107 #define MAX_TEXTLINE 3 #define MAX_FONTHEIGHT 36 #define SUB_DISPLAY 0 #define FONT_SIZE_UNIT 16 #define DEFAULT_TEXT_SIZE 24 #define SUB_SHOW_NEW_VALID 1 #define SUB_SHOW_OLD_VALID 2 #define SUB_SHOW_INVALID 0 #define SUB_HAS_NONE_COLOR 0 #define SUB_HAS_DEFINED_COLOR 1 #define SUB_HAS_DEFINED_FONTSIZE 1 #define SUB_HAS_NONE_FONTSIZE 0 #define SUB_HAS_DEFINED_STYLE 1 #define SUB_HAS_NONE_STYLE 0 #define SUB_INIT_SET_FONT_INFO 1 #define SUB_USER_SET_FONT_INFO 2 #define PROP_SUBTITLE_MAXFONTSIZE_KEY "media.stagefright.maxsubfont" #define SAVE_BITMAP_TO_PNG 0 #if SAVE_BITMAP_TO_PNG static bool save(const char filename[], SkBitmap &bitmap) { //remove(filename); if(!SkImageEncoder::EncodeFile(filename, bitmap, SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality)) { printf("save png %s failed \n",filename); } printf("%s saved ok\n",filename); return true; } #endif namespace android { static SkBitmap::Config convertPixelFormat(PixelFormat ePixelFormat) { switch (ePixelFormat) { case PIXEL_FORMAT_RGBX_8888: { return SkBitmap::kARGB_8888_Config; } case PIXEL_FORMAT_RGBA_8888: { return SkBitmap::kARGB_8888_Config; } case PIXEL_FORMAT_RGBA_4444: { return SkBitmap::kARGB_4444_Config; } case PIXEL_FORMAT_RGB_565: { return SkBitmap::kRGB_565_Config; } //case PIXEL_FORMAT_A_8: return SkBitmap::kA8_Config; default: { return SkBitmap::kNo_Config; } } } static inline int is_ws_(int ch) { return !((ch - 1) >> 5); } static inline int is_break(int c1,int c2) { if(c1 == 0x0D && c2 == 0x0A) { return true; } return false; } static size_t subLineBreak(const char cText[], const char cStop[], const SkPaint& paint, SkScalar margin,size_t *drawCount, int specialEffectFlag, SkScalar* lineWidth) { const char* pStart =NULL; #if(CONFIG_OS_VERSION == OPTION_OS_VERSION_ANDROID_4_2) SkAutoGlyphCache ac(paint, NULL); #else SkAutoGlyphCache ac(paint, NULL, NULL); #endif SkGlyphCache* cache = NULL; SkFixed w = 0; SkFixed limit=0; SkAutoKern autokern; size_t count = 0; const char* pWord_start = NULL; int prevWS = true; int isbreak = false; int forbidBreakFlag = 0; const char* pPrevText = NULL; const char* breaktext = NULL; SkUnichar uni; int currWS; SkUnichar nextuni; pStart = cText; cache = ac.getCache(); limit = SkScalarToFixed(margin); pWord_start = cText; forbidBreakFlag = ((specialEffectFlag==SUB_RENDER_EFFECT_BANNER_LTOR)|| (specialEffectFlag==SUB_RENDER_EFFECT_BANNER_RTOL)|| (specialEffectFlag==SUB_RENDER_EFFECT_KARAOKE)); while (cText < cStop) { pPrevText = cText; uni = SkUTF8_NextUnichar(&cText); currWS = is_ws_(uni); const SkGlyph& mGlyph = cache->getUnicharMetrics(uni); if (!currWS && prevWS) { pWord_start = pPrevText; } prevWS = currWS; if(uni == 0x0D) { breaktext = cText; nextuni = SkUTF8_NextUnichar(&breaktext); if(nextuni == 0x0A) { isbreak = true; } else { count += SkUTF8_CountUTF8Bytes(pPrevText); } } else { count += SkUTF8_CountUTF8Bytes(pPrevText); } w += autokern.adjust(mGlyph) + mGlyph.fAdvanceX; //if ((w > limit) || isbreak) if(isbreak ||((w>limit)&&(forbidBreakFlag==0))) { if (currWS) // eat the rest of the whitespace { *drawCount = count; while (cText < cStop && is_ws_(SkUTF8_ToUnichar(cText))) { cText += SkUTF8_CountUTF8Bytes(cText); } } else // backup until a whitespace (or 1 char) { if (pWord_start == pStart) { if (pPrevText > pStart) { cText = pPrevText; } } else { cText = pWord_start; } *drawCount = cText - pStart; } break; } } *lineWidth = (w>limit)? ((SkScalar)(limit>>16)): ((SkScalar)(w>>16)); if(cText >= cStop) { *drawCount = count; } return cText - pStart; } int CedarXSubTextBox::countLines(const char* pText, size_t len, const SkPaint& paint, SkScalar mWidth, SkScalar* subTextWidth, int specialEffectFlag) { const char* stop = pText + len; int nCount = 0; size_t charCount; SkScalar lineWidth = 0; *subTextWidth = 0; if (mWidth > 0) { do { nCount += 1; pText += subLineBreak(pText, stop, paint, mWidth, &charCount, specialEffectFlag, &lineWidth); if(*subTextWidth < lineWidth) { *subTextWidth = lineWidth; } } while (pText < stop); } return nCount; } ////////////////////////////////////////////////////////////////////////////// CedarXSubTextBox::CedarXSubTextBox() { mFBox.setEmpty(); mFSpacingMul = SK_Scalar1; mFSpacingAdd = 0; fMode = CedarXSubTextBoxLineBreak_Mode; fSpacingAlign = CedarXSubTextBoxEnd_SpacingAlign; mLastDispXPos = -1; mLastDispYPos = -1; } void CedarXSubTextBox::setMode(CedarXSubTextBoxMode mode) { fMode = SkToU8(mode); } void CedarXSubTextBox::setSpacingAlign(CedarXSubTextBoxSpacingAlign align) { fSpacingAlign = SkToU8(align); } void CedarXSubTextBox::subGetBox(SkRect* box) const { if (box) { *box = mFBox; } } void CedarXSubTextBox::subSetBox(const SkRect& box) { mFBox = box; } void CedarXSubTextBox::subSetBox(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) { mFBox.set(left, top, right, bottom); } void CedarXSubTextBox::subGetSpacing(SkScalar* mul, SkScalar* add) const { if (mul) { *mul = mFSpacingMul; } if (add) { *add = mFSpacingAdd; } } void CedarXSubTextBox::subSetSpacing(SkScalar mul, SkScalar add) { mFSpacingMul = mul; mFSpacingAdd = add; } int CedarXSubTextBox::getLastXPos() { return mLastDispXPos; } int CedarXSubTextBox::getLastYPos() { return mLastDispYPos; } ///////////////////////////////////////////////////////////////////////////////////////////// int CedarXSub::Show() { if(mShow == false) { mSurfaceControl->show(); mShow = true; } return NO_ERROR; } int CedarXSub::Hide() { if(mShow == true) { mSurfaceControl->hide(); mShow = false; } return NO_ERROR; } int CedarXSub::setZorderBottom() { mSurfaceControl->setLayer(mBottomBaseLayer); return NO_ERROR; } int CedarXSub::setZorderTop() { mSurfaceControl->setLayer(mTopBaseLayer); return NO_ERROR; } int CedarXSub::setLayer(int layer) { if(mShow == true) { SurfaceComposerClient::openGlobalTransaction(); mSurfaceControl->setLayer(layer); SurfaceComposerClient::closeGlobalTransaction(); } mLayer = layer; return NO_ERROR; } int CedarXSub::getLayer() { return mLayer; } int CedarXSub::setBackColor(int color) { if(mBackColor != color) { mBackColor = color; if(mShow == true) { startRender(); render(); endRender(); } } return NO_ERROR; } int CedarXSub::getBackColor() { return mBackColor; } int CedarXSub::getBitmapFormat() { int format; //format = (int)get_bitmap_format(); return PIXEL_FORMAT_RGBA_8888; } int CedarXSub::mapDecToRender(int deccharset) { switch(deccharset) { case SUB_ENCODING_UTF8: return SUB_CHARSET_UTF_8; case SUB_ENCODING_UTF16LE: return SUB_CHARSET_UTF_16LE; case SUB_ENCODING_UTF32LE: return SUB_CHARSET_UTF_32LE; case SUB_ENCODING_UTF32BE: return SUB_CHARSET_UTF_32BE; case SUB_ENCODING_BIG5: return SUB_CHARSET_BIG5; case SUB_ENCODING_GBK: return SUB_CHARSET_GBK; case SUB_ENCODING_UTF16BE: return SUB_CHARSET_UTF_16BE; default: return SUB_CHARSET_UNKNOWN; } } int CedarXSub::convertUniCode(sub_item_inf *sub_info) { int charset; const char* enc = NULL; //logd("******************CedarXSub::convertUniCode sub_info->encodingType = %d mCharset=%d",sub_info->encodingType,mCharset); charset = sub_info->encodingType; //mapDecToRender(sub_info->encodingType); if(charset == SUBTITLE_TEXT_FORMAT_UNKNOWN) { charset = mCharset; } #if 0 logd("((((((((((((((((((((((((((((((((((((((((((((( CedarXSub::convertUniCode charset = %d",charset); logd("CedarXSub::convertUniCode!sub_info->subTextBuf = %s",sub_info->subTextBuf); char fname[128]; sprintf(fname, "/data/camera/fuqiang.txt"); FILE *fp = fopen(fname, "w"); fwrite((void *)sub_info->subTextBuf, sub_info->subTextLen, 1, fp); fflush(fp); fclose(fp); #endif switch(charset) { case SUBTITLE_TEXT_FORMAT_UTF8: enc = "UTF-8"; break; case SUBTITLE_TEXT_FORMAT_GB2312: enc = "HZ-GB-2312" ; break; case SUBTITLE_TEXT_FORMAT_UTF16LE: enc = "UTF-16LE"; break; case SUBTITLE_TEXT_FORMAT_UTF16BE: enc = "UTF-16BE"; break; case SUBTITLE_TEXT_FORMAT_UTF32LE: enc = "UTF-32LE"; break; case SUBTITLE_TEXT_FORMAT_UTF32BE: enc = "UTF-32BE"; break; case SUBTITLE_TEXT_FORMAT_BIG5: enc = "Big5"; break; case SUBTITLE_TEXT_FORMAT_GBK: enc = "GBK"; break; case SUBTITLE_TEXT_FORMAT_ANSI: //can not match,set to "UTF-8" enc = "UTF-8"; break; default: enc = "UTF-8"; break; } if (enc) { UErrorCode status = U_ZERO_ERROR; UConverter *conv = ucnv_open(enc, &status); if (U_FAILURE(status)) { logw("could not create UConverter for %s\n", enc); return -1; } UConverter *utf8Conv = ucnv_open("UTF-8", &status); if (U_FAILURE(status)) { logw("could not create UConverter for UTF-8\n"); 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 const char* src = (const char*)sub_info->subTextBuf; int len = sub_info->subTextLen; // now convert from native encoding to UTF-8 int targetLength = len * 3 + 1; memset(mText,0,MAX_SUBLENGTH); char* target = &mText[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(mText,0,MAX_SUBLENGTH); } logv("CedarXSub::convertUniCode src = %s, mText: %s\n",sub_info->subTextBuf, mText); ucnv_close(conv); ucnv_close(utf8Conv); } return NO_ERROR; } //*************************************************************************************************// //*************************************************************************************************// int CedarXSub::setPosition(int posX,int posY) { if(true) { size_t count; int posx; int posy; mPosX = posX; mPosY = posY; if(mPosX + mMaxWidth > mScreenWidth) { //mPosX = mScreenWidth - mMaxWidth; mMaxWidth = mScreenWidth - mPosX; } if(mPosY + mMaxHeight > mScreenHeight) { //mPosY = mScreenHeight - mMaxHeight; mMaxHeight = mScreenHeight - mPosY; } SurfaceComposerClient::openGlobalTransaction(); mSurfaceControl->setPosition(mPosX,mPosY); SurfaceComposerClient::closeGlobalTransaction(); } return NO_ERROR; } int CedarXSub::setPositionYPercent(int percent) { int maxYPos = 0; if(mSubMode & PIC_SUBTITLE) { mPosY = (mScreenHeight - mMaxHeight)* (100 - percent) / 100; if(mPosY + mMaxHeight > mScreenHeight) { mPosY = mScreenHeight - mMaxHeight; } logd("2@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ %d %d", mPosX, mPosY); mSurfaceControl->setPosition(mPosX,mPosY); } else if((mShow == true) && (mSubMode & TEXT_SUBTITLE)) { maxYPos = mScreenHeight*(100-percent)/100; if(mEndy > maxYPos) { mEndy = maxYPos; } if((mEndy-mStarty)subSetBox(0,0,SkIntToScalar(mEndx-mStartx),SkIntToScalar(mEndy-mStarty)); } return NO_ERROR; } int CedarXSub::getPositionX() { return mPosX; } int CedarXSub::getPositionY() { return mPosY; } int CedarXSub::getWidth() { return mWidth; } int CedarXSub::getHeight() { return mHeight; } int CedarXSub::setFontSize(int fontsize) { int len; SkScalar textBoxHeight; if(mSubMode & PIC_SUBTITLE) { return NO_ERROR; } if(fontsize != mFontSize) { mFontSize = fontsize; mPaint.setTextSize(fontsize * mFontScaleRatio / FONT_SIZE_UNIT); if(mShow == true) { len = strlen((char*)mText); mTextBox->getTextVerInf(mText,len,mPaint,&mTextHeight,&mTextWidth, &textBoxHeight, mStartx, mEndx, mStarty, mEndy, mDispSubInfo->subEffectFlag); needModifyBoxInf(textBoxHeight); setPosition(mStartx,mStarty); mTextBox->subSetBox(0,0,SkIntToScalar(mEndx-mStartx),SkIntToScalar(mEndy-mStarty)); startRender(); render(); endRender(); } } return NO_ERROR; } int CedarXSub::getFontSize() { return mFontSize; } int CedarXSub::setTextColor(int color) { if(mTextColor != (unsigned int)color) { mTextColor = (unsigned int)color; mPaint.setColor(mTextColor); if(mShow == true) { startRender(); render(); endRender(); } } return NO_ERROR; } int CedarXSub::getTextColor() { return mTextColor; } int CedarXSub::setCharset(int Charset) { mCharset = Charset; return NO_ERROR; } int CedarXSub::getCharset() { return mCharset; } int CedarXSub::setTextAlign(int align) { if(mTextAlign != align) { mTextAlign = align; if((align & SUN_RENDER_HALIGN_MASK) == SUB_RENDER_HALIGN_LEFT) { mPaint.setTextAlign(SkPaint::kLeft_Align); } else if((align & SUN_RENDER_HALIGN_MASK) == SUB_RENDER_HALIGN_CENTER) { mPaint.setTextAlign(SkPaint::kCenter_Align); } else if((align & SUN_RENDER_HALIGN_MASK) == SUB_RENDER_HALIGN_RIGHT) { mPaint.setTextAlign(SkPaint::kRight_Align); } else { mPaint.setTextAlign(SkPaint::kLeft_Align); } if((align & SUN_RENDER_VALIGN_MASK) == SUB_RENDER_VALIGN_TOP) { if(mTextBox != NULL) { mTextBox->setSpacingAlign(CedarXSubTextBox::CedarXSubTextBoxStart_SpacingAlign); } } else if((align & SUN_RENDER_VALIGN_MASK) == SUB_RENDER_VALIGN_CENTER) { if(mTextBox != NULL) { mTextBox->setSpacingAlign(CedarXSubTextBox::CedarXSubTextBoxCenter_SpacingAlign); } } else if((align & SUN_RENDER_VALIGN_MASK) == SUB_RENDER_VALIGN_BOTTOM) { if(mTextBox != NULL) { mTextBox->setSpacingAlign(CedarXSubTextBox::CedarXSubTextBoxEnd_SpacingAlign); } } else { if(mTextBox != NULL) { mTextBox->setSpacingAlign(CedarXSubTextBox::CedarXSubTextBoxStart_SpacingAlign); } } if(mShow == true) { startRender(); render(); endRender(); } } return NO_ERROR; } int CedarXSub::getTextAlign() { return mTextAlign; } int CedarXSub::setFontStyle(int style) { if(mFontStyle != style) { mFontStyle = style; if((style & SUB_RENDER_STYLE_BOLD) == SUB_RENDER_STYLE_BOLD) { mPaint.setFakeBoldText(true); } else { mPaint.setFakeBoldText(false); } if((style & SUB_RENDER_STYLE_ITALIC) == SUB_RENDER_STYLE_ITALIC) { mPaint.setLinearText(true); } else { mPaint.setLinearText(false); } if((style & SUB_RENDER_STYLE_UNDERLINE) == SUB_RENDER_STYLE_UNDERLINE) { mPaint.setUnderlineText(true); } else { mPaint.setUnderlineText(false); } if((style & SUB_RENDER_STYLE_STRIKETHROUGH) == SUB_RENDER_STYLE_STRIKETHROUGH) { mPaint.setStrikeThruText(true); } else { mPaint.setStrikeThruText(false); } if(mShow == true) { startRender(); render(); endRender(); } } return NO_ERROR; } int CedarXSub::getFontStyle() { return mFontStyle; } //************************************************************************************************// //*************************************************************************************************// CedarXSubRender::CedarXSubRender() { sp cedarXSub; logd("CedarXSubRender::CedarXSubRender xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1"); mUserSetFontColor = 0; mUserSetFontSize = 20; mUserSetFontStyle = 0; mUserSetYPercent = 10; sub_pre = NULL; mInitSetFontColor = 0; mInitSetFontSize = 0; mInitSetFontStyle = 0; mDisplay = 0; mPid = 0; mBaseLayer = 0; cedarXSub = new CedarXSub(0, mUserSetFontColor, mUserSetFontSize, mUserSetFontStyle, mUserSetYPercent); logd("CedarXSubRender::CedarXSubRender xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx2"); /*create main cedarXSub*/ mCedarXSubs.add(cedarXSub); } CedarXSubRender::~CedarXSubRender() { logd("CedarXSubRender::~CedarXSubRender!xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); } int CedarXSubRender::cedarxSubShow() { size_t count; logv("CedarXSubRender::cedarxSubShow!xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); count = mCedarXSubs.size(); SurfaceComposerClient::openGlobalTransaction(); for(size_t i = 0;i < count;i++) { if(mCedarXSubs[i]->getSubShowFlag() == SUB_SHOW_NEW_VALID) { mCedarXSubs[i]->Show(); } } SurfaceComposerClient::closeGlobalTransaction(); return NO_ERROR; } int CedarXSubRender::cedarxSubHide(unsigned int systemTime, unsigned int* hasSubShowFlag) { size_t count; unsigned int remainSubShowFlag; logv("CedarXSubRender::cedarxSubHide!xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); count = mCedarXSubs.size(); SurfaceComposerClient::openGlobalTransaction(); remainSubShowFlag = 0; if(systemTime == 0xFFFFFFFF) { for(size_t i = 0;i < count;i++) { mCedarXSubs[i]->setSubShowFlag(SUB_SHOW_INVALID); mCedarXSubs[i]->Hide(); } } else { for(size_t i = 0;i < count;i++) { if(mCedarXSubs[i]->getSubShowFlag()!=SUB_SHOW_INVALID) { if((mCedarXSubs[i]->getSubShowEndTime())<=systemTime) { mCedarXSubs[i]->setSubShowFlag(SUB_SHOW_INVALID); mCedarXSubs[i]->Hide(); } else { remainSubShowFlag = 1; mCedarXSubs[i]->setSubShowFlag(SUB_SHOW_OLD_VALID); } } } } if(hasSubShowFlag != NULL) { *hasSubShowFlag = remainSubShowFlag; } SurfaceComposerClient::closeGlobalTransaction(); if(remainSubShowFlag == 1) { for(size_t i = 0;i < count;i++) { if(mCedarXSubs[i]->getSubShowFlag()!=SUB_SHOW_INVALID) { mCedarXSubs[i]->processSpecialEffect(systemTime); } } } return NO_ERROR; } int CedarXSubRender::cedarxSubSetZorderTop() { size_t count; logd("CedarXSubRender::cedarxSubSetZorderTop!xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); count = mCedarXSubs.size(); SurfaceComposerClient::openGlobalTransaction(); for(size_t i = 0;i < count;i++) { mCedarXSubs[i]->setZorderTop(); } SurfaceComposerClient::closeGlobalTransaction(); return NO_ERROR; } int CedarXSubRender::cedarxSubSetZorderBottom() { size_t count; logd("CedarXSubRender::cedarxSubSetZorderBottom!xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); count = mCedarXSubs.size(); SurfaceComposerClient::openGlobalTransaction(); for(size_t i = 0;i < count;i++) { mCedarXSubs[i]->setZorderBottom(); } SurfaceComposerClient::closeGlobalTransaction(); return NO_ERROR; } int CedarXSubRender::cedarxSubSetPosition(int index,int positionx,int positiony) { size_t count; count = mCedarXSubs.size(); if(index > (int)count) { logw("Invalid index value!\n"); return -1; } logd("???????????????????1"); return mCedarXSubs[index]->setPosition(positionx,positiony); } int CedarXSubRender::cedarxSubSetYPercent(int index,int percent) { size_t count; int i; count = mCedarXSubs.size(); if(index > (int)count) { logw("Invalid index value!\n"); return -1; } SurfaceComposerClient::openGlobalTransaction(); #if 0 if(index == -1) { for(index=0; index<(int)count; index++) { mCedarXSubs[index]->setPositionYPercent(percent); } } else { mCedarXSubs[index]->setPositionYPercent(percent); } #endif /* if(count == 1) { if(index==-1) { mCedarXSubs[0]->setPositionYPercent(percent); } else { mCedarXSubs[index]->setPositionYPercent(percent); } } */ mUserSetYPercent = percent; if(mCedarXSubs[0]->mShow == true) { cedarxSubHide(0xFFFFFFFF,NULL); if(sub_pre!=NULL) updateSubPara(sub_pre); cedarxSubShow(); } SurfaceComposerClient::closeGlobalTransaction(); return 0; } int CedarXSubRender::cedarxSubGetPositionX(int index) { size_t count; count = mCedarXSubs.size(); if(index > (int)count) { logw("Invalid index value!\n"); return -1; } return mCedarXSubs[index]->getPositionX(); } int CedarXSubRender::cedarxSubGetPositionY(int index) { size_t count; count = mCedarXSubs.size(); if(index > (int)count) { logw("Invalid index value!\n"); return -1; } return mCedarXSubs[index]->getPositionY(); } int CedarXSubRender::cedarxSubGetHeight(int index) { size_t count; count = mCedarXSubs.size(); if(index > (int)count) { logw("Invalid index value!\n"); return -1; } return mCedarXSubs[index]->getHeight(); } int CedarXSubRender::cedarxSubGetWidth(int index) { size_t count; count = mCedarXSubs.size(); if(index > (int)count) { logw("Invalid index value!\n"); return -1; } return mCedarXSubs[index]->getWidth(); } int CedarXSubRender::cedarxSubSetFontColor(int color) { size_t count; count = mCedarXSubs.size(); for(size_t i = 0;i < count;i++) { #if 0 if(mCedarXSubs[i]->getTextColorFlag() == SUB_HAS_NONE_COLOR) { mCedarXSubs[i]->setTextColor(color); } #else mCedarXSubs[i]->setTextColor(color); #endif } mInitSetFontColor = (mUserSetFontColor ==0)? SUB_INIT_SET_FONT_INFO : SUB_USER_SET_FONT_INFO; mUserSetFontColor = color; return NO_ERROR; } int CedarXSubRender::cedarxSubGetFontColor() { return mCedarXSubs[0]->getTextColor(); } int CedarXSubRender::cedarxSubSetFontSize(int size) { size_t count; count = mCedarXSubs.size(); for(size_t i = 0;i < count;i++) { #if 0 if(mCedarXSubs[i]->getTextFontSizeFlag() == SUB_HAS_NONE_FONTSIZE) { mCedarXSubs[i]->setFontSize(size); } #else mInitSetFontSize = (mUserSetFontSize ==0)? SUB_INIT_SET_FONT_INFO : SUB_USER_SET_FONT_INFO; mCedarXSubs[i]->setFontSize(size); #endif } mUserSetFontSize = size; return NO_ERROR; } int CedarXSubRender::cedarxSubGetFontSize() { return mCedarXSubs[0]->getFontSize(); } int CedarXSubRender::cedarxSubSetCharset(int charset) { size_t count; count = mCedarXSubs.size(); for(size_t i = 0;i < count;i++) { mCedarXSubs[i]->setCharset(charset); } return NO_ERROR; } int CedarXSubRender::cedarxSubGetCharset() { return mCedarXSubs[0]->getCharset(); } int CedarXSubRender::cedarxSubSetBackColor(int color) { size_t count; count = mCedarXSubs.size(); for(size_t i = 0;i < count;i++) { mCedarXSubs[i]->setBackColor(color); } return NO_ERROR; } int CedarXSubRender::cedarxSubGetBackColor() { return mCedarXSubs[0]->getBackColor(); } int CedarXSubRender::cedarxSubSetAlign(int align) { size_t count; count = mCedarXSubs.size(); for(size_t i = 0;i < count;i++) { mCedarXSubs[i]->setTextAlign(align); } return NO_ERROR; } int CedarXSubRender::cedarxSubGetAlign() { return mCedarXSubs[0]->getTextAlign(); } //**********************************************************************************************************// //**********************************************************************************************************// int CedarXSubRender::cedarxSubSetFontStyle(int style) { size_t count; count = mCedarXSubs.size(); for(size_t i = 0;i < count;i++) { #if 0 if(mCedarXSubs[i]->getTextFontStyleFlag() == SUB_HAS_NONE_STYLE) { mCedarXSubs[i]->setFontStyle(style); } #else mInitSetFontStyle = (mUserSetFontStyle ==0)? SUB_INIT_SET_FONT_INFO : SUB_USER_SET_FONT_INFO; mCedarXSubs[i]->setFontStyle(style); #endif } mUserSetFontStyle = style; return NO_ERROR; } int CedarXSubRender::cedarxSubGetFontStyle() { return mCedarXSubs[0]->getFontStyle(); } //**********************************************************************************************************// //**********************************************************************************************************// int CedarXSub::setSubInf(sub_item_inf *sub_info,int startx, int starty, int endx, int endy, int lastDispx, int lastDispy, int newShowSubFlag, int yPercent) { mSubShowFlag = SUB_SHOW_NEW_VALID; mDispSubInfo = sub_info; logv("setSubInf start"); if(sub_info->subMode != 0) { return 0; } setTextBox(sub_info, startx, starty, endx, endy, lastDispx, lastDispy, newShowSubFlag, yPercent); switch(sub_info->subEffectFlag) { case SUB_RENDER_EFFECT_NONE: { break; } case SUB_RENDER_EFFECT_SCROLL_UP: { mAlignment &= SUN_RENDER_HALIGN_MASK; mAlignment |= SUB_RENDER_VALIGN_TOP; mEndy = mDispSubInfo->effectEndyPos; mStarty = mEndy - mMaxHeight; if(mStarty < 0) { mStarty = 0; } break; } case SUB_RENDER_EFFECT_SCROLL_DOWN: { mAlignment &= SUN_RENDER_HALIGN_MASK; mAlignment |= SUB_RENDER_VALIGN_BOTTOM; mStarty = mDispSubInfo->effectStartyPos; mEndy = mStarty + mMaxHeight; if(mEndy > mScreenHeight) { mEndy = mScreenHeight; } break; } case SUB_RENDER_EFFECT_BANNER_LTOR: { mAlignment &= SUN_RENDER_VALIGN_MASK; mAlignment |= SUB_RENDER_HALIGN_RIGHT; mStartx = 0; mEndx = mScreenWidth; break; } case SUB_RENDER_EFFECT_BANNER_RTOL: { mAlignment &= SUN_RENDER_VALIGN_MASK; mAlignment |= SUB_RENDER_HALIGN_LEFT; mStartx = 0; mEndx = mScreenWidth; break; } case SUB_RENDER_EFFECT_MOVE: { mAlignment &= SUN_RENDER_HALIGN_MASK; mAlignment &= SUN_RENDER_VALIGN_MASK; mAlignment |= SUB_RENDER_VALIGN_TOP; mAlignment |= SUB_RENDER_HALIGN_LEFT; mStartx = 0; mEndx = mScreenWidth; mEndy = mScreenHeight; mStarty = mScreenHeight -mMaxHeight; break; } case SUB_RENDER_EFFECT_KARAOKE: { break; } } logv("setSubInf finish"); return NO_ERROR; } int CedarXSub::setSubShowFlag(int subShowFlag) { mSubShowFlag = subShowFlag; return NO_ERROR; } int CedarXSub::getSubShowFlag() { return mSubShowFlag; } unsigned int CedarXSub::getSubShowEndTime() { return mDispSubInfo->endTime; } int CedarXSub::getTextColorFlag() { if(mDispSubInfo == NULL) { return SUB_HAS_NONE_COLOR; } return (mDispSubInfo->primaryColor>0)? SUB_HAS_DEFINED_COLOR: SUB_HAS_NONE_COLOR; } int CedarXSub::getTextFontSizeFlag() { if(mDispSubInfo == NULL) { return SUB_HAS_NONE_STYLE; } return (mDispSubInfo->fontSize>0)? SUB_HAS_DEFINED_FONTSIZE: SUB_HAS_NONE_FONTSIZE; } int CedarXSub::getTextFontStyleFlag() { if(mDispSubInfo == NULL) { return SUB_HAS_NONE_STYLE; } return (mDispSubInfo->subStyle==SUB_RENDER_STYLE_NONE)? SUB_HAS_NONE_STYLE:SUB_HAS_DEFINED_STYLE; } //**************************************************************************************// //***************************************************************************************// int CedarXSub::processSpecialEffect(unsigned int systemTime) { int xPos = 0; int yPos = 0; int startx = 0; int endx = 0; int curSubSectionIdx = 0; int newAlignment = 0; if((mSubShowFlag==SUB_SHOW_INVALID) ||(mDispSubInfo->subEffectFlag==SUB_RENDER_EFFECT_NONE)) { return NO_ERROR; } switch(mDispSubInfo->subEffectFlag) { case SUB_RENDER_EFFECT_SCROLL_UP: { xPos = getPositionX(); yPos = mDispSubInfo->effectEndyPos - (systemTime-mDispSubInfo->startTime)/mDispSubInfo->effectTimeDelay; setPosition(xPos, yPos); break; } case SUB_RENDER_EFFECT_SCROLL_DOWN: { xPos = getPositionX(); yPos = mDispSubInfo->effectStartyPos+(systemTime-mDispSubInfo->startTime)/mDispSubInfo->effectTimeDelay; setPosition(xPos, yPos); break; } case SUB_RENDER_EFFECT_BANNER_LTOR: { xPos = mDispSubInfo->effectStartxPos+(systemTime-mDispSubInfo->startTime)/mDispSubInfo->effectTimeDelay; mTextBox->subSetBox(0,0,SkIntToScalar(xPos),SkIntToScalar(mEndy-mStarty)); break; } case SUB_RENDER_EFFECT_BANNER_RTOL: { xPos = mDispSubInfo->effectEndxPos-(systemTime-mDispSubInfo->startTime)/mDispSubInfo->effectTimeDelay; mTextBox->subSetBox(xPos,0,SkIntToScalar(mEndx-mStartx),SkIntToScalar(mEndy-mStarty)); break; } case SUB_RENDER_EFFECT_MOVE: { if(mDispSubInfo->effectStartyPos < mDispSubInfo->effectEndyPos) { yPos = mDispSubInfo->effectStartyPos + ((mDispSubInfo->effectEndyPos-mDispSubInfo->effectStartyPos)*(systemTime-mDispSubInfo->startTime))/(mDispSubInfo->endTime-mDispSubInfo->startTime); } else { yPos = mDispSubInfo->effectStartyPos - ((mDispSubInfo->effectStartyPos-mDispSubInfo->effectEndyPos)*(systemTime-mDispSubInfo->startTime))/(mDispSubInfo->endTime-mDispSubInfo->startTime); } if(mDispSubInfo->effectStartxPos < mDispSubInfo->effectEndxPos) { xPos = mDispSubInfo->effectStartxPos + ((mDispSubInfo->effectEndxPos-mDispSubInfo->effectStartxPos)*(systemTime-mDispSubInfo->startTime))/(mDispSubInfo->endTime-mDispSubInfo->startTime); } else { xPos = mDispSubInfo->effectStartxPos - ((mDispSubInfo->effectStartxPos-mDispSubInfo->effectEndxPos)*(systemTime-mDispSubInfo->startTime))/(mDispSubInfo->endTime-mDispSubInfo->startTime); } setPosition(xPos, yPos); break; } #if 0 case SUB_RENDER_EFFECT_KARAOKE: { if((systemTime-mDispSubInfo->startTime)> mDispSubInfo->effectTimeDelay) { return NO_ERROR; } if((mAlignment&SUN_RENDER_HALIGN_MASK) == SUB_RENDER_HALIGN_LEFT) { startx = mStartx; } else if((mAlignment&SUN_RENDER_HALIGN_MASK) == SUB_RENDER_HALIGN_CENTER) { startx = mStartx+(mEndx-mStartx-(int)mTextWidth)/2; } else if((mAlignment&SUN_RENDER_HALIGN_MASK) == SUB_RENDER_HALIGN_RIGHT) { startx = mEndx-(int)mTextWidth; } endx = startx+mTextWidth*(systemTime-mDispSubInfo->startTime)/mDispSubInfo->effectTimeDelay; setPosition(startx, mStarty); mTextBox->subSetBox(0,0,SkIntToScalar(endx-startx),SkIntToScalar(mEndy-mStarty)); newAlignment = mAlignment; newAlignment &= SUN_RENDER_VALIGN_MASK; newAlignment |= SUB_RENDER_HALIGN_LEFT; setTextAlign(newAlignment); SurfaceComposerClient::openGlobalTransaction(); if(mTextColor != mDispSubInfo->primaryColor) { mTextColor = mDispSubInfo->primaryColor; mPaint.setColor(mTextColor); } startRenderRegion(startx, mStarty, endx, mEndy); render(0); endRender(); SurfaceComposerClient::closeGlobalTransaction(); return NO_ERROR; } #endif #if 0 case SUB_RENDER_EFFECT_KARAOKE: { if((systemTime-mDispSubInfo->startTime)> mDispSubInfo->effectTimeDelay) { return NO_ERROR; } mDispSubInfo->subKarakoEffectInf->karaKoSectionLen[0] = 0; mDispSubInfo->subKarakoEffectInf->karaKoSectionLen[68] = 0; mDispSubInfo->subKarakoEffectInf->karaKoSectionLen[126] = 0; for(curSubSectionIdx=0; curSubSectionIdxsubKarakoEffectInf->karakoSectionNum; curSubSectionIdx++) { baseTime1 = mDispSubInfo->subKarakoEffectInf->karaKoSectionStartTime[curSubSectionIdx]; baseTime2 = mDispSubInfo->subKarakoEffectInf->karaKoSectionStartTime[curSubSectionIdx+1]; logd("***********baseTime1=%d, baseTime2=%d, diffTime=%d\n", baseTime1, baseTime2, (systemTime-mDispSubInfo->startTime)); if(((systemTime-mDispSubInfo->startTime)>=baseTime1)&& ((systemTime-mDispSubInfo->startTime)subKarakoEffectInf->karaKoSectionLen[curSubSectionIdx]; len2 = mDispSubInfo->subKarakoEffectInf->karaKoSectionLen[curSubSectionIdx+1]; logd("***********len1=%d, len2=%d, curSubSectionIdx=%d\n", len1, len2, curSubSectionIdx); startx += len1; endx = startx +(systemTime-mDispSubInfo->startTime-baseTime1)*(len2-len1)/(baseTime2-baseTime1); //endx = startx+mTextWidth*(systemTime-mDispSubInfo->startTime)/mDispSubInfo->effectTimeDelay; setPosition(startx, mStarty); mTextBox->subSetBox(0,0,SkIntToScalar(endx-startx),SkIntToScalar(mEndy-mStarty)); newAlignment = mAlignment; newAlignment &= SUN_RENDER_VALIGN_MASK; newAlignment |= SUB_RENDER_HALIGN_LEFT; setTextAlign(newAlignment); SurfaceComposerClient::openGlobalTransaction(); if(mTextColor != mDispSubInfo->primaryColor) { mTextColor = mDispSubInfo->primaryColor; mPaint.setColor(mTextColor); } startRenderRegion(startx, mStarty, endx, mEndy); render(0); endRender(); SurfaceComposerClient::closeGlobalTransaction(); return NO_ERROR; } #endif default: { return NO_ERROR; } } SurfaceComposerClient::openGlobalTransaction(); startRender(); render(); endRender(); SurfaceComposerClient::closeGlobalTransaction(); return NO_ERROR; } //************************************************************************************************************// //*********************************************************************************************************** // int CedarXSub::getTextBox(int* startx, int *starty, int* endx, int* endy, int *lastDispx, int *lastDispy) { *startx = mStartx; *starty = mStarty; *endx = mEndx; *endy = mEndy; *lastDispx = mStartDispx; *lastDispy = mStartDispy; return NO_ERROR; } //************************************************************************************************************// //*********************************************************************************************************** // int CedarXSub::setTextBox(sub_item_inf *sub_info,int startx, int starty, int endx, int endy, int lastDispx, int lastDispy, int newShowSubFlag, int yPercent) { int align = 0; int newStartx = 0; int newStarty = 0; int newEndx = 0; int newEndy = 0; int maxYPos = 0; mStartx = startx; mStarty = starty; mEndx = endx; mEndy = endy; mStartDispx = lastDispx; mStartDispy = lastDispy; mMaxWidth = mScreenWidth; //mMaxHeight = mMaxTextLine*mMaxFontHeight; mMaxHeight = mScreenHeight; mPosX = 0; mPosY = 0; maxYPos = mScreenHeight*(100-yPercent)/100; switch(sub_info->subDispPos) { case SUB_DISPPOS_TOP_LEFT: align |= SUB_RENDER_HALIGN_LEFT; align |= SUB_RENDER_VALIGN_TOP; newStartx = sub_info->startx; newStarty = sub_info->starty; newEndx = mScreenWidth; newEndy = newStarty+mMaxHeight; if(newEndy > maxYPos) { newEndy = maxYPos; } break; case SUB_DISPPOS_TOP_MID: align |= SUB_RENDER_HALIGN_CENTER; align |= SUB_RENDER_VALIGN_TOP; newStartx = 0; newStarty = sub_info->starty; newEndx = mScreenWidth; newEndy = newStarty+mMaxHeight; if(newEndy > maxYPos) { newEndy = maxYPos; } break; case SUB_DISPPOS_TOP_RIGHT: align |= SUB_RENDER_HALIGN_RIGHT; align |= SUB_RENDER_VALIGN_TOP; newStartx = 0; newStarty = sub_info->starty; newEndx = sub_info->endx; newEndy = newStarty+mMaxHeight; if(newEndy > maxYPos) { newEndy = maxYPos; } break; case SUB_DISPPOS_MID_LEFT: align |= SUB_RENDER_HALIGN_LEFT; align |= SUB_RENDER_VALIGN_CENTER; newStartx = sub_info->startx; newStarty = (mScreenHeight-mMaxHeight)>>1; newEndx = mScreenWidth; newEndy = newStarty+mMaxHeight; if(newEndy > maxYPos) { newEndy = maxYPos; } break; case SUB_DISPPOS_MID_MID: align |= SUB_RENDER_HALIGN_CENTER; align |= SUB_RENDER_VALIGN_CENTER; newStartx = 0; newStarty = (mScreenHeight-mMaxHeight)>>1; newEndx = mScreenWidth; newEndy = newStarty+mMaxHeight; if(newEndy > maxYPos) { newEndy = maxYPos; } break; case SUB_DISPPOS_MID_RIGHT: align |= SUB_RENDER_HALIGN_RIGHT; align |= SUB_RENDER_VALIGN_CENTER; newStartx = 0; newStarty = (mScreenHeight-mMaxHeight)>>1; newEndx = sub_info->endx; newEndy = newStarty+mMaxHeight; if(newEndy > maxYPos) { newEndy = maxYPos; } break; case SUB_DISPPOS_BOT_LEFT: align |= SUB_RENDER_HALIGN_LEFT; align |= SUB_RENDER_VALIGN_BOTTOM; newStartx = sub_info->startx; newEndy = sub_info->endy; if(newEndy > maxYPos) { newEndy = maxYPos; } newEndx = mScreenWidth; newStarty = newEndy-mMaxHeight; if(newStarty < 0) { newStarty = 0; } break; case SUB_DISPPOS_BOT_MID: align |= SUB_RENDER_HALIGN_CENTER; align |= SUB_RENDER_VALIGN_BOTTOM; newStartx = 0; newEndx = mScreenWidth; newEndy = sub_info->endy; if((newEndy+10) > maxYPos) { newEndy = maxYPos; } newStarty = newEndy-mMaxHeight; if(newStarty < 0) { newStarty = 0; } break; case SUB_DISPPOS_BOT_RIGHT: align |= SUB_RENDER_HALIGN_RIGHT; align |= SUB_RENDER_VALIGN_BOTTOM; newStartx = 0; newEndx = sub_info->endx; newEndy = sub_info->endy; if(newEndy > maxYPos) { newEndy = maxYPos; } newStarty = newEndy-mMaxHeight; if(newStarty < 0) { newStarty = 0; } break; default: align |= SUB_RENDER_HALIGN_CENTER; align |= SUB_RENDER_VALIGN_BOTTOM; newStartx = mPosX; newEndx = mPosX+mWidth; newEndy = maxYPos; newStarty = newEndy - mMaxHeight; if(newStarty < 0) { newStarty = 0; } break; } if((newShowSubFlag==0)&&(newStartx==mStartx)&&(newStarty==mStarty)&&(newEndx==mEndx)&&(newEndy==mEndy)) { mStartx = newStartx; mEndx = newEndx; mEndy = mStartDispy+mStarty; mStarty = mEndy-mMaxHeight; if(mStarty < 0) { mStarty = 0; } } else { mStartx = newStartx; mStarty = newStarty; mEndx = newEndx;; mEndy = newEndy; } mAlignment = align; logv("******rendere:align=%x,subDispPos=%d,startx=%d,starty=%d,endx=%d,endy=%d, orgStartx=%d,orgStarty=%d,orgEndx=%d,orgEndy=%d\n",align,sub_info->subDispPos,mStartx, mStarty, mEndx, mEndy,sub_info->startx,sub_info->starty,sub_info->endx,sub_info->endy); return NO_ERROR; } //************************************************************************************************************// //*********************************************************************************************************** // int CedarXSub::generateBitmap(sub_item_inf *sub_info) { ssize_t bpr = sub_info->subPicWidth * bytesPerPixel(PIXEL_FORMAT_RGBA_8888); mBitmap.setConfig(convertPixelFormat(PIXEL_FORMAT_RGBA_8888), sub_info->subPicWidth, sub_info->subPicHeight, bpr); mBitmap.setIsOpaque(true); if (sub_info->subPicWidth > 0 && sub_info->subPicHeight > 0) { //set R of bitmap(RGBA) to 0 for (int i = 0 ; i < sub_info->subPicWidth * sub_info->subPicHeight; i++ ) { sub_info->subBitmapBuf[4*i] = 0; } mBitmap.setPixels((void *)sub_info->subBitmapBuf); } else { // be safe with an empty bitmap. mBitmap.setPixels(NULL); } return NO_ERROR; } //***************************************************************************************// //**************************************************************************************// void CedarXSubTextBox::drawText(SkCanvas* canvas, const char *text, size_t len, const SkPaint& mPaint, SkScalar textHeight, int specialEffectFlag) { size_t drawCount; SkScalar lineWidth; SkASSERT(canvas && &mPaint && (text || len == 0)); SkScalar mMarginWidth = mFBox.width(); logv("*************&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&CedarXSubTextBox::drawText len = %d,mMarginWidth = %f\n",len,mMarginWidth); if (mMarginWidth <= 0 || len == 0) { return; } const char* textStop = text + len; SkScalar mSkScalarX=0, mSkScalarY=0, mScaledSpacing, height, mFontHeight; SkPaint::FontMetrics mMetrics; switch (mPaint.getTextAlign()) { case SkPaint::kLeft_Align: mSkScalarX = 0; break; case SkPaint::kCenter_Align: mSkScalarX = SkScalarHalf(mMarginWidth); break; default: mSkScalarX = mMarginWidth; break; } mSkScalarX += mFBox.fLeft; mFontHeight = mPaint.getFontMetrics(&mMetrics); mScaledSpacing = SkScalarMul(mFontHeight, mFSpacingMul) + mFSpacingAdd; height = mFBox.height(); // compute mSkScalarY position for first line { switch (fSpacingAlign) { case CedarXSubTextBoxStart_SpacingAlign: mSkScalarY = 0; break; case CedarXSubTextBoxCenter_SpacingAlign: mSkScalarY = SkScalarHalf(height - textHeight); break; default: mSkScalarY = height - textHeight; break; } mSkScalarY += mFBox.fTop - mMetrics.fAscent; //logd("CedarXSubTextBox::drawText mSkScalarY = %f,mFBox.fTop=%f,mMetrics.fAscent = %f,textHeight = %f,height = %f\n",mSkScalarY,mFBox.fTop,mMetrics.fAscent,textHeight,height); } mLastDispXPos = (int)mSkScalarX; mLastDispYPos = (int)(mSkScalarY-mScaledSpacing); for (;;) { len = subLineBreak(text, textStop, mPaint, mMarginWidth,&drawCount,specialEffectFlag, &lineWidth); if (mSkScalarY + mMetrics.fDescent + mMetrics.fLeading > 0) { canvas->drawText(text, drawCount, mSkScalarX, mSkScalarY, mPaint); logv("canvas->drawText!text = %s,drawCount = %d\n",text,drawCount); } text += len; if (text >= textStop) { break; } mSkScalarY += mScaledSpacing; if (mSkScalarY + mMetrics.fAscent >= height) { break; } } } //************************************************************************************************************// //*********************************************************************************************************** // int CedarXSub::render() { if(mCanvas == NULL) { logd("shit!!!!!!!!!"); } mCanvas->drawColor(mBackColor, SkXfermode::kSrc_Mode); if(mSubMode & TEXT_SUBTITLE) { int len; SkScalar textHeight; SkScalar textBoxHeight; len = strlen(mText); mTextBox->drawText(mCanvas, mText, len, mPaint, mTextHeight, mDispSubInfo->subEffectFlag); mStartDispx = mTextBox->getLastXPos(); mStartDispy = mTextBox->getLastYPos(); } else if(mSubMode & PIC_SUBTITLE) { int posx = 0; int posy = 0; int width = mBitmap.width(); int height = mBitmap.height(); if((mDispSubInfo->subScaleWidth==0)||(mDispSubInfo->subScaleHeight==0)) { posx = (mWidth - width)>>1; posy = (mHeight - height); posx = (posx<0)? 0 : posx; posy = (posy<0)? 0 : posy; #if SAVE_BITMAP_TO_PNG save("/data/local/tmp/subBitmapS011",mBitmap); #endif mCanvas->drawBitmap(mBitmap,posx,posy,&mPaint); #if SAVE_BITMAP_TO_PNG SkBitmap BitmapIncanvas = mCanvas->getDevice()->accessBitmap(false); save("/data/local/tmp/subBitmapS011-output",BitmapIncanvas); #endif } else { SkIRect src; SkRect dst; src.set(0,0,width, height); posx = (mWidth - mDispSubInfo->subScaleWidth)>>1; posy = (mHeight - mDispSubInfo->subScaleHeight); posx = (posx<0)? 0 : posx; posy = (posy<0)? 0 : posy; dst.set(posx,posy,posx+mDispSubInfo->subScaleWidth, posy+mDispSubInfo->subScaleHeight); mCanvas->drawBitmapRect(mBitmap, &src, dst,&mPaint); } } return NO_ERROR; } //************************************************************************************************************// //*********************************************************************************************************** // CedarXSub::CedarXSub(int index, int userSetFontColor, int userSetFontSize, int userSetFontStyle, int userSetYpercent) { status_t err; sp mSurface; char prop_value[4]; int int_val; DisplayInfo mDisplayInfo; logd("CedarXSub::CedarXSub #####################\n"); mDisplay = SUB_DISPLAY; mMaxTextLine = MAX_TEXTLINE; mFontScaleRatio = FONT_SIZE_UNIT; mMaxFontHeight = MAX_FONTHEIGHT; mPid = IPCThreadState::self()->getCallingPid(); mShow = false; sp mClient = new SurfaceComposerClient; mSurfaceClient = mClient; sp dtoken(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); SurfaceComposerClient::getDisplayInfo(dtoken, &mDisplayInfo); mScreenWidth = mDisplayInfo.w; mScreenHeight = mDisplayInfo.h; mMaxWidth = mScreenWidth; if(mScreenHeight >= 1080) { mFontScaleRatio = FONT_SIZE_UNIT * 3; //X3 mMaxFontHeight = mMaxFontHeight * 3; } else if (mScreenHeight >= 720) { mFontScaleRatio = FONT_SIZE_UNIT * 3 / 2; //X1.5 mMaxFontHeight = mMaxFontHeight * 3 / 2; } else if (mScreenHeight >= 600) { mFontScaleRatio = FONT_SIZE_UNIT * 5 / 4; //X1.25 mMaxFontHeight = mMaxFontHeight * 5 / 4; } mMaxHeight = mScreenHeight; if(mScreenHeight >= 1080) { if(mMaxHeight <= 300) { mMaxHeight = 300; } } else { if(mMaxHeight <= 300) { mMaxHeight = 300; } } if(mMaxWidth >= mScreenWidth) { mPosX = 0; } else { mPosX = (mScreenWidth - mMaxWidth)>>1; } if(mMaxHeight >= mScreenHeight) { mPosY = 0; } else { mPosY = (mScreenHeight - mMaxHeight)* (100 - userSetYpercent) / 100; } String8 name; const size_t SIZE = 128; char buffer[SIZE]; snprintf(buffer, SIZE, "", getpid()); name.append(buffer); mSurfaceControl = mClient->createSurface(name, mMaxWidth, mMaxHeight, PIXEL_FORMAT_TRANSPARENT, ISurfaceComposerClient::eFXSurfaceNormal); if(mSurfaceControl != NULL) { SurfaceComposerClient::openGlobalTransaction(); mTopBaseLayer = TOPBASELAYER * LAYER_MULTIPLIER + LAYER_OFFSET + 2 + index; mBottomBaseLayer= BOTTOMBASELAYER * LAYER_MULTIPLIER + LAYER_OFFSET - 10 + index; mLayer = mTopBaseLayer; logd("3@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ %d %d", mPosX, mPosY); mSurfaceControl->setPosition(mPosX,mPosY); //mSurfaceControl->setLayer(mLayer); mSurfaceControl->setLayer(99999); mSurfaceControl->hide(); SurfaceComposerClient::closeGlobalTransaction(); mCanvas = new SkCanvas; mWidth = mMaxWidth; mHeight = mMaxHeight; mPaint.setAntiAlias(true); logd("=**********************8 mFontScaleRatio = %d", mFontScaleRatio); if(userSetFontSize == 0) { mPaint.setTextSize(DEFAULT_TEXT_SIZE * mFontScaleRatio / FONT_SIZE_UNIT); } else { mPaint.setTextSize(userSetFontSize * mFontScaleRatio / FONT_SIZE_UNIT); } if(userSetFontColor == 0) { mPaint.setColor(0xFFFFFFFF); } else { mPaint.setColor(userSetFontColor); } if(userSetFontStyle == 0) { mFontStyle = SUB_RENDER_STYLE_NONE; setFontStyle(SUB_RENDER_STYLE_NONE); } else { setFontStyle(userSetFontStyle); } mPaint.setTextAlign(SkPaint::kCenter_Align); mBackColor = TRANSPARENT_COLOR; #if(CONFIG_OS_VERSION >= OPTION_OS_VERSION_ANDROID_5_0) mTypeface = SkTypeface::CreateFromFile("/system/fonts/DroidSansFallbackAndroid44.ttf"); #else mTypeface = SkTypeface::CreateFromFile("/system/fonts/DroidSansFallback.ttf"); #endif mPaint.setTypeface(mTypeface); mCharset = SUBTITLE_TEXT_FORMAT_GBK; mTextBox = NULL; mSubMode = 0; mDispSubInfo = NULL; mSubShowFlag = SUB_SHOW_INVALID; } } //************************************************************************************************************// //*********************************************************************************************************** // CedarXSub::~CedarXSub() { if(mTypeface != NULL) { mTypeface->unref(); } logd("CedarXSub::~CedarXSub1!\n"); if(mCanvas != NULL) { mCanvas->unref(); } logd("CedarXSub::~CedarXSub2!\n"); if(mTextBox != NULL) { delete mTextBox; } logd("CedarXSub::~CedarXSub3!\n"); if (SurfaceControl::isValid(mSurfaceControl)) { mSurfaceControl->clear(); } logd("CedarXSub::~CedarXSub4!\n"); } //************************************************************************************************************// //*********************************************************************************************************** // #if 0 int CedarXSub::startRenderRegion(int startx, int starty, int endx, int endy) { ANativeWindow_Buffer nativeWindowBuffer; status_t err; SkBitmap mBitmap; sp mSurface; Region dirtyRegion; Rect dirty; dirty.left = startx; dirty.top = starty; dirty.right = endx; dirty.bottom = endy; //dirtyRegion.set(dirty); mSurface = mSurfaceControl->getSurface(); err = mSurface->lock(&nativeWindowBuffer, &dirty); logd("//////////////////////////////////////////////////////1"); if (err < 0) { logw("get surface information failed!\n"); return -1; } ssize_t bpr = nativeWindowBuffer.width * bytesPerPixel(nativeWindowBuffer.format); mBitmap.setConfig(convertPixelFormat(nativeWindowBuffer.format), endx-startx, endy-starty, bpr); if (nativeWindowBuffer.format == PIXEL_FORMAT_RGBX_8888) { mBitmap.setIsOpaque(true); } if (nativeWindowBuffer.width > 0 && nativeWindowBuffer.height > 0) { //bitmap.setPixels(info.bits+4*(mStarty*mScreenWidth+mStartx)); mBitmap.setPixels(nativeWindowBuffer.bits); } else { // be safe with an empty bitmap. mBitmap.setPixels(NULL); } mCanvas->setBitmapDevice(mBitmap); //mCanvas->setDevice(SkNEW_ARGS(SkDevice, (bitmap))); //mCanvas->writePixels(bitmap,0,0,SkCanvas::Config8888::kNative_Premul_Config8888); mSaveCount = mCanvas->save(); return NO_ERROR; } #endif int CedarXSub::startRender() { #if(CONFIG_OS_VERSION == OPTION_OS_VERSION_ANDROID_4_2) Surface::SurfaceInfo info; status_t err; SkBitmap mBitmap; sp mSurface; mSurface = mSurfaceControl->getSurface(); err = mSurface->lock(&info, NULL); if (err < 0) { logw("get surface information failed!\n"); return -1; } ssize_t bpr = info.s * bytesPerPixel(info.format); mBitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, bpr); if (info.format == PIXEL_FORMAT_RGBX_8888) { mBitmap.setIsOpaque(true); } if (info.w > 0 && info.h > 0) { //bitmap.setPixels(info.bits+4*(mStarty*mScreenWidth+mStartx)); mBitmap.setPixels(info.bits); } else { // be safe with an empty bitmap. mBitmap.setPixels(NULL); } mCanvas->setBitmapDevice(mBitmap); mSaveCount = mCanvas->save(); return NO_ERROR; #else ANativeWindow_Buffer nativeWindowBuffer; status_t err; SkBitmap mBitmap; sp mSurface; mSurface = mSurfaceControl->getSurface(); err = mSurface->lock(&nativeWindowBuffer, NULL/*false*/); if (err < 0) { logw("get surface information failed!\n"); return -1; } ssize_t bpr = nativeWindowBuffer.width * bytesPerPixel(nativeWindowBuffer.format); mBitmap.setConfig(convertPixelFormat(nativeWindowBuffer.format), nativeWindowBuffer.width, nativeWindowBuffer.height, bpr); /* for(int k = 0; k < 1280 * 720; k ++) { ((unsigned int *)outBuffer.bits)[k] = 8334543; } */ if (nativeWindowBuffer.format == PIXEL_FORMAT_RGBX_8888) { mBitmap.setIsOpaque(true); } if (nativeWindowBuffer.width > 0 && nativeWindowBuffer.height > 0) { //bitmap.setPixels(info.bits+4*(mStarty*mScreenWidth+mStartx)); mBitmap.setPixels(nativeWindowBuffer.bits); } else { // be safe with an empty bitmap. mBitmap.setPixels(NULL); } /* static int num = 0; char fname[128]; sprintf(fname, "/data/camera/fuqiang%03d.rgba", num); num ++; FILE *fp = fopen(fname, "w"); fwrite((void *)outBuffer.bits, outBuffer.width * outBuffer.height * bytesPerPixel(outBuffer.format), 1, fp); fflush(fp); fclose(fp); */ mCanvas->setBitmapDevice(mBitmap); //mCanvas->writePixels(bitmap,0,0,SkCanvas::kNative_Premul_Config8888); mSaveCount = mCanvas->save(); return NO_ERROR; #endif } int CedarXSub::endRender() { status_t err; sp mSurface; mSurface = mSurfaceControl->getSurface(); // detach the canvas from the surface mCanvas->restoreToCount(mSaveCount); mSaveCount = 0; // unlock surface err = mSurface->unlockAndPost(); if (err < 0) { logw("surface unlockAndPost Failed!\n"); return -1; } return NO_ERROR; } //************************************************************************************************************// //*********************************************************************************************************** // int CedarXSubTextBox::getTextVerInf(const char *text, size_t len, const SkPaint& paint,SkScalar* subTextHeight,SkScalar* subTextWidth,SkScalar* textBoxHeight, int textBoxStartx, int textBoxEndx, int textBoxStarty, int textBoxEndy, int specialEffectFlag) { int nCount = 0; SkScalar mTextHeight = 0; const char* textStop; SkScalar mScaledSpacing, height, mFontHeight; SkPaint::FontMetrics metrics; SkScalar marginWidth; marginWidth = textBoxEndx - textBoxStartx + 1; mFontHeight = paint.getFontMetrics(&metrics); mScaledSpacing = SkScalarMul(mFontHeight, mFSpacingMul) + mFSpacingAdd; height = textBoxEndy - textBoxStarty + 1; textStop = text + len; mTextHeight = mFontHeight; if(fMode == CedarXSubTextBoxLineBreak_Mode) { nCount = countLines(text, textStop - text, paint, marginWidth, subTextWidth, specialEffectFlag); SkASSERT(nCount > 0); mTextHeight += mScaledSpacing * (nCount - 1); } *subTextHeight = mTextHeight; *textBoxHeight = (SkScalar)(textBoxEndy-textBoxStarty); return NO_ERROR; } //************************************************************************************************************// //*********************************************************************************************************** // int CedarXSub::needModifyBoxInf(SkScalar textBoxHeight) { int aglignMent= 0; int offset = 0; if(mTextHeight <= textBoxHeight) { return NO_ERROR; // not need modify text box vertical info } else { aglignMent = (mAlignment & 0xf0); if(aglignMent == SUB_RENDER_VALIGN_TOP) { if((SkScalar)(mScreenHeight-mStarty) > mTextHeight) { mEndy = mStarty + mTextHeight; if(mEndy >= mScreenHeight) { mEndy = mScreenHeight; } } else { mEndy = mScreenHeight; mStarty = mEndy - mTextHeight; if(mStarty < 0) { mStarty = 0; } } } else if(aglignMent == SUB_RENDER_VALIGN_CENTER) { offset = (mTextHeight - textBoxHeight)/2; mStarty -= offset; mEndy += offset; if(mStarty < 0) { mStarty = 0; } if(mEndy > mScreenHeight) { mEndy = mScreenHeight; } } else if(aglignMent == SUB_RENDER_VALIGN_BOTTOM) { if((SkScalar)mEndy > mTextHeight) { mStarty = mEndy - mTextHeight; if(mStarty < 0) { mStarty = 0; } } else { mStarty = 0; mEndy = mStarty + mTextHeight; if(mEndy > mScreenHeight) { mEndy = mScreenHeight; } } } } return NO_ERROR; } //************************************************************************************************************// //*********************************************************************************************************** // int CedarXSub::updatePara(sub_item_inf *sub_info, int initSetFontColor, int initSetFontSize, int initSetFontStyle, int Ypercent) { int len = 0; int fontIndex = 0; SkScalar textBoxHeight; if(sub_info == NULL) { logw("input para error!\n"); return -1; } mSubMode = 0; if(sub_info->subMode == 0) { mSubMode |= TEXT_SUBTITLE; convertUniCode(sub_info); } else { mSubMode |= PIC_SUBTITLE; generateBitmap(sub_info); } if(mSubMode & TEXT_SUBTITLE) { logv("CedarXSub::updatePara mText = %s\n",mText); if(mTextBox == NULL) { mTextBox = new CedarXSubTextBox; mTextAlign |= SUB_RENDER_HALIGN_CENTER; mTextAlign |= SUB_RENDER_VALIGN_BOTTOM; } if(sub_info->subHasFontInfFlag == 1) { if((initSetFontSize==SUB_INIT_SET_FONT_INFO)&&(sub_info->fontSize>0)) { #if 1 fontIndex = (sub_info->fontSize>>2)-2; fontIndex = (fontIndex<0)? 0:fontIndex; fontIndex = (fontIndex>16)? 16:fontIndex; fontIndex += 16; fontIndex = (fontIndex<25)? 25: fontIndex; #else fontIndex = sub_info->fontSize; #endif setFontSize(fontIndex); } if(mDispSubInfo->subEffectFlag==SUB_RENDER_EFFECT_KARAOKE) { if(sub_info->secondaryColor > 0) { setTextColor(sub_info->secondaryColor); } } else { if((initSetFontColor==SUB_INIT_SET_FONT_INFO)&&(sub_info->primaryColor>0)) { setTextColor(sub_info->primaryColor); } if((initSetFontStyle==SUB_INIT_SET_FONT_INFO) &&(sub_info->subStyle != SUB_RENDER_STYLE_NONE)) { setFontStyle(sub_info->subStyle); } } } len = strlen((char*)mText); #if 0 char fname[128]; sprintf(fname, "/data/camera/fuqiang1.txt"); FILE *fp = fopen(fname, "w"); fwrite((void *)mText, len, 1, fp); fflush(fp); fclose(fp); #endif mTextBox->getTextVerInf(mText,len,mPaint,&mTextHeight,&mTextWidth, &textBoxHeight, mStartx, mEndx, mStarty, mEndy, mDispSubInfo->subEffectFlag); needModifyBoxInf(textBoxHeight); setPosition(mStartx,mStarty -50); mTextBox->subSetBox(0,0,SkIntToScalar(mEndx-mStartx),SkIntToScalar(mEndy-mStarty)); setTextAlign(mAlignment); } else { mPosY = (mScreenHeight-mMaxFontHeight)* (Ypercent) / 100; logd("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ mPosY = %d, mScreenHeight = %d, mMaxFontHeight = %d", mPosY, mScreenHeight, mMaxFontHeight); /* if(mPosY + mMaxHeight > mScreenHeight) { mPosY = mScreenHeight - mMaxHeight; } */ mSurfaceControl->setPosition(mPosX,-mPosY); } if((mDispSubInfo->subEffectFlag==SUB_RENDER_EFFECT_NONE)||(mDispSubInfo->subEffectFlag==SUB_RENDER_EFFECT_KARAOKE)) { startRender(); render(); endRender(); } return NO_ERROR; } //************************************************************************************************************// //*********************************************************************************************************** // int CedarXSubRender::updateSubPara(sub_item_inf *sub_info) { sub_pre = sub_info; int count = 0; size_t size; sub_item_inf *current; sp cedarXSub; int dispStartx = 0; int dispStarty = 0; int dispHeight = 0; int align = 0; int lastPosValidFlag = 0; int startx = 0; int starty = 0; int endx = 0; int endy = 0; int lastDispx = 0; int lastDispy = 0; int newShowSubFlag = 0; if(sub_info == NULL) { logw("Invalid sub information!\n"); return -1; } current = sub_info; size = mCedarXSubs.size(); newShowSubFlag = 1; while(current != NULL) { if(count > 0) { mCedarXSubs[count-1]->getTextBox(&startx, &starty, &endx, &endy, &lastDispx, &lastDispy); } if(count >= (int)size) { cedarXSub = new CedarXSub(0, mUserSetFontColor, mUserSetFontSize, mUserSetFontStyle, mUserSetYPercent); /*create main cedarXSub*/ mCedarXSubs.add(cedarXSub); } if(mCedarXSubs[count]->getSubShowFlag() == SUB_SHOW_INVALID) { if(current == NULL) { logd("***********current is null **********"); } logv("@@startx = %d, starty = %d, endx = %d, endx = %d,lastDispx = %d lastDispy = %d, newShowSubFlag = %d", startx, starty, endx, endy, lastDispx, lastDispy, newShowSubFlag); mCedarXSubs[count]->setSubInf(current, startx, starty, endx, endy, lastDispx, lastDispy, newShowSubFlag, mUserSetYPercent); mCedarXSubs[count]->updatePara(current, mInitSetFontColor, mInitSetFontSize, mInitSetFontStyle, mUserSetYPercent); current = (sub_item_inf *)current->nextSubItem; newShowSubFlag = 0; } count++; } return NO_ERROR; } //************************************************************************************************************// //************************************************************************************************************// #ifdef __cplusplus extern "C" { #endif CedarXSubRender* gCedarXSubRender = NULL; static bool checkCedarXSubRenderUnitialized() { if (gCedarXSubRender == NULL) { return true; } return false; } int SubRenderCreate() { logd("****************SubRenderCreate!****************\n"); if(gCedarXSubRender == NULL) { gCedarXSubRender = new CedarXSubRender(); logd("****************SubRenderCreate success!****************\n"); } return NO_ERROR; } int SubRenderDestory() { logd("****************SubRenderDestory!****************\n"); if (checkCedarXSubRenderUnitialized()) { return -1; } logd("****************SubRenderDestory1!****************\n"); delete gCedarXSubRender; gCedarXSubRender = NULL; logd("****************SubRenderDestory2!****************\n"); return NO_ERROR; } int SubRenderDraw(sub_item_inf *sub_info) { if (checkCedarXSubRenderUnitialized()) { return -1; } logv("****************SubRenderDraw!****************\n"); return gCedarXSubRender->updateSubPara(sub_info); } int SubRenderShow() { if (checkCedarXSubRenderUnitialized()) { return -1; } logv("****************SubRenderShow!****************\n"); return gCedarXSubRender->cedarxSubShow(); } int SubRenderHide(unsigned int systemTime, unsigned int* hasSubShowFlag) { if (checkCedarXSubRenderUnitialized()) { return -1; } logv("****************SubRenderHide!****************\n"); return gCedarXSubRender->cedarxSubHide(systemTime, hasSubShowFlag); } int SubRenderSetZorderTop() { if (checkCedarXSubRenderUnitialized()) { return -1; } logv("****************SubRenderSetZorderTop!****************\n"); return gCedarXSubRender->cedarxSubSetZorderTop(); } int SubRenderSetZorderBottom() { if (checkCedarXSubRenderUnitialized()) { return -1; } logv("****************SubRenderSetZorderBottom!****************\n"); return gCedarXSubRender->cedarxSubSetZorderBottom(); } #ifdef __cplusplus } #endif } // namespace android