Tristan Matthews | 0a329cc | 2013-07-17 13:20:14 -0400 | [diff] [blame] | 1 | /* $Id$ */ |
| 2 | /* |
| 3 | * Copyright (C) 2011 Teluu Inc. (http://www.teluu.com) |
| 4 | * |
| 5 | * This program is free software; you can redistribute it and/or modify |
| 6 | * it under the terms of the GNU General Public License as published by |
| 7 | * the Free Software Foundation; either version 2 of the License, or |
| 8 | * (at your option) any later version. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, write to the Free Software |
| 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 18 | */ |
| 19 | #include <pjmedia-codec/h264_packetizer.h> |
| 20 | #include <pjmedia/types.h> |
| 21 | #include <pj/assert.h> |
| 22 | #include <pj/errno.h> |
| 23 | #include <pj/log.h> |
| 24 | #include <pj/pool.h> |
| 25 | #include <pj/string.h> |
| 26 | |
| 27 | |
| 28 | #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0) |
| 29 | |
| 30 | |
| 31 | #define THIS_FILE "h264_packetizer.c" |
| 32 | |
| 33 | #define DBG_PACKETIZE 0 |
| 34 | #define DBG_UNPACKETIZE 0 |
| 35 | |
| 36 | |
| 37 | /* H.264 packetizer definition */ |
| 38 | struct pjmedia_h264_packetizer |
| 39 | { |
| 40 | /* Current settings */ |
| 41 | pjmedia_h264_packetizer_cfg cfg; |
| 42 | |
| 43 | /* Unpacketizer state */ |
| 44 | unsigned unpack_last_sync_pos; |
| 45 | pj_bool_t unpack_prev_lost; |
| 46 | }; |
| 47 | |
| 48 | |
| 49 | /* Enumeration of H.264 NAL unit types */ |
| 50 | enum |
| 51 | { |
| 52 | NAL_TYPE_SINGLE_NAL_MIN = 1, |
| 53 | NAL_TYPE_SINGLE_NAL_MAX = 23, |
| 54 | NAL_TYPE_STAP_A = 24, |
| 55 | NAL_TYPE_FU_A = 28, |
| 56 | }; |
| 57 | |
| 58 | |
| 59 | /* |
| 60 | * Find next NAL unit from the specified H.264 bitstream data. |
| 61 | */ |
| 62 | static pj_uint8_t* find_next_nal_unit(pj_uint8_t *start, |
| 63 | pj_uint8_t *end) |
| 64 | { |
| 65 | pj_uint8_t *p = start; |
| 66 | |
| 67 | /* Simply lookup "0x000001" pattern */ |
| 68 | while (p <= end-3 && (p[0] || p[1] || p[2]!=1)) |
| 69 | ++p; |
| 70 | |
| 71 | if (p > end-3) |
| 72 | /* No more NAL unit in this bitstream */ |
| 73 | return NULL; |
| 74 | |
| 75 | /* Include 8 bits leading zero */ |
| 76 | if (p>start && *(p-1)==0) |
| 77 | return (p-1); |
| 78 | |
| 79 | return p; |
| 80 | } |
| 81 | |
| 82 | |
| 83 | /* |
| 84 | * Create H264 packetizer. |
| 85 | */ |
| 86 | PJ_DEF(pj_status_t) pjmedia_h264_packetizer_create( |
| 87 | pj_pool_t *pool, |
| 88 | const pjmedia_h264_packetizer_cfg *cfg, |
| 89 | pjmedia_h264_packetizer **p) |
| 90 | { |
| 91 | pjmedia_h264_packetizer *p_; |
| 92 | |
| 93 | PJ_ASSERT_RETURN(pool && p, PJ_EINVAL); |
| 94 | |
| 95 | if (cfg && |
| 96 | cfg->mode != PJMEDIA_H264_PACKETIZER_MODE_NON_INTERLEAVED && |
| 97 | cfg->mode != PJMEDIA_H264_PACKETIZER_MODE_SINGLE_NAL) |
| 98 | { |
| 99 | return PJ_ENOTSUP; |
| 100 | } |
| 101 | |
| 102 | p_ = PJ_POOL_ZALLOC_T(pool, pjmedia_h264_packetizer); |
| 103 | if (cfg) { |
| 104 | pj_memcpy(&p_->cfg, cfg, sizeof(*cfg)); |
| 105 | } else { |
| 106 | p_->cfg.mode = PJMEDIA_H264_PACKETIZER_MODE_NON_INTERLEAVED; |
| 107 | p_->cfg.mtu = PJMEDIA_MAX_VID_PAYLOAD_SIZE; |
| 108 | } |
| 109 | |
| 110 | *p = p_; |
| 111 | |
| 112 | return PJ_SUCCESS; |
| 113 | } |
| 114 | |
| 115 | |
| 116 | |
| 117 | /* |
| 118 | * Generate an RTP payload from H.264 frame bitstream, in-place processing. |
| 119 | */ |
| 120 | PJ_DEF(pj_status_t) pjmedia_h264_packetize(pjmedia_h264_packetizer *pktz, |
| 121 | pj_uint8_t *buf, |
| 122 | pj_size_t buf_len, |
| 123 | unsigned *pos, |
| 124 | const pj_uint8_t **payload, |
| 125 | pj_size_t *payload_len) |
| 126 | { |
| 127 | pj_uint8_t *nal_start = NULL, *nal_end = NULL, *nal_octet = NULL; |
| 128 | pj_uint8_t *p, *end; |
| 129 | enum { |
| 130 | HEADER_SIZE_FU_A = 2, |
| 131 | HEADER_SIZE_STAP_A = 3, |
| 132 | }; |
| 133 | enum { MAX_NALS_IN_AGGR = 32 }; |
| 134 | |
| 135 | #if DBG_PACKETIZE |
| 136 | if (*pos == 0 && buf_len) { |
| 137 | PJ_LOG(3, ("h264pack", "<< Start packing new frame >>")); |
| 138 | } |
| 139 | #endif |
| 140 | |
| 141 | p = buf + *pos; |
| 142 | end = buf + buf_len; |
| 143 | |
| 144 | /* Find NAL unit startcode */ |
| 145 | if (end-p >= 4) |
| 146 | nal_start = find_next_nal_unit(p, p+4); |
| 147 | if (nal_start) { |
| 148 | /* Get NAL unit octet pointer */ |
| 149 | while (*nal_start++ == 0); |
| 150 | nal_octet = nal_start; |
| 151 | } else { |
| 152 | /* This NAL unit is being fragmented */ |
| 153 | nal_start = p; |
| 154 | } |
| 155 | |
| 156 | /* Get end of NAL unit */ |
| 157 | p = nal_start+pktz->cfg.mtu+1; |
| 158 | if (p > end || pktz->cfg.mode==PJMEDIA_H264_PACKETIZER_MODE_SINGLE_NAL) |
| 159 | p = end; |
| 160 | nal_end = find_next_nal_unit(nal_start, p); |
| 161 | if (!nal_end) |
| 162 | nal_end = p; |
| 163 | |
| 164 | /* Validate MTU vs NAL length on single NAL unit packetization */ |
| 165 | if ((pktz->cfg.mode==PJMEDIA_H264_PACKETIZER_MODE_SINGLE_NAL) && |
| 166 | nal_end - nal_start > pktz->cfg.mtu) |
| 167 | { |
| 168 | //pj_assert(!"MTU too small for H.264 single NAL packetization mode"); |
| 169 | PJ_LOG(2,("h264_packetizer.c", |
| 170 | "MTU too small for H.264 (required=%u, MTU=%u)", |
| 171 | nal_end - nal_start, pktz->cfg.mtu)); |
| 172 | return PJ_ETOOSMALL; |
| 173 | } |
| 174 | |
| 175 | /* Evaluate the proper payload format structure */ |
| 176 | |
| 177 | /* Fragmentation (FU-A) packet */ |
| 178 | if ((pktz->cfg.mode != PJMEDIA_H264_PACKETIZER_MODE_SINGLE_NAL) && |
| 179 | (!nal_octet || nal_end-nal_start > pktz->cfg.mtu)) |
| 180 | { |
| 181 | pj_uint8_t NRI, TYPE; |
| 182 | |
| 183 | if (nal_octet) { |
| 184 | /* We have NAL unit octet, so this is the first fragment */ |
| 185 | NRI = (*nal_octet & 0x60) >> 5; |
| 186 | TYPE = *nal_octet & 0x1F; |
| 187 | |
| 188 | /* Skip nal_octet in nal_start to be overriden by FU header */ |
| 189 | ++nal_start; |
| 190 | } else { |
| 191 | /* Not the first fragment, get NRI and NAL unit type |
| 192 | * from the previous fragment. |
| 193 | */ |
| 194 | p = nal_start - pktz->cfg.mtu; |
| 195 | NRI = (*p & 0x60) >> 5; |
| 196 | TYPE = *(p+1) & 0x1F; |
| 197 | } |
| 198 | |
| 199 | /* Init FU indicator (one octet: F+NRI+TYPE) */ |
| 200 | p = nal_start - HEADER_SIZE_FU_A; |
| 201 | *p = (NRI << 5) | NAL_TYPE_FU_A; |
| 202 | ++p; |
| 203 | |
| 204 | /* Init FU header (one octed: S+E+R+TYPE) */ |
| 205 | *p = TYPE; |
| 206 | if (nal_octet) |
| 207 | *p |= (1 << 7); /* S bit flag = start of fragmentation */ |
| 208 | if (nal_end-nal_start+HEADER_SIZE_FU_A <= pktz->cfg.mtu) |
| 209 | *p |= (1 << 6); /* E bit flag = end of fragmentation */ |
| 210 | |
| 211 | /* Set payload, payload length */ |
| 212 | *payload = nal_start - HEADER_SIZE_FU_A; |
| 213 | if (nal_end-nal_start+HEADER_SIZE_FU_A > pktz->cfg.mtu) |
| 214 | *payload_len = pktz->cfg.mtu; |
| 215 | else |
| 216 | *payload_len = nal_end - nal_start + HEADER_SIZE_FU_A; |
| 217 | *pos = (unsigned)(*payload + *payload_len - buf); |
| 218 | |
| 219 | #if DBG_PACKETIZE |
| 220 | PJ_LOG(3, ("h264pack", "Packetized fragmented H264 NAL unit " |
| 221 | "(pos=%d, type=%d, NRI=%d, S=%d, E=%d, len=%d/%d)", |
| 222 | *payload-buf, TYPE, NRI, *p>>7, (*p>>6)&1, *payload_len, |
| 223 | buf_len)); |
| 224 | #endif |
| 225 | |
| 226 | return PJ_SUCCESS; |
| 227 | } |
| 228 | |
| 229 | /* Aggregation (STAP-A) packet */ |
| 230 | if ((pktz->cfg.mode != PJMEDIA_H264_PACKETIZER_MODE_SINGLE_NAL) && |
| 231 | (nal_end != end) && |
| 232 | (nal_end - nal_start + HEADER_SIZE_STAP_A) < pktz->cfg.mtu) |
| 233 | { |
| 234 | int total_size; |
| 235 | unsigned nal_cnt = 1; |
| 236 | pj_uint8_t *nal[MAX_NALS_IN_AGGR]; |
| 237 | pj_size_t nal_size[MAX_NALS_IN_AGGR]; |
| 238 | pj_uint8_t NRI; |
| 239 | |
| 240 | pj_assert(nal_octet); |
| 241 | |
| 242 | /* Init the first NAL unit in the packet */ |
| 243 | nal[0] = nal_start; |
| 244 | nal_size[0] = nal_end - nal_start; |
| 245 | total_size = (int)nal_size[0] + HEADER_SIZE_STAP_A; |
| 246 | NRI = (*nal_octet & 0x60) >> 5; |
| 247 | |
| 248 | /* Populate next NAL units */ |
| 249 | while (nal_cnt < MAX_NALS_IN_AGGR) { |
| 250 | pj_uint8_t *tmp_end; |
| 251 | |
| 252 | /* Find start address of the next NAL unit */ |
| 253 | p = nal[nal_cnt-1] + nal_size[nal_cnt-1]; |
| 254 | while (*p++ == 0); |
| 255 | nal[nal_cnt] = p; |
| 256 | |
| 257 | /* Find end address of the next NAL unit */ |
| 258 | tmp_end = p + (pktz->cfg.mtu - total_size); |
| 259 | if (tmp_end > end) |
| 260 | tmp_end = end; |
| 261 | p = find_next_nal_unit(p+1, tmp_end); |
| 262 | if (p) { |
| 263 | nal_size[nal_cnt] = p - nal[nal_cnt]; |
| 264 | } else { |
| 265 | break; |
| 266 | } |
| 267 | |
| 268 | /* Update total payload size (2 octet NAL size + NAL) */ |
| 269 | total_size += (2 + (int)nal_size[nal_cnt]); |
| 270 | if (total_size <= pktz->cfg.mtu) { |
| 271 | pj_uint8_t tmp_nri; |
| 272 | |
| 273 | /* Get maximum NRI of the aggregated NAL units */ |
| 274 | tmp_nri = (*(nal[nal_cnt]-1) & 0x60) >> 5; |
| 275 | if (tmp_nri > NRI) |
| 276 | NRI = tmp_nri; |
| 277 | } else { |
| 278 | break; |
| 279 | } |
| 280 | |
| 281 | ++nal_cnt; |
| 282 | } |
| 283 | |
| 284 | /* Only use STAP-A when we found more than one NAL units */ |
| 285 | if (nal_cnt > 1) { |
| 286 | unsigned i; |
| 287 | |
| 288 | /* Init STAP-A NAL header (F+NRI+TYPE) */ |
| 289 | p = nal[0] - HEADER_SIZE_STAP_A; |
| 290 | *p++ = (NRI << 5) | NAL_TYPE_STAP_A; |
| 291 | |
| 292 | /* Append all populated NAL units into payload (SIZE+NAL) */ |
| 293 | for (i = 0; i < nal_cnt; ++i) { |
| 294 | /* Put size (2 octets in network order) */ |
| 295 | pj_assert(nal_size[i] <= 0xFFFF); |
| 296 | *p++ = (pj_uint8_t)(nal_size[i] >> 8); |
| 297 | *p++ = (pj_uint8_t)(nal_size[i] & 0xFF); |
| 298 | |
| 299 | /* Append NAL unit, watchout memmove()-ing bitstream! */ |
| 300 | if (p != nal[i]) |
| 301 | pj_memmove(p, nal[i], nal_size[i]); |
| 302 | p += nal_size[i]; |
| 303 | } |
| 304 | |
| 305 | /* Set payload, payload length, and pos */ |
| 306 | *payload = nal[0] - HEADER_SIZE_STAP_A; |
| 307 | pj_assert(*payload >= buf+*pos); |
| 308 | *payload_len = p - *payload; |
| 309 | *pos = (unsigned)(nal[nal_cnt-1] + nal_size[nal_cnt-1] - buf); |
| 310 | |
| 311 | #if DBG_PACKETIZE |
| 312 | PJ_LOG(3, ("h264pack", "Packetized aggregation of " |
| 313 | "%d H264 NAL units (pos=%d, NRI=%d len=%d/%d)", |
| 314 | nal_cnt, *payload-buf, NRI, *payload_len, buf_len)); |
| 315 | #endif |
| 316 | |
| 317 | return PJ_SUCCESS; |
| 318 | } |
| 319 | } |
| 320 | |
| 321 | /* Single NAL unit packet */ |
| 322 | *payload = nal_start; |
| 323 | *payload_len = nal_end - nal_start; |
| 324 | *pos = (unsigned)(nal_end - buf); |
| 325 | |
| 326 | #if DBG_PACKETIZE |
| 327 | PJ_LOG(3, ("h264pack", "Packetized single H264 NAL unit " |
| 328 | "(pos=%d, type=%d, NRI=%d, len=%d/%d)", |
| 329 | nal_start-buf, *nal_octet&0x1F, (*nal_octet&0x60)>>5, |
| 330 | *payload_len, buf_len)); |
| 331 | #endif |
| 332 | |
| 333 | return PJ_SUCCESS; |
| 334 | } |
| 335 | |
| 336 | |
| 337 | /* |
| 338 | * Append RTP payload to a H.264 picture bitstream. Note that the only |
| 339 | * payload format that cares about packet lost is the NAL unit |
| 340 | * fragmentation format (FU-A/B), so we will only manage the "prev_lost" |
| 341 | * state for the FU-A/B packets. |
| 342 | */ |
| 343 | PJ_DEF(pj_status_t) pjmedia_h264_unpacketize(pjmedia_h264_packetizer *pktz, |
| 344 | const pj_uint8_t *payload, |
| 345 | pj_size_t payload_len, |
| 346 | pj_uint8_t *bits, |
| 347 | pj_size_t bits_len, |
| 348 | unsigned *bits_pos) |
| 349 | { |
| 350 | const pj_uint8_t nal_start_code[3] = {0, 0, 1}; |
| 351 | enum { MIN_PAYLOAD_SIZE = 2 }; |
| 352 | pj_uint8_t nal_type; |
| 353 | |
| 354 | PJ_UNUSED_ARG(pktz); |
| 355 | |
| 356 | #if DBG_UNPACKETIZE |
| 357 | if (*bits_pos == 0 && payload_len) { |
| 358 | PJ_LOG(3, ("h264unpack", ">> Start unpacking new frame <<")); |
| 359 | } |
| 360 | #endif |
| 361 | |
| 362 | /* Check if this is a missing/lost packet */ |
| 363 | if (payload == NULL) { |
| 364 | pktz->unpack_prev_lost = PJ_TRUE; |
| 365 | return PJ_SUCCESS; |
| 366 | } |
| 367 | |
| 368 | /* H264 payload size */ |
| 369 | if (payload_len < MIN_PAYLOAD_SIZE) { |
| 370 | /* Invalid bitstream, discard this payload */ |
| 371 | pktz->unpack_prev_lost = PJ_TRUE; |
| 372 | return PJ_EINVAL; |
| 373 | } |
| 374 | |
| 375 | /* Reset last sync point for every new picture bitstream */ |
| 376 | if (*bits_pos == 0) |
| 377 | pktz->unpack_last_sync_pos = 0; |
| 378 | |
| 379 | nal_type = *payload & 0x1F; |
| 380 | if (nal_type >= NAL_TYPE_SINGLE_NAL_MIN && |
| 381 | nal_type <= NAL_TYPE_SINGLE_NAL_MAX) |
| 382 | { |
| 383 | /* Single NAL unit packet */ |
| 384 | pj_uint8_t *p = bits + *bits_pos; |
| 385 | |
| 386 | /* Validate bitstream length */ |
| 387 | if (bits_len-*bits_pos < payload_len+PJ_ARRAY_SIZE(nal_start_code)) { |
| 388 | /* Insufficient bistream buffer, discard this payload */ |
| 389 | pj_assert(!"Insufficient H.263 bitstream buffer"); |
| 390 | return PJ_ETOOSMALL; |
| 391 | } |
| 392 | |
| 393 | /* Write NAL unit start code */ |
| 394 | pj_memcpy(p, &nal_start_code, PJ_ARRAY_SIZE(nal_start_code)); |
| 395 | p += PJ_ARRAY_SIZE(nal_start_code); |
| 396 | |
| 397 | /* Write NAL unit */ |
| 398 | pj_memcpy(p, payload, payload_len); |
| 399 | p += payload_len; |
| 400 | |
| 401 | /* Update the bitstream writing offset */ |
| 402 | *bits_pos = (unsigned)(p - bits); |
| 403 | pktz->unpack_last_sync_pos = *bits_pos; |
| 404 | |
| 405 | #if DBG_UNPACKETIZE |
| 406 | PJ_LOG(3, ("h264unpack", "Unpacked single H264 NAL unit " |
| 407 | "(type=%d, NRI=%d, len=%d)", |
| 408 | nal_type, (*payload&0x60)>>5, payload_len)); |
| 409 | #endif |
| 410 | |
| 411 | } |
| 412 | else if (nal_type == NAL_TYPE_STAP_A) |
| 413 | { |
| 414 | /* Aggregation packet */ |
| 415 | pj_uint8_t *p, *p_end; |
| 416 | const pj_uint8_t *q, *q_end; |
| 417 | unsigned cnt = 0; |
| 418 | |
| 419 | /* Validate bitstream length */ |
| 420 | if (bits_len - *bits_pos < payload_len + 32) { |
| 421 | /* Insufficient bistream buffer, discard this payload */ |
| 422 | pj_assert(!"Insufficient H.263 bitstream buffer"); |
| 423 | return PJ_ETOOSMALL; |
| 424 | } |
| 425 | |
| 426 | /* Fill bitstream */ |
| 427 | p = bits + *bits_pos; |
| 428 | p_end = bits + bits_len; |
| 429 | q = payload + 1; |
| 430 | q_end = payload + payload_len; |
| 431 | while (q < q_end && p < p_end) { |
| 432 | pj_uint16_t tmp_nal_size; |
| 433 | |
| 434 | /* Write NAL unit start code */ |
| 435 | pj_memcpy(p, &nal_start_code, PJ_ARRAY_SIZE(nal_start_code)); |
| 436 | p += PJ_ARRAY_SIZE(nal_start_code); |
| 437 | |
| 438 | /* Get NAL unit size */ |
| 439 | tmp_nal_size = (*q << 8) | *(q+1); |
| 440 | q += 2; |
| 441 | if (q + tmp_nal_size > q_end) { |
| 442 | /* Invalid bitstream, discard the rest of the payload */ |
| 443 | return PJ_EINVAL; |
| 444 | } |
| 445 | |
| 446 | /* Write NAL unit */ |
| 447 | pj_memcpy(p, q, tmp_nal_size); |
| 448 | p += tmp_nal_size; |
| 449 | q += tmp_nal_size; |
| 450 | ++cnt; |
| 451 | |
| 452 | /* Update the bitstream writing offset */ |
| 453 | *bits_pos = (unsigned)(p - bits); |
| 454 | pktz->unpack_last_sync_pos = *bits_pos; |
| 455 | } |
| 456 | |
| 457 | #if DBG_UNPACKETIZE |
| 458 | PJ_LOG(3, ("h264unpack", "Unpacked %d H264 NAL units (len=%d)", |
| 459 | cnt, payload_len)); |
| 460 | #endif |
| 461 | |
| 462 | } |
| 463 | else if (nal_type == NAL_TYPE_FU_A) |
| 464 | { |
| 465 | /* Fragmentation packet */ |
| 466 | pj_uint8_t *p; |
| 467 | const pj_uint8_t *q = payload; |
| 468 | pj_uint8_t NRI, TYPE, S, E; |
| 469 | |
| 470 | p = bits + *bits_pos; |
| 471 | |
| 472 | /* Validate bitstream length */ |
| 473 | if (bits_len-*bits_pos < payload_len+PJ_ARRAY_SIZE(nal_start_code)) { |
| 474 | /* Insufficient bistream buffer, drop this packet */ |
| 475 | pj_assert(!"Insufficient H.263 bitstream buffer"); |
| 476 | pktz->unpack_prev_lost = PJ_TRUE; |
| 477 | return PJ_ETOOSMALL; |
| 478 | } |
| 479 | |
| 480 | /* Get info */ |
| 481 | S = *(q+1) & 0x80; /* Start bit flag */ |
| 482 | E = *(q+1) & 0x40; /* End bit flag */ |
| 483 | TYPE = *(q+1) & 0x1f; |
| 484 | NRI = (*q & 0x60) >> 5; |
| 485 | |
| 486 | /* Fill bitstream */ |
| 487 | if (S) { |
| 488 | /* This is the first part, write NAL unit start code */ |
| 489 | pj_memcpy(p, &nal_start_code, PJ_ARRAY_SIZE(nal_start_code)); |
| 490 | p += PJ_ARRAY_SIZE(nal_start_code); |
| 491 | |
| 492 | /* Write NAL unit octet */ |
| 493 | *p++ = (NRI << 5) | TYPE; |
| 494 | } else if (pktz->unpack_prev_lost) { |
| 495 | /* If prev packet was lost, revert the bitstream pointer to |
| 496 | * the last sync point. |
| 497 | */ |
| 498 | pj_assert(pktz->unpack_last_sync_pos <= *bits_pos); |
| 499 | *bits_pos = pktz->unpack_last_sync_pos; |
| 500 | /* And discard this payload (and the following fragmentation |
| 501 | * payloads carrying this same NAL unit. |
| 502 | */ |
| 503 | return PJ_EIGNORED; |
| 504 | } |
| 505 | q += 2; |
| 506 | |
| 507 | /* Write NAL unit */ |
| 508 | pj_memcpy(p, q, payload_len - 2); |
| 509 | p += (payload_len - 2); |
| 510 | |
| 511 | /* Update the bitstream writing offset */ |
| 512 | *bits_pos = (unsigned)(p - bits); |
| 513 | if (E) { |
| 514 | /* Update the sync pos only if the end bit flag is set */ |
| 515 | pktz->unpack_last_sync_pos = *bits_pos; |
| 516 | } |
| 517 | |
| 518 | #if DBG_UNPACKETIZE |
| 519 | PJ_LOG(3, ("h264unpack", "Unpacked fragmented H264 NAL unit " |
| 520 | "(type=%d, NRI=%d, len=%d)", |
| 521 | TYPE, NRI, payload_len)); |
| 522 | #endif |
| 523 | |
| 524 | } else { |
| 525 | *bits_pos = 0; |
| 526 | return PJ_ENOTSUP; |
| 527 | } |
| 528 | |
| 529 | pktz->unpack_prev_lost = PJ_FALSE; |
| 530 | |
| 531 | return PJ_SUCCESS; |
| 532 | } |
| 533 | |
| 534 | |
| 535 | #endif /* PJMEDIA_HAS_VIDEO */ |