| 1 | /*************************************************************************** |
|---|
| 2 | * Copyright (c) 2006-2009, 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: bcmindexer_vc1.c $ |
|---|
| 11 | * $brcm_Revision: 7 $ |
|---|
| 12 | * $brcm_Date: 2/25/09 4:48p $ |
|---|
| 13 | * |
|---|
| 14 | * Module Description: Converts startcode index to bcmplayer index |
|---|
| 15 | * |
|---|
| 16 | * Revision History: |
|---|
| 17 | * |
|---|
| 18 | * $brcm_Log: /BSEAV/lib/bcmplayer/src/bcmindexer_vc1.c $ |
|---|
| 19 | * |
|---|
| 20 | * 7 2/25/09 4:48p erickson |
|---|
| 21 | * PR52471: added const keyword |
|---|
| 22 | * |
|---|
| 23 | * 6 1/27/09 9:05a erickson |
|---|
| 24 | * PR51468: make global symbols static |
|---|
| 25 | * |
|---|
| 26 | * 5 1/26/09 1:55p erickson |
|---|
| 27 | * PR51468: global variable naming convention |
|---|
| 28 | * |
|---|
| 29 | * 4 10/22/08 4:59p vishk |
|---|
| 30 | * PR 48073: Coverity Defect ID:12258 DEADCODE bcmindexer_vc1.c |
|---|
| 31 | * Product=97401linux |
|---|
| 32 | * |
|---|
| 33 | * 3 2/26/08 11:21a katrep |
|---|
| 34 | * PR38691: Fixed compiler warnings |
|---|
| 35 | * |
|---|
| 36 | * 2 9/26/07 6:01p jtna |
|---|
| 37 | * PR35267: LIB-Coverity (CID 369): NEGATIVE_RETURNS |
|---|
| 38 | * |
|---|
| 39 | * Irvine_BSEAVSW_Devel/3 3/9/06 3:49p erickson |
|---|
| 40 | * PR19853: read correct interlace bit in SEQUENCE and then don't read FCM |
|---|
| 41 | * is !interlace |
|---|
| 42 | * |
|---|
| 43 | * Irvine_BSEAVSW_Devel/2 3/8/06 3:34p erickson |
|---|
| 44 | * PR19853: set SC offset correctly |
|---|
| 45 | * |
|---|
| 46 | * Irvine_BSEAVSW_Devel/1 3/6/06 1:21p erickson |
|---|
| 47 | * PR19853: added VC1 PES support |
|---|
| 48 | * |
|---|
| 49 | ****************************************************************************/ |
|---|
| 50 | #include "bstd.h" |
|---|
| 51 | #include "bkni.h" |
|---|
| 52 | #include "bcmindexer.h" |
|---|
| 53 | #include "bcmindexerpriv.h" |
|---|
| 54 | #include "mpeg2types.h" |
|---|
| 55 | |
|---|
| 56 | BDBG_MODULE(bcmindexer_vc1); |
|---|
| 57 | |
|---|
| 58 | #if 0 |
|---|
| 59 | #undef BDBG_MSG |
|---|
| 60 | #define BDBG_MSG BDBG_WRN |
|---|
| 61 | #endif |
|---|
| 62 | |
|---|
| 63 | struct vc1_vlc_code { |
|---|
| 64 | unsigned long bitstring; |
|---|
| 65 | int length; |
|---|
| 66 | eSCType frameType; |
|---|
| 67 | }; |
|---|
| 68 | |
|---|
| 69 | static const struct vc1_vlc_code g_fcm[] = { |
|---|
| 70 | {0x0, 1, 0}, /* 0 - progressive */ |
|---|
| 71 | {0x2, 2, 0}, /* 10 - frame-interlace */ |
|---|
| 72 | {0x3, 2, 0}, /* 11 - field-interlace */ |
|---|
| 73 | {0,0,0} /* terminal */ |
|---|
| 74 | }; |
|---|
| 75 | static const struct vc1_vlc_code g_ptype[] = { |
|---|
| 76 | {0x6, 3, eSCTypeIFrame}, /* I */ |
|---|
| 77 | {0x0, 1, eSCTypePFrame}, /* P */ |
|---|
| 78 | {0x2, 2, eSCTypeBFrame}, /* B */ |
|---|
| 79 | {0xE, 4, eSCTypeBFrame}, /* BI */ |
|---|
| 80 | {0xF, 4, eSCTypeBFrame}, /* skipped */ |
|---|
| 81 | {0,0,0} /* terminal */ |
|---|
| 82 | }; |
|---|
| 83 | static const struct vc1_vlc_code g_fptype[] = { |
|---|
| 84 | {0x0, 3, eSCTypeIFrame}, /* I,I */ |
|---|
| 85 | {010, 3, eSCTypePFrame}, /* I,P */ |
|---|
| 86 | {0x2, 3, eSCTypePFrame}, /* P,I */ |
|---|
| 87 | {0x3, 3, eSCTypePFrame}, /* P,P */ |
|---|
| 88 | {0x4, 3, eSCTypeBFrame}, /* B,B */ |
|---|
| 89 | {0x5, 3, eSCTypeBFrame}, /* B,BI */ |
|---|
| 90 | {0x6, 3, eSCTypeBFrame}, /* BI,B */ |
|---|
| 91 | {0x7, 3, eSCTypeBFrame}, /* BI,BI */ |
|---|
| 92 | {0,0,0} /* terminal */ |
|---|
| 93 | }; |
|---|
| 94 | |
|---|
| 95 | static const unsigned char g_mask[] = {0,1,3,7,0xf}; |
|---|
| 96 | |
|---|
| 97 | static int BNAV_Indexer_completeVC1Frame(BNAV_Indexer_Handle handle) |
|---|
| 98 | { |
|---|
| 99 | return BNAV_Indexer_completeFrameAux(handle, &handle->avcEntry, sizeof(handle->avcEntry)); |
|---|
| 100 | } |
|---|
| 101 | |
|---|
| 102 | static int b_vc1_vlc_decode(const uint8_t *data, unsigned size, unsigned current_index, |
|---|
| 103 | unsigned current_bit, unsigned *next_index, unsigned *next_bit,const struct vc1_vlc_code *pattern) |
|---|
| 104 | { |
|---|
| 105 | int i; |
|---|
| 106 | BSTD_UNUSED(size); |
|---|
| 107 | /* TODO: make it span bytes, if needed. don't think so for vc1. */ |
|---|
| 108 | for (i=0;pattern[i].length;i++) { |
|---|
| 109 | unsigned char d = data[0] >> (current_bit - pattern[i].length + 1); |
|---|
| 110 | d &= g_mask[pattern[i].length]; |
|---|
| 111 | if (d == pattern[i].bitstring) { |
|---|
| 112 | *next_index = current_index; |
|---|
| 113 | *next_bit = current_bit - pattern[i].length; |
|---|
| 114 | return i; |
|---|
| 115 | } |
|---|
| 116 | } |
|---|
| 117 | return -1; |
|---|
| 118 | } |
|---|
| 119 | |
|---|
| 120 | static void BNAV_P_ProcessPES(BNAV_Indexer_Handle handle) |
|---|
| 121 | { |
|---|
| 122 | unsigned char *buf = handle->pes.buf; |
|---|
| 123 | unsigned char sc = buf[0]; |
|---|
| 124 | const unsigned char *payload = &buf[1]; |
|---|
| 125 | unsigned index = 0, bit = 7; |
|---|
| 126 | BNAV_AVC_Entry *entry = &handle->avcEntry; |
|---|
| 127 | |
|---|
| 128 | #define VC1_SC_FRAME 0x0D |
|---|
| 129 | #define VC1_SC_ENTRYPOINT 0x0E |
|---|
| 130 | #define VC1_SC_SEQUENCE 0x0F |
|---|
| 131 | |
|---|
| 132 | /* TODO: detect PES start code and capture PTS */ |
|---|
| 133 | |
|---|
| 134 | if (sc != VC1_SC_FRAME && sc != VC1_SC_ENTRYPOINT && sc != VC1_SC_SEQUENCE) { |
|---|
| 135 | return; |
|---|
| 136 | } |
|---|
| 137 | |
|---|
| 138 | BDBG_MSG(("SC %02x", sc)); |
|---|
| 139 | |
|---|
| 140 | /* complete any pending SEQUENCE or ENTRYPOINT */ |
|---|
| 141 | if (handle->pes.sequence_size == -1) { |
|---|
| 142 | handle->pes.sequence_size = handle->pes.offset - handle->pes.sequence_offset; |
|---|
| 143 | } |
|---|
| 144 | else if (handle->pes.entrypoint_size == -1) { |
|---|
| 145 | handle->pes.entrypoint_size = handle->pes.offset - handle->pes.entrypoint_offset; |
|---|
| 146 | } |
|---|
| 147 | |
|---|
| 148 | /* complete any pending frame */ |
|---|
| 149 | handle->picEnd = handle->pes.offset; |
|---|
| 150 | BNAV_Indexer_completeVC1Frame(handle); |
|---|
| 151 | |
|---|
| 152 | /* coverity[dead_error_condition] */ |
|---|
| 153 | switch (sc) { |
|---|
| 154 | case VC1_SC_FRAME: |
|---|
| 155 | { |
|---|
| 156 | int fcm, ptype; |
|---|
| 157 | |
|---|
| 158 | /* TODO: I/P or P/I after EP can be I */ |
|---|
| 159 | if (handle->pes.vc1_interlace) { |
|---|
| 160 | fcm = b_vc1_vlc_decode(payload, MIN_PES_PAYLOAD, index, bit, &index, &bit, g_fcm); |
|---|
| 161 | BDBG_MSG((" fcm %d", fcm)); |
|---|
| 162 | } |
|---|
| 163 | else { |
|---|
| 164 | fcm = 0; |
|---|
| 165 | } |
|---|
| 166 | |
|---|
| 167 | switch (fcm) { |
|---|
| 168 | case 0: /* progressive */ |
|---|
| 169 | case 1: /* frame interlace */ |
|---|
| 170 | ptype = b_vc1_vlc_decode(payload, MIN_PES_PAYLOAD, index, bit, &index, &bit, g_ptype); |
|---|
| 171 | if (ptype > -1 && ptype < 5) { |
|---|
| 172 | BNAV_set_frameType(entry, g_ptype[ptype].frameType); |
|---|
| 173 | } |
|---|
| 174 | else { |
|---|
| 175 | BDBG_ERR((" invalid PTYPE %d", ptype)); |
|---|
| 176 | } |
|---|
| 177 | break; |
|---|
| 178 | case 2: /* field interlace */ |
|---|
| 179 | ptype = b_vc1_vlc_decode(payload, MIN_PES_PAYLOAD, index, bit, &index, &bit, g_fptype); |
|---|
| 180 | if (ptype > -1 && ptype < 8) { |
|---|
| 181 | BNAV_set_frameType(entry, g_fptype[ptype].frameType); |
|---|
| 182 | } |
|---|
| 183 | else { |
|---|
| 184 | BDBG_ERR((" invalid FPTYPE %d", ptype)); |
|---|
| 185 | } |
|---|
| 186 | break; |
|---|
| 187 | default: |
|---|
| 188 | BDBG_ERR((" invalid FCM %d", fcm)); |
|---|
| 189 | return; |
|---|
| 190 | } |
|---|
| 191 | |
|---|
| 192 | if (BNAV_get_frameType(entry) == eSCTypeIFrame && handle->pes.entrypoint_size && handle->pes.sequence_size) { |
|---|
| 193 | handle->hitFirstISlice = 1; |
|---|
| 194 | } |
|---|
| 195 | |
|---|
| 196 | handle->picStart = handle->pes.offset; |
|---|
| 197 | BNAV_set_frameOffsetLo(entry, handle->pes.offset & 0xFFFFFFFF); |
|---|
| 198 | BNAV_set_frameOffsetHi(entry, handle->pes.offset >> 32); |
|---|
| 199 | |
|---|
| 200 | /* Set Sequence offset (using SeqHdr) and Entrypoint offset (using SPS) */ |
|---|
| 201 | BNAV_set_seqHdrStartOffset(entry, (unsigned long)(handle->pes.offset - handle->pes.sequence_offset)); |
|---|
| 202 | BNAV_set_seqHdrSize(entry, handle->pes.sequence_size); |
|---|
| 203 | BNAV_set_SPS_Offset(entry, (unsigned long)(handle->pes.offset - handle->pes.entrypoint_offset)); |
|---|
| 204 | BNAV_set_SPS_Size(entry, handle->pes.entrypoint_size); |
|---|
| 205 | BDBG_MSG(("frame %x, %x, %x, %x, %x",handle->pes.offset,handle->pes.sequence_offset,handle->pes.sequence_size, |
|---|
| 206 | handle->pes.entrypoint_offset,handle->pes.entrypoint_size)); |
|---|
| 207 | } |
|---|
| 208 | break; |
|---|
| 209 | |
|---|
| 210 | case VC1_SC_ENTRYPOINT: |
|---|
| 211 | { |
|---|
| 212 | handle->pes.entrypoint_offset = handle->pes.offset; |
|---|
| 213 | handle->pes.entrypoint_size = -1; /* pending completion */ |
|---|
| 214 | } |
|---|
| 215 | break; |
|---|
| 216 | |
|---|
| 217 | case VC1_SC_SEQUENCE: |
|---|
| 218 | { |
|---|
| 219 | handle->pes.vc1_interlace = payload[5] & 0x40; /* 42nd bit after SC */ |
|---|
| 220 | BDBG_MSG((" interlace? %s", handle->pes.vc1_interlace?"yes":"no")); |
|---|
| 221 | |
|---|
| 222 | handle->pes.sequence_offset = handle->pes.offset; |
|---|
| 223 | handle->pes.sequence_size = -1; /* pending completion */ |
|---|
| 224 | } |
|---|
| 225 | break; |
|---|
| 226 | /* coverity[dead_error_begin] */ |
|---|
| 227 | default: |
|---|
| 228 | break; |
|---|
| 229 | } |
|---|
| 230 | } |
|---|
| 231 | |
|---|
| 232 | int BNAV_P_FeedPES_VC1(BNAV_Indexer_Handle handle, uint8_t *p_bfr, unsigned size) |
|---|
| 233 | { |
|---|
| 234 | unsigned i; |
|---|
| 235 | |
|---|
| 236 | BDBG_ASSERT(handle->settings.navVersion == BNAV_Version_VC1_PES); |
|---|
| 237 | |
|---|
| 238 | /* search for start codes */ |
|---|
| 239 | for (i=0; i<size; i++, handle->pes.offset++) { |
|---|
| 240 | if (handle->pes.sccount == 3) { |
|---|
| 241 | int required = MIN_PES_PAYLOAD - handle->pes.bufsize; |
|---|
| 242 | int available = size - i; |
|---|
| 243 | int n; |
|---|
| 244 | |
|---|
| 245 | /* memcpy as much as possible, up to required */ |
|---|
| 246 | n = required; |
|---|
| 247 | if (n > available) n = available; |
|---|
| 248 | BKNI_Memcpy((void*)&(handle->pes.buf[handle->pes.bufsize]), &p_bfr[i], n); |
|---|
| 249 | handle->pes.bufsize += n; |
|---|
| 250 | |
|---|
| 251 | /* check if we have enough to process the header */ |
|---|
| 252 | if (handle->pes.bufsize < MIN_PES_PAYLOAD) { |
|---|
| 253 | /* wait for next feed */ |
|---|
| 254 | return 0; |
|---|
| 255 | } |
|---|
| 256 | |
|---|
| 257 | /* process the start code & header */ |
|---|
| 258 | handle->pes.offset -= 3; /* back up to start of 00 00 01 SC */ |
|---|
| 259 | BNAV_P_ProcessPES(handle); |
|---|
| 260 | handle->pes.offset += 3; |
|---|
| 261 | handle->pes.sccount = 0; |
|---|
| 262 | handle->pes.bufsize = 0; /*: TODO: not actually correct */ |
|---|
| 263 | } |
|---|
| 264 | |
|---|
| 265 | switch (p_bfr[i]) { |
|---|
| 266 | case 0: |
|---|
| 267 | if (handle->pes.sccount >= 1) |
|---|
| 268 | handle->pes.sccount = 2; |
|---|
| 269 | else |
|---|
| 270 | handle->pes.sccount = 1; |
|---|
| 271 | break; |
|---|
| 272 | case 1: |
|---|
| 273 | if (handle->pes.sccount == 2) { |
|---|
| 274 | /* we've got a start code! */ |
|---|
| 275 | handle->pes.sccount = 3; |
|---|
| 276 | } |
|---|
| 277 | break; |
|---|
| 278 | default: |
|---|
| 279 | handle->pes.sccount = 0; |
|---|
| 280 | break; |
|---|
| 281 | } |
|---|
| 282 | } |
|---|
| 283 | return 0; |
|---|
| 284 | } |
|---|