Статьи

Android — поддержка субтитров Google TV

Одним из наиболее частых вопросов от пользователей Serenity для Google TV является возможность воспроизведения субтитров с фильмом. Plex действительно предоставляет информацию, если она там есть, но до Android 4.1 (она же Jelly Bean) не было встроенной поддержки субтитров для видеопроигрывателя. Даже тогда, кажется, есть проблемы с чтением потоков для субтитров. Устройства Google TV в настоящее время основаны на Android 3.2 (Honeycomb), у которой нет API для воспроизведения субтитров. Plex в этих случаях обычно транскодирует субтитры в видеопоток, однако Serenity не поддерживает транскодирование. Так что делать. Простой поворот к программному обеспечению с открытым исходным кодом для некоторой помощи.


Получить его в Google Play

На GitHub скрыт конвертер субтитров Дж. Дэвида Рекехо. Это был исследовательский проект PHD, и он позволяет конвертировать из одного формата субтитров в другой. Приятно то, что TimedTextObject содержит общий формат для субтитров. Как только он в этом формате, это вопрос навигации по дереву и проверки смещения времени, когда заголовок отображается и когда он должен исчезнуть.

Поскольку устройства Google TV не имеют встроенной поддержки отображения субтитров, как нам поступить? Serenity использует модифицированную версию MediaController и SurfaceView. Основное действие содержит следующий макет XML:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version='1.0' encoding='utf-8'?>
<RelativeLayout xmlns:android='http://schemas.android.com/apk/res/android'
    android:layout_width='fill_parent'
    android:layout_height='fill_parent'
    android:orientation='vertical'
    android:id='@+id/video_playeback'
    android:background='#000000'
    android:keepScreenOn='true' >
<SurfaceView android:id='@+id/surfaceView'
android:layout_width='wrap_content'
android:layout_height='wrap_content'
android:layout_centerInParent='true'
/>
 
<TextView android:id='@+id/txtSubtitles'
android:layout_alignParentBottom='true'
android:layout_height='wrap_content'
android:layout_width='wrap_content'
android:gravity='center'
android:layout_centerHorizontal='true'
android:visibility='invisible'
style='@android:style/TextAppearance.Large'/>
 
</RelativeLayout>

Он содержит вид поверхности для видео, которое будет нарисовано, и TextView, который будет использоваться для отображения субтитров. Чтобы узнать, когда отображать субтитры во время воспроизведения, мы используем обработчик с небольшой задержкой, когда он должен выполняться. Когда он вызывается в первый раз, он запускается сразу. Каждое последующее выполнение задерживается на 100 миллисекунд.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
private Handler subtitleDisplayHandler = new Handler();
private Runnable subtitle = new Runnable() {
 public void run() {
   if (isMediaPlayerStateValid() && mediaPlayer.isPlaying()) {
      int currentPos = mediaPlayer.getCurrentPosition();
      Collection<Caption> subtitles =  srt.captions.values();
      for(Caption caption : subtitles) {
         if (currentPos >= caption.start.getMilliseconds() && currentPos <= caption.end.getMilliseconds()) {
            onTimedText(caption);
            break;
     } else if (currentPos > caption.end.getMilliseconds()) {
        onTimedText(null);
         }
      }
   }
   subtitleDisplayHandler.postDelayed(this, SUBTITLE_DISPLAY_CHECK);
 };
};

PostDelayed повторно выполнит обработчик с запуском на указанное количество миллисекунд. OnTimedText — это то, что отвечает за отображение или скрытие субтитров во время воспроизведения.

1
2
3
4
5
6
7
8
9
public void onTimedText(Caption text) {
   TextView subtitles = (TextView) findViewById(R.id.txtSubtitles);
   if (text == null) {
      subtitles.setVisibility(View.INVISIBLE);
      return;
   }
   subtitles.setText(Html.fromHtml(text.content));
   subtitles.setVisibility(View.VISIBLE);
}

Поскольку субтитры могут быть помечены HTML для указания курсива, полужирного шрифта или подчеркивания, мы используем метод Html.fromHtml, чтобы установить соответствующий текст и настроить видимость. Если текст был нулевым, вид скрыт. Весь процесс запускается асинхронной задачей, которая извлекает субтитры из Plex в виде потока.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
public class SubtitleAsyncTask extends AsyncTask<Void, Void, Void> {
  
  @Override
  protected Void doInBackground(Void... params) {
    if (subtitleURL != null) {
       try {
          URL url = new URL(subtitleURL);
          InputStream stream = url.openStream();
          FormatSRT formatSRT = new FormatSRT();
          srt = formatSRT.parseFile(stream);
          subtitleDisplayHandler.post(subtitle);
       } catch (Exception e) {
          Log.e(getClass().getName(), e.getMessage(), e);
       }
    }
    // TODO Auto-generated method stub
    return null;
  }
}

Это просто читает поток и анализирует отформатированные файлы субтитров SubRip (SRT) в TimedTextObject, а затем запускает обработчик.

Важно убедиться, что по завершении вашей деятельности вы удалите все обратные вызовы в обработчике. Поэтому обязательно сделайте следующее в вашем методе onFinish:

1
subtitleDisplayHandler.removeCallbacks(subtitle);

Это должно работать независимо от версии Android. Он был протестирован на Android 3.2 в последней версии JellyBean. Если вам нужно манипулировать субтитрами, использовать их или преобразовывать их в другие форматы, вы можете попробовать проект subtitleConverter. Ожидайте увидеть эту поддержку с Serenity для Google TV v1.1.0.

Ссылка: Android — поддержка Google TV Subtitle от нашего партнера JCG Дэвида Карвера в блоге Intellectual Cramps .