diff options
Diffstat (limited to 'libavformat')
-rw-r--r-- | libavformat/Makefile | 3 | ||||
-rw-r--r-- | libavformat/allformats.c | 1 | ||||
-rw-r--r-- | libavformat/flvdec.c | 30 | ||||
-rw-r--r-- | libavformat/http.c | 6 | ||||
-rw-r--r-- | libavformat/ilbc.c | 141 | ||||
-rw-r--r-- | libavformat/isom.c | 1 | ||||
-rw-r--r-- | libavformat/mov.c | 1 | ||||
-rw-r--r-- | libavformat/movenc.c | 3 | ||||
-rw-r--r-- | libavformat/mpegts.c | 94 | ||||
-rw-r--r-- | libavformat/rtmpproto.c | 8 | ||||
-rw-r--r-- | libavformat/rtpdec.c | 1 | ||||
-rw-r--r-- | libavformat/rtpdec_formats.h | 1 | ||||
-rw-r--r-- | libavformat/rtpdec_ilbc.c | 73 | ||||
-rw-r--r-- | libavformat/rtpenc.c | 44 | ||||
-rw-r--r-- | libavformat/rtsp.c | 2 | ||||
-rw-r--r-- | libavformat/sdp.c | 6 | ||||
-rw-r--r-- | libavformat/version.h | 2 |
17 files changed, 287 insertions, 130 deletions
diff --git a/libavformat/Makefile b/libavformat/Makefile index 3dca060994..f38b8a575c 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -123,6 +123,8 @@ OBJS-$(CONFIG_ICO_DEMUXER) += icodec.o OBJS-$(CONFIG_IDCIN_DEMUXER) += idcin.o OBJS-$(CONFIG_IDF_DEMUXER) += bintext.o OBJS-$(CONFIG_IFF_DEMUXER) += iff.o +OBJS-$(CONFIG_ILBC_DEMUXER) += ilbc.o +OBJS-$(CONFIG_ILBC_MUXER) += ilbc.o OBJS-$(CONFIG_IMAGE2_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_IMAGE2_MUXER) += img2enc.o img2.o OBJS-$(CONFIG_IMAGE2PIPE_DEMUXER) += img2dec.o img2.o @@ -281,6 +283,7 @@ OBJS-$(CONFIG_RTPDEC) += rdt.o \ rtpdec_h263.o \ rtpdec_h263_rfc2190.o \ rtpdec_h264.o \ + rtpdec_ilbc.o \ rtpdec_latm.o \ rtpdec_mpeg4.o \ rtpdec_qcelp.o \ diff --git a/libavformat/allformats.c b/libavformat/allformats.c index ed9227e5b6..b5738e4d97 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -116,6 +116,7 @@ void av_register_all(void) REGISTER_DEMUXER (IDCIN, idcin); REGISTER_DEMUXER (IDF, idf); REGISTER_DEMUXER (IFF, iff); + REGISTER_MUXDEMUX (ILBC, ilbc); REGISTER_MUXDEMUX (IMAGE2, image2); REGISTER_MUXDEMUX (IMAGE2PIPE, image2pipe); REGISTER_DEMUXER (INGENIENT, ingenient); diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c index aa016ee4de..31f306872f 100644 --- a/libavformat/flvdec.c +++ b/libavformat/flvdec.c @@ -759,33 +759,6 @@ static int flv_read_seek(AVFormatContext *s, int stream_index, return avio_seek_time(s->pb, stream_index, ts, flags); } -#if 0 /* don't know enough to implement this */ -static int flv_read_seek2(AVFormatContext *s, int stream_index, - int64_t min_ts, int64_t ts, int64_t max_ts, int flags) -{ - int ret = AVERROR(ENOSYS); - - if (ts - min_ts > (uint64_t)(max_ts - ts)) flags |= AVSEEK_FLAG_BACKWARD; - - if (!s->pb->seekable) { - if (stream_index < 0) { - stream_index = av_find_default_stream_index(s); - if (stream_index < 0) - return -1; - - /* timestamp for default must be expressed in AV_TIME_BASE units */ - ts = av_rescale_rnd(ts, 1000, AV_TIME_BASE, - flags & AVSEEK_FLAG_BACKWARD ? AV_ROUND_DOWN : AV_ROUND_UP); - } - ret = avio_seek_time(s->pb, stream_index, ts, flags); - } - - if (ret == AVERROR(ENOSYS)) - ret = av_seek_frame(s, stream_index, ts, flags); - return ret; -} -#endif - AVInputFormat ff_flv_demuxer = { .name = "flv", .long_name = NULL_IF_CONFIG_SMALL("FLV format"), @@ -794,9 +767,6 @@ AVInputFormat ff_flv_demuxer = { .read_header = flv_read_header, .read_packet = flv_read_packet, .read_seek = flv_read_seek, -#if 0 - .read_seek2 = flv_read_seek2, -#endif .read_close = flv_read_close, .extensions = "flv", }; diff --git a/libavformat/http.c b/libavformat/http.c index fb4a83ad0e..96a7eeda0a 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -308,15 +308,15 @@ static int process_line(URLContext *h, char *line, int line_count, strcpy(s->location, p); *new_location = 1; } else if (!av_strcasecmp (tag, "Content-Length") && s->filesize == -1) { - s->filesize = atoll(p); + s->filesize = strtoll(p, NULL, 10); } else if (!av_strcasecmp (tag, "Content-Range")) { /* "bytes $from-$to/$document_size" */ const char *slash; if (!strncmp (p, "bytes ", 6)) { p += 6; - s->off = atoll(p); + s->off = strtoll(p, NULL, 10); if ((slash = strchr(p, '/')) && strlen(slash) > 0) - s->filesize = atoll(slash+1); + s->filesize = strtoll(slash+1, NULL, 10); } h->is_streamed = 0; /* we _can_ in fact seek */ } else if (!av_strcasecmp(tag, "Accept-Ranges") && !strncmp(p, "bytes", 5)) { diff --git a/libavformat/ilbc.c b/libavformat/ilbc.c new file mode 100644 index 0000000000..d4f4583545 --- /dev/null +++ b/libavformat/ilbc.c @@ -0,0 +1,141 @@ +/* + * iLBC storage file format + * Copyright (c) 2012 Martin Storsjo + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avformat.h" +#include "internal.h" + +static const char mode20_header[] = "#!iLBC20\n"; +static const char mode30_header[] = "#!iLBC30\n"; + +static int ilbc_write_header(AVFormatContext *s) +{ + AVIOContext *pb = s->pb; + AVCodecContext *enc; + + if (s->nb_streams != 1) { + av_log(s, AV_LOG_ERROR, "Unsupported number of streams\n"); + return AVERROR(EINVAL); + } + enc = s->streams[0]->codec; + + if (enc->codec_id != CODEC_ID_ILBC) { + av_log(s, AV_LOG_ERROR, "Unsupported codec\n"); + return AVERROR(EINVAL); + } + + if (enc->block_align == 50) { + avio_write(pb, mode30_header, sizeof(mode30_header) - 1); + } else if (enc->block_align == 38) { + avio_write(pb, mode20_header, sizeof(mode20_header) - 1); + } else { + av_log(s, AV_LOG_ERROR, "Unsupported mode\n"); + return AVERROR(EINVAL); + } + avio_flush(pb); + return 0; +} + +static int ilbc_write_packet(AVFormatContext *s, AVPacket *pkt) +{ + avio_write(s->pb, pkt->data, pkt->size); + avio_flush(s->pb); + return 0; +} + +static int ilbc_probe(AVProbeData *p) +{ + // Only check for "#!iLBC" which matches both formats + if (!memcmp(p->buf, mode20_header, 6)) + return AVPROBE_SCORE_MAX; + else + return 0; +} + +static int ilbc_read_header(AVFormatContext *s) +{ + AVIOContext *pb = s->pb; + AVStream *st; + uint8_t header[9]; + + avio_read(pb, header, 9); + + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + st->codec->codec_id = CODEC_ID_ILBC; + st->codec->sample_rate = 8000; + st->codec->channels = 1; + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + st->start_time = 0; + avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); + if (!memcmp(header, mode20_header, sizeof(mode20_header) - 1)) { + st->codec->block_align = 38; + st->codec->bit_rate = 15200; + } else if (!memcmp(header, mode30_header, sizeof(mode30_header) - 1)) { + st->codec->block_align = 50; + st->codec->bit_rate = 13333; + } else { + av_log(s, AV_LOG_ERROR, "Unrecognized iLBC file header\n"); + return AVERROR_INVALIDDATA; + } + + return 0; +} + +static int ilbc_read_packet(AVFormatContext *s, + AVPacket *pkt) +{ + AVCodecContext *enc = s->streams[0]->codec; + int ret; + + if ((ret = av_new_packet(pkt, enc->block_align)) < 0) + return ret; + + pkt->stream_index = 0; + pkt->pos = avio_tell(s->pb); + pkt->duration = enc->block_align == 38 ? 160 : 240; + if ((ret = avio_read(s->pb, pkt->data, enc->block_align)) != enc->block_align) { + av_free_packet(pkt); + return ret < 0 ? ret : AVERROR(EIO); + } + + return 0; +} + +AVInputFormat ff_ilbc_demuxer = { + .name = "ilbc", + .long_name = NULL_IF_CONFIG_SMALL("iLBC storage file format"), + .read_probe = ilbc_probe, + .read_header = ilbc_read_header, + .read_packet = ilbc_read_packet, + .flags = AVFMT_GENERIC_INDEX, +}; + +AVOutputFormat ff_ilbc_muxer = { + .name = "ilbc", + .long_name = NULL_IF_CONFIG_SMALL("iLBC storage file format"), + .mime_type = "audio/iLBC", + .extensions = "lbc", + .audio_codec = CODEC_ID_ILBC, + .write_header = ilbc_write_header, + .write_packet = ilbc_write_packet, + .flags = AVFMT_NOTIMESTAMPS, +}; diff --git a/libavformat/isom.c b/libavformat/isom.c index e4575033e2..0ddbb813ec 100644 --- a/libavformat/isom.c +++ b/libavformat/isom.c @@ -259,6 +259,7 @@ const AVCodecTag ff_codec_movaudio_tags[] = { { CODEC_ID_DVAUDIO, MKTAG('v', 'd', 'v', 'a') }, { CODEC_ID_DVAUDIO, MKTAG('d', 'v', 'c', 'a') }, { CODEC_ID_GSM, MKTAG('a', 'g', 's', 'm') }, + { CODEC_ID_ILBC, MKTAG('i', 'l', 'b', 'c') }, { CODEC_ID_MACE3, MKTAG('M', 'A', 'C', '3') }, { CODEC_ID_MACE6, MKTAG('M', 'A', 'C', '6') }, { CODEC_ID_MP1, MKTAG('.', 'm', 'p', '1') }, diff --git a/libavformat/mov.c b/libavformat/mov.c index 9548f215f3..3aab48ffff 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -1540,6 +1540,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) case CODEC_ID_GSM: case CODEC_ID_ADPCM_MS: case CODEC_ID_ADPCM_IMA_WAV: + case CODEC_ID_ILBC: st->codec->block_align = sc->bytes_per_frame; break; case CODEC_ID_ALAC: diff --git a/libavformat/movenc.c b/libavformat/movenc.c index d5eb25bcc2..89072d5ded 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -3371,7 +3371,8 @@ static int mov_write_header(AVFormatContext *s) av_log(s, AV_LOG_WARNING, "track %d: codec frame size is not set\n", i); track->audio_vbr = 1; }else if(st->codec->codec_id == CODEC_ID_ADPCM_MS || - st->codec->codec_id == CODEC_ID_ADPCM_IMA_WAV){ + st->codec->codec_id == CODEC_ID_ADPCM_IMA_WAV || + st->codec->codec_id == CODEC_ID_ILBC){ if (!st->codec->block_align) { av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set for adpcm\n", i); goto error; diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c index 3acca0230c..3a5ed696c8 100644 --- a/libavformat/mpegts.c +++ b/libavformat/mpegts.c @@ -19,8 +19,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -//#define USE_SYNCPOINT_SEARCH - #include "libavutil/crc.h" #include "libavutil/intreadwrite.h" #include "libavutil/log.h" @@ -2161,92 +2159,6 @@ static int64_t mpegts_get_dts(AVFormatContext *s, int stream_index, return AV_NOPTS_VALUE; } -#ifdef USE_SYNCPOINT_SEARCH - -static int read_seek2(AVFormatContext *s, - int stream_index, - int64_t min_ts, - int64_t target_ts, - int64_t max_ts, - int flags) -{ - int64_t pos; - - int64_t ts_ret, ts_adj; - int stream_index_gen_search; - AVStream *st; - AVParserState *backup; - - backup = ff_store_parser_state(s); - - // detect direction of seeking for search purposes - flags |= (target_ts - min_ts > (uint64_t)(max_ts - target_ts)) ? - AVSEEK_FLAG_BACKWARD : 0; - - if (flags & AVSEEK_FLAG_BYTE) { - // use position directly, we will search starting from it - pos = target_ts; - } else { - // search for some position with good timestamp match - if (stream_index < 0) { - stream_index_gen_search = av_find_default_stream_index(s); - if (stream_index_gen_search < 0) { - ff_restore_parser_state(s, backup); - return -1; - } - - st = s->streams[stream_index_gen_search]; - // timestamp for default must be expressed in AV_TIME_BASE units - ts_adj = av_rescale(target_ts, - st->time_base.den, - AV_TIME_BASE * (int64_t)st->time_base.num); - } else { - ts_adj = target_ts; - stream_index_gen_search = stream_index; - } - pos = ff_gen_search(s, stream_index_gen_search, ts_adj, - 0, INT64_MAX, -1, - AV_NOPTS_VALUE, - AV_NOPTS_VALUE, - flags, &ts_ret, mpegts_get_pcr); - if (pos < 0) { - ff_restore_parser_state(s, backup); - return -1; - } - } - - // search for actual matching keyframe/starting position for all streams - if (ff_gen_syncpoint_search(s, stream_index, pos, - min_ts, target_ts, max_ts, - flags) < 0) { - ff_restore_parser_state(s, backup); - return -1; - } - - ff_free_parser_state(s, backup); - return 0; -} - -static int read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, int flags) -{ - int ret; - if (flags & AVSEEK_FLAG_BACKWARD) { - flags &= ~AVSEEK_FLAG_BACKWARD; - ret = read_seek2(s, stream_index, INT64_MIN, target_ts, target_ts, flags); - if (ret < 0) - // for compatibility reasons, seek to the best-fitting timestamp - ret = read_seek2(s, stream_index, INT64_MIN, target_ts, INT64_MAX, flags); - } else { - ret = read_seek2(s, stream_index, target_ts, target_ts, INT64_MAX, flags); - if (ret < 0) - // for compatibility reasons, seek to the best-fitting timestamp - ret = read_seek2(s, stream_index, INT64_MIN, target_ts, INT64_MAX, flags); - } - return ret; -} - -#endif - /**************************************************************/ /* parsing functions - called from other demuxers such as RTP */ @@ -2313,9 +2225,6 @@ AVInputFormat ff_mpegts_demuxer = { .read_close = mpegts_read_close, .read_timestamp = mpegts_get_dts, .flags = AVFMT_SHOW_IDS | AVFMT_TS_DISCONT, -#ifdef USE_SYNCPOINT_SEARCH - .read_seek2 = read_seek2, -#endif }; AVInputFormat ff_mpegtsraw_demuxer = { @@ -2327,8 +2236,5 @@ AVInputFormat ff_mpegtsraw_demuxer = { .read_close = mpegts_read_close, .read_timestamp = mpegts_get_dts, .flags = AVFMT_SHOW_IDS | AVFMT_TS_DISCONT, -#ifdef USE_SYNCPOINT_SEARCH - .read_seek2 = read_seek2, -#endif .priv_class = &mpegtsraw_class, }; diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c index 07ec62cc43..4bdda4d097 100644 --- a/libavformat/rtmpproto.c +++ b/libavformat/rtmpproto.c @@ -76,6 +76,7 @@ typedef struct RTMPContext { uint8_t* flv_data; ///< buffer with data for demuxer int flv_size; ///< current buffer size int flv_off; ///< number of bytes read from current buffer + int flv_nb_packets; ///< number of flv packets published RTMPPacket out_pkt; ///< rtmp packet, created from flv a/v or metadata (for output) uint32_t client_report_size; ///< number of bytes after which client should report to server uint32_t bytes_read; ///< number of bytes read from server @@ -90,6 +91,7 @@ typedef struct RTMPContext { char* swfurl; ///< url of the swf player int server_bw; ///< server bandwidth int client_buffer_time; ///< client buffer time in ms + int flush_interval; ///< number of packets flushed in the same request (RTMPT only) } RTMPContext; #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing @@ -1361,9 +1363,14 @@ static int rtmp_write(URLContext *s, const uint8_t *buf, int size) rt->flv_size = 0; rt->flv_off = 0; rt->flv_header_bytes = 0; + rt->flv_nb_packets++; } } while (buf_temp - buf < size); + if (rt->flv_nb_packets < rt->flush_interval) + return size; + rt->flv_nb_packets = 0; + /* set stream into nonblocking mode */ rt->stream->flags |= AVIO_FLAG_NONBLOCK; @@ -1404,6 +1411,7 @@ static const AVOption rtmp_options[] = { {"rtmp_buffer", "Set buffer time in milliseconds. The default is 3000.", OFFSET(client_buffer_time), AV_OPT_TYPE_INT, {3000}, 0, INT_MAX, DEC|ENC}, {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC}, {"rtmp_flashver", "Version of the Flash plugin used to run the SWF player.", OFFSET(flashver), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC}, + {"rtmp_flush_interval", "Number of packets flushed in the same request (RTMPT only).", OFFSET(flush_interval), AV_OPT_TYPE_INT, {10}, 0, INT_MAX, ENC}, {"rtmp_live", "Specify that the media is a live stream.", OFFSET(live), AV_OPT_TYPE_INT, {-2}, INT_MIN, INT_MAX, DEC, "rtmp_live"}, {"any", "both", 0, AV_OPT_TYPE_CONST, {-2}, 0, 0, DEC, "rtmp_live"}, {"live", "live stream", 0, AV_OPT_TYPE_CONST, {-1}, 0, 0, DEC, "rtmp_live"}, diff --git a/libavformat/rtpdec.c b/libavformat/rtpdec.c index b7240a2d51..3a272e33c7 100644 --- a/libavformat/rtpdec.c +++ b/libavformat/rtpdec.c @@ -68,6 +68,7 @@ void av_register_rtp_dynamic_payload_handlers(void) ff_register_dynamic_payload_handler(&ff_h263_2000_dynamic_handler); ff_register_dynamic_payload_handler(&ff_h263_rfc2190_dynamic_handler); ff_register_dynamic_payload_handler(&ff_h264_dynamic_handler); + ff_register_dynamic_payload_handler(&ff_ilbc_dynamic_handler); ff_register_dynamic_payload_handler(&ff_vorbis_dynamic_handler); ff_register_dynamic_payload_handler(&ff_theora_dynamic_handler); ff_register_dynamic_payload_handler(&ff_qdm2_dynamic_handler); diff --git a/libavformat/rtpdec_formats.h b/libavformat/rtpdec_formats.h index 73ffe1f49e..a0c61a84b9 100644 --- a/libavformat/rtpdec_formats.h +++ b/libavformat/rtpdec_formats.h @@ -45,6 +45,7 @@ extern RTPDynamicProtocolHandler ff_h263_1998_dynamic_handler; extern RTPDynamicProtocolHandler ff_h263_2000_dynamic_handler; extern RTPDynamicProtocolHandler ff_h263_rfc2190_dynamic_handler; extern RTPDynamicProtocolHandler ff_h264_dynamic_handler; +extern RTPDynamicProtocolHandler ff_ilbc_dynamic_handler; extern RTPDynamicProtocolHandler ff_mp4a_latm_dynamic_handler; extern RTPDynamicProtocolHandler ff_mp4v_es_dynamic_handler; extern RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler; diff --git a/libavformat/rtpdec_ilbc.c b/libavformat/rtpdec_ilbc.c new file mode 100644 index 0000000000..247c779bfc --- /dev/null +++ b/libavformat/rtpdec_ilbc.c @@ -0,0 +1,73 @@ +/* + * RTP iLBC Depacketizer, RFC 3952 + * Copyright (c) 2012 Martin Storsjo + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avformat.h" +#include "rtpdec_formats.h" +#include "libavutil/avstring.h" + +static int ilbc_parse_fmtp(AVStream *stream, PayloadContext *data, + char *attr, char *value) +{ + if (!strcmp(attr, "mode")) { + int mode = atoi(value); + switch (mode) { + case 20: + stream->codec->block_align = 38; + break; + case 30: + stream->codec->block_align = 50; + break; + default: + av_log(NULL, AV_LOG_ERROR, "Unsupported iLBC mode %d\n", mode); + return AVERROR(EINVAL); + } + } + return 0; +} + +static int ilbc_parse_sdp_line(AVFormatContext *s, int st_index, + PayloadContext *data, const char *line) +{ + const char *p; + AVStream *st; + + if (st_index < 0) + return 0; + st = s->streams[st_index]; + + if (av_strstart(line, "fmtp:", &p)) { + int ret = ff_parse_fmtp(st, data, p, ilbc_parse_fmtp); + if (ret < 0) + return ret; + if (!st->codec->block_align) { + av_log(s, AV_LOG_ERROR, "No iLBC mode set\n"); + return AVERROR(EINVAL); + } + } + return 0; +} + +RTPDynamicProtocolHandler ff_ilbc_dynamic_handler = { + .enc_name = "iLBC", + .codec_type = AVMEDIA_TYPE_AUDIO, + .codec_id = CODEC_ID_ILBC, + .parse_sdp_a_line = ilbc_parse_sdp_line, +}; diff --git a/libavformat/rtpenc.c b/libavformat/rtpenc.c index e16e610820..f7e2cf0630 100644 --- a/libavformat/rtpenc.c +++ b/libavformat/rtpenc.c @@ -74,6 +74,7 @@ static int is_supported(enum CodecID id) case CODEC_ID_VP8: case CODEC_ID_ADPCM_G722: case CODEC_ID_ADPCM_G726: + case CODEC_ID_ILBC: return 1; default: return 0; @@ -187,6 +188,16 @@ static int rtp_write_header(AVFormatContext *s1) * 8000, even if the sample rate is 16000. See RFC 3551. */ avpriv_set_pts_info(st, 32, 1, 8000); break; + case CODEC_ID_ILBC: + if (st->codec->block_align != 38 && st->codec->block_align != 50) { + av_log(s1, AV_LOG_ERROR, "Incorrect iLBC block size specified\n"); + goto fail; + } + if (!s->max_frames_per_packet) + s->max_frames_per_packet = 1; + s->max_frames_per_packet = FFMIN(s->max_frames_per_packet, + s->max_payload_size / st->codec->block_align); + goto defaultcase; case CODEC_ID_AMR_NB: case CODEC_ID_AMR_WB: if (!s->max_frames_per_packet) @@ -395,6 +406,36 @@ static void rtp_send_mpegts_raw(AVFormatContext *s1, } } +static int rtp_send_ilbc(AVFormatContext *s1, const uint8_t *buf, int size) +{ + RTPMuxContext *s = s1->priv_data; + AVStream *st = s1->streams[0]; + int frame_duration = av_get_audio_frame_duration(st->codec, 0); + int frame_size = st->codec->block_align; + int frames = size / frame_size; + + while (frames > 0) { + int n = FFMIN(s->max_frames_per_packet - s->num_frames, frames); + + if (!s->num_frames) { + s->buf_ptr = s->buf; + s->timestamp = s->cur_timestamp; + } + memcpy(s->buf_ptr, buf, n * frame_size); + frames -= n; + s->num_frames += n; + s->buf_ptr += n * frame_size; + buf += n * frame_size; + s->cur_timestamp += n * frame_duration; + + if (s->num_frames == s->max_frames_per_packet) { + ff_rtp_send_data(s1, s->buf, s->buf_ptr - s->buf, 1); + s->num_frames = 0; + } + } + return 0; +} + static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt) { RTPMuxContext *s = s1->priv_data; @@ -483,6 +524,9 @@ static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt) case CODEC_ID_VP8: ff_rtp_send_vp8(s1, pkt->data, size); break; + case CODEC_ID_ILBC: + rtp_send_ilbc(s1, pkt->data, size); + break; default: /* better than nothing : send the codec raw data */ rtp_send_raw(s1, pkt->data, size); diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c index 891afc92a4..68ca247b00 100644 --- a/libavformat/rtsp.c +++ b/libavformat/rtsp.c @@ -1279,7 +1279,7 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port, "%s/UDP;multicast", trans_pref); } if (s->oformat) { - av_strlcat(transport, ";mode=receive", sizeof(transport)); + av_strlcat(transport, ";mode=record", sizeof(transport)); } else if (rt->server_type == RTSP_SERVER_REAL || rt->server_type == RTSP_SERVER_WMS) av_strlcat(transport, ";mode=play", sizeof(transport)); diff --git a/libavformat/sdp.c b/libavformat/sdp.c index 5d5e9515f7..352dea0335 100644 --- a/libavformat/sdp.c +++ b/libavformat/sdp.c @@ -549,6 +549,12 @@ static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c, c->sample_rate); break; } + case CODEC_ID_ILBC: + av_strlcatf(buff, size, "a=rtpmap:%d iLBC/%d\r\n" + "a=fmtp:%d mode=%d\r\n", + payload_type, c->sample_rate, + payload_type, c->block_align == 38 ? 20 : 30); + break; default: /* Nothing special to do here... */ break; diff --git a/libavformat/version.h b/libavformat/version.h index 0b1bff2764..3b61ea34fc 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -30,7 +30,7 @@ #include "libavutil/avutil.h" #define LIBAVFORMAT_VERSION_MAJOR 54 -#define LIBAVFORMAT_VERSION_MINOR 8 +#define LIBAVFORMAT_VERSION_MINOR 9 #define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ |