package com.wistron.StereoUI; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; import Utilities.CSStaticData; import android.content.Context; import android.graphics.Color; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.Gravity; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.widget.RelativeLayout; import android.widget.TextView; /** * Copyright(c)2011 Wistron SWPC ALL rights reserved. * created: 2012-02-01 * filename:CaptionsResolve.java * * purpose:字幕解析 * */ public class CaptionsResolve { private Context mContext = null; private StringBuilder mNewString = null; private CaptionsBean mCaptionsBean = null; private int mTimeError = 0; // 在此设定需要调整的时间秒数,正数为延迟,负数为提早 private int mLine = 0; private ArrayList<Long> mStartTime = null; private ArrayList<Long> mEndTime = null; private ArrayList<StringBuilder> mCaptionsList = null; private ArrayList<StringBuilder> mStartTimeFormatList = null; private ArrayList<StringBuilder> mEndTimeFormatList = null; public Handler mHandler = null;//控制字幕显示的Handler private TextView mCaptionsTV = null;//用于显示字幕的TextView private String mTempString = null, mStartTimeFormat = null, mEndTimeFormat = null, mFileType = null, mCharset = null, mSystemCharset = null, mFilePath = null, mRegex = null; private Matcher mMatcher = null; private static final String FILE_TYPE_SRT = ".srt",//.SRT格式的字幕 FILE_TYPE_SMI = ".smi",//.SMI格式的字幕 TAG = "CaptionsResolve"; // private MsgBox mMsgBox = null; public CaptionsResolve(Context context) { mContext = context; // 初始化控件 initialize(); } public void initialize() { mCaptionsBean = new CaptionsBean(); mCaptionsTV = new TextView(mContext); mCaptionsTV.setTextSize(24); mCaptionsTV.setTextColor(Color.WHITE); RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); layoutParams.setMargins(0, 0, 0, 0); mCaptionsTV.setLayoutParams(layoutParams); mCaptionsTV.setShadowLayer(3, 0, 0, 0xFF0000FF); mCaptionsTV.setGravity(Gravity.CENTER_HORIZONTAL); mStartTime = new ArrayList<Long>(); mEndTime = new ArrayList<Long>(); mCaptionsList = new ArrayList<StringBuilder>(); mStartTimeFormatList = new ArrayList<StringBuilder>(); mEndTimeFormatList = new ArrayList<StringBuilder>(); mHandler(); } public void setCaptionPath(String path){ mFilePath = path; } public void addToLayout(ViewGroup layout){ // mParentLayout = layout; if(layout == null){ return; } layout.addView(mCaptionsTV); } /** * 开始解析字幕 * @param path */ public void readFile(String path){ mFilePath = path; mSystemCharset = System.getProperty("file.encoding"); //如果用户未选择字幕的编码方式,默认启动系统的编码方式 if (getCharset() == null) { mCharset = mSystemCharset; } if (CSStaticData.DEBUG) { Log.v(TAG,"系统语言user.language:"+System.getProperty("user.language")); //zh Log.v(TAG,"用户注册user.region:"+System.getProperty("user.region")); //CN Log.v(TAG,"系统编码方式file.encoding:"+mSystemCharset); Log.v(TAG,"已采用的编码方式"+mCharset); } try { mFilePath = mFilePath + ".srt"; InputStreamReader iStream = new InputStreamReader(new FileInputStream(mFilePath), mCharset); BufferedReader reader = new BufferedReader(iStream); mNewString = new StringBuilder(); while ((mTempString = reader.readLine()) != null) { mNewString.append(mTempString); mNewString.append("\n"); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } if (mNewString == null) { try { mFilePath = mFilePath + ".smi"; InputStreamReader iStream = new InputStreamReader(new FileInputStream(mFilePath), mCharset); BufferedReader reader = new BufferedReader(iStream); mNewString = new StringBuilder(); while ((mTempString = reader.readLine()) != null) { mNewString.append(mTempString); mNewString.append("\n"); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } if (mNewString == null) { if (CSStaticData.DEBUG) { Log.v(TAG, "字幕解析失败,没有找到对应的字幕文件!"); } // mMsgBox = new MsgBox(mContext); // mMsgBox.setMessage("Sorry,no suitable caption found!"); // mMsgBox.setModelStatus(false); // mMsgBox.hideDelay(3000); // mMsgBox.setSize(500, 200); // mMsgBox.addToLayout(mParentLayout); // mMsgBox.show(); // Toast.makeText(mContext, "Sorry,no suitable caption found!", 1000).show(); return; }else { if (CSStaticData.DEBUG) { Log.v(TAG, "字幕解析成功!"); } // mMsgBox = new MsgBox(mContext); // mMsgBox.setMessage("Loaded caption successfully!"); // mMsgBox.setModelStatus(false); // mMsgBox.hideDelay(3000); // mMsgBox.setSize(500, 200); // mMsgBox.addToLayout(mParentLayout); // mMsgBox.show(); // Toast.makeText(mContext, "Loaded caption successfully!", 1000).show(); } mFileType = mFilePath.substring(mFilePath.length() - 4, mFilePath.length()); if (mFileType.equals(FILE_TYPE_SRT)) { // 正则表达式,用于匹配类似于“01:54:16,332 --> 01:54:18,163”的时间描述字符行 mRegex = "([0-9]*\\n)([0-9]*:[0-9]*:[0-9]*,[0-9]*[\\s]*-->[\\s]*[0-9]*:[0-9]*:[0-9]*,[0-9]*\\n)(.*[\\s\\S]\\D*(?![0-9]*:[0-9]*:[0-9]*,[0-9]*[\\s]*-->[\\s]*[0-9]*:[0-9]*:[0-9]*,[0-9]*\\n))";// 匹配时间后的两行 if (mNewString == null) { return; } else { mMatcher = Pattern.compile(mRegex, Pattern.CASE_INSENSITIVE).matcher(mNewString); } while (mMatcher.find()) { // 以下对时间描述字符行进行格式转换和数学运算 int second_start = Integer.parseInt(mMatcher.group(2).substring(6, 8)); int minute_start = Integer.parseInt(mMatcher.group(2).substring(3, 5)); int hour_start = Integer.parseInt(mMatcher.group(2).substring(0, 2)); long startTime = (mTimeError + second_start + minute_start * 60 + hour_start * 3600) * 1000; mStartTimeFormat = mMatcher.group(2).substring(0, 12); mEndTimeFormat = mMatcher.group(2).substring(17, 29); int second_end = Integer.parseInt(mMatcher.group(2).substring(23, 25)); int minute_end = Integer.parseInt(mMatcher.group(2).substring(20, 22)); int hour_end = Integer.parseInt(mMatcher.group(2).substring(17, 19)); long endTime = (mTimeError + second_end + minute_end * 60 + hour_end * 3600) * 1000; mStartTime.add(startTime); mEndTime.add(endTime); StringBuilder sb_captions = new StringBuilder(mMatcher.group(3)); StringBuilder sb_startTime_format = new StringBuilder(mStartTimeFormat); StringBuilder sb_endTime_format = new StringBuilder(mEndTimeFormat); mCaptionsList.add(sb_captions); mStartTimeFormatList.add(sb_startTime_format); mEndTimeFormatList.add(sb_endTime_format); mCaptionsBean.setM_startTime(mStartTime); mCaptionsBean.setM_endTime(mEndTime); mCaptionsBean.setM_captions(mCaptionsList); } } else if (mFileType.equals(FILE_TYPE_SMI)) {//解析.SMI格式的字幕 mRegex = "<SYNC[\\s]*Start=([0-9]*)>([^<]*(?! ))"; mMatcher = Pattern.compile(mRegex, Pattern.CASE_INSENSITIVE).matcher(mNewString); String m_text_sim = null; while (mMatcher.find()) { if (mMatcher.group(2).contains(" ")) { m_text_sim = mMatcher.group(2).replace(" ", ""); } else { m_text_sim = mMatcher.group(2); } long startTime = Integer.parseInt(mMatcher.group(1)); mStartTime.add(startTime); StringBuilder sb_captions = new StringBuilder(m_text_sim); mCaptionsList.add(sb_captions); String string_second = mMatcher.group(1).substring(0, mMatcher.group(1).length() - 3); String string_ms = mMatcher.group(1).substring(mMatcher.group(1).length() - 3, mMatcher.group(1).length()); mStartTimeFormat = String.format("%02d:%02d:%02d:%03d", startTime / 3600000, startTime / 60000, Integer.parseInt(string_second) % 60, Integer.parseInt(string_ms)); StringBuilder sb_startTime_format = new StringBuilder(mStartTimeFormat); mStartTimeFormatList.add(sb_startTime_format); mCaptionsBean.setM_startTime(mStartTime); mCaptionsBean.setM_endTime(mStartTime); mCaptionsBean.setM_captions(mCaptionsList); } } else { mRegex = "([0-9]*\\n)([0-9]*:[0-9]*:[0-9]*,[0-9]*[\\s]*-->[\\s]*[0-9]*:[0-9]*:[0-9]*,[0-9]*\\n)(.*[\\s\\S]\\D*(?![0-9]*:[0-9]*:[0-9]*,[0-9]*[\\s]*-->[\\s]*[0-9]*:[0-9]*:[0-9]*,[0-9]*\\n))";// 匹配时间后的两行 } } public void mHandler() { mHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 1: long msgobj = (Integer) msg.obj; for (int i = 0; i < mStartTime.size(); i++) { if (msgobj / 1000 == mStartTime.get(i) / 1000) { mLine = i; updateText(); if (mEndTime.size()!=0&&mEndTime.get(mLine) > msgobj) { mHandler.sendEmptyMessageDelayed(3, mEndTime.get(mLine) - msgobj); } } } break; case 2: // updateTime(); break; case 3: hideText(); break; } } }; } public void updateText() { if (mLine < mStartTime.size()) { mCaptionsTV.setText(mCaptionsList.get(mLine)); } } public void hideText() { mCaptionsTV.setText(""); } public static String getCharset(File file) { String charset = "GBK"; byte[] first3Bytes = new byte[3]; try { boolean checked = false; BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); bis.mark(0); int read = bis.read(first3Bytes, 0, 3); if (read == -1) return charset; if (first3Bytes[0] == (byte) 0xFF && first3Bytes[1] == (byte) 0xFE) { charset = "UTF-16LE"; checked = true; } else if (first3Bytes[0] == (byte) 0xFE && first3Bytes[1] == (byte) 0xFF) { charset = "UTF-16BE"; checked = true; } else if (first3Bytes[0] == (byte) 0xEF && first3Bytes[1] == (byte) 0xBB && first3Bytes[2] == (byte) 0xBF) { charset = "UTF-8"; checked = true; } bis.reset(); if (!checked) { while ((read = bis.read()) != -1) { if (read >= 0xF0) break; if (0x80 <= read && read <= 0xBF) // 单独出现BF以下的,也算是GBK break; if (0xC0 <= read && read <= 0xDF) { read = bis.read(); if (0x80 <= read && read <= 0xBF) // 双字节 (0xC0 - 0xDF) // (0x80 // - 0xBF),也可能在GB编码内 continue; else break; } else if (0xE0 <= read && read <= 0xEF) {// 也有可能出错,但是几率较小 read = bis.read(); if (0x80 <= read && read <= 0xBF) { read = bis.read(); if (0x80 <= read && read <= 0xBF) { charset = "UTF-8"; break; } else break; } else break; } } } bis.close(); } catch (Exception e) { e.printStackTrace(); } return charset; } public void setCharset(String charset) { mCharset = charset; } public String getCharset(){ return mCharset; } }