Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a0e816ac authored by Dongwon Kang's avatar Dongwon Kang
Browse files

MediaPlayer2: use protobuf instead of parcel for TimedText

Test: MediaPlayer2Test
Bug: 112767225
Change-Id: I3f6b06d49b2a245e8350d792c01bccb9fd44037f
parent 41929fb5
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -60,7 +60,7 @@ cc_library {
        "libprotobuf-cpp-lite",
        "libstagefright_nuplayer2",
        "libstagefright_rtsp",
        "libstagefright_timedtext",
        "libstagefright_timedtext2",
    ],

    export_include_dirs: [
+9 −10
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@
#include "NuPlayer2Source.h"
#include "RTSPSource2.h"
#include "GenericSource2.h"
#include "TextDescriptions.h"
#include "TextDescriptions2.h"

#include "ATSParser.h"

@@ -2870,7 +2870,7 @@ void NuPlayer2::sendTimedTextData(const sp<ABuffer> &buffer) {
    const void *data;
    size_t size = 0;
    int64_t timeUs;
    int32_t flag = TextDescriptions::IN_BAND_TEXT_3GPP;
    int32_t flag = TextDescriptions2::IN_BAND_TEXT_3GPP;

    AString mime;
    CHECK(buffer->meta()->findString("mime", &mime));
@@ -2879,22 +2879,21 @@ void NuPlayer2::sendTimedTextData(const sp<ABuffer> &buffer) {
    data = buffer->data();
    size = buffer->size();

    Parcel parcel;
    PlayerMessage playerMsg;
    if (size > 0) {
        CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
        int32_t global = 0;
        if (buffer->meta()->findInt32("global", &global) && global) {
            flag |= TextDescriptions::GLOBAL_DESCRIPTIONS;
            flag |= TextDescriptions2::GLOBAL_DESCRIPTIONS;
        } else {
            flag |= TextDescriptions::LOCAL_DESCRIPTIONS;
            flag |= TextDescriptions2::LOCAL_DESCRIPTIONS;
        }
        TextDescriptions::getParcelOfDescriptions(
                (const uint8_t *)data, size, flag, timeUs / 1000, &parcel);
        TextDescriptions2::getPlayerMessageOfDescriptions(
                (const uint8_t *)data, size, flag, timeUs / 1000, &playerMsg);
    }

    if ((parcel.dataSize() > 0)) {
        // TODO: convert text data to PlayerMessage
        // notifyListener(mSrcId, MEDIA2_TIMED_TEXT, 0, 0, &parcel);
    if (playerMsg.values_size() > 0) {
        notifyListener(mSrcId, MEDIA2_TIMED_TEXT, 0, 0, &playerMsg);
    } else {  // send an empty timed text
        notifyListener(mSrcId, MEDIA2_TIMED_TEXT, 0, 0);
    }
+33 −0
Original line number Diff line number Diff line
@@ -25,3 +25,36 @@ cc_library_static {

    shared_libs: ["libmedia"],
}

cc_library_static {
    name: "libstagefright_timedtext2",

    srcs: ["TextDescriptions2.cpp"],

    static_libs: [
        "libmediaplayer2-protos",
        "libprotobuf-cpp-lite",
    ],

    cflags: [
        "-Wno-multichar",
        "-Werror",
        "-Wall",
    ],

    sanitize: {
        misc_undefined: [
            "signed-integer-overflow",
        ],
        cfi: true,
        diag: {
            cfi: true,
        },
    },

    include_dirs: [
        "frameworks/av/media/libstagefright",
    ],

    shared_libs: ["libmedia"],
}
+188 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "TextDescriptions2.h"
#include <media/stagefright/foundation/ByteUtils.h>
#include <media/stagefright/MediaErrors.h>

namespace android {

TextDescriptions2::TextDescriptions2() {
}

status_t TextDescriptions2::getPlayerMessageOfDescriptions(
        const uint8_t *data, ssize_t size,
        uint32_t flags, int timeMs, PlayerMessage *playerMsg) {
    if (flags & IN_BAND_TEXT_3GPP) {
        if (flags & GLOBAL_DESCRIPTIONS) {
            return extract3GPPGlobalDescriptions(data, size, playerMsg);
        } else if (flags & LOCAL_DESCRIPTIONS) {
            return extract3GPPLocalDescriptions(data, size, timeMs, playerMsg);
        }
    } else if (flags & OUT_OF_BAND_TEXT_SRT) {
        if (flags & LOCAL_DESCRIPTIONS) {
            return extractSRTLocalDescriptions(data, size, timeMs, playerMsg);
        }
    }

    return ERROR_UNSUPPORTED;
}

// Parse the SRT text sample, and store the timing and text sample in a PlayerMessage.
// The PlayerMessage will be sent to MediaPlayer2.java through event, and will be
// parsed in TimedText.java.
status_t TextDescriptions2::extractSRTLocalDescriptions(
        const uint8_t *data, ssize_t size, int timeMs, PlayerMessage *playerMsg) {
    playerMsg->add_values()->set_int32_value(KEY_LOCAL_SETTING);
    playerMsg->add_values()->set_int32_value(KEY_START_TIME);
    playerMsg->add_values()->set_int32_value(timeMs);

    playerMsg->add_values()->set_int32_value(KEY_STRUCT_TEXT);
    playerMsg->add_values()->set_bytes_value(data, size);

    return OK;
}

// Extract the local 3GPP display descriptions. 3GPP local descriptions
// are appended to the text sample if any.
status_t TextDescriptions2::extract3GPPLocalDescriptions(
        const uint8_t *data, ssize_t size,
        int timeMs, PlayerMessage *playerMsg) {

    playerMsg->add_values()->set_int32_value(KEY_LOCAL_SETTING);

    // write start time to display this text sample
    playerMsg->add_values()->set_int32_value(KEY_START_TIME);
    playerMsg->add_values()->set_int32_value(timeMs);

    if (size < 2) {
        return OK;
    }
    ssize_t textLen = (*data) << 8 | (*(data + 1));

    if (size < textLen + 2) {
        return OK;
    }

    // write text sample length and text sample itself
    playerMsg->add_values()->set_int32_value(KEY_STRUCT_TEXT);
    playerMsg->add_values()->set_bytes_value(data + 2, textLen);

    if (size > textLen + 2) {
        data += (textLen + 2);
        size -= (textLen + 2);
    } else {
        return OK;
    }

    while (size >= 8) {
        const uint8_t *tmpData = data;
        ssize_t chunkSize = U32_AT(tmpData);      // size includes size and type
        uint32_t chunkType = U32_AT(tmpData + 4);

        if (chunkSize <= 8 || chunkSize > size) {
            return OK;
        }

        size_t remaining = chunkSize - 8;

        tmpData += 8;

        switch(chunkType) {
            // 'tbox' box to indicate the position of the text with values
            // of top, left, bottom and right
            case FOURCC('t', 'b', 'o', 'x'):
            {
                if (remaining < 8) {
                    return OK;
                }
                playerMsg->add_values()->set_int32_value(KEY_STRUCT_TEXT_POS);
                playerMsg->add_values()->set_int32_value(U16_AT(tmpData));
                playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 2));
                playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 4));
                playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 6));

                tmpData += 8;
                remaining -= 8;
                break;
            }
            default:
            {
                break;
            }
        }

        data += chunkSize;
        size -= chunkSize;
    }

    return OK;
}

// To extract box 'tx3g' defined in 3GPP TS 26.245, and store it in a PlayerMessage
status_t TextDescriptions2::extract3GPPGlobalDescriptions(
        const uint8_t *data, ssize_t size, PlayerMessage *playerMsg) {

    playerMsg->add_values()->set_int32_value(KEY_GLOBAL_SETTING);

    while (size >= 8) {
        ssize_t chunkSize = U32_AT(data);
        uint32_t chunkType = U32_AT(data + 4);
        const uint8_t *tmpData = data;
        tmpData += 8;
        size_t remaining = size - 8;

        if (size < chunkSize) {
            return OK;
        }
        switch(chunkType) {
            case FOURCC('t', 'x', '3', 'g'):
            {
                if (remaining < 18) {
                    return OK;
                }
                // Skip DISPLAY_FLAGS, STRUCT_JUSTIFICATION, and BACKGROUND_COLOR_RGBA
                tmpData += 18;
                remaining -= 18;

                if (remaining < 8) {
                    return OK;
                }
                playerMsg->add_values()->set_int32_value(KEY_STRUCT_TEXT_POS);
                playerMsg->add_values()->set_int32_value(U16_AT(tmpData));
                playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 2));
                playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 4));
                playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 6));

                tmpData += 8;
                remaining -= 18;
                // Ignore remaining data.
                break;
            }
            default:
            {
                break;
            }
        }

        data += chunkSize;
        size -= chunkSize;
    }

    return OK;
}

}  // namespace android
+88 −0
Original line number Diff line number Diff line
 /*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef TEXT_DESCRIPTIONS2_H_

#define TEXT_DESCRIPTIONS2_H_

#include <binder/Parcel.h>
#include <media/stagefright/foundation/ABase.h>

#include "mediaplayer2.pb.h"

using android::media::MediaPlayer2Proto::PlayerMessage;

namespace android {

class TextDescriptions2 {
public:
    enum {
        IN_BAND_TEXT_3GPP             = 0x01,
        OUT_OF_BAND_TEXT_SRT          = 0x02,

        GLOBAL_DESCRIPTIONS           = 0x100,
        LOCAL_DESCRIPTIONS            = 0x200,
    };

    static status_t getPlayerMessageOfDescriptions(
            const uint8_t *data, ssize_t size,
            uint32_t flags, int timeMs, PlayerMessage *playerMsg);
private:
    TextDescriptions2();

    enum {
        // These keys must be in sync with the keys in TimedText.java
        KEY_DISPLAY_FLAGS                 = 1, // int
        KEY_STYLE_FLAGS                   = 2, // int
        KEY_BACKGROUND_COLOR_RGBA         = 3, // int
        KEY_HIGHLIGHT_COLOR_RGBA          = 4, // int
        KEY_SCROLL_DELAY                  = 5, // int
        KEY_WRAP_TEXT                     = 6, // int
        KEY_START_TIME                    = 7, // int
        KEY_STRUCT_BLINKING_TEXT_LIST     = 8, // List<CharPos>
        KEY_STRUCT_FONT_LIST              = 9, // List<Font>
        KEY_STRUCT_HIGHLIGHT_LIST         = 10, // List<CharPos>
        KEY_STRUCT_HYPER_TEXT_LIST        = 11, // List<HyperText>
        KEY_STRUCT_KARAOKE_LIST           = 12, // List<Karaoke>
        KEY_STRUCT_STYLE_LIST             = 13, // List<Style>
        KEY_STRUCT_TEXT_POS               = 14, // TextPos
        KEY_STRUCT_JUSTIFICATION          = 15, // Justification
        KEY_STRUCT_TEXT                   = 16, // Text

        KEY_GLOBAL_SETTING                = 101,
        KEY_LOCAL_SETTING                 = 102,
        KEY_START_CHAR                    = 103,
        KEY_END_CHAR                      = 104,
        KEY_FONT_ID                       = 105,
        KEY_FONT_SIZE                     = 106,
        KEY_TEXT_COLOR_RGBA               = 107,
    };

    static status_t extractSRTLocalDescriptions(
            const uint8_t *data, ssize_t size,
            int timeMs, PlayerMessage *playerMsg);
    static status_t extract3GPPGlobalDescriptions(
            const uint8_t *data, ssize_t size,
            PlayerMessage *playerMsg);
    static status_t extract3GPPLocalDescriptions(
            const uint8_t *data, ssize_t size,
            int timeMs, PlayerMessage *playerMsg);

    DISALLOW_EVIL_CONSTRUCTORS(TextDescriptions2);
};

}  // namespace android
#endif  // TEXT_DESCRIPTIONS2_H_