1 /* 2 * Copyright (C) 2011 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 "TextDescriptions.h" 18 #include <media/stagefright/Utils.h> 19 #include <media/stagefright/MediaErrors.h> 20 21 namespace android { 22 23 TextDescriptions::TextDescriptions() { 24 } 25 26 status_t TextDescriptions::getParcelOfDescriptions( 27 const uint8_t *data, ssize_t size, 28 uint32_t flags, int timeMs, Parcel *parcel) { 29 parcel->freeData(); 30 31 if (flags & IN_BAND_TEXT_3GPP) { 32 if (flags & GLOBAL_DESCRIPTIONS) { 33 return extract3GPPGlobalDescriptions(data, size, parcel, 0); 34 } else if (flags & LOCAL_DESCRIPTIONS) { 35 return extract3GPPLocalDescriptions(data, size, timeMs, parcel, 0); 36 } 37 } else if (flags & OUT_OF_BAND_TEXT_SRT) { 38 if (flags & LOCAL_DESCRIPTIONS) { 39 return extractSRTLocalDescriptions(data, size, timeMs, parcel); 40 } 41 } 42 43 return ERROR_UNSUPPORTED; 44 } 45 46 // Parse the SRT text sample, and store the timing and text sample in a Parcel. 47 // The Parcel will be sent to MediaPlayer.java through event, and will be 48 // parsed in TimedText.java. 49 status_t TextDescriptions::extractSRTLocalDescriptions( 50 const uint8_t *data, ssize_t size, int timeMs, Parcel *parcel) { 51 parcel->writeInt32(KEY_LOCAL_SETTING); 52 parcel->writeInt32(KEY_START_TIME); 53 parcel->writeInt32(timeMs); 54 55 parcel->writeInt32(KEY_STRUCT_TEXT); 56 // write the size of the text sample 57 parcel->writeInt32(size); 58 // write the text sample as a byte array 59 parcel->writeInt32(size); 60 parcel->write(data, size); 61 62 return OK; 63 } 64 65 // Extract the local 3GPP display descriptions. 3GPP local descriptions 66 // are appended to the text sample if any. The descriptions could include 67 // information such as text styles, highlights, karaoke and so on. They 68 // are contained in different boxes, such as 'styl' box contains text 69 // styles, and 'krok' box contains karaoke timing and positions. 70 status_t TextDescriptions::extract3GPPLocalDescriptions( 71 const uint8_t *data, ssize_t size, 72 int timeMs, Parcel *parcel, int depth) { 73 if (depth == 0) { 74 parcel->writeInt32(KEY_LOCAL_SETTING); 75 76 // write start time to display this text sample 77 parcel->writeInt32(KEY_START_TIME); 78 parcel->writeInt32(timeMs); 79 80 ssize_t textLen = (*data) << 8 | (*(data + 1)); 81 82 // write text sample length and text sample itself 83 parcel->writeInt32(KEY_STRUCT_TEXT); 84 parcel->writeInt32(textLen); 85 parcel->writeInt32(textLen); 86 parcel->write(data + 2, textLen); 87 88 if (size > textLen) { 89 data += (textLen + 2); 90 size -= (textLen + 2); 91 } else { 92 return OK; 93 } 94 } 95 96 const uint8_t *tmpData = data; 97 ssize_t chunkSize = U32_AT(tmpData); 98 uint32_t chunkType = U32_AT(tmpData + 4); 99 100 if (chunkSize <= 0) { 101 return OK; 102 } 103 104 tmpData += 8; 105 106 switch(chunkType) { 107 // 'styl' box specifies the style of the text. 108 case FOURCC('s', 't', 'y', 'l'): 109 { 110 uint16_t count = U16_AT(tmpData); 111 112 tmpData += 2; 113 114 for (int i = 0; i < count; i++) { 115 parcel->writeInt32(KEY_STRUCT_STYLE_LIST); 116 parcel->writeInt32(KEY_START_CHAR); 117 parcel->writeInt32(U16_AT(tmpData)); 118 119 parcel->writeInt32(KEY_END_CHAR); 120 parcel->writeInt32(U16_AT(tmpData + 2)); 121 122 parcel->writeInt32(KEY_FONT_ID); 123 parcel->writeInt32(U16_AT(tmpData + 4)); 124 125 parcel->writeInt32(KEY_STYLE_FLAGS); 126 parcel->writeInt32(*(tmpData + 6)); 127 128 parcel->writeInt32(KEY_FONT_SIZE); 129 parcel->writeInt32(*(tmpData + 7)); 130 131 parcel->writeInt32(KEY_TEXT_COLOR_RGBA); 132 uint32_t rgba = *(tmpData + 8) << 24 | *(tmpData + 9) << 16 133 | *(tmpData + 10) << 8 | *(tmpData + 11); 134 parcel->writeInt32(rgba); 135 136 tmpData += 12; 137 } 138 139 break; 140 } 141 // 'krok' box. The number of highlight events is specified, and each 142 // event is specified by a starting and ending char offset and an end 143 // time for the event. 144 case FOURCC('k', 'r', 'o', 'k'): 145 { 146 147 parcel->writeInt32(KEY_STRUCT_KARAOKE_LIST); 148 149 int startTime = U32_AT(tmpData); 150 uint16_t count = U16_AT(tmpData + 4); 151 parcel->writeInt32(count); 152 153 tmpData += 6; 154 int lastEndTime = 0; 155 156 for (int i = 0; i < count; i++) { 157 parcel->writeInt32(startTime + lastEndTime); 158 159 lastEndTime = U32_AT(tmpData); 160 parcel->writeInt32(lastEndTime); 161 162 parcel->writeInt32(U16_AT(tmpData + 4)); 163 parcel->writeInt32(U16_AT(tmpData + 6)); 164 165 tmpData += 8; 166 } 167 168 break; 169 } 170 // 'hlit' box specifies highlighted text 171 case FOURCC('h', 'l', 'i', 't'): 172 { 173 parcel->writeInt32(KEY_STRUCT_HIGHLIGHT_LIST); 174 175 // the start char offset to highlight 176 parcel->writeInt32(U16_AT(tmpData)); 177 // the last char offset to highlight 178 parcel->writeInt32(U16_AT(tmpData + 2)); 179 180 break; 181 } 182 // 'hclr' box specifies the RGBA color: 8 bits each of 183 // red, green, blue, and an alpha(transparency) value 184 case FOURCC('h', 'c', 'l', 'r'): 185 { 186 parcel->writeInt32(KEY_HIGHLIGHT_COLOR_RGBA); 187 188 uint32_t rgba = *(tmpData) << 24 | *(tmpData + 1) << 16 189 | *(tmpData + 2) << 8 | *(tmpData + 3); 190 parcel->writeInt32(rgba); 191 192 break; 193 } 194 // 'dlay' box specifies a delay after a scroll in and/or 195 // before scroll out. 196 case FOURCC('d', 'l', 'a', 'y'): 197 { 198 parcel->writeInt32(KEY_SCROLL_DELAY); 199 200 uint32_t delay = *(tmpData) << 24 | *(tmpData + 1) << 16 201 | *(tmpData + 2) << 8 | *(tmpData + 3); 202 parcel->writeInt32(delay); 203 204 break; 205 } 206 // 'href' box for hyper text link 207 case FOURCC('h', 'r', 'e', 'f'): 208 { 209 parcel->writeInt32(KEY_STRUCT_HYPER_TEXT_LIST); 210 211 // the start offset of the text to be linked 212 parcel->writeInt32(U16_AT(tmpData)); 213 // the end offset of the text 214 parcel->writeInt32(U16_AT(tmpData + 2)); 215 216 // the number of bytes in the following URL 217 int len = *(tmpData + 4); 218 parcel->writeInt32(len); 219 220 // the linked-to URL 221 parcel->writeInt32(len); 222 parcel->write(tmpData + 5, len); 223 224 tmpData += (5 + len); 225 226 // the number of bytes in the following "alt" string 227 len = *tmpData; 228 parcel->writeInt32(len); 229 230 // an "alt" string for user display 231 parcel->writeInt32(len); 232 parcel->write(tmpData + 1, len); 233 234 break; 235 } 236 // 'tbox' box to indicate the position of the text with values 237 // of top, left, bottom and right 238 case FOURCC('t', 'b', 'o', 'x'): 239 { 240 parcel->writeInt32(KEY_STRUCT_TEXT_POS); 241 parcel->writeInt32(U16_AT(tmpData)); 242 parcel->writeInt32(U16_AT(tmpData + 2)); 243 parcel->writeInt32(U16_AT(tmpData + 4)); 244 parcel->writeInt32(U16_AT(tmpData + 6)); 245 246 break; 247 } 248 // 'blnk' to specify the char range to be blinked 249 case FOURCC('b', 'l', 'n', 'k'): 250 { 251 parcel->writeInt32(KEY_STRUCT_BLINKING_TEXT_LIST); 252 253 // start char offset 254 parcel->writeInt32(U16_AT(tmpData)); 255 // end char offset 256 parcel->writeInt32(U16_AT(tmpData + 2)); 257 258 break; 259 } 260 // 'twrp' box specifies text wrap behavior. If the value if 0x00, 261 // then no wrap. If it's 0x01, then automatic 'soft' wrap is enabled. 262 // 0x02-0xff are reserved. 263 case FOURCC('t', 'w', 'r', 'p'): 264 { 265 parcel->writeInt32(KEY_WRAP_TEXT); 266 parcel->writeInt32(*tmpData); 267 268 break; 269 } 270 default: 271 { 272 break; 273 } 274 } 275 276 if (size > chunkSize) { 277 data += chunkSize; 278 size -= chunkSize; 279 // continue to parse next box 280 return extract3GPPLocalDescriptions(data, size, 0, parcel, 1); 281 } 282 283 return OK; 284 } 285 286 // To extract box 'tx3g' defined in 3GPP TS 26.245, and store it in a Parcel 287 status_t TextDescriptions::extract3GPPGlobalDescriptions( 288 const uint8_t *data, ssize_t size, Parcel *parcel, int depth) { 289 290 ssize_t chunkSize = U32_AT(data); 291 uint32_t chunkType = U32_AT(data + 4); 292 const uint8_t *tmpData = data; 293 tmpData += 8; 294 295 if (size < chunkSize) { 296 return OK; 297 } 298 299 if (depth == 0) { 300 parcel->writeInt32(KEY_GLOBAL_SETTING); 301 } 302 switch(chunkType) { 303 case FOURCC('t', 'x', '3', 'g'): 304 { 305 tmpData += 8; // skip the first 8 bytes 306 parcel->writeInt32(KEY_DISPLAY_FLAGS); 307 parcel->writeInt32(U32_AT(tmpData)); 308 309 parcel->writeInt32(KEY_STRUCT_JUSTIFICATION); 310 parcel->writeInt32(tmpData[4]); 311 parcel->writeInt32(tmpData[5]); 312 313 parcel->writeInt32(KEY_BACKGROUND_COLOR_RGBA); 314 uint32_t rgba = *(tmpData + 6) << 24 | *(tmpData + 7) << 16 315 | *(tmpData + 8) << 8 | *(tmpData + 9); 316 parcel->writeInt32(rgba); 317 318 tmpData += 10; 319 parcel->writeInt32(KEY_STRUCT_TEXT_POS); 320 parcel->writeInt32(U16_AT(tmpData)); 321 parcel->writeInt32(U16_AT(tmpData + 2)); 322 parcel->writeInt32(U16_AT(tmpData + 4)); 323 parcel->writeInt32(U16_AT(tmpData + 6)); 324 325 tmpData += 8; 326 parcel->writeInt32(KEY_STRUCT_STYLE_LIST); 327 parcel->writeInt32(KEY_START_CHAR); 328 parcel->writeInt32(U16_AT(tmpData)); 329 330 parcel->writeInt32(KEY_END_CHAR); 331 parcel->writeInt32(U16_AT(tmpData + 2)); 332 333 parcel->writeInt32(KEY_FONT_ID); 334 parcel->writeInt32(U16_AT(tmpData + 4)); 335 336 parcel->writeInt32(KEY_STYLE_FLAGS); 337 parcel->writeInt32(*(tmpData + 6)); 338 339 parcel->writeInt32(KEY_FONT_SIZE); 340 parcel->writeInt32(*(tmpData + 7)); 341 342 parcel->writeInt32(KEY_TEXT_COLOR_RGBA); 343 rgba = *(tmpData + 8) << 24 | *(tmpData + 9) << 16 344 | *(tmpData + 10) << 8 | *(tmpData + 11); 345 parcel->writeInt32(rgba); 346 347 tmpData += 12; 348 parcel->writeInt32(KEY_STRUCT_FONT_LIST); 349 uint16_t count = U16_AT(tmpData); 350 parcel->writeInt32(count); 351 352 tmpData += 2; 353 for (int i = 0; i < count; i++) { 354 // font ID 355 parcel->writeInt32(U16_AT(tmpData)); 356 357 // font name length 358 parcel->writeInt32(*(tmpData + 2)); 359 360 int len = *(tmpData + 2); 361 362 parcel->write(tmpData + 3, len); 363 tmpData += 3 + len; 364 } 365 366 break; 367 } 368 default: 369 { 370 break; 371 } 372 } 373 374 data += chunkSize; 375 size -= chunkSize; 376 377 if (size > 0) { 378 // continue to extract next 'tx3g' 379 return extract3GPPGlobalDescriptions(data, size, parcel, 1); 380 } 381 382 return OK; 383 } 384 385 } // namespace android 386