rendered paste bodydiff --git a/libavformat/avformat.h b/libavformat/avformat.hindex 16170d4..5b3fa29 100644--- a/libavformat/avformat.h+++ b/libavformat/avformat.h@@ -566,6 +566,7 @@ typedef struct AVFormatContext { #define AVFMT_FLAG_GENPTS 0x0001 ///< Generate missing pts even if it requires parsing future frames. #define AVFMT_FLAG_IGNIDX 0x0002 ///< Ignore index. #define AVFMT_FLAG_NONBLOCK 0x0004 ///< Do not block when reading packets from input.+#define AVFMT_FLAG_LATM 0x0008 ///< Generate LATM rtp stream for mpeg4audio codec. int loop_input; /** decoding: size of data to probe; encoding: unused. */diff --git a/libavformat/avio.c b/libavformat/avio.cindex b6329a9..0e1c847 100644--- a/libavformat/avio.c+++ b/libavformat/avio.c@@ -87,6 +87,7 @@ int url_open_protocol (URLContext **puc, struct URLProtocol *up, uc->flags = flags; uc->is_streamed = 0; /* default = not streamed */ uc->max_packet_size = 0; /* default: stream file */+ uc->rtp_payload_type = -1; /* default: depends on codec */ err = up->url_open(uc, filename, flags); if (err < 0) { av_free(uc);@@ -232,6 +233,11 @@ int url_get_max_packet_size(URLContext *h) return h->max_packet_size; } +int url_get_rtp_payload_type(URLContext *h)+{+ return h->rtp_payload_type;+}+ void url_get_filename(URLContext *h, char *buf, int buf_size) { av_strlcpy(buf, h->filename, buf_size);diff --git a/libavformat/avio.h b/libavformat/avio.hindex d44e300..f8078e5 100644--- a/libavformat/avio.h+++ b/libavformat/avio.h@@ -49,6 +49,7 @@ typedef struct URLContext { int flags; int is_streamed; /**< true if streamed (no seek possible), default = false */ int max_packet_size; /**< if non zero, the stream is packetized with this max packet size */+ int rtp_payload_type; /**< if non zero, the rtp stream is packetized with this payload type */ void *priv_data; char *filename; /**< specified filename */ } URLContext;@@ -94,6 +95,17 @@ int url_get_file_handle(URLContext *h); * @return maximum packet size in bytes */ int url_get_max_packet_size(URLContext *h);++/**+ * Return the rtp payload type associated to packetized file+ * handle. If the file is not packetized (stream like HTTP or file on+ * disk), then -1 is returned.+ *+ * @param h file handle+ * @return rtp payload type+ */+int url_get_rtp_payload_type(URLContext *h);+ void url_get_filename(URLContext *h, char *buf, int buf_size); /**@@ -198,6 +210,7 @@ typedef struct { int write_flag; /**< true if open for writing */ int is_streamed; int max_packet_size;+ int rtp_payload_type; unsigned long checksum; unsigned char *checksum_ptr; unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size);@@ -355,6 +368,16 @@ URLContext *url_fileno(ByteIOContext *s); */ int url_fget_max_packet_size(ByteIOContext *s); +/**+ * Return the payload type, associated to rtp packetized buffered file+ * handle. If the file is not packetized (stream like http or file on+ * disk), then -1 is returned.+ *+ * @param s buffered file handle+ * @return rtp payload type+ */+int url_fget_rtp_payload_type(ByteIOContext *s);+ int url_open_buf(ByteIOContext **s, uint8_t *buf, int buf_size, int flags); /** return the written or read size */diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.cindex f270139..d734efc 100644--- a/libavformat/aviobuf.c+++ b/libavformat/aviobuf.c@@ -52,6 +52,7 @@ int init_put_byte(ByteIOContext *s, s->error = 0; s->is_streamed = 0; s->max_packet_size = 0;+ s->rtp_payload_type = -1; s->update_checksum= NULL; if(!read_packet && !write_flag){ s->pos = buffer_size;@@ -529,10 +530,11 @@ uint64_t ff_get_v(ByteIOContext *bc){ int url_fdopen(ByteIOContext **s, URLContext *h) { uint8_t *buffer;- int buffer_size, max_packet_size;+ int buffer_size, max_packet_size, rtp_payload_type; max_packet_size = url_get_max_packet_size(h);+ rtp_payload_type = url_get_rtp_payload_type(h); if (max_packet_size) { buffer_size = max_packet_size; /* no need to bufferize more than one packet */ } else {@@ -557,6 +559,7 @@ int url_fdopen(ByteIOContext **s, URLContext *h) } (*s)->is_streamed = h->is_streamed; (*s)->max_packet_size = max_packet_size;+ (*s)->rtp_payload_type = rtp_payload_type; if(h->prot) { (*s)->read_pause = (int (*)(void *, int))h->prot->url_read_pause; (*s)->read_seek = (int64_t (*)(void *, int, int64_t, int))h->prot->url_read_seek;@@ -666,6 +669,11 @@ int url_fget_max_packet_size(ByteIOContext *s) return s->max_packet_size; } +int url_fget_rtp_payload_type(ByteIOContext *s)+{+ return s->rtp_payload_type;+}+ int av_url_read_fpause(ByteIOContext *s, int pause) { if (!s->read_pause)diff --git a/libavformat/options.c b/libavformat/options.cindex 795d02b..b96d1dd 100644--- a/libavformat/options.c+++ b/libavformat/options.c@@ -46,6 +46,7 @@ static const AVOption options[]={ {"fflags", NULL, OFFSET(flags), FF_OPT_TYPE_FLAGS, DEFAULT, INT_MIN, INT_MAX, D|E, "fflags"}, {"ignidx", "ignore index", 0, FF_OPT_TYPE_CONST, AVFMT_FLAG_IGNIDX, INT_MIN, INT_MAX, D, "fflags"}, {"genpts", "generate pts", 0, FF_OPT_TYPE_CONST, AVFMT_FLAG_GENPTS, INT_MIN, INT_MAX, D, "fflags"},+{"latm", "packetize mpeg4audio to LATM (RFC 3016)", 0, FF_OPT_TYPE_CONST, AVFMT_FLAG_LATM, INT_MIN, INT_MAX, D, "fflags"}, #if LIBAVFORMAT_VERSION_INT < (53<<16) {"track", " set the track number", OFFSET(track), FF_OPT_TYPE_INT, DEFAULT, 0, INT_MAX, E}, {"year", "set the year", OFFSET(year), FF_OPT_TYPE_INT, DEFAULT, INT_MIN, INT_MAX, E},diff --git a/libavformat/rtp_aac.c b/libavformat/rtp_aac.cindex e19b286..8852857 100644--- a/libavformat/rtp_aac.c+++ b/libavformat/rtp_aac.c@@ -83,3 +83,45 @@ void ff_rtp_send_aac(AVFormatContext *s1, const uint8_t *buff, int size) } } }+++++/* latm muxer */+void ff_rtp_send_aac_latm(AVFormatContext *s1, const uint8_t *buff, int size)+{+ RTPMuxContext *s = s1->priv_data;+ int len, max_packet_size;+ uint8_t *p = s->buf;+ int latmhdrsize;++ /* skip ADTS header, if present */+ if ((s1->streams[0]->codec->extradata_size) == 0) {+ size -= 7;+ buff += 7;+ }++ latmhdrsize = size/0xff + 1;+ max_packet_size = s->max_payload_size - latmhdrsize;+ s->timestamp = s->cur_timestamp;+ + while (size > 0) {+ len = FFMIN(size, max_packet_size);+ memcpy(p + latmhdrsize, buff, len);+ if(latmhdrsize) {+ /* write latm header in 1st packet */+ int tmp = size;+ while (tmp > 0xfe){+ *p = 0xff;+ p++;+ tmp -= 0xff;+ }+ *p = tmp;+ }+ + ff_rtp_send_data(s1, s->buf, len + latmhdrsize, (len == size));+ size -= len;+ buff += len;+ latmhdrsize = 0;+ }+}diff --git a/libavformat/rtpenc.c b/libavformat/rtpenc.cindex 2a0770e..d9788c4 100644--- a/libavformat/rtpenc.c+++ b/libavformat/rtpenc.c@@ -83,9 +83,12 @@ static int rtp_write_header(AVFormatContext *s1) return -1; } - payload_type = ff_rtp_get_payload_type(st->codec);- if (payload_type < 0)- payload_type = RTP_PT_PRIVATE; /* private payload type */+ payload_type = url_fget_rtp_payload_type(s1->pb);+ if (payload_type < 0) {+ payload_type = ff_rtp_get_payload_type(st->codec);+ if (payload_type < 0)+ payload_type = RTP_PT_PRIVATE; /* private payload type */+ } s->payload_type = payload_type; // following 2 FIXMEs could be set based on the current time, there is normally no info leak, as RTP will likely be transmitted immediately@@ -383,7 +386,10 @@ static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt) ff_rtp_send_mpegvideo(s1, buf1, size); break; case CODEC_ID_AAC:- ff_rtp_send_aac(s1, buf1, size);+ if(s1->flags & AVFMT_FLAG_LATM)+ ff_rtp_send_aac_latm(s1, buf1, size);+ else+ ff_rtp_send_aac(s1, buf1, size); break; case CODEC_ID_AMR_NB: case CODEC_ID_AMR_WB:diff --git a/libavformat/rtpenc.h b/libavformat/rtpenc.hindex 5710160..905667f 100644--- a/libavformat/rtpenc.h+++ b/libavformat/rtpenc.h@@ -59,6 +59,7 @@ void ff_rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len, int m); void ff_rtp_send_h264(AVFormatContext *s1, const uint8_t *buf1, int size); void ff_rtp_send_h263(AVFormatContext *s1, const uint8_t *buf1, int size); void ff_rtp_send_aac(AVFormatContext *s1, const uint8_t *buff, int size);+void ff_rtp_send_aac_latm(AVFormatContext *s1, const uint8_t *buff, int size); void ff_rtp_send_amr(AVFormatContext *s1, const uint8_t *buff, int size); void ff_rtp_send_mpegvideo(AVFormatContext *s1, const uint8_t *buf1, int size); diff --git a/libavformat/rtpproto.c b/libavformat/rtpproto.cindex 9d80ddf..ac0b3bd 100644--- a/libavformat/rtpproto.c+++ b/libavformat/rtpproto.c@@ -98,7 +98,7 @@ static void url_add_option(char *buf, int buf_size, const char *fmt, ...) static void build_udp_url(char *buf, int buf_size, const char *hostname, int port, int local_port, int ttl,- int max_packet_size)+ int max_packet_size, int rtp_payload_type) { snprintf(buf, buf_size, "udp://%s:%d", hostname, port); if (local_port >= 0)@@ -107,6 +107,8 @@ static void build_udp_url(char *buf, int buf_size, url_add_option(buf, buf_size, "ttl=%d", ttl); if (max_packet_size >=0) url_add_option(buf, buf_size, "pkt_size=%d", max_packet_size);+ if (rtp_payload_type >=0)+ url_add_option(buf, buf_size, "payload_type=%d", rtp_payload_type); } /**@@ -120,7 +122,7 @@ static void build_udp_url(char *buf, int buf_size, static int rtp_open(URLContext *h, const char *uri, int flags) { RTPContext *s;- int port, is_output, ttl, local_port, max_packet_size;+ int port, is_output, ttl, local_port, max_packet_size, rtp_payload_type; char hostname[256]; char buf[1024]; char path[1024];@@ -139,6 +141,7 @@ static int rtp_open(URLContext *h, const char *uri, int flags) ttl = -1; local_port = -1; max_packet_size = -1;+ rtp_payload_type = -1; p = strchr(uri, '?'); if (p) {@@ -151,10 +154,13 @@ static int rtp_open(URLContext *h, const char *uri, int flags) if (find_info_tag(buf, sizeof(buf), "pkt_size", p)) { max_packet_size = strtol(buf, NULL, 10); }+ if (find_info_tag(buf, sizeof(buf), "payload_type", p)) {+ rtp_payload_type = strtol(buf, NULL, 10);+ } } build_udp_url(buf, sizeof(buf),- hostname, port, local_port, ttl, max_packet_size);+ hostname, port, local_port, ttl, max_packet_size, rtp_payload_type); if (url_open(&s->rtp_hd, buf, flags) < 0) goto fail; local_port = udp_get_local_port(s->rtp_hd);@@ -163,7 +169,7 @@ static int rtp_open(URLContext *h, const char *uri, int flags) /* well, should suppress localport in path */ build_udp_url(buf, sizeof(buf),- hostname, port + 1, local_port + 1, ttl, max_packet_size);+ hostname, port + 1, local_port + 1, ttl, max_packet_size, rtp_payload_type); if (url_open(&s->rtcp_hd, buf, flags) < 0) goto fail; @@ -172,6 +178,7 @@ static int rtp_open(URLContext *h, const char *uri, int flags) s->rtp_fd = url_get_file_handle(s->rtp_hd); s->rtcp_fd = url_get_file_handle(s->rtcp_hd); + h->rtp_payload_type = url_get_rtp_payload_type(s->rtp_hd); h->max_packet_size = url_get_max_packet_size(s->rtp_hd); h->is_streamed = 1; return 0;diff --git a/libavformat/sdp.c b/libavformat/sdp.cindex 67b10a2..cd0d443 100644--- a/libavformat/sdp.c+++ b/libavformat/sdp.c@@ -20,6 +20,8 @@ #include "libavutil/avstring.h" #include "libavutil/base64.h"+#include "libavcodec/get_bits.h"+#include "libavcodec/mpeg4audio.h" #include "avformat.h" #include "internal.h" #include "avc.h"@@ -163,10 +165,46 @@ static char *extradata2config(AVCodecContext *c) return config; } -static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c, int payload_type)+static char *extradata2latmConfig(AVCodecContext *c) {- char *config = NULL;+ char *config;+ unsigned char binConfig[6];+ int sample_rate_index, channels_index, objecttype;+ GetBitContext gb;+ + /* this for aac+, we have to look at extradata to detect AAC (not he-aac) samplerate and channels */+ init_get_bits(&gb, c->extradata, c->extradata_size * 8);+ objecttype = get_bits(&gb, 5) - 1;+ sample_rate_index = get_bits(&gb, 4);+ channels_index = get_bits(&gb, 4);+ //*channels = ff_mpeg4audio_channels[channels_index];+ //*sample_rate = ff_mpeg4audio_sample_rates[sample_rate_index];+ + + binConfig[0]=0x40;+ binConfig[1]=0;+ binConfig[2]=0x20|sample_rate_index;+ binConfig[3]=channels_index<<4;+ binConfig[4]=0x3f;+ binConfig[5]=0xc0;+ + config = av_malloc(10 + 12);+ if (config == NULL) {+ av_log(c, AV_LOG_ERROR, "Cannot allocate memory for the config info.\n");+ return NULL;+ }+ + memcpy(config, "; config=", 9);+ ff_data_to_hex(config + 9, binConfig, 6);+ config[9 + 12] = 0; + return config;+}++static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c, int payload_type, int latm)+{+ char *config = NULL;+ switch (c->codec_id) { case CODEC_ID_H264: if (c->extradata_size) {@@ -192,7 +230,11 @@ static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c, break; case CODEC_ID_AAC: if (c->extradata_size) {- config = extradata2config(c);+ if(latm) {+ config = extradata2latmConfig(c/*, &sample_rate, &channels*/);+ } else {+ config = extradata2config(c);+ } } else { /* FIXME: maybe we can forge config information based on the * codec parameters...@@ -203,12 +245,20 @@ static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c, if (config == NULL) { return NULL; }- av_strlcatf(buff, size, "a=rtpmap:%d MPEG4-GENERIC/%d/%d\r\n"- "a=fmtp:%d profile-level-id=1;"- "mode=AAC-hbr;sizelength=13;indexlength=3;"- "indexdeltalength=3%s\r\n",- payload_type, c->sample_rate, c->channels,- payload_type, config);+ if(latm) {+ av_strlcatf(buff, size, "a=rtpmap:%d MP4A-LATM/%d/%d\r\n"+ "a=fmtp:%d profile-level-id=15;"+ "object=2; cpresent=0%s\r\n",+ payload_type, /*sample_rate, channels*/ c->sample_rate, c->channels,+ payload_type, config);+ } else {+ av_strlcatf(buff, size, "a=rtpmap:%d MPEG4-GENERIC/%d/%d\r\n"+ "a=fmtp:%d profile-level-id=1;"+ "mode=AAC-hbr;sizelength=13;indexlength=3;"+ "indexdeltalength=3%s\r\n",+ payload_type, c->sample_rate, c->channels,+ payload_type, config);+ } break; case CODEC_ID_PCM_S16BE: if (payload_type >= 96)@@ -250,15 +300,9 @@ static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c, return buff; } -static void sdp_write_media(char *buff, int size, AVCodecContext *c, const char *dest_addr, int port, int ttl)+static void sdp_write_media(char *buff, int size, AVCodecContext *c, const char *dest_addr, int port, int ttl, int payload_type, int latm) { const char *type;- int payload_type;-- payload_type = ff_rtp_get_payload_type(c);- if (payload_type < 0) {- payload_type = 96; /* FIXME: how to assign a private pt? rtp.c is broken too */- } switch (c->codec_type) { case CODEC_TYPE_VIDEO : type = "video" ; break;@@ -273,14 +317,14 @@ static void sdp_write_media(char *buff, int size, AVCodecContext *c, const char av_strlcatf(buff, size, "b=AS:%d\r\n", c->bit_rate / 1000); } - sdp_write_media_attributes(buff, size, c, payload_type);+ sdp_write_media_attributes(buff, size, c, payload_type, latm); } int avf_sdp_create(AVFormatContext *ac[], int n_files, char *buff, int size) { AVMetadataTag *title = av_metadata_get(ac[0]->metadata, "title", NULL, 0); struct sdp_session_level s;- int i, j, port, ttl;+ int i, j, port, ttl, payload_type; char dst[32]; memset(buff, 0, size);@@ -306,9 +350,17 @@ int avf_sdp_create(AVFormatContext *ac[], int n_files, char *buff, int size) port = sdp_get_address(dst, sizeof(dst), &ttl, ac[i]->filename); } for (j = 0; j < ac[i]->nb_streams; j++) {+ payload_type = url_fget_rtp_payload_type(ac[i]->pb);+ if (payload_type < 0) {+ payload_type = ff_rtp_get_payload_type(ac[i]->streams[j]->codec);+ if (payload_type < 0)+ payload_type = RTP_PT_PRIVATE; /* private payload type */+ }+ sdp_write_media(buff, size, ac[i]->streams[j]->codec, dst[0] ? dst : NULL,- (port > 0) ? port + j * 2 : 0, ttl);+ (port > 0) ? port + j * 2 : 0, ttl,+ payload_type, ac[i]->flags & AVFMT_FLAG_LATM ? 1 : 0); if (port <= 0) { av_strlcatf(buff, size, "a=control:streamid=%d\r\n", i + j);diff --git a/libavformat/udp.c b/libavformat/udp.cindex a89de00..89a8c4e 100644--- a/libavformat/udp.c+++ b/libavformat/udp.c@@ -383,6 +383,9 @@ static int udp_open(URLContext *h, const char *uri, int flags) if (find_info_tag(buf, sizeof(buf), "buffer_size", p)) { s->buffer_size = strtol(buf, NULL, 10); }+ if (find_info_tag(buf, sizeof(buf), "payload_type", p)) {+ h->rtp_payload_type = strtol(buf, NULL, 10);+ } } /* fill the dest addr */