• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "TextDescriptions2.h"
18 #include <media/stagefright/foundation/ByteUtils.h>
19 #include <media/stagefright/MediaErrors.h>
20 
21 namespace android {
22 
TextDescriptions2()23 TextDescriptions2::TextDescriptions2() {
24 }
25 
getPlayerMessageOfDescriptions(const uint8_t * data,ssize_t size,uint32_t flags,int timeMs,PlayerMessage * playerMsg)26 status_t TextDescriptions2::getPlayerMessageOfDescriptions(
27         const uint8_t *data, ssize_t size,
28         uint32_t flags, int timeMs, PlayerMessage *playerMsg) {
29     if (flags & IN_BAND_TEXT_3GPP) {
30         if (flags & GLOBAL_DESCRIPTIONS) {
31             return extract3GPPGlobalDescriptions(data, size, playerMsg);
32         } else if (flags & LOCAL_DESCRIPTIONS) {
33             return extract3GPPLocalDescriptions(data, size, timeMs, playerMsg);
34         }
35     } else if (flags & OUT_OF_BAND_TEXT_SRT) {
36         if (flags & LOCAL_DESCRIPTIONS) {
37             return extractSRTLocalDescriptions(data, size, timeMs, playerMsg);
38         }
39     }
40 
41     return ERROR_UNSUPPORTED;
42 }
43 
44 // Parse the SRT text sample, and store the timing and text sample in a PlayerMessage.
45 // The PlayerMessage will be sent to MediaPlayer2.java through event, and will be
46 // parsed in TimedText.java.
extractSRTLocalDescriptions(const uint8_t * data,ssize_t size,int timeMs,PlayerMessage * playerMsg)47 status_t TextDescriptions2::extractSRTLocalDescriptions(
48         const uint8_t *data, ssize_t size, int timeMs, PlayerMessage *playerMsg) {
49     playerMsg->add_values()->set_int32_value(KEY_LOCAL_SETTING);
50     playerMsg->add_values()->set_int32_value(KEY_START_TIME);
51     playerMsg->add_values()->set_int32_value(timeMs);
52 
53     playerMsg->add_values()->set_int32_value(KEY_STRUCT_TEXT);
54     playerMsg->add_values()->set_bytes_value(data, size);
55 
56     return OK;
57 }
58 
59 // Extract the local 3GPP display descriptions. 3GPP local descriptions
60 // are appended to the text sample if any.
extract3GPPLocalDescriptions(const uint8_t * data,ssize_t size,int timeMs,PlayerMessage * playerMsg)61 status_t TextDescriptions2::extract3GPPLocalDescriptions(
62         const uint8_t *data, ssize_t size,
63         int timeMs, PlayerMessage *playerMsg) {
64 
65     playerMsg->add_values()->set_int32_value(KEY_LOCAL_SETTING);
66 
67     // write start time to display this text sample
68     playerMsg->add_values()->set_int32_value(KEY_START_TIME);
69     playerMsg->add_values()->set_int32_value(timeMs);
70 
71     if (size < 2) {
72         return OK;
73     }
74     ssize_t textLen = (*data) << 8 | (*(data + 1));
75 
76     if (size < textLen + 2) {
77         return OK;
78     }
79 
80     // write text sample length and text sample itself
81     playerMsg->add_values()->set_int32_value(KEY_STRUCT_TEXT);
82     playerMsg->add_values()->set_bytes_value(data + 2, textLen);
83 
84     if (size > textLen + 2) {
85         data += (textLen + 2);
86         size -= (textLen + 2);
87     } else {
88         return OK;
89     }
90 
91     while (size >= 8) {
92         const uint8_t *tmpData = data;
93         ssize_t chunkSize = U32_AT(tmpData);      // size includes size and type
94         uint32_t chunkType = U32_AT(tmpData + 4);
95 
96         if (chunkSize <= 8 || chunkSize > size) {
97             return OK;
98         }
99 
100         size_t remaining = chunkSize - 8;
101 
102         tmpData += 8;
103 
104         switch(chunkType) {
105             // 'tbox' box to indicate the position of the text with values
106             // of top, left, bottom and right
107             case FOURCC('t', 'b', 'o', 'x'):
108             {
109                 if (remaining < 8) {
110                     return OK;
111                 }
112                 playerMsg->add_values()->set_int32_value(KEY_STRUCT_TEXT_POS);
113                 playerMsg->add_values()->set_int32_value(U16_AT(tmpData));
114                 playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 2));
115                 playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 4));
116                 playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 6));
117 
118                 tmpData += 8;
119                 remaining -= 8;
120                 break;
121             }
122             default:
123             {
124                 break;
125             }
126         }
127 
128         data += chunkSize;
129         size -= chunkSize;
130     }
131 
132     return OK;
133 }
134 
135 // To extract box 'tx3g' defined in 3GPP TS 26.245, and store it in a PlayerMessage
extract3GPPGlobalDescriptions(const uint8_t * data,ssize_t size,PlayerMessage * playerMsg)136 status_t TextDescriptions2::extract3GPPGlobalDescriptions(
137         const uint8_t *data, ssize_t size, PlayerMessage *playerMsg) {
138 
139     playerMsg->add_values()->set_int32_value(KEY_GLOBAL_SETTING);
140 
141     while (size >= 8) {
142         ssize_t chunkSize = U32_AT(data);
143         uint32_t chunkType = U32_AT(data + 4);
144         const uint8_t *tmpData = data;
145         tmpData += 8;
146         size_t remaining = size - 8;
147 
148         if (chunkSize <= 8 || size < chunkSize) {
149             return OK;
150         }
151         switch(chunkType) {
152             case FOURCC('t', 'x', '3', 'g'):
153             {
154                 if (remaining < 18) {
155                     return OK;
156                 }
157                 // Skip DISPLAY_FLAGS, STRUCT_JUSTIFICATION, and BACKGROUND_COLOR_RGBA
158                 tmpData += 18;
159                 remaining -= 18;
160 
161                 if (remaining < 8) {
162                     return OK;
163                 }
164                 playerMsg->add_values()->set_int32_value(KEY_STRUCT_TEXT_POS);
165                 playerMsg->add_values()->set_int32_value(U16_AT(tmpData));
166                 playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 2));
167                 playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 4));
168                 playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 6));
169 
170                 tmpData += 8;
171                 remaining -= 18;
172                 // Ignore remaining data.
173                 break;
174             }
175             default:
176             {
177                 break;
178             }
179         }
180 
181         data += chunkSize;
182         size -= chunkSize;
183     }
184 
185     return OK;
186 }
187 
188 }  // namespace android
189