Re #1219:
- Initial version of H264 implementation (codec & packetization).
- Added vid_codec_util.h/c for video codec utilities (e.g: fmtp parser).
- Updated video RTP packetizations to be configurable and have internal state (to be more resilient to packet lost, etc).
- Fixed wrong SPF calculation in PJMEDIA_SPF2.
- Updated vid_codec_test.c to also have RTP packetization test.
- Updated sdp_neg.c to verify H.264 capability match.
git-svn-id: https://svn.pjsip.org/repos/pjproject/branches/projects/2.0-dev@3493 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjmedia/include/pjmedia-codec/h263_packetizer.h b/pjmedia/include/pjmedia-codec/h263_packetizer.h
index 930115a..b80faf8 100644
--- a/pjmedia/include/pjmedia-codec/h263_packetizer.h
+++ b/pjmedia/include/pjmedia-codec/h263_packetizer.h
@@ -22,121 +22,122 @@
/**
* @file h263_packetizer.h
- * @brief Packetizes H.263 bitstream into RTP payload.
+ * @brief Packetizes/unpacketizes H.263 bitstream into RTP payload.
*/
-#include <pj/errno.h>
+#include <pj/pool.h>
+#include <pj/types.h>
PJ_BEGIN_DECL
-/**
- * Find synchronization point (PSC, slice, GSBC, EOS, EOSBS) in H.263
- * bitstream, in reversed manner.
- */
-PJ_INLINE(pj_uint8_t*) pjmedia_h263_find_sync_point_rev(pj_uint8_t *data,
- pj_size_t data_len)
-{
- pj_uint8_t *p = data+data_len-1;
-
- while (p > data && *p && *(p+1))
- --p;
-
- if (p == data)
- return (data + data_len);
-
- return p;
-}
/**
- * Generate an RTP payload from H.263 frame bitstream, in-place processing.
+ * Opaque declaration for H.263 packetizer.
*/
-PJ_INLINE(pj_status_t) pjmedia_h263_packetize(pj_uint8_t *buf,
- pj_size_t buf_len,
- unsigned *pos,
- int max_payload_len,
- const pj_uint8_t **payload,
- pj_size_t *payload_len)
+typedef struct pjmedia_h263_packetizer pjmedia_h263_packetizer;
+
+
+/**
+ * Enumeration of H.263 packetization modes.
+ */
+typedef enum
{
- pj_uint8_t *p, *p_end;
-
- p = buf + *pos;
- p_end = buf + buf_len;
-
- /* Put two octets payload header */
- if ((p_end-p > 2) && *p==0 && *(p+1)==0) {
- /* The bitstream starts with synchronization point, just override
- * the two zero octets (sync point mark) for payload header.
- */
- *p = 0x04;
- } else {
- /* Not started in synchronization point, we will use two octets
- * preceeding the bitstream for payload header!
- */
-
- if (*pos < 2) {
- /* Invalid H263 bitstream, it's not started with PSC */
- return PJ_EINVAL;
- }
-
- p -= 2;
- *p = 0;
- }
- *(p+1) = 0;
-
- /* When bitstream truncation needed because of payload length/MTU
- * limitation, try to use sync point for the payload boundary.
+ /**
+ * H.263 RTP packetization using RFC 4629.
*/
- if (p_end-p > max_payload_len) {
- p_end = pjmedia_h263_find_sync_point_rev(p+2, max_payload_len-2);
- }
+ PJMEDIA_H263_PACKETIZER_MODE_RFC4629,
- *payload = p;
- *payload_len = p_end-p;
- *pos = p_end - buf;
+ /**
+ * H.263 RTP packetization using legacy RFC 2190.
+ * This is currently not supported.
+ */
+ PJMEDIA_H263_PACKETIZER_MODE_RFC2190,
- return PJ_SUCCESS;
-}
+} pjmedia_h263_packetizer_mode;
+
/**
- * Append RTP payload to a H.263 picture bitstream.
+ * H.263 packetizer configuration.
*/
-PJ_INLINE(pj_status_t) pjmedia_h263_unpacketize(const pj_uint8_t *payload,
- pj_size_t payload_len,
- pj_uint8_t *bits,
- pj_size_t *bits_len)
+typedef struct pjmedia_h263_packetizer_cfg
{
- pj_uint8_t P, V, PLEN;
- const pj_uint8_t *p=payload;
- pj_size_t max_len = *bits_len;
+ /**
+ * Maximum payload length.
+ * Default: PJMEDIA_MAX_MTU
+ */
+ int mtu;
- P = *p & 0x04;
- V = *p & 0x02;
- PLEN = ((*p & 0x01) << 5) + ((*(p+1) & 0xF8)>>3);
+ /**
+ * Packetization mode.
+ * Default: PJMEDIA_H263_PACKETIZER_MODE_RFC4629
+ */
+ pjmedia_h263_packetizer_mode mode;
- /* Get bitstream pointer */
- p += 2;
- if (V)
- p += 1; /* Skip VRC data */
- if (PLEN)
- p += PLEN; /* Skip extra picture header data */
+} pjmedia_h263_packetizer_cfg;
- /* Get bitstream length */
- payload_len -= (p-payload);
- *bits_len = payload_len + (P?2:0);
- PJ_ASSERT_RETURN(max_len >= *bits_len, PJ_ETOOSMALL);
+/**
+ * Create H.263 packetizer.
+ *
+ * @param pool The memory pool.
+ * @param cfg Packetizer settings, if NULL, default setting
+ * will be used.
+ * @param p_pktz Pointer to receive the packetizer.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_h263_packetizer_create(
+ pj_pool_t *pool,
+ const pjmedia_h263_packetizer_cfg *cfg,
+ pjmedia_h263_packetizer **p_pktz);
- /* Add two zero octets when payload flagged with sync point */
- if (P) {
- *bits++ = 0;
- *bits++ = 0;
- }
- /* Add the bitstream */
- pj_memcpy(bits, p, payload_len);
+/**
+ * Generate an RTP payload from a H.263 picture bitstream. Note that this
+ * function will apply in-place processing, so the bitstream may be modified
+ * during the packetization.
+ *
+ * @param pktz The packetizer.
+ * @param bits The picture bitstream to be packetized.
+ * @param bits_len The length of the bitstream.
+ * @param bits_pos The bitstream offset to be packetized.
+ * @param payload The output payload.
+ * @param payload_len The output payload length.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_h263_packetize(pjmedia_h263_packetizer *pktz,
+ pj_uint8_t *bits,
+ pj_size_t bits_len,
+ unsigned *bits_pos,
+ const pj_uint8_t **payload,
+ pj_size_t *payload_len);
- return PJ_SUCCESS;
-}
+
+/**
+ * Append an RTP payload to an H.263 picture bitstream. Note that in case of
+ * noticing packet lost, application should keep calling this function with
+ * payload pointer set to NULL, as the packetizer need to update its internal
+ * state.
+ *
+ * @param pktz The packetizer.
+ * @param payload The payload to be unpacketized.
+ * @param payload_len The payload length.
+ * @param bits The bitstream buffer.
+ * @param bits_size The bitstream buffer size.
+ * @param bits_pos The bitstream offset to put the unpacketized payload
+ * in the bitstream, upon return, this will be updated
+ * to the latest offset as a result of the unpacketized
+ * payload.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_h263_unpacketize(pjmedia_h263_packetizer *pktz,
+ const pj_uint8_t *payload,
+ pj_size_t payload_len,
+ pj_uint8_t *bits,
+ pj_size_t bits_size,
+ unsigned *bits_pos);
PJ_END_DECL
diff --git a/pjmedia/include/pjmedia-codec/h264_packetizer.h b/pjmedia/include/pjmedia-codec/h264_packetizer.h
new file mode 100644
index 0000000..a676a04
--- /dev/null
+++ b/pjmedia/include/pjmedia-codec/h264_packetizer.h
@@ -0,0 +1,157 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2011 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __PJMEDIA_H264_PACKETIZER_H__
+#define __PJMEDIA_H264_PACKETIZER_H__
+
+/**
+ * @file h264_packetizer.h
+ * @brief Packetizes H.264 bitstream into RTP payload and vice versa.
+ */
+
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * Opaque declaration for H.264 packetizer.
+ */
+typedef struct pjmedia_h264_packetizer pjmedia_h264_packetizer;
+
+
+/**
+ * Enumeration of H.264 packetization modes.
+ */
+typedef enum
+{
+ /**
+ * Single NAL unit packetization mode will only generate payloads
+ * containing a complete single NAL unit packet. As H.264 NAL unit
+ * size can be very large, this mode is usually not applicable for
+ * network environments with MTU size limitation.
+ */
+ PJMEDIA_H264_PACKETIZER_MODE_SINGLE_NAL,
+
+ /**
+ * Non-interleaved packetization mode will generate payloads with the
+ * following possible formats:
+ * - single NAL unit packets,
+ * - NAL units aggregation STAP-A packets,
+ * - fragmented NAL unit FU-A packets.
+ */
+ PJMEDIA_H264_PACKETIZER_MODE_NON_INTERLEAVED,
+
+ /**
+ * Interleaved packetization mode will generate payloads with the
+ * following possible formats:
+ * - single NAL unit packets,
+ * - NAL units aggregation STAP-A & STAP-B packets,
+ * - fragmented NAL unit FU-A & FU-B packets.
+ * This packetization mode is currently unsupported.
+ */
+ PJMEDIA_H264_PACKETIZER_MODE_INTERLEAVED,
+} pjmedia_h264_packetizer_mode;
+
+
+/**
+ * H.264 packetizer setting.
+ */
+typedef struct pjmedia_h264_packetizer_cfg
+{
+ /**
+ * Maximum payload length.
+ * Default: PJMEDIA_MAX_MTU
+ */
+ int mtu;
+
+ /**
+ * Packetization mode.
+ * Default: PJMEDIA_H264_PACKETIZER_MODE_NON_INTERLEAVED
+ */
+ pjmedia_h264_packetizer_mode mode;
+}
+pjmedia_h264_packetizer_cfg;
+
+
+/**
+ * Create H.264 packetizer.
+ *
+ * @param pool The memory pool.
+ * @param cfg Packetizer settings, if NULL, default setting
+ * will be used.
+ * @param p_pktz Pointer to receive the packetizer.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_h264_packetizer_create(
+ pj_pool_t *pool,
+ const pjmedia_h264_packetizer_cfg *cfg,
+ pjmedia_h264_packetizer **p_pktz);
+
+
+/**
+ * Generate an RTP payload from a H.264 picture bitstream. Note that this
+ * function will apply in-place processing, so the bitstream may be modified
+ * during the packetization.
+ *
+ * @param pktz The packetizer.
+ * @param bits The picture bitstream to be packetized.
+ * @param bits_len The length of the bitstream.
+ * @param bits_pos The bitstream offset to be packetized.
+ * @param payload The output payload.
+ * @param payload_len The output payload length.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_h264_packetize(pjmedia_h264_packetizer *pktz,
+ pj_uint8_t *bits,
+ pj_size_t bits_len,
+ unsigned *bits_pos,
+ const pj_uint8_t **payload,
+ pj_size_t *payload_len);
+
+
+/**
+ * Append an RTP payload to an H.264 picture bitstream. Note that in case of
+ * noticing packet lost, application should keep calling this function with
+ * payload pointer set to NULL, as the packetizer need to update its internal
+ * state.
+ *
+ * @param pktz The packetizer.
+ * @param payload The payload to be unpacketized.
+ * @param payload_len The payload length.
+ * @param bits The bitstream buffer.
+ * @param bits_size The bitstream buffer size.
+ * @param bits_pos The bitstream offset to put the unpacketized payload
+ * in the bitstream, upon return, this will be updated
+ * to the latest offset as a result of the unpacketized
+ * payload.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_h264_unpacketize(pjmedia_h264_packetizer *pktz,
+ const pj_uint8_t *payload,
+ pj_size_t payload_len,
+ pj_uint8_t *bits,
+ pj_size_t bits_len,
+ unsigned *bits_pos);
+
+
+PJ_END_DECL
+
+#endif /* __PJMEDIA_H264_PACKETIZER_H__ */
diff --git a/pjmedia/include/pjmedia/format.h b/pjmedia/include/pjmedia/format.h
index ae31f98..5fcf8f3 100644
--- a/pjmedia/include/pjmedia/format.h
+++ b/pjmedia/include/pjmedia/format.h
@@ -457,12 +457,12 @@
unsigned channel_count)
{
#if PJ_HAS_INT64
- return ((unsigned)((pj_uint64_t)clock_rate * fr->num \
- / fr->denum / channel_count));
+ return ((unsigned)((pj_uint64_t)clock_rate * fr->denum \
+ / fr->num / channel_count));
#elif PJ_HAS_FLOATING_POINT
- return ((unsigned)(1.0 * clock_rate * fr->num /fr->denum /channel_count));
+ return ((unsigned)(1.0* clock_rate * fr->denum / fr->num /channel_count));
#else
- return ((unsigned)(1L * clock_rate * fr->num / fr->denum / channel_count));
+ return ((unsigned)(1L * clock_rate * fr->denum / fr->num / channel_count));
#endif
}
diff --git a/pjmedia/include/pjmedia/vid_codec.h b/pjmedia/include/pjmedia/vid_codec.h
index 55d6abb..f36727b 100644
--- a/pjmedia/include/pjmedia/vid_codec.h
+++ b/pjmedia/include/pjmedia/vid_codec.h
@@ -223,7 +223,9 @@
* picture boundary detection by itself, e.g: for RTP delivery, payloads
* belong to the same picture will share the same RTP timestamp and also
* there is marker bit in the RTP header that is usually reserved for
- * end-of-picture flag.
+ * end-of-picture flag. Also note that in case of noticing packet lost,
+ * application should keep calling this function with payload pointer
+ * set to NULL, as the packetizer need to update its internal state.
*
* @param codec The codec instance
* @param pkt The input packet.
@@ -241,7 +243,8 @@
const pj_uint8_t *payload,
pj_size_t payload_len,
pj_uint8_t *bits,
- pj_size_t *bits_len);
+ pj_size_t bits_len,
+ unsigned *bits_pos);
/**
* Instruct the codec to encode the specified input frame. The input
diff --git a/pjmedia/include/pjmedia/vid_codec_util.h b/pjmedia/include/pjmedia/vid_codec_util.h
new file mode 100644
index 0000000..64271d1
--- /dev/null
+++ b/pjmedia/include/pjmedia/vid_codec_util.h
@@ -0,0 +1,120 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
+ * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __PJMEDIA_VID_CODEC_UTIL_H__
+#define __PJMEDIA_VID_CODEC_UTIL_H__
+
+
+/**
+ * @file vid_codec_util.h
+ * @brief Video codec utilities.
+ */
+
+#include <pjmedia/vid_codec.h>
+
+
+PJ_BEGIN_DECL
+
+
+/**
+ * Definition of H.263 parameters.
+ */
+typedef struct pjmedia_vid_codec_h263_fmtp
+{
+ unsigned mpi_cnt; /**< # of parsed MPI param */
+ struct mpi {
+ pjmedia_rect_size size; /**< Picture size/resolution */
+ unsigned val; /**< MPI value */
+ } mpi[8]; /**< Minimum Picture Interval parameter */
+
+} pjmedia_vid_codec_h263_fmtp;
+
+
+/**
+ * Parse SDP fmtp of H.263.
+ *
+ * @param fmtp The H.263 SDP fmtp to be parsed.
+ * @param h263_fmtp The parsing result.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_vid_codec_h263_parse_fmtp(
+ const pjmedia_codec_fmtp *fmtp,
+ pjmedia_vid_codec_h263_fmtp *h263_fmtp);
+
+
+/**
+ * Parse, negotiate, and apply the encoding and decoding SDP fmtp of H.263
+ * in the specified codec parameter.
+ *
+ * @param param The codec parameter.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_vid_codec_h263_apply_fmtp(
+ pjmedia_vid_codec_param *param);
+
+
+/**
+ * Definition of H.264 parameters.
+ */
+typedef struct pjmedia_vid_codec_h264_fmtp
+{
+ /* profile-level-id */
+ pj_uint8_t profile_idc; /**< Profile ID */
+ pj_uint8_t profile_iop; /**< Profile constraints bits */
+ pj_uint8_t level; /**< Level */
+
+ /* packetization-mode */
+ pj_uint8_t packetization_mode; /**< Packetization mode */
+
+ /* max-mbps, max-fs, max-cpb, max-dpb, and max-br */
+ unsigned max_mbps; /**< Max macroblock processing rate */
+ unsigned max_fs; /**< Max frame size (in macroblocks) */
+ unsigned max_cpb; /**< Max coded picture buffer size */
+ unsigned max_dpb; /**< Max decoded picture buffer size */
+ unsigned max_br; /**< Max video bit rate */
+
+ /* sprop-parameter-sets, in NAL units */
+ pj_size_t sprop_param_sets_len; /**< Parameter set length */
+ pj_uint8_t sprop_param_sets[256]; /**< Parameter set (SPS & PPS),
+ in NAL unit bitstream */
+
+} pjmedia_vid_codec_h264_fmtp;
+
+
+/**
+ * Parse SDP fmtp of H.264.
+ *
+ * @param fmtp The H.264 SDP fmtp to be parsed.
+ * @param h264_fmtp The parsing result.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_vid_codec_parse_h264_fmtp(
+ const pjmedia_codec_fmtp *fmtp,
+ pjmedia_vid_codec_h264_fmtp *h264_fmtp);
+
+
+
+
+PJ_END_DECL
+
+
+#endif /* __PJMEDIA_VID_CODEC_UTIL_H__ */