Configure Subtitle Display Method Media Player Subsystem and Interactive Application

The Subtitle Display method provides the ability to discern between image and text-based subtitles and how to render image or text. This accommodates non-4K legacy media that is not packaged with text-based subtitles in the same Interactive application.

Text-based subtitles are the preferred method on NEXT and future monitors. Text-based subtitles provide more flexibility around rendering subtitles, such as color, size and coordinates, and additionally serve to meet accessibility requirements.

This guide details how to configure subtitle displays for the Media Player subsystem and Interactive application.

Prerequisites

You will need the following:

  • An Interactive application that contains media.

Subtitle Display Method Configuration

Set Subtitle_Display_Method to the following:

  • 0 — Image rendered by the Media Player subsystem

  • 1 — Image rendered by the Interactive application

Example:

Subtitle_Display_Method = 1;

Media Player Subsystem

When Subtitle_Display_Method is set to 1, the Media Player subsystem notifies the client to display a subtitle image.

The notification includes the starting coordinates and name of the file containing the image. The end coordinates are set to -1. If the name of the file is NULL, nothing displays.

On Android, the MediaPlayer class is expected to implement onTimedTextListener and receive a TimedText object using onTimedText.

Regardless of the configuration value, if the media is prepared with text-based subtitles, the notification includes text to display. The starting and ending coordinates are set to non-negative numbers.

Interactive Application

For an image-based subtitle to be rendered by the Interactive application, MediaPlayer is notified via OnTimedText() of the image file to display and starting coordinates of the image. The ending coordinates are set to -1.

When the image-based subtitle is in the onTimedText callback of MediaPlayer, the image path is received.

Subtitle Display Sample Code

@Override
public void onTimedText(MediaPlayer mpTimedText, TimedText text) {
    if (text == null)
        return;

    if (text == null) {
        return;
    }
    Rect rect = text.getBounds();

    String content = text.getText();
    if (content == null)
        content = "";
    if (rect.bottom >= 0 && rect.left >= 0 && rect.right >= 0 && rect.top >=
        0) {
        // this is text based subtitle.
        Log.d(TAG, "onTimedText text subtitle text = " + content + " 
            bottom = " + rect.bottom + 
            " left = " + rect.left + " right = " + rect.right + " top = " +
            rect.top);
        // add code to display subtitle at the given position
    } else {
        // this is image based subtitle.

        Log.d(TAG, "onTimedText imagePath = " + content + " bottom = " +
            rect.bottom +
            " left = " + rect.left + " right = " + rect.right + " top = " +
            rect.top);
        mSubtitleImageView.setVisibility(View.VISIBLE);

        String path = content;

        int left = text.getBounds().left;
        int top = text.getBounds().top;

        Log.i(APP, "onTimedText location - " + path + " left - " + left +
            " top  - " + top + " bottom = " +
            text.getBounds().bottom +
            " right = " + text.getBounds().right);

        displayImageSubtitle(path, left, top);
    }
}

private void displayImageSubtitle(String subPath, int left, int top) {

    if (subPath != null && fileExists(subPath)) {
        Bitmap srcBitmap = BitmapFactory.decodeFile(subPath);
        if (srcBitmap == null) {
            Log.e(APP, "Unable to decode bitmap " + subPath);
            mSubtitleImageView.setImageDrawable(null);
            return;
        }
        Bitmap filteredBitmap = srcBitmap.copy(Bitmap.Config.ARGB_8888,
            true);
        int subtitleWidth = filteredBitmap.getWidth();
        int subtitleHeight = filteredBitmap.getHeight();

        int videoHeight = 0;
        int videoWidth = 0;

        if (mVpaMediaPlayer != null) {
            videoHeight = mVpaMediaPlayer.getVideoHeight();
            videoWidth = mVpaMediaPlayer.getVideoWidth();
        }

        if (videoHeight == 0 || subtitleWidth == 0 || videoWidth == 0) {
            Log.e(APP, "drawSub invalid videoHeight = " + videoHeight +
                " subtitleWidth = " + subtitleWidth);
            mSubtitleImageView.setImageDrawable(null);
            return;
        }

        int[] allpixels = new int[subtitleWidth * subtitleHeight];
        srcBitmap.getPixels(allpixels, 0, subtitleWidth, 0, 0,
            subtitleWidth, subtitleHeight);

        int maskColor = Color.rgb(0, 1, 0);
        for (int i = 0; i < allpixels.length; i++) {
            // convert background color to transparent
            if (allpixels[i] == Color.BLACK || allpixels[i] == maskColor) {
                allpixels[i] = Color.TRANSPARENT;
            }
        }

        filteredBitmap.setPixels(allpixels, 0, subtitleWidth, 0, 0,
            subtitleWidth, subtitleHeight);

        double scaleFactor = ((double) mScreenWidth) / subtitleWidth;

        int scaledSubtitleHeight = (int)(scaleFactor * subtitleHeight);

        int scaledX = (int)((double) left / videoWidth) * mScreenWidth;
        int scaledY = (int)(((double) top / videoHeight) * mScreenHeight);

        Log.d(APP, "drawSub scaledSubtitleWidth = " + mScreenWidth +
            " scaledSubtitleHeight = " + scaledSubtitleHeight +
            " subtitleWidth = " + subtitleWidth +
            " subtitleHeight = " + subtitleHeight + " screenWidth = " +
            mScreenWidth + " screenHeight = " + mScreenHeight +
            " scaledX = " + scaledX + " scaledY = " + scaledY +
            " orig x = " + left + " orig y = " + top);

        Bitmap scaledBitmap = Bitmap.createScaledBitmap(filteredBitmap,
            mScreenWidth, scaledSubtitleHeight, true);

        RelativeLayout.LayoutParams params = (LayoutParams) mSubtitleImageView

            .getLayoutParams();
        params.leftMargin = scaledX;
        params.topMargin = scaledY;
        mSubtitleImageView.setLayoutParams(params);

        mSubtitleImageView.setImageBitmap(scaledBitmap);
    } else {
        Log.d(APP, "subtitle image does not exist");
        mSubtitleImageView.setImageDrawable(null);
    }
}