[asterisk-commits] oej: branch oej/videocaps r101343 - in /team/oej/videocaps: channels/ include...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Jan 30 15:27:30 CST 2008
Author: oej
Date: Wed Jan 30 15:27:30 2008
New Revision: 101343
URL: http://svn.digium.com/view/asterisk?view=rev&rev=101343
Log:
Adding MPEG4 and H264 plus to videocaps
code from neutrino88 - thanks!!!
(closes issue #11881)
Reported by: neutrino88
Patches:
capability.c uploaded by neutrino88 (license 297)
capability.h uploaded by neutrino88 (license 297)
chan_sip.c uploaded by neutrino88 (license 297)
channel.h uploaded by neutrino88 (license 297)
channel.c uploaded by neutrino88 (license 297)
Modified:
team/oej/videocaps/channels/chan_sip.c
team/oej/videocaps/include/asterisk/capability.h
team/oej/videocaps/include/asterisk/channel.h
team/oej/videocaps/main/Makefile
team/oej/videocaps/main/capability.c
team/oej/videocaps/main/channel.c
Modified: team/oej/videocaps/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/oej/videocaps/channels/chan_sip.c?view=diff&rev=101343&r1=101342&r2=101343
==============================================================================
--- team/oej/videocaps/channels/chan_sip.c (original)
+++ team/oej/videocaps/channels/chan_sip.c Wed Jan 30 15:27:30 2008
@@ -1715,6 +1715,7 @@
static int sip_senddigit_begin(struct ast_channel *ast, char digit);
static int sip_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
static const char *sip_get_callid(struct ast_channel *chan);
+static int sip_get_negotiated_caps(struct ast_channel *ast, struct ast_capabilities *jcaps);
static int handle_request_do(struct sip_request *req, struct sockaddr_in *sin);
static int sip_standard_port(struct sip_socket s);
@@ -1791,6 +1792,7 @@
static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action);
static void ast_build_h2613_fmtp(struct ast_str **buf, int rtp_code, struct ast_h2613_video_cap *video_cap);
static void ast_build_h264_fmtp(struct ast_str **buf, int rtp_code, struct ast_h264_video_cap *video_cap);
+static void ast_build_mp4v_fmtp(struct ast_str **buf, int rtp_code, struct ast_h264_video_cap *video_cap);
static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate,
struct ast_str **m_buf, struct ast_str **a_buf,
int debug, int *min_packet_size);
@@ -2079,6 +2081,7 @@
.early_bridge = ast_rtp_early_bridge,
.send_text = sip_sendtext, /* called with chan locked */
.set_capabilities = sip_set_capabilities,
+ .get_negotiated_caps = sip_get_negotiated_caps,
.func_channel_read = acf_channel_read,
.get_pvt_uniqueid = sip_get_callid,
};
@@ -4867,7 +4870,15 @@
return res;
}
-/*! \brief sip_set_capabilities: called when channel needs to have caps updated from another channel
+/*! \brief Get prefered codecs to send back to the calling party */
+static int sip_get_negotiated_caps(struct ast_channel *ast, struct ast_capabilities *jcaps)
+{
+ int dst = jcaps->cap = ast->nativeformats;
+
+ return dst;
+}
+
+/*! \brief Called when channel needs to have caps updated from another channel
When * is making an outgoing call, the confcaps will be set (sip_new has already been called) but
jointcaps and peer caps will be zero
On the REVERSE cap exchange we'll need to do a MIN(joint, chancap);
@@ -6824,7 +6835,16 @@
break;
case '3' :
/* ast_verbose("Found a H.263 media type\n");*/
- p->peercaps.h263.valid = 1;
+ if (mimeSubtype[4]) {
+ if (!strcasecmp(mimeSubtype, "H263-1998")){
+ p->peercaps.h263p.valid = 1;
+ } else {
+ ast_verbose("Found unsupported media type\n");
+ }
+ } else {
+ p->peercaps.h263.valid = 1;
+ }
+ break;
break;
case '4' :
/* ast_verbose("Found a H.264 media type\n"); */
@@ -6836,7 +6856,14 @@
break;
}
}
- } else if (!strncasecmp(mimeSubtype, "T140",4)) { /* Text */
+ } else if (!strncasecmp(mimeSubtype, "MP4V", 4)) {
+ if (p->vrtp) {
+ ast_verbose("----- Adding video (%d) mimeSubtype (%s) to videortp struct\n", codec, mimeSubtype);
+ ast_rtp_set_rtpmap_type(newvideortp, codec, "video", mimeSubtype, 0);
+ p->peercaps.mp4v.valid = 1;
+ p->peercaps.mp4v.rtpnum = codec;
+ }
+ } else if (!strncasecmp(mimeSubtype, "T140", 4)) { /* Text */
if (p->trtp) {
/* ast_verbose("Adding t140 mimeSubtype to textrtp struct\n"); */
ast_rtp_set_rtpmap_type(newtextrtp, codec, "text", mimeSubtype, 0);
@@ -6881,6 +6908,14 @@
case AST_FORMAT_H264:
a += len;
process_h264_fmtp(a, &p->peercaps.h264, framerate);
+ break;
+ case AST_FORMAT_H263_PLUS:
+ a += len;
+ parse_h2613_conf_line(a, &p->peercaps.h263p, framerate);
+ break;
+ case AST_FORMAT_MP4_VIDEO:
+ a += len;
+ parse_mp4v_conf_line(a, &p->peercaps.mp4v, framerate);
break;
default:
if (option_debug > 1) {
@@ -7932,24 +7967,58 @@
return 0;
}
-/*! \brief Build fmtp headers for H261, H263 video */
+/*! \brief Build fmtp headers for H261, H263, H263+ video */
static void ast_build_h2613_fmtp(struct ast_str **buf, int rtp_code, struct ast_h2613_video_cap *video_cap)
{
- int i;
-
- if(video_cap->valid) {
- ast_str_append(buf, 0, "a=fmtp:%d ",rtp_code);
- for (i = 0; i < MAX_VIDEO_SIZES; i++) {
- if (video_cap->maxfr[i] > 0)
- ast_str_append(buf, 0, "%s=%d ", videoSizes[i].type, 30/video_cap->maxfr[i]);
- }
- if (video_cap->maxbr > 0)
- ast_str_append(buf, 0, "maxbr=%d",video_cap->maxbr/100);
+ int i;
+ char tab[30]="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ unsigned char comp=0xFF;
+ int mask=1;
+ int init=1;
+
+ if (!video_cap->valid) {
+ ast_debug(1, "WARNING Video cap is not valid but have been asked to add fmtp\n");
+ ast_str_append(buf, 0, "a=fmtp:%d;CIF=1;QCIF=1;maxbr=3840\r\n", rtp_code);
+ return;
+ }
+ for (i = 0; i < MAX_VIDEO_SIZES; i++) {
+ if (video_cap->maxfr[i] > 0) {
+ if (init)
+ ast_str_append(buf, 0, "a=fmtp:%d ", rtp_code);
+ ast_str_append(buf, 0, "%s%s=%d", init ? "" : ";" ,videoSizes[i].type, 30/video_cap->maxfr[i]);
+ init=0;
+ }
+ }
+ if (video_cap->maxbr > 0) {
+ if (init)
+ ast_str_append(buf, 0, "a=fmtp:%d ",rtp_code);
+ ast_str_append(buf, 0, "%smaxbr=%d", init ? "" : ";" , video_cap->maxbr/100);
+ init=0;
+ }
+ if (video_cap->annexes){ /* h263+ */
+ if (init)
+ ast_str_append(buf, 0, "a=fmtp:%d ",rtp_code);
+ for (i=0; i<26; i++) {
+ if (mask&video_cap->annexes) {
+ ast_str_append(buf, 0, "%s%c=%d", init ? "" : ";" ,tab[i], tab[i] == 'N' ? 4:1);
+ init=0;
+ }
+ mask=mask<<1;
+ }
+ }
+ if (video_cap->profile != comp) { /* h263+ */
+ if (init)
+ ast_str_append(buf, 0, "a=fmtp:%d ",rtp_code);
+ ast_str_append(buf, 0, "%sprofile=%x; ", init ? "" : ";" , video_cap->profile);
+ init=0;
+ }
+ if (video_cap->level != comp) { /*h263+ */
+ if (init)
+ ast_str_append(buf, 0, "a=fmtp:%d ",rtp_code);
+ ast_str_append(buf, 0, "level=%02x",video_cap->level);
+ }
+ if (!init)
ast_str_append(buf, 0, "\r\n");
- } else {
- ast_verbose("WARNING Video cap is not valid but have been asked to add fmtp\n");
- ast_str_append(buf, 0, "a=fmtp:%d;CIF=1;QCIF=1;maxbr=3840\r\n", rtp_code);
- }
}
/*! \brief Build fmtp headers for H264 video */
@@ -7957,16 +8026,41 @@
{
/* ast_build_string(a_buf, a_size, "a=fmtp:%d profile-level-id=42800C; packetization-mode=0; max-br=384; max-mbps=10000\r\n", rtp_code); */
- if(video_cap->valid) {
- ast_str_append(buf, 0, "a=fmtp:%d ", rtp_code);
- ast_str_append(buf, 0, "profile-level-id=42800C; packetization-mode=0; ");
- if (video_cap->maxmbps > 0)
- ast_str_append(buf, 0, "max-mbps=%d; ",video_cap->maxmbps);
- if (video_cap->maxbr > 0)
- ast_str_append(buf, 0, "max-br=%d",video_cap->maxbr/1000);
- ast_str_append(buf, 0, "\r\n");
- }
-}
+ if(!video_cap->valid) {
+ ast_debug(1, "WARNING Video cap is not valid but have been asked to add fmtp\n");
+ ast_str_append(buf, 0, "a=fmtp:%d profile-level-id=420033; packetization-mode=0\r\n", rtp_code);
+ return;
+ }
+ ast_str_append(buf, 0, "a=fmtp:%d ", rtp_code);
+ ast_str_append(buf, 0, "profile-level-id=42800C; packetization-mode=0; ");
+ if (video_cap->maxmbps > 0)
+ ast_str_append(buf, 0, "max-mbps=%d; ", video_cap->maxmbps);
+ if (video_cap->maxbr > 0)
+ ast_str_append(buf, 0, "max-br=%d", video_cap->maxbr/1000);
+ ast_str_append(buf, 0, "\r\n");
+}
+
+/*! \brief Build fmtp headers for MPEG4 video */
+static void ast_build_mp4v_fmtp(struct ast_str **buf, int rtp_code, struct ast_h264_video_cap *video_cap)
+{
+
+ int profile_level = 0;
+
+ if (!video_cap->valid) {
+ ast_debug(1, "WARNING Video cap is not valid but have been asked to add fmtp\n");
+ ast_str_append(buf, 0, "a=fmtp:%d profile-level-id=1\r\n", rtp_code);
+ return;
+ }
+ ast_str_append(buf, 0, "a=fmtp:%d ", rtp_code);
+ profile_level = video_cap->profile<<4 | video_cap->level;
+ ast_str_append(buf, 0, "profil-level-id=%d",profile_level);
+ if (video_cap->maxmbps > 0)
+ ast_str_append(buf, 0, "max-mbps=%d; ", video_cap->maxmbps);
+ if (video_cap->maxbr > 0)
+ ast_str_append(buf, 0, "max-br=%d", video_cap->maxbr/1000);
+ ast_str_append(buf, 0, "\r\n");
+}
+
/*! \brief Add codec offer to SDP offer/answer body in INVITE or 200 OK */
static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate,
@@ -8042,6 +8136,14 @@
ast_verbose("Adding h264 fmtp with rtpnum %d\n", p->jointcaps.h264.rtpnum);
}
ast_build_h264_fmtp(a_buf, rtp_code, (struct ast_h264_video_cap*)&p->jointcaps.h264);
+ } else if (codec == AST_FORMAT_MP4_VIDEO) {
+ if (sipdebug_caps)
+ ast_verbose("Adding MP4v fmtp with rtpnum %d\n",p->jointcaps.mp4v.rtpnum);
+ ast_build_mp4v_fmtp(a_buf, rtp_code, (struct ast_h264_video_cap*)&p->jointcaps.mp4v);
+ } else if (codec == AST_FORMAT_H263_PLUS) {
+ if (sipdebug_caps)
+ ast_verbose("Adding H263+ fmtp with rtpnum %d\n",p->jointcaps.mp4v.rtpnum);
+ ast_build_h2613_fmtp(a_buf, rtp_code, (struct ast_h2613_video_cap*)&p->jointcaps.h263p);
}
/*! /todo Room for MPEG4 */
Modified: team/oej/videocaps/include/asterisk/capability.h
URL: http://svn.digium.com/view/asterisk/team/oej/videocaps/include/asterisk/capability.h?view=diff&rev=101343&r1=101342&r2=101343
==============================================================================
--- team/oej/videocaps/include/asterisk/capability.h (original)
+++ team/oej/videocaps/include/asterisk/capability.h Wed Jan 30 15:27:30 2008
@@ -45,15 +45,20 @@
* In this file, we specify attributes structures to handle a range of video
* codecs
*
- * - H.261
+ * - \b H.261
* - only handled in passthrough mode in Asterisk, no codec module
* - \ref format_h261.c
- * - H.263
+ * - \b H.263
* - only handled in passthrough mode in Asterisk, no codec module
* - \ref format_h263.c
- * - H.264
+ * - \b H.264
* - only handled in passthrough mode in Asterisk, no codec module
* - \ref format_h264.c
+ * - \b H.263+
+ * - only handled in passthrough mode in Asterisk, no codec module
+ *
+ * - \b MPGE4
+ * - only handled in passthrough mode in Asterisk, no codec module
*
* In protocols that use SDP, the Session Description Protocol, we negotiate
* these attributes according to the SDP offer/answer model.
@@ -105,24 +110,52 @@
/*! The h.264 profile level is the profile (eg 1.1 x 10) */
typedef enum
{
- level_1 = 10, /* 0x0A */
- level_1_1 = 11, /* 0x0B */
- level_1_2 = 12, /* 0x0C */
- level_1_3 = 13, /* 0x0D */
- level_2 = 20, /* 0x14 */
- level_2_1 = 21, /* 0x15 */
- level_2_2 = 22, /* 0x16 */
- level_3 = 30, /* 0x1E */
- level_3_1 = 31, /* 0x1F */
- level_3_2 = 32, /* 0x20 */
- level_4 = 40, /* 0x28 */
- level_4_1 = 41, /* 0x29 */
- level_4_2 = 42, /* 0x2A */
- level_5 = 50, /* 0x32 */
- level_5_1 = 51, /* 0x33 */
+ level_1 = 10, /*!< 0x0A */
+ level_1_1 = 11, /*!< 0x0B */
+ level_1_2 = 12, /*!< 0x0C */
+ level_1_3 = 13, /*!< 0x0D */
+ level_2 = 20, /*!< 0x14 */
+ level_2_1 = 21, /*!< 0x15 */
+ level_2_2 = 22, /*!< 0x16 */
+ level_3 = 30, /*!< 0x1E */
+ level_3_1 = 31, /*!< 0x1F */
+ level_3_2 = 32, /*!< 0x20 */
+ level_4 = 40, /*!< 0x28 */
+ level_4_1 = 41, /*!< 0x29 */
+ level_4_2 = 42, /*!< 0x2A */
+ level_5 = 50, /*!< 0x32 */
+ level_5_1 = 51, /*!< 0x33 */
} ast_h264_profile_level;
-/*!The following array defines the video sizes we know about */
+/*! \brief MPEG 4 video profile_and_level_indication as in table G-1 ISO 14496-2 */
+typedef enum
+{
+ sp_level_1 = 1, /*!< Simple profile level 1 */
+ sp_level_2 = 2, /*!< Simple profile level 2 */
+ sp_level_3 = 3, /*!< Simple profile level 3 */
+ ssp_level_1 = 0x11, /*!< Simple Scalable profile level 1 */
+ ssp_level_2 = 0x12, /*!< Simple Scalable profile level 2 */
+ cp_level_1 = 0x21, /*!< core profile level 1 */
+ cp_level_2 = 0x22, /*!< core profile level 2 */
+ mp_level_2 = 0x32, /*!< main profile level 2 */
+ mp_level_3 = 0x33, /*!< main profile level 3 */
+ mp_level_4 = 0x34, /*!< main profile level 4 */
+ bnp_level_2 = 0x42, /*!< N-bit profile level 2 */
+ stp_level_1 = 0x51, /*!< scalable texture profile level 1 */
+ sap_level_1 = 0x61, /*!< Simple face animation profile level 1*/
+ sap_level_2 = 0x62, /*!< Simple face animation profile level 2*/
+ fba_level_1 = 0x63, /*!< Simple FBA profile level 1 */
+ fba_level_2 = 0x64, /*!< Simple FBA profile level 2 */
+ batp_level_1 = 0x71, /*!< Basic Animated Texture Profile level 1 */
+ batp_level_2 = 0x72, /*!< Basic Animated Texture Profile level 1 */
+ hp_level_1 = 0x81, /*!< Hybrid profile level 1 */
+ asp_level_1 = 0x91, /*!< Advanced simple profile level 1 */
+ asp_level_2 = 0x92, /*!< Advanced simple profile level 2 */
+ asp_level_3 = 0x93, /*!< Advanced simple profile level 3 */
+ asp_level_4 = 0x94, /*!< Advanced simple profile level 4 */
+} ast_mpeg4v_profile_level;
+
+/*! \brief The following array defines the video sizes we know about */
struct videoSize {
char* type;
unsigned int num_mbs;
@@ -136,6 +169,8 @@
struct ast_h2613_video_cap {
int valid; /*!< 1 = This codec is specified, 0 = not specified */
unsigned int annexes; /*!< Video annexes - stored as bitfield 2^(annex-ascii(A))*/
+ unsigned char profile; /*!< Video flags -- will only be used for h263+ */
+ unsigned char level; /*!< Profile level -- will only be used for h263+ */
unsigned char maxfr[MAX_VIDEO_SIZES]; /*!< Maximum framerate (framerate = 30/mpi) */
unsigned int maxbr; /*!< Maximum supported bitrate for this capability */
};
@@ -160,8 +195,11 @@
unsigned int maxvideobitrate; /*!< Max video bitrate */
struct ast_h2613_video_cap h261; /*!< H261 video capabilities */
struct ast_h2613_video_cap h263; /*!< H263 video capabilities */
+ struct ast_h2613_video_cap h263p; /*!< H263+ video capabilities */
+ struct ast_h264_video_cap mp4v; /*!< MPEG4 video capabilities */
struct ast_h264_video_cap h264; /*!< H264 video capabilities */
unsigned char t140; /*!< T140 text capabilities */
+ unsigned char red; /*!< RED text capabilities */
struct ast_variable *x_settings; /*!< Settings outside of the specification received in SDP */
};
@@ -173,7 +211,6 @@
*/
int ast_set_capabilities(struct ast_channel *chan, struct ast_capabilities *chancaps);
-/*! \brief Allocate capability structure for video */
struct ast_capabilities *ast_alloc_capabilities(void);
void ast_dump_caps(struct ast_capabilities *caps);
@@ -186,6 +223,10 @@
void ast_resolve_h264_video_cap(struct ast_h264_video_cap *dstcap, struct ast_h264_video_cap *s1cap, struct ast_h264_video_cap *s2cap);
+void ast_resolve_h263p_video_cap(struct ast_h2613_video_cap *dstcap, struct ast_h2613_video_cap *s1cap, struct ast_h2613_video_cap *s2cap);
+
+void ast_resolve_mp4v_video_cap(struct ast_h264_video_cap *dstcap, struct ast_h264_video_cap *s1cap, struct ast_h264_video_cap *s2cap);
+
int ast_copy_capabilities(struct ast_capabilities *dstcap, struct ast_capabilities *srccap);
int ast_resolve_capabilities(struct ast_capabilities *dst, struct ast_capabilities *s1caps, struct ast_capabilities *s2caps, int debug);
@@ -196,9 +237,13 @@
int ast_get_int_from_capabilities(struct ast_capabilities *caps);
+int ast_get_negotiated_caps(struct ast_channel *chan, struct ast_capabilities *chancaps);
+
int check_set_video_bitrates(struct ast_capabilities *caps, int debug);
int parse_h2613_conf_line(const char *fmtstr, struct ast_h2613_video_cap *vidcap, unsigned int framerate);
+
+int parse_mp4v_conf_line(const char *fmtstr, struct ast_h264_video_cap *vidcap, int framerate);
int parse_h264_conf_line(const char *fmtstr, struct ast_h264_video_cap *vidcap, int framerate);
Modified: team/oej/videocaps/include/asterisk/channel.h
URL: http://svn.digium.com/view/asterisk/team/oej/videocaps/include/asterisk/channel.h?view=diff&rev=101343&r1=101342&r2=101343
==============================================================================
--- team/oej/videocaps/include/asterisk/channel.h (original)
+++ team/oej/videocaps/include/asterisk/channel.h Wed Jan 30 15:27:30 2008
@@ -337,6 +337,9 @@
/*! \brief Set Channel Capabilities */
int (* const set_capabilities)(struct ast_channel *chan, struct ast_capabilities *chancaps);
+
+ /*! \brief Get Negociated Capabilities */
+ int (* const get_negotiated_caps)(struct ast_channel *chan, struct ast_capabilities *chancaps);
/*! \brief Retrieve base channel (agent and local) */
struct ast_channel* (* get_base_channel)(struct ast_channel *chan);
Modified: team/oej/videocaps/main/Makefile
URL: http://svn.digium.com/view/asterisk/team/oej/videocaps/main/Makefile?view=diff&rev=101343&r1=101342&r2=101343
==============================================================================
--- team/oej/videocaps/main/Makefile (original)
+++ team/oej/videocaps/main/Makefile Wed Jan 30 15:27:30 2008
@@ -30,7 +30,7 @@
cryptostub.o sha1.o http.o fixedjitterbuf.o abstract_jb.o \
strcompat.o threadstorage.o dial.o event.o adsistub.o audiohook.o \
astobj2.o hashtab.o global_datastores.o $(RESAMPLE_OBJS) version.o \
- features.o
+ capability.o features.o
# we need to link in the objects statically, not as a library, because
# otherwise modules will not have them available if none of the static
Modified: team/oej/videocaps/main/capability.c
URL: http://svn.digium.com/view/asterisk/team/oej/videocaps/main/capability.c?view=diff&rev=101343&r1=101342&r2=101343
==============================================================================
--- team/oej/videocaps/main/capability.c (original)
+++ team/oej/videocaps/main/capability.c Wed Jan 30 15:27:30 2008
@@ -49,14 +49,17 @@
struct ast_capabilities ast_default_caps =
{
0,
- {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /* Audio preference order */
DEFAULT_MAX_CALL_BITRATE,
DEFAULT_MAX_CALL_BITRATE,
- {0, 0, {0,0,30,0,0,30,0,0,0,0,0}, DEFAULT_MAX_CALL_BITRATE}, /* H.261 */
- {0, 0, {0,0,30,0,0,30,0,0,0,0,0}, DEFAULT_MAX_CALL_BITRATE}, /* H.263 */
- {0, 0, 0x42, 0x0c, 0x80, 7128, 0, DEFAULT_MAX_CALL_BITRATE}, /* H.264 */
- 0,
- NULL, /* X-variables */
+ {0, 0, 0xFF, 0xFF, {0,0,30,0,0,30,0,0,0,0,0}, DEFAULT_MAX_CALL_BITRATE}, /* H.261 */
+ {0, 0, 0xFF, 0xFF, {0,0,30,0,0,30,0,0,0,0,0}, DEFAULT_MAX_CALL_BITRATE}, /* H.263 */
+ {0, 0, 0xFF, 0xFF, {0,0,30,0,0,30,0,0,0,0,0}, DEFAULT_MAX_CALL_BITRATE}, /* H.263+ */
+ {0, 0, 0xFF, 0xFF, 0x00, 7128, 0, DEFAULT_MAX_CALL_BITRATE}, /* MPEG4 Video */
+ {0, 0, 0xFF, 0xFF, 0x00, 7128, 0, DEFAULT_MAX_CALL_BITRATE}, /* H.264 */
+ 0, /* T140 */
+ 0, /* RED */
+ NULL, /* X-variables */
};
/*! \brief Allocate a capability structure
@@ -79,9 +82,23 @@
return res;
}
+/*! \brief called from channel.c:channel_make_compatible, to retrieve the peer prefered codecs */
+int ast_get_negotiated_caps(struct ast_channel *chan, struct ast_capabilities *chancaps)
+{
+ if (!chan)
+ return -1;
+
+ if (chan->tech->get_negotiated_caps)
+ chan->tech->get_negotiated_caps(chan, chancaps);
+
+ return 0;
+}
+
+
void ast_dump_h2613_video_cap(struct ast_h2613_video_cap *vidcap)
{
int i;
+ unsigned char comp=0xFF;
if (vidcap->valid) {
ast_verbose(" MaxBR: %dkbps\n", vidcap->maxbr/1000);
@@ -90,17 +107,39 @@
ast_verbose(" %-11s %1dfps\n", videoSizes[i].type, vidcap->maxfr[i]);
}
if (vidcap->annexes)
- ast_verbose(" Annexes: 0x%08x\n",vidcap->annexes);
+ ast_verbose(" Annexes: 0x%08x\n", vidcap->annexes);
+ else
+ ast_verbose(" Annexes: -\n");
+
+ /* h263+ : */
+ if (vidcap->profile != comp)
+ ast_verbose(" Profile: %02d\n", vidcap->profile);
+ else
+ ast_verbose(" Profile: -\n");
+ if (vidcap->level != comp)
+ ast_verbose(" Level: %02d\n", vidcap->level);
+ else
+ ast_verbose(" Level: -\n");
+
} else
ast_verbose("\n");
}
void ast_dump_h264_video_cap(struct ast_h264_video_cap *vidcap)
{
+ unsigned char comp=0xFF;
if (vidcap->valid) {
ast_verbose(" RTPnum: %03d\n",vidcap->rtpnum);
- ast_verbose(" Profile: %02x\n",vidcap->profile);
- ast_verbose(" Level: %02x\n",vidcap->level);
+
+ if (vidcap->profile != comp)
+ ast_verbose(" Profile: %02d\n", vidcap->profile);
+ else
+ ast_verbose(" Profile: -\n");
+ if (vidcap->level != comp)
+ ast_verbose(" Level: %02d\n", vidcap->level);
+ else
+ ast_verbose(" Level: -\n");
+
ast_verbose(" Constraint: %02x\n",vidcap->constraint);
ast_verbose(" PMode %d\n", vidcap->packet_mode);
ast_verbose(" MaxBR: %dkbps\n", vidcap->maxbr/1000);
@@ -109,6 +148,7 @@
ast_verbose("\n");
}
+
void ast_dump_caps(struct ast_capabilities *caps)
{
ast_verbose(" Bitrates:\n MaxCall %dkbps\n MaxVideo %dkbps\n", caps->maxcallbitrate/1000,caps->maxvideobitrate/1000);
@@ -120,12 +160,25 @@
ast_verbose(" H263:\n");
ast_dump_h2613_video_cap(&caps->h263);
}
+
+ /* added for h263+ */
+ if (caps->h263p.valid) {
+ ast_verbose(" H263+:\n");
+ ast_dump_h2613_video_cap(&caps->h263p);
+ }
+
+ if (caps->mp4v.valid) {
+ ast_verbose(" MPEG4 Video:\n");
+ ast_dump_h264_video_cap(&caps->mp4v); /* We should have an mp4 dump function */
+ }
if (caps->h264.valid) {
ast_verbose(" H264:\n");
ast_dump_h264_video_cap(&caps->h264);
}
- /* if (caps->t140.valid) */
+ /*
+ if (caps->t140.valid)
ast_verbose(" T140\n");
+ */
ast_verbose("\n");
}
@@ -162,11 +215,50 @@
/* Resolve bitrates */
dstcap->maxbr = MIN(s1cap->maxbr, s2cap->maxbr);
-
-}
-
-/*! \brief Finds the highest common capability between the two source caps and applies it to the destination cap */
-/* Can be called with dst same as one of the src caps */
+}
+
+
+
+
+
+/*! \brief Finds the highest common capability between the two source caps and applies it to the destination cap
+ * * Can be called with dst same as one of the src caps */
+void ast_resolve_h263p_video_cap(struct ast_h2613_video_cap *dstcap, struct ast_h2613_video_cap *s1cap, struct ast_h2613_video_cap *s2cap)
+{
+ int i;
+
+ /*... resolve valids */
+ if (s1cap->valid && s2cap->valid)
+ dstcap->valid = 1;
+ else {
+ dstcap->valid = 0;
+ memset(dstcap->maxfr, 0, sizeof(dstcap->maxfr[0]) * MAX_VIDEO_SIZES);
+ dstcap->maxbr = 0;
+ dstcap->profile = 0;
+ dstcap->level = 0;
+ return;
+ }
+
+ /* Use the lowest frame rate even if zero */
+ for (i = 0; i < MAX_VIDEO_SIZES; i++)
+ dstcap->maxfr[i] = MIN(s1cap->maxfr[i], s2cap->maxfr[i]);
+
+ /* Union of annexes */
+ dstcap->annexes = s1cap->annexes | s2cap->annexes;
+
+ /* Resolve bitrates */
+ dstcap->maxbr = MIN(s1cap->maxbr, s2cap->maxbr);
+
+ /* Added for h263+ */
+ /* Resolve profiles */
+ dstcap->profile = MIN(s1cap->profile, s2cap->profile);
+ /* Resolve levels */
+ dstcap->level = MIN(s1cap->level, s2cap->level);;
+}
+
+
+/*! \brief Finds the highest common capability between the two source caps and applies it to the destination cap
+ Can be called with dst same as one of the src caps */
void ast_resolve_h264_video_cap(struct ast_h264_video_cap *dstcap, struct ast_h264_video_cap *s1cap, struct ast_h264_video_cap *s2cap)
{
/*... resolve valids */
@@ -182,13 +274,13 @@
dstcap->maxmbps = 0;
return;
}
-
+
/* Resolve profiles */
dstcap->profile = MIN(s1cap->profile, s2cap->profile);
/* Resolve levels */
dstcap->level = MIN(s1cap->level, s2cap->level);
/* Resolve constraints */
- dstcap->constraint = MIN(s1cap->constraint, s2cap->constraint);
+ dstcap->constraint = s1cap->constraint | s2cap->constraint;
/* Resolve bitrates */
dstcap->maxbr = MIN(s1cap->maxbr, s2cap->maxbr);
@@ -198,11 +290,33 @@
dstcap->rtpnum = s2cap->rtpnum;
}
-/*! \brief ast_resolve_capabilities: called when we need to have dst = MIN(s1cap, s2cap), or in set theory terms s1cap INTERSECT s2cap (s1 n s2) */
+void ast_resolve_mp4v_video_cap(struct ast_h264_video_cap *dstcap, struct ast_h264_video_cap *s1cap, struct ast_h264_video_cap *s2cap)
+{
+ /*... resolve valids*/
+ if (s1cap->valid && s2cap->valid)
+ dstcap->valid = 1;
+ else {
+ dstcap->valid = 0;
+ dstcap->rtpnum = 0;
+ dstcap->profile = 0;
+ dstcap->constraint = 0;
+ dstcap->level = 0;
+ dstcap->maxbr = 0;
+ dstcap->maxmbps = 0;
+ return;
+ }
+
+ /* Resolve profiles */
+ dstcap->profile = MIN(s1cap->profile, s2cap->profile);
+ /* Resolve levels */
+ dstcap->level = MIN(s1cap->level, s2cap->level);
+}
+
+/*! \brief cClled when we need to have dst = MIN(s1cap, s2cap), or in set theory terms s1cap INTERSECT s2cap (s1 n s2) */
int ast_resolve_capabilities(struct ast_capabilities *dst, struct ast_capabilities *s1caps, struct ast_capabilities *s2caps, int debug)
{
int res = 0;
-
+
if (debug) {
ast_verbose("\nResolve: Input Caps1:\n");
ast_dump_caps(s1caps);
@@ -214,6 +328,8 @@
dst->maxvideobitrate = MIN(s1caps->maxvideobitrate, s2caps->maxvideobitrate);
ast_resolve_h2613_video_cap(&dst->h261, &s1caps->h261, &s2caps->h261);
ast_resolve_h2613_video_cap(&dst->h263, &s1caps->h263, &s2caps->h263);
+ ast_resolve_h263p_video_cap(&dst->h263p, &s1caps->h263p, &s2caps->h263p);
+ ast_resolve_mp4v_video_cap(&dst->mp4v, &s1caps->mp4v, &s2caps->mp4v);
ast_resolve_h264_video_cap(&dst->h264, &s1caps->h264, &s2caps->h264);
if (debug) {
@@ -224,17 +340,19 @@
return res;
}
-/*! \brief ast_set_capabilities_from_int: called when we need to make sure the complex caps are inline with old integer caps */
+/*! \brief called when we need to make sure the complex caps are inline with old integer caps */
int ast_set_capabilities_from_int(struct ast_capabilities *caps, int simplecap)
{
caps->h261.valid = ((simplecap & AST_FORMAT_H261) == AST_FORMAT_H261) ? 1 : 0;
caps->h263.valid = ((simplecap & AST_FORMAT_H263) == AST_FORMAT_H263) ? 1 : 0;
+ caps->h263p.valid = ((simplecap & AST_FORMAT_H263_PLUS) == AST_FORMAT_H263_PLUS) ? 1 : 0;
caps->h264.valid = ((simplecap & AST_FORMAT_H264) == AST_FORMAT_H264) ? 1 : 0;
+ caps->mp4v.valid = ((simplecap & AST_FORMAT_MP4_VIDEO) == AST_FORMAT_MP4_VIDEO) ? 1 : 0;
return 0;
}
-/*! \brief ast_set_capabilities_from_int: called when we need to make sure the complex caps are inline with old integer caps */
+/*! \brief Called when we need to make sure the complex caps are inline with old integer caps */
int ast_get_int_from_capabilities(struct ast_capabilities *caps)
{
int res=0;
@@ -245,8 +363,14 @@
if (caps->h263.valid)
res |= AST_FORMAT_H263;
+ if (caps->h263p.valid)
+ res |= AST_FORMAT_H263_PLUS;
+
if (caps->h264.valid)
res |= AST_FORMAT_H264;
+
+ if (caps->mp4v.valid)
+ res |= AST_FORMAT_MP4_VIDEO;
return 0;
}
@@ -262,7 +386,7 @@
return 0;
}
-/*! \brief Checks all the video bitrates to make sure they conform to the following:
+/* Checks all the video bitrates to make sure they conform to the following:
enforce maxcallbitrate >= maxvideobitrate >= maxbr
This will be called when any bitrates can be set (incoming call, reload etc).
The maxcallbitrate will override everything
@@ -274,12 +398,13 @@
int maxvbr = caps->maxvideobitrate;
int maxh261 = caps->h261.valid ? caps->h261.maxbr : 0;
int maxh263 = caps->h263.valid ? caps->h263.maxbr : 0;
+ int maxh263p = caps->h263p.valid ? caps->h263p.maxbr : 0;
int maxh264 = caps->h264.valid ? caps->h264.maxbr : 0;
int maxmedia = MAX(maxh261, MAX(maxh263, maxh264));
if(debug) {
- ast_verbose ("CHECK SET BITRATES (IN): ct=%d, vbr=%d, h261=%d, h263=%d, h264=%d, maxmedia=%d\n",
- maxctbr, maxvbr, maxh261, maxh263, maxh264, maxmedia);
+ ast_verbose ("CHECK SET BITRATES (IN): ct=%d, vbr=%d, h261=%d, h263=%d, h263p=%d, h264=%d, maxmedia=%d\n",
+ maxctbr, maxvbr, maxh261, maxh263, maxh263p, maxh264, maxmedia);
}
/* Make sure ct and vbr are set to something sensible */
@@ -306,18 +431,23 @@
maxh264 = maxvbr;
if (maxh263 > maxvbr)
maxh263 = maxvbr;
+
+ if (maxh263p > maxvbr)
+ maxh263p = maxvbr;
+
if (maxh261 > maxvbr)
maxh261 = maxvbr;
caps->h264.maxbr = maxh264;
caps->h263.maxbr = maxh263;
+ caps->h263p.maxbr = maxh263p;
caps->h261.maxbr = maxh261;
caps->maxvideobitrate = maxvbr;
caps->maxcallbitrate = maxctbr;
- if(debug) {
+ if(debug) {/*! \note: to check for H263+... */
maxmedia = MAX(maxh261, MAX(maxh263, maxh264));
-
+
ast_verbose ("CHECK SET BITRATES (OUT): ct=%d, vbr=%d, h261=%d, h263=%d, h264=%d, maxmedia=%d\n",
maxctbr, maxvbr, maxh261, maxh263, maxh264, maxmedia);
}
@@ -325,9 +455,7 @@
return 0;
}
-/*! Parse configuration file item for H.261/H.263
- \note syntax is as follows:
- <Free space to fill in a syntax >
+/*! \brief Parse sdp description file file item for H.261/H.263
*/
int parse_h2613_conf_line(const char *fmtstr, struct ast_h2613_video_cap *vidcap, unsigned int framerate)
{
@@ -337,12 +465,25 @@
int i;
unsigned int tmp;
int found=0;
+ int profile = 0;
+ int level = 0;
memset(vidcap, 0, sizeof(struct ast_h2613_video_cap));
+ /* Initialize 'profile' and 'level' as 'Not Defined' */
+ vidcap->profile = 0xFF;
+ vidcap->level = 0xFF;
+
parse = ast_strdupa(fmtstr);
/* Get the fmtp: and payload type out of the way */
for ((loop_str = strsep(&parse, sep)); loop_str; (loop_str = strsep(&parse, sep)) != NULL) {
+
+ /* H263+ related */
+ if (loop_str[0] == '\0') {
+ loop_str++;
+ continue;
+ }
+
if((equals = strchr(loop_str, '='))==NULL)
return -1;
found = 0;
@@ -356,17 +497,36 @@
/* ast_verbose("MaxBR=%d\n", vidcap->maxbr); */
} else
ast_verbose("Failed to parse maxbr in process_h261_h261_fmtp()\n");
+
+ /* Process for H263+ ----------------- */
+ } else if (!strncasecmp(loop_str, "profile", len)) {
+ if(sscanf(value_str, "%02x", &profile)){
+ found = 1;
+ vidcap->valid = 1;
+ vidcap->profile = profile;
+ } else
+ ast_verbose("----- Failed to parse profile in process_h2613_fmtp()!\n");
+ } else if (!strncasecmp(loop_str, "level", len)) {
+ if(sscanf(value_str, "%02x", &level)){
+ found = 1;
+ vidcap->valid = 1;
+ vidcap->level = level;
+ } else
+ ast_verbose("----- Failed to parse level in process_h2613_fmtp()!\n");
} else if (len == 1 && loop_str[0] >= 'A' && loop_str[0] <= 'Z') { /* this is an annex */
vidcap->annexes |= (1 << (loop_str[0] - 'A'));
found = 1;
- ast_verbose("Found annex %c, we now have %08x\n", loop_str[0], vidcap->annexes);
+ ast_verbose("----- Found annex %c, we now have %08x\n", loop_str[0], vidcap->annexes);
+ /* TO BE DONE : get the annex value, e.g.: */
+ /*'K', 'N' and 'P' could be set from '1' to '4' */
+ /* => see "rfc4629 - RTP Payload Format for ITU-T Rec. H.263 Video" */
+
} else { /* Check video sizes */
for (i = 0; i < MAX_VIDEO_SIZES; i++) {
if (strlen(videoSizes[i].type) == len && !strncasecmp(loop_str, videoSizes[i].type, len)) {
if (sscanf(value_str, "%d", &tmp)){
found = 1;
- /* vidcap->maxfr[i] = framerate < (30 / tmp) ? framerate : (30 /tmp); */
- vidcap->maxfr[i] = (tmp > 30) ? 30 : (tmp < 0) ? 0 : tmp;
+ vidcap->maxfr[i] = framerate < (30 / tmp) ? framerate : (30 /tmp);
vidcap->valid = 1;
}
/* ast_verbose("%s->FR=%d, len=%d, string=%s\n", videoSizes[i].type, vidcap->maxfr[i], len, loop_str); */
@@ -374,7 +534,7 @@
}
}
if (!found)
- ast_verbose("Unable to parse %s in fmtp\n", loop_str);
+ ast_verbose("----- Unable to parse %s in fmtp\n", loop_str);
}
if (vidcap->valid && vidcap->maxbr)
@@ -399,12 +559,10 @@
int level = 0;
int constraint = 0;
int packetmode = 0;
- int rtpnum=0;
/* "a=fmtp:%d profile-level-id=42800C; packetization-mode=0; max-br=384; max-mbps=7128\r\n" */
memcpy(myVideoSizes, videoSizes, sizeof(myVideoSizes));
-
parse = ast_strdupa(fmtstr);
/* Get the fmtp: and payload type out of the way */
@@ -423,30 +581,28 @@
if(sscanf(value_str, "%d", &maxbr))
found = 1;
else
- ast_verbose("Failed to parse max-br in process_h264_fmtp()\n");
+ ast_verbose("----- Failed to parse max-br in process_h264_fmtp()!\n");
} else if (!strncasecmp(loop_str, "max-mbps", len)) {
if(sscanf(value_str, "%d", &maxmbps))
found = 1;
else
- ast_verbose("Failed to parse max-mbps in process_h264_fmtp()\n");
+ ast_verbose("----- Failed to parse max-mbps in process_h264_fmtp()!\n");
} else if (!strncasecmp(loop_str, "profile-level-id", len)) {
if(sscanf(value_str, "%02x%02x%02x", &profile, &constraint, &level))
found = 1;
else
- ast_verbose("Failed to parse profile-level-id in process_h264_fmtp()\n");
+ ast_verbose("----- Failed to parse profile-level-id in process_h264_fmtp()!\n");
} else if (!strncasecmp(loop_str, "packetization-mode", len)) {
if(sscanf(value_str, "%d", &packetmode))
found = 1;
else
- ast_verbose("Failed to parse packetization-mode in process_h264_fmtp()\n");
- } else if (!strncasecmp(loop_str, "rtpnum", len)) {
- if(sscanf(value_str, "%d", &rtpnum))
- found = 1;
- else
- ast_verbose("Failed to parse rtpnum in process_h264_fmtp()\n");
+ ast_verbose("----- Failed to parse packetization-mode in process_h264_fmtp()!\n");
+ } else if (!strncasecmp(loop_str, "sprop-parameter-sets", len)){
+ /*! \todo XXX TO BE DONE, see "rfc3984 - RTP Payload Format for H.264 Video" */
}
+
if (!found)
- ast_verbose("Unable to parse %s in fmtp\n", loop_str);
+ ast_verbose("----- Unable to parse %s in fmtp\n", loop_str);
}
/* Work out picture sizes from supplied level */
@@ -493,7 +649,94 @@
vidcap->level = level;
vidcap->constraint = constraint;
vidcap->valid = 1;
- vidcap->rtpnum = rtpnum;
+ /* vidcap->rtpnum = rtpnum; */
return 0;
}
+
+int parse_mp4v_conf_line(const char *fmtstr, struct ast_h264_video_cap *vidcap, int framerate)
+{
+ char *parse, *loop_str, *equals, *value_str;
+ char *sep = " ;:/,";
+ int len;
+ struct videoSize myVideoSizes[MAX_VIDEO_SIZES];
+ int found=0;
+ int level = 0;
+ int profile_level = 0;
+ int profile = 0;
+ int low_mask = 15; //Level
+ int high_mask = 240; //Profile
+
+ /* "a=fmtp:%d profile-level-id=34; config=08462A8CE6D" */
+ memcpy(myVideoSizes, videoSizes, sizeof(myVideoSizes));
+
+ parse = ast_strdupa(fmtstr);
+
+ loop_str = strsep(&parse, sep);
+
+ for (; loop_str != NULL; loop_str = strsep(&parse, sep) ) {
+ if (loop_str[0] == '\0') {
+ loop_str++;
+ continue;
+ }
+ if((equals = strchr(loop_str, '='))==NULL)
+ return -1;
+ found = 0;
+ len = equals - loop_str;
+ value_str = loop_str+len+1;
+ /* Now check other parameters than can appear in a video fmtp */
+ if (!strncasecmp(loop_str, "profile-level-id", len)) {
+ if(sscanf(value_str, "%d", &profile_level)){
+ level = low_mask&profile_level;
+ profile = (high_mask&profile_level)>>4;
+ found = 1;
+ } else
+ ast_verbose("----- Failed to parse profile-level-id in process_mp4_fmtp()\n");
+ } else if (!strncasecmp(loop_str, "config", len)){
+ /*! \todo XXX TO BE DONE, see "rfc3016 - RTP Payload Format for MPEG-4 AudioVisual Streams" */
+ }
+ }
+
+ /* Work out picture sizes from supplied level */
+ switch (level) {
+ case sp_level_1 :
+ /*! \todo Figure out these picture sizes */
+ /*level_maxbr = 64000; */
+ /*level_maxmbps = 1485; */
+ break;
+ case sp_level_2 :
+ /*level_maxbr = 64000; */
+ /*level_maxmbps = 3000; */
+ break;
+ case sp_level_3 :
+ /*level_maxbr = 128000; */
+ /*level_maxmbps = 6000; */
+ break;
+ case asp_level_1:
+ /*level_maxbr = 384000; */
+ /*level_maxmbps = 11880; */
+ break;
+ case asp_level_2:
+ /*level_maxbr = 768000; */
+ /*level_maxmbps = 11880; */
+ break;
+ case asp_level_3:
+ /*level_maxbr = 768000; */
+ /*level_maxmbps = 11880; */
+ break;
+ case asp_level_4:
+ /*level_maxbr = 768000; */
+ /*level_maxmbps = 11880; */
+ break;
+ default:
+ /*level_maxbr = 2000000; */
+ /*level_maxmbps = 11880; */
+ break;
+ }
+
+
+ vidcap->profile = profile;
+ vidcap->level = level;
+
+ return 0;
+}
Modified: team/oej/videocaps/main/channel.c
URL: http://svn.digium.com/view/asterisk/team/oej/videocaps/main/channel.c?view=diff&rev=101343&r1=101342&r2=101343
==============================================================================
--- team/oej/videocaps/main/channel.c (original)
+++ team/oej/videocaps/main/channel.c Wed Jan 30 15:27:30 2008
@@ -3329,32 +3329,78 @@
return ast_channel_sendhtml(chan, AST_HTML_URL, url, strlen(url) + 1);
}
-/*! \brief Set up translation from one channel to another */
-static int ast_channel_make_compatible_helper(struct ast_channel *from, struct ast_channel *to)
-{
- int src;
- int dst;
-
- if (from->readformat == to->writeformat && from->writeformat == to->readformat) {
- /* Already compatible! Moving on ... */
- return 0;
- }
-
- /* Set up translation from the 'from' channel to the 'to' channel */
- src = from->nativeformats & AST_FORMAT_AUDIO_MASK;
- dst = to->nativeformats & AST_FORMAT_AUDIO_MASK;
- if (ast_translator_best_choice(&dst, &src) < 0) {
- ast_log(LOG_WARNING, "No path to translate from %s(0x%08x) to %s(0x%08x)\n", from->name, src, to->name, dst);
- return -1;
- }
+static int negotiate_formats(const char *chan_name, int *src, const char *peer_name, int *dst)
+{
+ int asrc, vsrc, tsrc;
+ int adst, vdst, tdst;
+
+ asrc = *src & AST_FORMAT_AUDIO_MASK;
+ adst = *dst & AST_FORMAT_AUDIO_MASK;
+
+ vsrc = *src & AST_FORMAT_VIDEO_MASK;
+ vdst = *dst & AST_FORMAT_VIDEO_MASK;
+
+ tsrc = *src & AST_FORMAT_TEXT_MASK;
+ tdst = *dst & AST_FORMAT_TEXT_MASK;
+
+ if (ast_translator_best_choice(&adst, &asrc) < 0) {
+ ast_log(LOG_WARNING, "No path to translate AUDIO from chan=%s (%08x) to peer=%s (%08x)\n", chan_name, asrc, peer_name, adst);
+ return -1;
+ }
/* if the best path is not 'pass through', then
transcoding is needed; if desired, force transcode path
to use SLINEAR between channels, but only if there is
no direct conversion available */
- if ((src != dst) && ast_opt_transcode_via_slin &&
- (ast_translate_path_steps(dst, src) != 1))
- dst = AST_FORMAT_SLINEAR;
+ if ((asrc != adst) && ast_opt_transcode_via_slin && (ast_translate_path_steps(adst, asrc) != 1)) {
[... 79 lines stripped ...]
More information about the asterisk-commits
mailing list