| 1 | /*************************************************************************** |
|---|
| 2 | * Copyright (c) 2002, Broadcom Corporation |
|---|
| 3 | * All Rights Reserved |
|---|
| 4 | * Confidential Property of Broadcom Corporation |
|---|
| 5 | * |
|---|
| 6 | * THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE |
|---|
| 7 | * AGREEMENT BETWEEN THE USER AND BROADCOM. YOU HAVE NO RIGHT TO USE OR |
|---|
| 8 | * EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT. |
|---|
| 9 | * |
|---|
| 10 | * $brcm_Workfile: bcmDccTransportParse.c $ |
|---|
| 11 | * $brcm_Revision: SanJose_MSTV_Devel/3 $ |
|---|
| 12 | * $brcm_Date: 10/11/02 12:13p $ |
|---|
| 13 | * |
|---|
| 14 | * Module Description: |
|---|
| 15 | * |
|---|
| 16 | * Revision History: |
|---|
| 17 | * |
|---|
| 18 | * $brcm_Log: /SetTop/applications/vbi/MPEGCCTransportLib/source/bcmDccTransportParse.c $ |
|---|
| 19 | * |
|---|
| 20 | * SanJose_MSTV_Devel/3 10/11/02 12:13p erikg |
|---|
| 21 | * Various Changes: 1. Fixed NTSC Caption Parsing from A53 2. Supports |
|---|
| 22 | * pkt seq discontinuity reset 3. Support shortened pkts 4. Fixed |
|---|
| 23 | * underline during monospaced simulation 5. Added parity checking to |
|---|
| 24 | * chars in 608 transcoder 6. Correctly skips XDS and Text modes in |
|---|
| 25 | * transcoder 7. Supports transparent space 8. Fixed Flashing |
|---|
| 26 | * (FLASH_BY_2SURFACES) 9. DLY and DLC imply ETX 10.Force all combos of |
|---|
| 27 | * PDir/SDir to L2R/B2T 11. Packet interface has changed Merge from |
|---|
| 28 | * SanJose_MSTV_Devel_erikg_week_oct7_2002_10_07_0927_44 10-Oct- |
|---|
| 29 | * 02.11:30:39 \SetTop\applications\vbi\public_inc\bcmDcc.h various |
|---|
| 30 | * improvements: |
|---|
| 31 | * 1. correctly skip over XDS and Text in transcoder |
|---|
| 32 | * 2. force pdir/sdir to l2r and b2t |
|---|
| 33 | * 3. fixed underline during monospace |
|---|
| 34 | * 4. fixed packet processing: short pkts and discontinuous pkts --- 08- |
|---|
| 35 | * Oct-02.16:00:59 |
|---|
| 36 | * \SetTop\applications\vbi\MPEGCCTransportLib\source\bcmDccTransportPars |
|---|
| 37 | * e.c diff treatment for cc_type --- 11-Oct-02.11:49:16 |
|---|
| 38 | * \SetTop\applications\vbi\MPEGCCTransportLib\source\bcmDccTransportPars |
|---|
| 39 | * e.c cleaned up in prep for release --- 10-Oct-02.11:26:59 |
|---|
| 40 | * \SetTop\applications\vbi\Common\bcmDccCBuf.c added cbUnPeek --- 11- |
|---|
| 41 | * Oct-02.11:49:21 \SetTop\applications\vbi\Common\bcmDccCBuf.c cleaned |
|---|
| 42 | * up in prep for release --- 10-Oct-02.11:27:05 |
|---|
| 43 | * \SetTop\applications\vbi\Common\bcmDccCBuf.h added cbUnPeek --- 11- |
|---|
| 44 | * Oct-02.11:49:24 \SetTop\applications\vbi\Common\bcmDccCBuf.h cleaned |
|---|
| 45 | * up in prep for release --- 10-Oct-02.11:30:44 |
|---|
| 46 | * 1. correctly skip over XDS and Text in transcoder |
|---|
| 47 | * 2. force pdir/sdir to l2r and b2t |
|---|
| 48 | * 3. fixed underline during monospace |
|---|
| 49 | * 4. fixed packet processing: short pkts and discontinuous pkts --- 10- |
|---|
| 50 | * Oct-02.11:30:47 |
|---|
| 51 | * \SetTop\applications\vbi\DTVCCLib\source\bcmDccPacket.c various |
|---|
| 52 | * improvements: |
|---|
| 53 | * 1. correctly skip over XDS and Text in transcoder |
|---|
| 54 | * 2. force pdir/sdir to l2r and b2t |
|---|
| 55 | * 3. fixed underline during monospace |
|---|
| 56 | * 4. fixed packet processing: short pkts and discontinuous pkts --- 08- |
|---|
| 57 | * Oct-02.16:01:23 |
|---|
| 58 | * \SetTop\applications\vbi\DTVCCLib\source\bcmDccIntGfx.c force l2r pdir |
|---|
| 59 | * --- 10-Oct-02.11:30:51 |
|---|
| 60 | * \SetTop\applications\vbi\DTVCCLib\source\bcmDccIntGfx.c various |
|---|
| 61 | * improvements: |
|---|
| 62 | * 1. correctly skip over XDS and Text in transcoder |
|---|
| 63 | * 2. force pdir/sdir to l2r and b2t |
|---|
| 64 | * 3. fixed underline during monospace |
|---|
| 65 | * 4. fixed packet processing: short pkts and discontinuous pkts --- 10- |
|---|
| 66 | * Oct-02.12:38:10 |
|---|
| 67 | * \SetTop\applications\vbi\DTVCCLib\source\bcmDccCoding.c DLY and DLC |
|---|
| 68 | * imply ETX --- 10-Oct-02.14:09:02 |
|---|
| 69 | * \SetTop\applications\vbi\DTVCCLib\source\bcmDccCoding.c support |
|---|
| 70 | * transparent space |
|---|
| 71 | * and fix RemapMultiByteTextToC1 --- 11-Oct-02.12:00:25 |
|---|
| 72 | * \SetTop\applications\vbi\DTVCCLib\CCGfx\7030 Added file element |
|---|
| 73 | * "arial_20.c". Added file element "arial_20_italic.c". --- 08-Oct- |
|---|
| 74 | * 02.16:03:24 \SetTop\applications\vbi\DTVCCLib\CCGfx\7030\bcmDccGfx.c |
|---|
| 75 | * split ccgfxRenderChar into two DoRenderChar calls --- 10-Oct- |
|---|
| 76 | * 02.11:30:54 \SetTop\applications\vbi\DTVCCLib\CCGfx\7030\bcmDccGfx.c |
|---|
| 77 | * various improvements: |
|---|
| 78 | * 1. correctly skip over XDS and Text in transcoder |
|---|
| 79 | * 2. force pdir/sdir to l2r and b2t |
|---|
| 80 | * 3. fixed underline during monospace |
|---|
| 81 | * 4. fixed packet processing: short pkts and discontinuous pkts --- 10- |
|---|
| 82 | * Oct-02.14:09:08 |
|---|
| 83 | * \SetTop\applications\vbi\DTVCCLib\CCGfx\7030\bcmDccGfx.c support |
|---|
| 84 | * transparent space |
|---|
| 85 | * and fix RemapMultiByteTextToC1 --- 10-Oct-02.17:04:05 |
|---|
| 86 | * \SetTop\applications\vbi\DTVCCLib\CCGfx\7030\bcmDccGfx.c fixed |
|---|
| 87 | * flashing by 2 surfaces |
|---|
| 88 | * this was broken when render incremental was added --- 11-Oct- |
|---|
| 89 | * 02.11:49:27 \SetTop\applications\vbi\DTVCCLib\CCGfx\7030\bcmDccGfx.c |
|---|
| 90 | * cleaned up in prep for release --- 11-Oct-02.12:01:00 |
|---|
| 91 | * \SetTop\applications\vbi\DTVCCLib\CCGfx\7030\bcmDccGfx.c added a |
|---|
| 92 | * comment for the font files --- 10-Oct-02.11:30:59 |
|---|
| 93 | * \SetTop\applications\vbi\Common\bcmDccEngine.h various improvements: |
|---|
| 94 | * 1. correctly skip over XDS and Text in transcoder |
|---|
| 95 | * 2. force pdir/sdir to l2r and b2t |
|---|
| 96 | * 3. fixed underline during monospace |
|---|
| 97 | * 4. fixed packet processing: short pkts and discontinuous pkts --- 10- |
|---|
| 98 | * Oct-02.11:31:03 \SetTop\applications\vbi\Common\bcmDccEngine.c various |
|---|
| 99 | * improvements: |
|---|
| 100 | * 1. correctly skip over XDS and Text in transcoder |
|---|
| 101 | * 2. force pdir/sdir to l2r and b2t |
|---|
| 102 | * 3. fixed underline during monospace |
|---|
| 103 | * 4. fixed packet processing: short pkts and discontinuous pkts --- 08- |
|---|
| 104 | * Oct-02.16:02:32 |
|---|
| 105 | * \SetTop\applications\vbi\DTVCCLib\source\bcmDcc608Transcoder.c add |
|---|
| 106 | * support for XDS and fix Text mode --- 10-Oct-02.11:31:07 |
|---|
| 107 | * \SetTop\applications\vbi\DTVCCLib\source\bcmDcc608Transcoder.c various |
|---|
| 108 | * improvements: |
|---|
| 109 | * 1. correctly skip over XDS and Text in transcoder |
|---|
| 110 | * 2. force pdir/sdir to l2r and b2t |
|---|
| 111 | * 3. fixed underline during monospace |
|---|
| 112 | * 4. fixed packet processing: short pkts and discontinuous pkts --- 10- |
|---|
| 113 | * Oct-02.15:25:03 |
|---|
| 114 | * \SetTop\applications\vbi\DTVCCLib\source\bcmDcc608Transcoder.c fixed |
|---|
| 115 | * bug with XDS detection --- 11-Oct-02.11:49:31 |
|---|
| 116 | * \SetTop\applications\vbi\DTVCCLib\source\bcmDcc608Transcoder.c cleaned |
|---|
| 117 | * up in prep for release --- 08-Oct-02.16:02:36 |
|---|
| 118 | * \SetTop\applications\vbi\DTVCCLib\public_inc\bcmDcc608Transcoder.h add |
|---|
| 119 | * support for XDS and fix Text mode --- 08-Oct-02.16:03:39 |
|---|
| 120 | * \SetTop\applications\vbi\Docs\SarnoffTesting.xls added set 1 |
|---|
| 121 | * placeholder --- 11-Oct-02.12:01:30 |
|---|
| 122 | * \SetTop\applications\vbi\Docs\SarnoffTesting.xls updated for oct 11 |
|---|
| 123 | * release --- 11-Oct-02.12:00:12 |
|---|
| 124 | * |
|---|
| 125 | * SanJose_MSTV_Devel/SanJose_MSTV_Devel_erikg_week_oct7_2002_10_07_0927_44/2 10/11/02 11:49a erikg |
|---|
| 126 | * cleaned up in prep for release |
|---|
| 127 | * |
|---|
| 128 | * SanJose_MSTV_Devel/SanJose_MSTV_Devel_erikg_week_oct7_2002_10_07_0927_44/1 10/8/02 4:1p erikg |
|---|
| 129 | * diff treatment for cc_type |
|---|
| 130 | * |
|---|
| 131 | * SanJose_MSTV_Devel\2 5/13/02 1:13p erikg |
|---|
| 132 | * snapshot of dtvcc code Merge from |
|---|
| 133 | * SanJose_MSTV_Devel_erikg_DTVCC_Int_2002_05_02_1128_00 13-May- |
|---|
| 134 | * 02.11:55:52 \SetTop\applications\vbi Added directory element |
|---|
| 135 | * "DTVCCLib". --- 13-May-02.13:08:38 \SetTop\applications\vbi\Common |
|---|
| 136 | * First version of the Dcc 708 Rendering Libraries --- 13-May- |
|---|
| 137 | * 02.13:08:10 \SetTop\applications\vbi\Common\bcmDccBits.h Added ifdef |
|---|
| 138 | * to ensure included only once. |
|---|
| 139 | * Added extern "C" for __cplusplus --- 13-May-02.13:07:04 |
|---|
| 140 | * \SetTop\applications\vbi\MPEGCCTransportLib\source\bcmDccTransportPars |
|---|
| 141 | * e.c NextStartCode() now specifically scans for start codes until it |
|---|
| 142 | * finds |
|---|
| 143 | * 00 00 01 B2. --- 13-May-02.13:08:40 |
|---|
| 144 | * \SetTop\applications\vbi\Common@@\main\SanJose_MSTV_Devel\SanJose_MSTV |
|---|
| 145 | * _Devel_erikg_DTVCC_Int_2002_05_02_1128_00\1\bcmDccCBuf.c First version |
|---|
| 146 | * of the Dcc 708 Rendering Libraries --- 13-May-02.13:08:43 |
|---|
| 147 | * \SetTop\applications\vbi\Common@@\main\SanJose_MSTV_Devel\SanJose_MSTV |
|---|
| 148 | * _Devel_erikg_DTVCC_Int_2002_05_02_1128_00\1\bcmDccCBuf.h First version |
|---|
| 149 | * of the Dcc 708 Rendering Libraries --- 13-May-02.11:55:59 |
|---|
| 150 | * \SetTop\applications\vbi@@\main\SanJose_MSTV_Devel\SanJose_MSTV_Devel_ |
|---|
| 151 | * erikg_DTVCC_Int_2002_05_02_1128_00\1\DTVCCLib Added directory element |
|---|
| 152 | * "source". Added directory element "public_inc". --- |
|---|
| 153 | * |
|---|
| 154 | * SanJose_MSTV_Devel\SanJose_MSTV_Devel_erikg_DTVCC_Int_2002_05_02_1128_00\1 5/13/02 1:6p erikg |
|---|
| 155 | * NextStartCode() now specifically scans for start codes until it finds |
|---|
| 156 | * 00 00 01 B2. |
|---|
| 157 | * |
|---|
| 158 | * \main\SanJose_MSTV_Devel\1 3/12/02 4:45p erikg |
|---|
| 159 | * Merge from SanJose_MSTV_Devel_erikg_mpegccxport2_2002_03_06_1118_38 |
|---|
| 160 | * |
|---|
| 161 | * \main\SanJose_MSTV_Devel_erikg_mpegccxport2_2002_03_06_1118_38\5 3/12/02 2:57p erikg |
|---|
| 162 | * debugged using base platform |
|---|
| 163 | * |
|---|
| 164 | * \main\SanJose_MSTV_Devel_erikg_mpegccxport2_2002_03_06_1118_38\4 3/11/02 2:21p erikg |
|---|
| 165 | * added comments |
|---|
| 166 | * |
|---|
| 167 | * \main\SanJose_MSTV_Devel_erikg_mpegccxport2_2002_03_06_1118_38\3 3/11/02 8:12a erikg |
|---|
| 168 | * fixed some build problems |
|---|
| 169 | * |
|---|
| 170 | * \main\SanJose_MSTV_Devel_erikg_mpegccxport2_2002_03_06_1118_38\2 3/7/02 4:21p erikg |
|---|
| 171 | * more fleshing out |
|---|
| 172 | * |
|---|
| 173 | * \main\SanJose_MSTV_Devel_erikg_mpegccxport2_2002_03_06_1118_38\1 3/6/02 2:20p erikg |
|---|
| 174 | * Added file element "bcmDccTransportParse.c". |
|---|
| 175 | * |
|---|
| 176 | ***************************************************************************/ |
|---|
| 177 | |
|---|
| 178 | /********************** |
|---|
| 179 | * |
|---|
| 180 | * INCLUDES |
|---|
| 181 | * |
|---|
| 182 | **********************/ |
|---|
| 183 | |
|---|
| 184 | #include "bcmDccTransport.h" |
|---|
| 185 | #include "bcmDccTransportMux.h" |
|---|
| 186 | #include "bcmDccPriv.h" |
|---|
| 187 | #include "bcmDccBits.h" |
|---|
| 188 | #include "bcmDccTransportParse.h" |
|---|
| 189 | |
|---|
| 190 | /********************** |
|---|
| 191 | * |
|---|
| 192 | * ProtoTypes |
|---|
| 193 | * |
|---|
| 194 | **********************/ |
|---|
| 195 | |
|---|
| 196 | unsigned int |
|---|
| 197 | ParsePUD_053( |
|---|
| 198 | unsigned char * pInputBuf, |
|---|
| 199 | // unsigned int InputBufSize, |
|---|
| 200 | // unsigned long ulPicInfo, |
|---|
| 201 | // DCC_OUTBUF_INFO * p608BufInfo, |
|---|
| 202 | DCC_OUTBUF_INFO * pDTVCCBufInfo) ; |
|---|
| 203 | |
|---|
| 204 | unsigned int |
|---|
| 205 | ParsePUD_157( |
|---|
| 206 | unsigned char * pInputBuf, |
|---|
| 207 | unsigned int InputBufSize, |
|---|
| 208 | unsigned long ulPicInfo, |
|---|
| 209 | DCC_OUTBUF_INFO * p608BufInfo) ; |
|---|
| 210 | |
|---|
| 211 | unsigned int |
|---|
| 212 | FieldFromPicInfo( |
|---|
| 213 | unsigned long ulMainPicInfo, |
|---|
| 214 | unsigned long index, |
|---|
| 215 | unsigned long numPairs) ; |
|---|
| 216 | |
|---|
| 217 | |
|---|
| 218 | #define DETECTED_608 1 |
|---|
| 219 | #define DETECTED_DTVCC 2 |
|---|
| 220 | |
|---|
| 221 | |
|---|
| 222 | |
|---|
| 223 | |
|---|
| 224 | /************************************************************************** |
|---|
| 225 | * |
|---|
| 226 | * Function: find_next_start_code |
|---|
| 227 | * |
|---|
| 228 | * Inputs: |
|---|
| 229 | * pInputCur - input buffer w/ User Data |
|---|
| 230 | * InputCurSize - num bytes of input buffer |
|---|
| 231 | * |
|---|
| 232 | * Outputs: |
|---|
| 233 | * pStartCodeIndex - index of start code returned here |
|---|
| 234 | * |
|---|
| 235 | * Returns: 1 iff the next start code was found, 0 otherwise |
|---|
| 236 | * |
|---|
| 237 | * Description: |
|---|
| 238 | * |
|---|
| 239 | * This function finds the next start code in a buffer. |
|---|
| 240 | * |
|---|
| 241 | **************************************************************************/ |
|---|
| 242 | int NextStartCode( |
|---|
| 243 | unsigned char * pInputCur, |
|---|
| 244 | unsigned int InputCurSize, |
|---|
| 245 | unsigned int * pStartCodeIndex) |
|---|
| 246 | { |
|---|
| 247 | int ByteOff = 0 ; |
|---|
| 248 | int BitOff = 0 ; |
|---|
| 249 | int err ; |
|---|
| 250 | |
|---|
| 251 | if ( NULL == pInputCur || NULL == pStartCodeIndex ) |
|---|
| 252 | { |
|---|
| 253 | return(0) ; |
|---|
| 254 | } |
|---|
| 255 | |
|---|
| 256 | do |
|---|
| 257 | { |
|---|
| 258 | if ( (err = next_start_code(pInputCur, &ByteOff, &BitOff, InputCurSize)) ) |
|---|
| 259 | { |
|---|
| 260 | return(0) ; |
|---|
| 261 | } |
|---|
| 262 | *pStartCodeIndex = ByteOff ; |
|---|
| 263 | |
|---|
| 264 | /* consume the 3 bytes */ |
|---|
| 265 | ByteOff += 3 ; |
|---|
| 266 | |
|---|
| 267 | } while ( nextbits(pInputCur, ByteOff, BitOff, 8) != 0xB2 ) ; |
|---|
| 268 | |
|---|
| 269 | return(1) ; |
|---|
| 270 | |
|---|
| 271 | } /* find_next_start_code */ |
|---|
| 272 | |
|---|
| 273 | |
|---|
| 274 | /************************************************************************** |
|---|
| 275 | * |
|---|
| 276 | * Function: ParseOnePicUserDataForCC |
|---|
| 277 | * |
|---|
| 278 | * Inputs: |
|---|
| 279 | * pObj - transport object |
|---|
| 280 | * pInputBuf - input buffer w/ User Data |
|---|
| 281 | * InputBufSize - num bytes of input buffer |
|---|
| 282 | * ulPicInfo - PicInfo from bcmMPIReadCCStatus |
|---|
| 283 | * |
|---|
| 284 | * Outputs: |
|---|
| 285 | * p608BufInfo - 608 output |
|---|
| 286 | * pDTVCCBufInfo - DTVCC output |
|---|
| 287 | * |
|---|
| 288 | * Returns: dccSuccess or a standard DCCERR error code |
|---|
| 289 | * |
|---|
| 290 | * Description: |
|---|
| 291 | * |
|---|
| 292 | * This function parses a buffer containing one MPEG picture user data. |
|---|
| 293 | * |
|---|
| 294 | **************************************************************************/ |
|---|
| 295 | DCCERR |
|---|
| 296 | ParseOnePicUserDataForCC( |
|---|
| 297 | DCC_TRANSPORT_OBJECT * pObj, /* transport session object */ |
|---|
| 298 | unsigned char * pInputBuf, /* input buffer, remaining */ |
|---|
| 299 | unsigned int InputBufSize, /* input buffer size, remaining */ |
|---|
| 300 | // unsigned long ulPicInfo, /* picture info */ |
|---|
| 301 | DCC_OUTBUF_INFO * p608BufInfo, /* output buffer info for 608 type */ |
|---|
| 302 | DCC_OUTBUF_INFO * pDTVCCBufInfo) /* output buffer info for DTVCC type */ |
|---|
| 303 | { |
|---|
| 304 | DCC_OUTBUF_INFO * p608Output ; |
|---|
| 305 | int f608Output_A53 = 0 ; |
|---|
| 306 | int f608Output_DVS157 = 0 ; |
|---|
| 307 | unsigned int ret ; |
|---|
| 308 | |
|---|
| 309 | /* |
|---|
| 310 | * Decide up front which 608 type |
|---|
| 311 | * we'll output. |
|---|
| 312 | */ |
|---|
| 313 | switch ( pObj->CC608Type ) |
|---|
| 314 | { |
|---|
| 315 | case CC608_A53 : |
|---|
| 316 | f608Output_A53 = 1 ; |
|---|
| 317 | break ; |
|---|
| 318 | |
|---|
| 319 | case CC608_DVS157 : |
|---|
| 320 | f608Output_DVS157 = 1 ; |
|---|
| 321 | break ; |
|---|
| 322 | |
|---|
| 323 | case CC608_A53Preferred : |
|---|
| 324 | if ( CC608Mux_IsDetected(&pObj->CC608MuxState, cctA053_608) ) |
|---|
| 325 | f608Output_A53 = 1 ; |
|---|
| 326 | else if ( CC608Mux_IsDetected(&pObj->CC608MuxState, cctDVS157) ) |
|---|
| 327 | f608Output_DVS157 = 1 ; |
|---|
| 328 | break ; |
|---|
| 329 | } |
|---|
| 330 | |
|---|
| 331 | /*********************************** |
|---|
| 332 | * check for DVS 157, DIGICIPHER II |
|---|
| 333 | ***********************************/ |
|---|
| 334 | |
|---|
| 335 | if ( pInputBuf[0] == 0x03 ) |
|---|
| 336 | { |
|---|
| 337 | if ( f608Output_DVS157 ) |
|---|
| 338 | { |
|---|
| 339 | ;//ParsePUD_157(pInputBuf, InputBufSize, ulPicInfo, p608BufInfo) ; |
|---|
| 340 | } |
|---|
| 341 | ;///CC608Mux_Accumulate(&pObj->CC608MuxState, cctDVS157) ; |
|---|
| 342 | } |
|---|
| 343 | |
|---|
| 344 | /*********************************** |
|---|
| 345 | * check for ATSC A53, EIA-708 |
|---|
| 346 | ***********************************/ |
|---|
| 347 | else if ( pInputBuf[0] == 0x47 /* first 4 bytes are 47 41 39 34 */ |
|---|
| 348 | && pInputBuf[1] == 0x41 |
|---|
| 349 | && pInputBuf[2] == 0x39 |
|---|
| 350 | && pInputBuf[3] == 0x34 |
|---|
| 351 | && pInputBuf[4] == 0x03 ) /* Type == 03 */ |
|---|
| 352 | { |
|---|
| 353 | if ( f608Output_A53 ) |
|---|
| 354 | p608Output = p608BufInfo ; |
|---|
| 355 | else |
|---|
| 356 | { |
|---|
| 357 | /* |
|---|
| 358 | * Even if we're not outputting this |
|---|
| 359 | * type of 608 CC data, we still need |
|---|
| 360 | * to parse the A53 data because it may |
|---|
| 361 | * contain DTVCC data. |
|---|
| 362 | */ |
|---|
| 363 | p608Output = NULL ; /* this means ignore 608 CC data when parsing */ |
|---|
| 364 | } |
|---|
| 365 | |
|---|
| 366 | /* parse, ret indicates what the A53 data actually contained */ |
|---|
| 367 | //ret = ParsePUD_053(pInputBuf, InputBufSize, ulPicInfo, p608Output, pDTVCCBufInfo) ; |
|---|
| 368 | ret = ParsePUD_053(pInputBuf,pDTVCCBufInfo) ; |
|---|
| 369 | |
|---|
| 370 | /* accumulate */ |
|---|
| 371 | if ( ret & DETECTED_608 ) |
|---|
| 372 | CC608Mux_Accumulate(&pObj->CC608MuxState, cctA053_608) ; |
|---|
| 373 | if ( ret & DETECTED_DTVCC ) |
|---|
| 374 | CC608Mux_Accumulate(&pObj->CC608MuxState, cctA053_DTVCC) ; |
|---|
| 375 | |
|---|
| 376 | } |
|---|
| 377 | |
|---|
| 378 | /*********************************** |
|---|
| 379 | * check for unknown type |
|---|
| 380 | ***********************************/ |
|---|
| 381 | else |
|---|
| 382 | { |
|---|
| 383 | CC608Mux_Accumulate(&pObj->CC608MuxState, cctUnknown) ; |
|---|
| 384 | } |
|---|
| 385 | |
|---|
| 386 | return(dccSuccess) ; |
|---|
| 387 | |
|---|
| 388 | } /* ParseOnePicUserDataForCC */ |
|---|
| 389 | |
|---|
| 390 | |
|---|
| 391 | |
|---|
| 392 | |
|---|
| 393 | |
|---|
| 394 | |
|---|
| 395 | /************************************************************************** |
|---|
| 396 | * |
|---|
| 397 | * Function: ParsePUD_053 |
|---|
| 398 | * |
|---|
| 399 | * Inputs: |
|---|
| 400 | * pInputBuf - user data to parse |
|---|
| 401 | * InputBufSize - num bytes of user data |
|---|
| 402 | * ulPicInfo - pic info from MPEG library |
|---|
| 403 | * |
|---|
| 404 | * Outputs: |
|---|
| 405 | * p608BufInfo - 608 bytes go here if not NULL |
|---|
| 406 | * pDTVCCBufInfo - DTVCC bytes go here if not NULL |
|---|
| 407 | * |
|---|
| 408 | * Returns: bitmask of DETECTED_608 and/or DETECTED_DTVCC |
|---|
| 409 | * |
|---|
| 410 | * Description: |
|---|
| 411 | * |
|---|
| 412 | * This function parses a buffer of MPEG picture user data, looking for |
|---|
| 413 | * valid CC bytes. It assumes that the user data is in the ATSC 053 |
|---|
| 414 | * format. |
|---|
| 415 | * |
|---|
| 416 | **************************************************************************/ |
|---|
| 417 | |
|---|
| 418 | |
|---|
| 419 | |
|---|
| 420 | |
|---|
| 421 | #if 0 |
|---|
| 422 | unsigned int |
|---|
| 423 | ParsePUD_053( |
|---|
| 424 | unsigned char * pInputBuf, |
|---|
| 425 | unsigned int InputBufSize, |
|---|
| 426 | unsigned long ulPicInfo, |
|---|
| 427 | DCC_OUTBUF_INFO * p608BufInfo, |
|---|
| 428 | DCC_OUTBUF_INFO * pDTVCCBufInfo) |
|---|
| 429 | { |
|---|
| 430 | unsigned int retCode = 0 ; |
|---|
| 431 | |
|---|
| 432 | /* |
|---|
| 433 | * This code is adapted from DVS053GetXDSData() |
|---|
| 434 | */ |
|---|
| 435 | |
|---|
| 436 | int i; /* index into pInputBuf */ |
|---|
| 437 | int numCCPairs; /* pairs in user data, not all nec. valid */ |
|---|
| 438 | unsigned char cc_type ; |
|---|
| 439 | unsigned char dtvcc_type ; |
|---|
| 440 | |
|---|
| 441 | i = 4; |
|---|
| 442 | |
|---|
| 443 | /* process user_data_type 0x03 */ |
|---|
| 444 | if (pInputBuf[i] == 0x03) |
|---|
| 445 | { |
|---|
| 446 | int j; |
|---|
| 447 | i++; |
|---|
| 448 | /* if process_cc_data_flag != 1, return */ |
|---|
| 449 | if ( !(pInputBuf[i] & 0x40) ) |
|---|
| 450 | return(retCode) ; |
|---|
| 451 | |
|---|
| 452 | numCCPairs = pInputBuf[i] & 0x1f; |
|---|
| 453 | i += 2; /* skip em_data */ |
|---|
| 454 | for (j = 0; j < numCCPairs; j++) |
|---|
| 455 | { |
|---|
| 456 | if ( (pInputBuf[i] & 0xF8) != 0xF8 ) |
|---|
| 457 | { |
|---|
| 458 | /* marker bits not correct */ |
|---|
| 459 | } |
|---|
| 460 | |
|---|
| 461 | if ( !(pInputBuf[i] & 0x04) ) |
|---|
| 462 | { |
|---|
| 463 | /* if cc_valid != 1, continue to next pair */ |
|---|
| 464 | i += 3; |
|---|
| 465 | continue; |
|---|
| 466 | } |
|---|
| 467 | |
|---|
| 468 | cc_type = pInputBuf[i] & 0x03 ; |
|---|
| 469 | dtvcc_type = pInputBuf[i] & 0x02 ; |
|---|
| 470 | i++ ; |
|---|
| 471 | |
|---|
| 472 | if ( dtvcc_type ) |
|---|
| 473 | { |
|---|
| 474 | /* |
|---|
| 475 | * For DTVCC, output 3 bytes |
|---|
| 476 | * [0] : cc_type |
|---|
| 477 | * [1] : DTVCC Byte[0] |
|---|
| 478 | * [2] : DTVCC Byte[1] |
|---|
| 479 | */ |
|---|
| 480 | retCode |= DETECTED_DTVCC ; |
|---|
| 481 | |
|---|
| 482 | if ( pDTVCCBufInfo ) |
|---|
| 483 | { |
|---|
| 484 | /* make sure we have enough room */ |
|---|
| 485 | if ( (pDTVCCBufInfo->OutputBytesProduced + 3) > pDTVCCBufInfo->OutputBufSize ) |
|---|
| 486 | { |
|---|
| 487 | /* not enough room, error */ |
|---|
| 488 | pDTVCCBufInfo->DccError = dccErrOutputBufTooSmall ; |
|---|
| 489 | } |
|---|
| 490 | else |
|---|
| 491 | { |
|---|
| 492 | pDTVCCBufInfo->pOutputBuf[ (pDTVCCBufInfo->OutputBytesProduced) + 0 ] = cc_type ; |
|---|
| 493 | pDTVCCBufInfo->pOutputBuf[ (pDTVCCBufInfo->OutputBytesProduced) + 1 ] = pInputBuf[i+0] ; |
|---|
| 494 | pDTVCCBufInfo->pOutputBuf[ (pDTVCCBufInfo->OutputBytesProduced) + 2 ] = pInputBuf[i+1] ; |
|---|
| 495 | pDTVCCBufInfo->OutputBytesProduced += 3 ; |
|---|
| 496 | } |
|---|
| 497 | } |
|---|
| 498 | } |
|---|
| 499 | else |
|---|
| 500 | { |
|---|
| 501 | /* |
|---|
| 502 | * For 608, output 3 bytes |
|---|
| 503 | * [0] : field |
|---|
| 504 | * [1] : CC Byte[0] |
|---|
| 505 | * [2] : CC Byte[1] |
|---|
| 506 | */ |
|---|
| 507 | retCode |= DETECTED_608 ; |
|---|
| 508 | |
|---|
| 509 | if ( p608BufInfo ) |
|---|
| 510 | { |
|---|
| 511 | /* make sure we have enough room */ |
|---|
| 512 | if ( (p608BufInfo->OutputBytesProduced + 3) > p608BufInfo->OutputBufSize ) |
|---|
| 513 | { |
|---|
| 514 | /* not enough room, error */ |
|---|
| 515 | p608BufInfo->DccError = dccErrOutputBufTooSmall ; |
|---|
| 516 | } |
|---|
| 517 | else |
|---|
| 518 | { |
|---|
| 519 | #if 1 |
|---|
| 520 | p608BufInfo->pOutputBuf[ (p608BufInfo->OutputBytesProduced) + 0 ] = ((cc_type == 0) ? DCC_608_FIELD_TOP : DCC_608_FIELD_BOTTOM) ; |
|---|
| 521 | #else |
|---|
| 522 | p608BufInfo->pOutputBuf[ (p608BufInfo->OutputBytesProduced) + 0 ] = FieldFromPicInfo(ulPicInfo,j,numCCPairs) ; |
|---|
| 523 | #endif |
|---|
| 524 | p608BufInfo->pOutputBuf[ (p608BufInfo->OutputBytesProduced) + 1 ] = pInputBuf[i+0] ; |
|---|
| 525 | p608BufInfo->pOutputBuf[ (p608BufInfo->OutputBytesProduced) + 2 ] = pInputBuf[i+1] ; |
|---|
| 526 | p608BufInfo->OutputBytesProduced += 3 ; |
|---|
| 527 | } |
|---|
| 528 | } |
|---|
| 529 | } |
|---|
| 530 | |
|---|
| 531 | i += 2 ; |
|---|
| 532 | } |
|---|
| 533 | } |
|---|
| 534 | |
|---|
| 535 | return(retCode) ; |
|---|
| 536 | |
|---|
| 537 | } /* ParsePUD_053 */ |
|---|
| 538 | |
|---|
| 539 | #endif |
|---|
| 540 | |
|---|
| 541 | |
|---|
| 542 | unsigned int ParsePUD_053(unsigned char * pInputBuf, DCC_OUTBUF_INFO * pDTVCCBufInfo) |
|---|
| 543 | { |
|---|
| 544 | unsigned int retCode = 0 ; |
|---|
| 545 | |
|---|
| 546 | /* |
|---|
| 547 | * This code is adapted from DVS053GetXDSData() |
|---|
| 548 | */ |
|---|
| 549 | |
|---|
| 550 | int i,j; /* index into pInputBuf */ |
|---|
| 551 | int numCCPairs; /* pairs in user data, not all nec. valid */ |
|---|
| 552 | unsigned char cc_type ; |
|---|
| 553 | unsigned char dtvcc_type ; |
|---|
| 554 | |
|---|
| 555 | i = 4; |
|---|
| 556 | /* process user_data_type 0x03 */ |
|---|
| 557 | if (pInputBuf[i] == 0x03) |
|---|
| 558 | { |
|---|
| 559 | i++; |
|---|
| 560 | /* if process_cc_data_flag != 1, return */ |
|---|
| 561 | if ( !(pInputBuf[i] & 0x40) ) |
|---|
| 562 | return(retCode) ; |
|---|
| 563 | |
|---|
| 564 | numCCPairs = pInputBuf[i] & 0x1f; |
|---|
| 565 | i += 2; /* skip em_data */ |
|---|
| 566 | for (j = 0; j < numCCPairs; j++) |
|---|
| 567 | { |
|---|
| 568 | if ( (pInputBuf[i] & 0xF8) != 0xF8 ) |
|---|
| 569 | { |
|---|
| 570 | /* marker bits not correct */ |
|---|
| 571 | } |
|---|
| 572 | |
|---|
| 573 | #if 0 /* JPF Need to pass invalid data */ |
|---|
| 574 | if ( !(pInputBuf[i] & 0x04) ) |
|---|
| 575 | { |
|---|
| 576 | /* if cc_valid != 1, continue to next pair */ |
|---|
| 577 | i += 3; |
|---|
| 578 | continue; |
|---|
| 579 | } |
|---|
| 580 | #endif |
|---|
| 581 | //cc_type = pInputBuf[i] & 0x03 ; |
|---|
| 582 | cc_type = pInputBuf[i] & 0x03 ; |
|---|
| 583 | dtvcc_type = pInputBuf[i] & 0x02 ; |
|---|
| 584 | i++ ; |
|---|
| 585 | #if 1 /* JPF Need to pass invalid data */ |
|---|
| 586 | |
|---|
| 587 | if ( dtvcc_type ) |
|---|
| 588 | #endif |
|---|
| 589 | { |
|---|
| 590 | /* |
|---|
| 591 | * For DTVCC, output 3 bytes |
|---|
| 592 | * [0] : cc_type |
|---|
| 593 | * [1] : DTVCC Byte[0] |
|---|
| 594 | * [2] : DTVCC Byte[1] |
|---|
| 595 | */ |
|---|
| 596 | retCode |= DETECTED_DTVCC ; |
|---|
| 597 | |
|---|
| 598 | if ( pDTVCCBufInfo ) |
|---|
| 599 | { |
|---|
| 600 | /* make sure we have enough room */ |
|---|
| 601 | if ( (pDTVCCBufInfo->OutputBytesProduced + 2) >= pDTVCCBufInfo->OutputBufSize ) |
|---|
| 602 | { |
|---|
| 603 | /* not enough room, error */ |
|---|
| 604 | pDTVCCBufInfo->DccError = dccErrOutputBufTooSmall ; |
|---|
| 605 | } |
|---|
| 606 | else |
|---|
| 607 | { |
|---|
| 608 | pDTVCCBufInfo->pOutputBuf[ (pDTVCCBufInfo->OutputBytesProduced) + 0 ] = cc_type ; |
|---|
| 609 | pDTVCCBufInfo->pOutputBuf[ (pDTVCCBufInfo->OutputBytesProduced) + 1 ] = pInputBuf[i+0] ; |
|---|
| 610 | pDTVCCBufInfo->pOutputBuf[ (pDTVCCBufInfo->OutputBytesProduced) + 2 ] = pInputBuf[i+1] ; |
|---|
| 611 | pDTVCCBufInfo->OutputBytesProduced += 3 ; |
|---|
| 612 | } |
|---|
| 613 | } |
|---|
| 614 | } |
|---|
| 615 | |
|---|
| 616 | i += 2 ; |
|---|
| 617 | } |
|---|
| 618 | } |
|---|
| 619 | |
|---|
| 620 | return(retCode) ; |
|---|
| 621 | |
|---|
| 622 | } /* ParsePUD_053 */ |
|---|
| 623 | |
|---|
| 624 | |
|---|
| 625 | /************************************************************************** |
|---|
| 626 | * |
|---|
| 627 | * Function: ParsePUD_157 |
|---|
| 628 | * |
|---|
| 629 | * Inputs: |
|---|
| 630 | * pInputBuf - user data to parse |
|---|
| 631 | * InputBufSize - num bytes of user data |
|---|
| 632 | * ulPicInfo - pic info from MPEG library |
|---|
| 633 | * |
|---|
| 634 | * Outputs: |
|---|
| 635 | * p608BufInfo - 608 bytes go here if not NULL |
|---|
| 636 | * |
|---|
| 637 | * Returns: bitmask of DETECTED_608 |
|---|
| 638 | * |
|---|
| 639 | * Description: |
|---|
| 640 | * |
|---|
| 641 | * This function parses a buffer of MPEG picture user data, looking for |
|---|
| 642 | * valid CC bytes. It assumes that the user data is in the DVS 157 |
|---|
| 643 | * format. |
|---|
| 644 | * |
|---|
| 645 | **************************************************************************/ |
|---|
| 646 | unsigned int |
|---|
| 647 | ParsePUD_157( |
|---|
| 648 | unsigned char * pInputBuf, |
|---|
| 649 | unsigned int InputBufSize, |
|---|
| 650 | unsigned long ulPicInfo, |
|---|
| 651 | DCC_OUTBUF_INFO * p608BufInfo) |
|---|
| 652 | { |
|---|
| 653 | unsigned int retCode = 0 ; |
|---|
| 654 | /* |
|---|
| 655 | * This code is adapted from DVS053GetXDSData() |
|---|
| 656 | */ |
|---|
| 657 | |
|---|
| 658 | int byteoff = 0 ; |
|---|
| 659 | int bitoff = 0 ; |
|---|
| 660 | unsigned int field_num ; |
|---|
| 661 | unsigned int line_offset ; |
|---|
| 662 | unsigned int priority, marker ; |
|---|
| 663 | unsigned char cc_data[2] ; |
|---|
| 664 | |
|---|
| 665 | int i; /* index into pInputBuf */ |
|---|
| 666 | unsigned int numCCPairs; /* pairs in user data, not all nec. valid */ |
|---|
| 667 | |
|---|
| 668 | i = 0 ; |
|---|
| 669 | |
|---|
| 670 | /* process user_data_type 0x03 */ |
|---|
| 671 | if ( getnextbits(pInputBuf,&byteoff,&bitoff,8) == 0x03 ) |
|---|
| 672 | { |
|---|
| 673 | unsigned int j; |
|---|
| 674 | |
|---|
| 675 | /* ignore the next 7 bits */ |
|---|
| 676 | getnextbits(pInputBuf,&byteoff,&bitoff,7) ; |
|---|
| 677 | |
|---|
| 678 | /* check vbi_data_flag */ |
|---|
| 679 | if ( getnextbits(pInputBuf,&byteoff,&bitoff,1) != 1 ) |
|---|
| 680 | { |
|---|
| 681 | /* vbi_data_flag not set, get out */ |
|---|
| 682 | return(retCode) ; |
|---|
| 683 | } |
|---|
| 684 | |
|---|
| 685 | /* the next 5 bits are the cc_count */ |
|---|
| 686 | numCCPairs = getnextbits(pInputBuf,&byteoff,&bitoff,5) ; |
|---|
| 687 | |
|---|
| 688 | for ( j=0 ; j < numCCPairs ; j++ ) |
|---|
| 689 | { |
|---|
| 690 | /* cc_priority: 2 bits */ |
|---|
| 691 | priority = getnextbits(pInputBuf,&byteoff,&bitoff,2) ; |
|---|
| 692 | |
|---|
| 693 | /* field_number: 2 bits */ |
|---|
| 694 | field_num = getnextbits(pInputBuf,&byteoff,&bitoff,2) ; |
|---|
| 695 | |
|---|
| 696 | /* line_offset: 5 bits */ |
|---|
| 697 | line_offset = getnextbits(pInputBuf,&byteoff,&bitoff,5) ; |
|---|
| 698 | |
|---|
| 699 | /* cc_data_1[1:8] 8 bits (bit reversed) */ |
|---|
| 700 | cc_data[0] = (unsigned char)getnextbits_rev(pInputBuf,&byteoff,&bitoff,8) ; |
|---|
| 701 | |
|---|
| 702 | /* cc_data_2[1:8] 8 bits (bit reversed) */ |
|---|
| 703 | cc_data[1] = (unsigned char)getnextbits_rev(pInputBuf,&byteoff,&bitoff,8) ; |
|---|
| 704 | |
|---|
| 705 | /* marker_bit: 1 bits */ |
|---|
| 706 | marker = getnextbits(pInputBuf,&byteoff,&bitoff,1) ; |
|---|
| 707 | |
|---|
| 708 | if ( field_num != 0 && line_offset == 11 ) |
|---|
| 709 | { |
|---|
| 710 | retCode |= DETECTED_608 ; |
|---|
| 711 | |
|---|
| 712 | if ( p608BufInfo ) |
|---|
| 713 | { |
|---|
| 714 | /* make sure we have enough room */ |
|---|
| 715 | if ( (p608BufInfo->OutputBytesProduced + 2) >= p608BufInfo->OutputBufSize ) |
|---|
| 716 | { |
|---|
| 717 | /* not enough room, error */ |
|---|
| 718 | p608BufInfo->DccError = dccErrOutputBufTooSmall ; |
|---|
| 719 | } |
|---|
| 720 | else |
|---|
| 721 | { |
|---|
| 722 | p608BufInfo->pOutputBuf[ (p608BufInfo->OutputBytesProduced) + 0 ] = FieldFromPicInfo(ulPicInfo,j,numCCPairs) ; |
|---|
| 723 | p608BufInfo->pOutputBuf[ (p608BufInfo->OutputBytesProduced) + 1 ] = cc_data[0] ; |
|---|
| 724 | p608BufInfo->pOutputBuf[ (p608BufInfo->OutputBytesProduced) + 2 ] = cc_data[1] ; |
|---|
| 725 | p608BufInfo->OutputBytesProduced += 3 ; |
|---|
| 726 | } |
|---|
| 727 | } |
|---|
| 728 | } |
|---|
| 729 | |
|---|
| 730 | } /* for each pair */ |
|---|
| 731 | |
|---|
| 732 | } /* if type == 03 */ |
|---|
| 733 | |
|---|
| 734 | return(retCode) ; |
|---|
| 735 | |
|---|
| 736 | } /* Parse_157 */ |
|---|
| 737 | |
|---|
| 738 | |
|---|
| 739 | /************************************************************************** |
|---|
| 740 | * |
|---|
| 741 | * Function: FieldFromPicInfo |
|---|
| 742 | * |
|---|
| 743 | * Inputs: |
|---|
| 744 | * |
|---|
| 745 | * Outputs: |
|---|
| 746 | * |
|---|
| 747 | * Returns: |
|---|
| 748 | * |
|---|
| 749 | * Description: |
|---|
| 750 | * |
|---|
| 751 | * |
|---|
| 752 | **************************************************************************/ |
|---|
| 753 | unsigned int |
|---|
| 754 | FieldFromPicInfo( |
|---|
| 755 | unsigned long ulMainPicInfo, |
|---|
| 756 | unsigned long index, |
|---|
| 757 | unsigned long numPairs) |
|---|
| 758 | { |
|---|
| 759 | if ( (ulMainPicInfo & 3) == 1 ) |
|---|
| 760 | { |
|---|
| 761 | return(DCC_608_FIELD_TOP) ; |
|---|
| 762 | } |
|---|
| 763 | else if ( (ulMainPicInfo & 3) == 2 ) |
|---|
| 764 | { |
|---|
| 765 | return(DCC_608_FIELD_BOTTOM) ; |
|---|
| 766 | } |
|---|
| 767 | else if ( (ulMainPicInfo & 3) == 3 ) |
|---|
| 768 | { |
|---|
| 769 | /* frame */ |
|---|
| 770 | if ( 1 ) //(ulMainPicInfo & 0x100) ) |
|---|
| 771 | { |
|---|
| 772 | /* progressive frame */ |
|---|
| 773 | |
|---|
| 774 | if ( numPairs == 1 || |
|---|
| 775 | (numPairs==2 && (ulMainPicInfo & 0x10)) ) /* 0x10 means repeat first field */ |
|---|
| 776 | { |
|---|
| 777 | /* this is very strange */ |
|---|
| 778 | return(DCC_608_FIELD_TOP) ; |
|---|
| 779 | } |
|---|
| 780 | else |
|---|
| 781 | { |
|---|
| 782 | switch ( ulMainPicInfo & 0x30 ) |
|---|
| 783 | { |
|---|
| 784 | case 0x00 : |
|---|
| 785 | /* bottom field first, repeat first field = 0 */ |
|---|
| 786 | return( index ? DCC_608_FIELD_TOP : DCC_608_FIELD_BOTTOM ) ; |
|---|
| 787 | case 0x10 : |
|---|
| 788 | /* bottom field first, repeat first field = 1 */ |
|---|
| 789 | return( (index==1) ? DCC_608_FIELD_TOP : DCC_608_FIELD_BOTTOM ) ; |
|---|
| 790 | case 0x20 : |
|---|
| 791 | /* top field first, repeat first field = 0 */ |
|---|
| 792 | return( index ? DCC_608_FIELD_BOTTOM : DCC_608_FIELD_TOP ) ; |
|---|
| 793 | case 0x30 : |
|---|
| 794 | /* top field first, repeat first field = 1 */ |
|---|
| 795 | return( (index==1) ? DCC_608_FIELD_BOTTOM : DCC_608_FIELD_TOP ) ; |
|---|
| 796 | } |
|---|
| 797 | } |
|---|
| 798 | } |
|---|
| 799 | else |
|---|
| 800 | { |
|---|
| 801 | if ( (ulMainPicInfo & 0x20) ) |
|---|
| 802 | { |
|---|
| 803 | /* top field first */ |
|---|
| 804 | return(DCC_608_FIELD_TOP) ; |
|---|
| 805 | } |
|---|
| 806 | else |
|---|
| 807 | { |
|---|
| 808 | return(DCC_608_FIELD_BOTTOM) ; |
|---|
| 809 | } |
|---|
| 810 | } |
|---|
| 811 | } |
|---|
| 812 | |
|---|
| 813 | return(DCC_608_FIELD_BOTTOM) ; //??? |
|---|
| 814 | } /* FieldFromPicInfo */ |
|---|
| 815 | |
|---|
| 816 | |
|---|