1
/* $Id: h263_packetizer.c 4006 2012-04-02 08:40:54Z nanang $ */
3
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
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.
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.
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
19
#include <pjmedia-codec/h263_packetizer.h>
20
#include <pjmedia/types.h>
21
#include <pj/assert.h>
23
#include <pj/string.h>
26
#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
29
#define THIS_FILE "h263_packetizer.c"
32
/* H.263 packetizer definition */
33
struct pjmedia_h263_packetizer {
34
/* Current settings */
35
pjmedia_h263_packetizer_cfg cfg;
37
/* Unpacketizer state */
38
unsigned unpack_last_sync_pos;
39
pj_bool_t unpack_prev_lost;
44
* Find synchronization point (PSC, slice, GSBC, EOS, EOSBS) in H.263
47
static pj_uint8_t* find_sync_point(pj_uint8_t *data,
50
pj_uint8_t *p = data, *end = data+data_len-1;
52
while (p < end && (*p || *(p+1)))
63
* Find synchronization point (PSC, slice, GSBC, EOS, EOSBS) in H.263
64
* bitstream, in reversed manner.
66
static pj_uint8_t* find_sync_point_rev(pj_uint8_t *data,
69
pj_uint8_t *p = data+data_len-2;
71
while (p >= data && (*p || *(p+1)))
75
return (data + data_len);
82
* Create H263 packetizer.
84
PJ_DEF(pj_status_t) pjmedia_h263_packetizer_create(
86
const pjmedia_h263_packetizer_cfg *cfg,
87
pjmedia_h263_packetizer **p)
89
pjmedia_h263_packetizer *p_;
91
PJ_ASSERT_RETURN(pool && p, PJ_EINVAL);
93
if (cfg && cfg->mode != PJMEDIA_H263_PACKETIZER_MODE_RFC4629)
96
p_ = PJ_POOL_ZALLOC_T(pool, pjmedia_h263_packetizer);
98
pj_memcpy(&p_->cfg, cfg, sizeof(*cfg));
100
p_->cfg.mode = PJMEDIA_H263_PACKETIZER_MODE_RFC4629;
101
p_->cfg.mtu = PJMEDIA_MAX_VID_PAYLOAD_SIZE;
111
* Generate an RTP payload from H.263 frame bitstream, in-place processing.
113
PJ_DEF(pj_status_t) pjmedia_h263_packetize(pjmedia_h263_packetizer *pktz,
117
const pj_uint8_t **payload,
118
pj_size_t *payload_len)
122
pj_assert(pktz && bits && pos && payload && payload_len);
123
pj_assert(*pos <= bits_len);
126
end = bits + bits_len;
128
/* Put two octets payload header */
129
if ((end-p > 2) && *p==0 && *(p+1)==0) {
130
/* The bitstream starts with synchronization point, just override
131
* the two zero octets (sync point mark) for payload header.
135
/* Not started in synchronization point, we will use two octets
136
* preceeding the bitstream for payload header!
140
/* Invalid H263 bitstream, it's not started with PSC */
149
/* When bitstream truncation needed because of payload length/MTU
150
* limitation, try to use sync point for the payload boundary.
152
if (end-p > pktz->cfg.mtu) {
153
end = find_sync_point_rev(p+2, pktz->cfg.mtu-2);
157
*payload_len = end-p;
165
* Append an RTP payload to a H.263 picture bitstream.
167
PJ_DEF(pj_status_t) pjmedia_h263_unpacketize (pjmedia_h263_packetizer *pktz,
168
const pj_uint8_t *payload,
169
pj_size_t payload_len,
174
pj_uint8_t P, V, PLEN;
175
const pj_uint8_t *p = payload;
180
/* Check if this is a missing/lost packet */
181
if (payload == NULL) {
182
pktz->unpack_prev_lost = PJ_TRUE;
186
/* H263 payload header size is two octets */
187
if (payload_len < 2) {
188
/* Invalid bitstream, discard this payload */
189
pktz->unpack_prev_lost = PJ_TRUE;
193
/* Reset last sync point for every new picture bitstream */
195
pktz->unpack_last_sync_pos = 0;
197
/* Get payload header info */
200
PLEN = ((*p & 0x01) << 5) + ((*(p+1) & 0xF8)>>3);
202
/* Get start bitstream pointer */
203
p += 2; /* Skip payload header */
205
p += 1; /* Skip VRC data */
207
p += PLEN; /* Skip extra picture header data */
209
/* Get bitstream length */
210
if (payload_len > (pj_size_t)(p - payload)) {
211
payload_len -= (p - payload);
213
/* Invalid bitstream, discard this payload */
214
pktz->unpack_prev_lost = PJ_TRUE;
218
/* Validate bitstream length */
219
if (bits_size < *pos + payload_len + 2) {
220
/* Insufficient bistream buffer, discard this payload */
221
pj_assert(!"Insufficient H.263 bitstream buffer");
222
pktz->unpack_prev_lost = PJ_TRUE;
226
/* Start writing bitstream */
228
/* No sync point flag */
231
/* Previous packet must be lost */
232
pktz->unpack_prev_lost = PJ_TRUE;
234
/* If there is extra picture header, let's use it. */
236
/* Write two zero octets for PSC */
239
/* Copy the picture header */
241
pj_memcpy(q, p, PLEN);
245
} else if (pktz->unpack_prev_lost) {
246
/* If prev packet was lost, revert the bitstream pointer to
247
* the last sync point.
249
pj_assert(pktz->unpack_last_sync_pos <= *pos);
250
q = bits + pktz->unpack_last_sync_pos;
253
/* There was packet lost, see if this payload contain sync point
256
if (pktz->unpack_prev_lost) {
258
sync = find_sync_point((pj_uint8_t*)p, payload_len);
260
/* Got sync point, update P/sync-point flag */
262
/* Skip the two zero octets */
264
/* Update payload length and start bitstream pointer */
265
payload_len -= (sync - p);
268
/* No sync point in it, just discard this payload */
274
/* Write two zero octets when payload flagged with sync point */
276
pktz->unpack_last_sync_pos = q - bits;
281
/* Write the payload to the bitstream */
282
pj_memcpy(q, p, payload_len);
285
/* Update the bitstream writing offset */
288
pktz->unpack_prev_lost = PJ_FALSE;
294
#endif /* PJMEDIA_HAS_VIDEO */