blob: f48eaccbe35db74760961e71c5c47d99a155435c [file] [log] [blame]
/*
* 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