blob: 1d3b92de97474d5ad7a177e04294e94cf2992d87 [file] [log] [blame]
Nanang Izzuddind91af572011-03-31 17:29:54 +00001/* $Id$ */
2/*
Nanang Izzuddinfad6f692011-08-19 09:35:25 +00003 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
Nanang Izzuddind91af572011-03-31 17:29:54 +00004 *
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/h263_packetizer.h>
20#include <pjmedia/types.h>
21#include <pj/assert.h>
22#include <pj/errno.h>
23#include <pj/string.h>
24
Nanang Izzuddin63b3c132011-07-19 11:11:07 +000025
26#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
27
28
Nanang Izzuddind91af572011-03-31 17:29:54 +000029#define THIS_FILE "h263_packetizer.c"
30
31
32/* H.263 packetizer definition */
33struct pjmedia_h263_packetizer {
34 /* Current settings */
35 pjmedia_h263_packetizer_cfg cfg;
36
37 /* Unpacketizer state */
38 unsigned unpack_last_sync_pos;
39 pj_bool_t unpack_prev_lost;
40};
41
42
43/*
44 * Find synchronization point (PSC, slice, GSBC, EOS, EOSBS) in H.263
45 * bitstream.
46 */
47static pj_uint8_t* find_sync_point(pj_uint8_t *data,
48 pj_size_t data_len)
49{
Benny Prijono1594fbd2011-04-13 18:05:09 +000050 pj_uint8_t *p = data, *end = data+data_len-1;
Nanang Izzuddind91af572011-03-31 17:29:54 +000051
Nanang Izzuddineda06092011-04-13 18:57:57 +000052 while (p < end && (*p || *(p+1)))
Nanang Izzuddind91af572011-03-31 17:29:54 +000053 ++p;
54
55 if (p == end)
56 return NULL;
57
58 return p;
59}
60
61
62/*
63 * Find synchronization point (PSC, slice, GSBC, EOS, EOSBS) in H.263
64 * bitstream, in reversed manner.
65 */
66static pj_uint8_t* find_sync_point_rev(pj_uint8_t *data,
67 pj_size_t data_len)
68{
Benny Prijono1594fbd2011-04-13 18:05:09 +000069 pj_uint8_t *p = data+data_len-2;
Nanang Izzuddind91af572011-03-31 17:29:54 +000070
Nanang Izzuddineda06092011-04-13 18:57:57 +000071 while (p >= data && (*p || *(p+1)))
Nanang Izzuddind91af572011-03-31 17:29:54 +000072 --p;
73
Benny Prijono1594fbd2011-04-13 18:05:09 +000074 if (p < data)
Nanang Izzuddind91af572011-03-31 17:29:54 +000075 return (data + data_len);
76
77 return p;
78}
79
80
81/*
82 * Create H263 packetizer.
83 */
84PJ_DEF(pj_status_t) pjmedia_h263_packetizer_create(
85 pj_pool_t *pool,
86 const pjmedia_h263_packetizer_cfg *cfg,
87 pjmedia_h263_packetizer **p)
88{
89 pjmedia_h263_packetizer *p_;
90
91 PJ_ASSERT_RETURN(pool && p, PJ_EINVAL);
92
93 if (cfg && cfg->mode != PJMEDIA_H263_PACKETIZER_MODE_RFC4629)
94 return PJ_ENOTSUP;
95
96 p_ = PJ_POOL_ZALLOC_T(pool, pjmedia_h263_packetizer);
97 if (cfg) {
98 pj_memcpy(&p_->cfg, cfg, sizeof(*cfg));
99 } else {
100 p_->cfg.mode = PJMEDIA_H263_PACKETIZER_MODE_RFC4629;
101 p_->cfg.mtu = PJMEDIA_MAX_MTU;
102 }
103
104 *p = p_;
105
106 return PJ_SUCCESS;
107}
108
109
110/*
111 * Generate an RTP payload from H.263 frame bitstream, in-place processing.
112 */
113PJ_DEF(pj_status_t) pjmedia_h263_packetize(pjmedia_h263_packetizer *pktz,
114 pj_uint8_t *bits,
115 pj_size_t bits_len,
116 unsigned *pos,
117 const pj_uint8_t **payload,
118 pj_size_t *payload_len)
119{
120 pj_uint8_t *p, *end;
121
122 pj_assert(pktz && bits && pos && payload && payload_len);
123 pj_assert(*pos <= bits_len);
124
125 p = bits + *pos;
126 end = bits + bits_len;
127
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.
132 */
133 *p = 0x04;
134 } else {
135 /* Not started in synchronization point, we will use two octets
136 * preceeding the bitstream for payload header!
137 */
138
139 if (*pos < 2) {
140 /* Invalid H263 bitstream, it's not started with PSC */
141 return PJ_EINVAL;
142 }
143
144 p -= 2;
145 *p = 0;
146 }
147 *(p+1) = 0;
148
149 /* When bitstream truncation needed because of payload length/MTU
150 * limitation, try to use sync point for the payload boundary.
151 */
152 if (end-p > pktz->cfg.mtu) {
153 end = find_sync_point_rev(p+2, pktz->cfg.mtu-2);
154 }
155
156 *payload = p;
157 *payload_len = end-p;
158 *pos = end - bits;
159
160 return PJ_SUCCESS;
161}
162
163
164/*
165 * Append an RTP payload to a H.263 picture bitstream.
166 */
167PJ_DEF(pj_status_t) pjmedia_h263_unpacketize (pjmedia_h263_packetizer *pktz,
168 const pj_uint8_t *payload,
169 pj_size_t payload_len,
170 pj_uint8_t *bits,
171 pj_size_t bits_size,
172 unsigned *pos)
173{
174 pj_uint8_t P, V, PLEN;
175 const pj_uint8_t *p = payload;
176 pj_uint8_t *q;
177
178 q = bits + *pos;
179
180 /* Check if this is a missing/lost packet */
181 if (payload == NULL) {
182 pktz->unpack_prev_lost = PJ_TRUE;
183 return PJ_SUCCESS;
184 }
185
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;
190 return PJ_EINVAL;
191 }
192
Nanang Izzuddin2636c142011-04-01 07:12:59 +0000193 /* Reset last sync point for every new picture bitstream */
Nanang Izzuddin81c78af2011-04-01 07:21:44 +0000194 if (*pos == 0)
Nanang Izzuddin2636c142011-04-01 07:12:59 +0000195 pktz->unpack_last_sync_pos = 0;
196
Nanang Izzuddind91af572011-03-31 17:29:54 +0000197 /* Get payload header info */
198 P = *p & 0x04;
199 V = *p & 0x02;
200 PLEN = ((*p & 0x01) << 5) + ((*(p+1) & 0xF8)>>3);
201
202 /* Get start bitstream pointer */
203 p += 2; /* Skip payload header */
204 if (V)
205 p += 1; /* Skip VRC data */
206 if (PLEN)
207 p += PLEN; /* Skip extra picture header data */
208
209 /* Get bitstream length */
210 if (payload_len > (pj_size_t)(p - payload)) {
211 payload_len -= (p - payload);
212 } else {
213 /* Invalid bitstream, discard this payload */
214 pktz->unpack_prev_lost = PJ_TRUE;
215 return PJ_EINVAL;
216 }
217
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;
223 return PJ_ETOOSMALL;
224 }
225
226 /* Start writing bitstream */
227
228 /* No sync point flag */
229 if (!P) {
230 if (*pos == 0) {
231 /* Previous packet must be lost */
232 pktz->unpack_prev_lost = PJ_TRUE;
233
234 /* If there is extra picture header, let's use it. */
235 if (PLEN) {
236 /* Write two zero octets for PSC */
237 *q++ = 0;
238 *q++ = 0;
239 /* Copy the picture header */
240 p -= PLEN;
241 pj_memcpy(q, p, PLEN);
242 p += PLEN;
243 q += PLEN;
244 }
245 } else if (pktz->unpack_prev_lost) {
246 /* If prev packet was lost, revert the bitstream pointer to
247 * the last sync point.
248 */
249 pj_assert(pktz->unpack_last_sync_pos <= *pos);
250 q = bits + pktz->unpack_last_sync_pos;
251 }
252
253 /* There was packet lost, see if this payload contain sync point
254 * (usable data).
255 */
256 if (pktz->unpack_prev_lost) {
257 pj_uint8_t *sync;
258 sync = find_sync_point((pj_uint8_t*)p, payload_len);
259 if (sync) {
260 /* Got sync point, update P/sync-point flag */
261 P = 1;
262 /* Skip the two zero octets */
263 sync += 2;
264 /* Update payload length and start bitstream pointer */
265 payload_len -= (sync - p);
266 p = sync;
267 } else {
268 /* No sync point in it, just discard this payload */
269 return PJ_EIGNORED;
270 }
271 }
272 }
273
274 /* Write two zero octets when payload flagged with sync point */
275 if (P) {
276 pktz->unpack_last_sync_pos = q - bits;
277 *q++ = 0;
278 *q++ = 0;
279 }
280
281 /* Write the payload to the bitstream */
282 pj_memcpy(q, p, payload_len);
283 q += payload_len;
284
285 /* Update the bitstream writing offset */
286 *pos = q - bits;
287
288 pktz->unpack_prev_lost = PJ_FALSE;
289
290 return PJ_SUCCESS;
291}
Nanang Izzuddin63b3c132011-07-19 11:11:07 +0000292
293
294#endif /* PJMEDIA_HAS_VIDEO */