From 66d652cbf38eb39377f20a6b536f939b6150e952 Mon Sep 17 00:00:00 2001 From: Martin Storsjö Date: Mon, 8 Oct 2012 22:25:55 +0300 Subject: rtpdec_vp8: Make the depacketizer implement the latest spec draft MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not all details are implemented, but it's enough for proper playback as long as there is no packet loss. Tested to work with the packetizer in gstreamer (which although uses a different codec name, to clarify that it is still a spec draft). Signed-off-by: Martin Storsjö --- libavformat/rtpdec_vp8.c | 117 ++++++++++++++++++++++++++--------------------- 1 file changed, 64 insertions(+), 53 deletions(-) (limited to 'libavformat') diff --git a/libavformat/rtpdec_vp8.c b/libavformat/rtpdec_vp8.c index f21ce6f91f..a52be4b644 100644 --- a/libavformat/rtpdec_vp8.c +++ b/libavformat/rtpdec_vp8.c @@ -1,6 +1,7 @@ /* * RTP VP8 Depacketizer * Copyright (c) 2010 Josh Allmann + * Copyright (c) 2012 Martin Storsjo * * This file is part of Libav. * @@ -23,7 +24,7 @@ * @file * @brief RTP support for the VP8 payload * @author Josh Allmann - * @see http://www.webmproject.org/code/specs/rtp/ + * @see http://tools.ietf.org/html/draft-ietf-payload-vp8-05 */ #include "libavcodec/bytestream.h" @@ -33,14 +34,12 @@ struct PayloadContext { AVIOContext *data; uint32_t timestamp; - int is_keyframe; }; static void prepare_packet(AVPacket *pkt, PayloadContext *vp8, int stream) { av_init_packet(pkt); pkt->stream_index = stream; - pkt->flags = vp8->is_keyframe ? AV_PKT_FLAG_KEY : 0; pkt->size = avio_close_dyn_buf(vp8->data, &pkt->data); pkt->destruct = av_destruct_packet; vp8->data = NULL; @@ -54,70 +53,84 @@ static int vp8_handle_packet(AVFormatContext *ctx, const uint8_t *buf, int len, int flags) { - int start_packet, end_packet, has_au, ret = AVERROR(EAGAIN); - - if (!buf) { - // only called when vp8_handle_packet returns 1 - if (!vp8->data) { - av_log(ctx, AV_LOG_ERROR, "Invalid VP8 data passed\n"); + int start_partition, end_packet; + int extended_bits, non_ref, part_id; + int pictureid_present = 0, tl0picidx_present = 0, tid_present = 0, + keyidx_present = 0; + int pictureid = -1, keyidx = -1; + + if (len < 1) + return AVERROR_INVALIDDATA; + + extended_bits = buf[0] & 0x80; + non_ref = buf[0] & 0x20; + start_partition = buf[0] & 0x10; + part_id = buf[0] & 0x0f; + end_packet = flags & RTP_FLAG_MARKER; + buf++; + len--; + if (extended_bits) { + if (len < 1) return AVERROR_INVALIDDATA; + pictureid_present = buf[0] & 0x80; + tl0picidx_present = buf[0] & 0x40; + tid_present = buf[0] & 0x20; + keyidx_present = buf[0] & 0x10; + buf++; + len--; + } + if (pictureid_present) { + if (len < 1) + return AVERROR_INVALIDDATA; + if (buf[0] & 0x80) { + if (len < 2) + return AVERROR_INVALIDDATA; + pictureid = AV_RB16(buf) & 0x7fff; + buf += 2; + len -= 2; + } else { + pictureid = buf[0] & 0x7f; + buf++; + len--; } - prepare_packet(pkt, vp8, st->index); - *timestamp = vp8->timestamp; - return 0; } + if (tl0picidx_present) { + // Ignoring temporal level zero index + buf++; + len--; + } + if (tid_present || keyidx_present) { + // Ignoring temporal layer index and layer sync bit + if (len < 1) + return AVERROR_INVALIDDATA; + if (keyidx_present) + keyidx = buf[0] & 0x1f; + buf++; + len--; + } + if (len < 1) + return AVERROR_INVALIDDATA; - start_packet = *buf & 1; - end_packet = flags & RTP_FLAG_MARKER; - has_au = *buf & 2; - buf++; - len--; - - if (start_packet) { + if (start_partition && part_id == 0) { int res; - uint32_t ts = *timestamp; if (vp8->data) { - // missing end marker; return old frame anyway. untested - prepare_packet(pkt, vp8, st->index); - *timestamp = vp8->timestamp; // reset timestamp from old frame - - // if current frame fits into one rtp packet, need to hold - // that for the next av_get_packet call - ret = end_packet ? 1 : 0; + uint8_t *tmp; + avio_close_dyn_buf(vp8->data, &tmp); + av_free(tmp); + vp8->data = NULL; } if ((res = avio_open_dyn_buf(&vp8->data)) < 0) return res; - vp8->is_keyframe = *buf & 1; - vp8->timestamp = ts; + vp8->timestamp = *timestamp; } - if (!vp8->data || vp8->timestamp != *timestamp && ret == AVERROR(EAGAIN)) { + if (!vp8->data || vp8->timestamp != *timestamp) { av_log(ctx, AV_LOG_WARNING, "Received no start marker; dropping frame\n"); return AVERROR(EAGAIN); } - // cycle through VP8AU headers if needed - // not tested with actual VP8AUs - while (len) { - int au_len = len; - if (has_au && len > 2) { - au_len = AV_RB16(buf); - buf += 2; - len -= 2; - if (buf + au_len > buf + len) { - av_log(ctx, AV_LOG_ERROR, "Invalid VP8AU length\n"); - return AVERROR_INVALIDDATA; - } - } - - avio_write(vp8->data, buf, au_len); - buf += au_len; - len -= au_len; - } - - if (ret != AVERROR(EAGAIN)) // did we miss a end marker? - return ret; + avio_write(vp8->data, buf, len); if (end_packet) { prepare_packet(pkt, vp8, st->index); @@ -129,8 +142,6 @@ static int vp8_handle_packet(AVFormatContext *ctx, static PayloadContext *vp8_new_context(void) { - av_log(NULL, AV_LOG_ERROR, "RTP VP8 payload implementation is incompatible " - "with the latest spec drafts.\n"); return av_mallocz(sizeof(PayloadContext)); } -- cgit v1.2.3 From c9b10cc4dbb67a94c29359fde79fb882d71fef6f Mon Sep 17 00:00:00 2001 From: Martin Storsjö Date: Mon, 8 Oct 2012 23:18:38 +0300 Subject: rtpenc_vp8: Update the packetizer to the latest spec version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tested to work with the gstreamer depacketizer. Signed-off-by: Martin Storsjö --- libavformat/rtpenc.c | 4 ---- libavformat/rtpenc_vp8.c | 6 ++++-- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'libavformat') diff --git a/libavformat/rtpenc.c b/libavformat/rtpenc.c index dc257f6391..36064ed610 100644 --- a/libavformat/rtpenc.c +++ b/libavformat/rtpenc.c @@ -181,10 +181,6 @@ static int rtp_write_header(AVFormatContext *s1) s->max_payload_size -= 6; // ident+frag+tdt/vdt+pkt_num+pkt_length s->num_frames = 0; goto defaultcase; - case AV_CODEC_ID_VP8: - av_log(s1, AV_LOG_ERROR, "RTP VP8 payload implementation is " - "incompatible with the latest spec drafts.\n"); - break; case AV_CODEC_ID_ADPCM_G722: /* Due to a historical error, the clock rate for G722 in RTP is * 8000, even if the sample rate is 16000. See RFC 3551. */ diff --git a/libavformat/rtpenc_vp8.c b/libavformat/rtpenc_vp8.c index afedbb49c0..1730379874 100644 --- a/libavformat/rtpenc_vp8.c +++ b/libavformat/rtpenc_vp8.c @@ -22,7 +22,7 @@ #include "rtpenc.h" /* Based on a draft spec for VP8 RTP. - * ( http://www.webmproject.org/code/specs/rtp/ ) */ + * ( http://tools.ietf.org/html/draft-ietf-payload-vp8-05 ) */ void ff_rtp_send_vp8(AVFormatContext *s1, const uint8_t *buf, int size) { RTPMuxContext *s = s1->priv_data; @@ -32,7 +32,9 @@ void ff_rtp_send_vp8(AVFormatContext *s1, const uint8_t *buf, int size) s->timestamp = s->cur_timestamp; max_packet_size = s->max_payload_size - 1; // minus one for header byte - *s->buf_ptr++ = 1; // 0b1 indicates start of frame + // no extended control bits, reference frame, start of partition, + // partition id 0 + *s->buf_ptr++ = 0x10; while (size > 0) { len = FFMIN(size, max_packet_size); -- cgit v1.2.3 From e04826c34e9b19cc4da60fd028334f12f84b4b2a Mon Sep 17 00:00:00 2001 From: Yusuke Nakamura Date: Tue, 9 Oct 2012 16:00:28 +0900 Subject: file: Set the return value type for lseek to int64_t. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a regression in 4ed5ac5. Signed-off-by: Martin Storsjö --- libavformat/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libavformat') diff --git a/libavformat/file.c b/libavformat/file.c index fc0af92277..c552a9eaa5 100644 --- a/libavformat/file.c +++ b/libavformat/file.c @@ -121,7 +121,7 @@ static int file_open(URLContext *h, const char *filename, int flags) static int64_t file_seek(URLContext *h, int64_t pos, int whence) { FileContext *c = h->priv_data; - int ret; + int64_t ret; if (whence == AVSEEK_SIZE) { struct stat st; -- cgit v1.2.3 From c136a813d77ed0c8698386d140990e9003d5d38c Mon Sep 17 00:00:00 2001 From: Martin Storsjö Date: Tue, 9 Oct 2012 00:51:42 +0300 Subject: rtp: Support packetization/depacketization of opus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Storsjö --- libavformat/rtpdec.c | 7 +++++++ libavformat/rtpenc.c | 19 +++++++++++++++++++ libavformat/sdp.c | 4 ++++ 3 files changed, 30 insertions(+) (limited to 'libavformat') diff --git a/libavformat/rtpdec.c b/libavformat/rtpdec.c index 0f4e1d1d86..dac367dd86 100644 --- a/libavformat/rtpdec.c +++ b/libavformat/rtpdec.c @@ -55,6 +55,12 @@ static RTPDynamicProtocolHandler speex_dynamic_handler = { .codec_id = AV_CODEC_ID_SPEEX, }; +static RTPDynamicProtocolHandler opus_dynamic_handler = { + .enc_name = "opus", + .codec_type = AVMEDIA_TYPE_AUDIO, + .codec_id = AV_CODEC_ID_OPUS, +}; + /* statistics functions */ static RTPDynamicProtocolHandler *RTPFirstDynamicPayloadHandler= NULL; @@ -85,6 +91,7 @@ void av_register_rtp_dynamic_payload_handlers(void) ff_register_dynamic_payload_handler(&ff_qcelp_dynamic_handler); ff_register_dynamic_payload_handler(&realmedia_mp3_dynamic_handler); ff_register_dynamic_payload_handler(&speex_dynamic_handler); + ff_register_dynamic_payload_handler(&opus_dynamic_handler); ff_register_dynamic_payload_handler(&ff_ms_rtp_asf_pfv_handler); ff_register_dynamic_payload_handler(&ff_ms_rtp_asf_pfa_handler); diff --git a/libavformat/rtpenc.c b/libavformat/rtpenc.c index 36064ed610..b17c4651b6 100644 --- a/libavformat/rtpenc.c +++ b/libavformat/rtpenc.c @@ -77,6 +77,7 @@ static int is_supported(enum AVCodecID id) case AV_CODEC_ID_ILBC: case AV_CODEC_ID_MJPEG: case AV_CODEC_ID_SPEEX: + case AV_CODEC_ID_OPUS: return 1; default: return 0; @@ -186,6 +187,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 AV_CODEC_ID_OPUS: + if (st->codec->channels > 2) { + av_log(s1, AV_LOG_ERROR, "Multistream opus not supported in RTP\n"); + goto fail; + } + /* The opus RTP RFC says that all opus streams should use 48000 Hz + * as clock rate, since all opus sample rates can be expressed in + * this clock rate, and sample rate changes on the fly are supported. */ + avpriv_set_pts_info(st, 32, 1, 48000); + break; case AV_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"); @@ -525,6 +536,14 @@ static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt) case AV_CODEC_ID_MJPEG: ff_rtp_send_jpeg(s1, pkt->data, size); break; + case AV_CODEC_ID_OPUS: + if (size > s->max_payload_size) { + av_log(s1, AV_LOG_ERROR, + "Packet size %d too large for max RTP payload size %d\n", + size, s->max_payload_size); + return AVERROR(EINVAL); + } + /* Intentional fallthrough */ default: /* better than nothing : send the codec raw data */ rtp_send_raw(s1, pkt->data, size); diff --git a/libavformat/sdp.c b/libavformat/sdp.c index 91de413dc6..0f7eb2f00d 100644 --- a/libavformat/sdp.c +++ b/libavformat/sdp.c @@ -576,6 +576,10 @@ static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c, av_strlcatf(buff, size, "a=rtpmap:%d speex/%d\r\n", payload_type, c->sample_rate); break; + case AV_CODEC_ID_OPUS: + av_strlcatf(buff, size, "a=rtpmap:%d opus/48000\r\n", + payload_type); + break; default: /* Nothing special to do here... */ break; -- cgit v1.2.3 From f75f4194d1ea4e5a0176b13452345eff87164416 Mon Sep 17 00:00:00 2001 From: Diego Biurrun Date: Mon, 8 Oct 2012 19:08:03 +0200 Subject: Restructure av_log_missing_feature message Some invocations include a verb in the log message, others do not. Yet av_log_missing_feature expects callers to provide a verb. Change the function to include a verb instead and update the callers accordingly. The result is a more natural function API and correct English in the function invocations. --- libavcodec/aac_adtstoasc_bsf.c | 4 ++-- libavcodec/aacdec.c | 12 ++++++------ libavcodec/cavsdec.c | 2 +- libavcodec/h264.c | 2 +- libavcodec/mjpegdec.c | 7 +++---- libavcodec/utils.c | 2 +- libavformat/oggparseskeleton.c | 4 ++-- 7 files changed, 16 insertions(+), 17 deletions(-) (limited to 'libavformat') diff --git a/libavcodec/aac_adtstoasc_bsf.c b/libavcodec/aac_adtstoasc_bsf.c index 55181bbf55..a6599345bd 100644 --- a/libavcodec/aac_adtstoasc_bsf.c +++ b/libavcodec/aac_adtstoasc_bsf.c @@ -61,7 +61,7 @@ static int aac_adtstoasc_filter(AVBitStreamFilterContext *bsfc, } if (!hdr.crc_absent && hdr.num_aac_frames > 1) { - av_log_missing_feature(avctx, "Multiple RDBs per frame with CRC is", 0); + av_log_missing_feature(avctx, "Multiple RDBs per frame with CRC", 0); return -1; } @@ -74,7 +74,7 @@ static int aac_adtstoasc_filter(AVBitStreamFilterContext *bsfc, if (!hdr.chan_config) { init_get_bits(&gb, buf, buf_size * 8); if (get_bits(&gb, 3) != 5) { - av_log_missing_feature(avctx, "PCE based channel configuration, where the PCE is not the first syntax element is", 0); + av_log_missing_feature(avctx, "PCE based channel configuration, where the PCE is not the first syntax element", 0); return -1; } init_put_bits(&pb, pce_data, MAX_PCE_SIZE); diff --git a/libavcodec/aacdec.c b/libavcodec/aacdec.c index 1c59ec5937..859414adc9 100644 --- a/libavcodec/aacdec.c +++ b/libavcodec/aacdec.c @@ -633,7 +633,7 @@ static int decode_ga_specific_config(AACContext *ac, AVCodecContext *avctx, int tags = 0; if (get_bits1(gb)) { // frameLengthFlag - av_log_missing_feature(avctx, "960/120 MDCT window is", 1); + av_log_missing_feature(avctx, "960/120 MDCT window", 1); return -1; } @@ -2323,7 +2323,7 @@ static int parse_adts_frame_header(AACContext *ac, GetBitContext *gb) size = avpriv_aac_parse_header(gb, &hdr_info); if (size > 0) { if (hdr_info.num_aac_frames != 1) { - av_log_missing_feature(ac->avctx, "More than one AAC RDB per ADTS frame is", 0); + av_log_missing_feature(ac->avctx, "More than one AAC RDB per ADTS frame", 0); return -1; } push_output_configuration(ac); @@ -2607,8 +2607,8 @@ static int latm_decode_audio_specific_config(struct LATMContext *latmctx, asclen = get_bits_left(gb); if (config_start_bit % 8) { - av_log_missing_feature(latmctx->aac_ctx.avctx, "audio specific " - "config not byte aligned.\n", 1); + av_log_missing_feature(latmctx->aac_ctx.avctx, + "Non-byte-aligned audio-specific config", 1); return AVERROR_INVALIDDATA; } if (asclen <= 0) @@ -2663,7 +2663,7 @@ static int read_stream_mux_config(struct LATMContext *latmctx, // numPrograms if (get_bits(gb, 4)) { // numPrograms av_log_missing_feature(latmctx->aac_ctx.avctx, - "multiple programs are not supported\n", 1); + "multiple programs", 1); return AVERROR_PATCHWELCOME; } @@ -2672,7 +2672,7 @@ static int read_stream_mux_config(struct LATMContext *latmctx, // for each layer (which there is only on in DVB) if (get_bits(gb, 3)) { // numLayer av_log_missing_feature(latmctx->aac_ctx.avctx, - "multiple layers are not supported\n", 1); + "multiple layers", 1); return AVERROR_PATCHWELCOME; } diff --git a/libavcodec/cavsdec.c b/libavcodec/cavsdec.c index e55e4f6e07..b1dd3bd27b 100644 --- a/libavcodec/cavsdec.c +++ b/libavcodec/cavsdec.c @@ -1065,7 +1065,7 @@ static int decode_seq_header(AVSContext *h) { width = get_bits(&s->gb, 14); height = get_bits(&s->gb, 14); if ((s->width || s->height) && (s->width != width || s->height != height)) { - av_log_missing_feature(s, "Width/height changing in CAVS is", 0); + av_log_missing_feature(s, "Width/height changing in CAVS", 0); return AVERROR_PATCHWELCOME; } s->width = width; diff --git a/libavcodec/h264.c b/libavcodec/h264.c index 3c5870ce0d..8648a8d90b 100644 --- a/libavcodec/h264.c +++ b/libavcodec/h264.c @@ -2462,7 +2462,7 @@ static int decode_slice_header(H264Context *h, H264Context *h0) av_cmp_q(h->sps.sar, s->avctx->sample_aspect_ratio))) { if (h != h0 || (HAVE_THREADS && h->s.avctx->active_thread_type & FF_THREAD_FRAME)) { av_log_missing_feature(s->avctx, - "Width/height changing with threads is", 0); + "Width/height changing with threads", 0); return AVERROR_PATCHWELCOME; // width / height changed during parallelized decoding } free_tables(h, 0); diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c index afe1f3db65..ecccd687f1 100644 --- a/libavcodec/mjpegdec.c +++ b/libavcodec/mjpegdec.c @@ -244,8 +244,8 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) return -1; if (s->ls && !(s->bits <= 8 || nb_components == 1)) { av_log_missing_feature(s->avctx, - "only <= 8 bits/component or " - "16-bit gray accepted for JPEG-LS\n", 0); + "For JPEG-LS anything except <= 8 bits/component" + " or 16-bit gray", 0); return AVERROR_PATCHWELCOME; } s->nb_components = nb_components; @@ -270,8 +270,7 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) } if (s->ls && (s->h_max > 1 || s->v_max > 1)) { - av_log_missing_feature(s->avctx, - "Subsampling in JPEG-LS is not supported.\n", 0); + av_log_missing_feature(s->avctx, "Subsampling in JPEG-LS", 0); return AVERROR_PATCHWELCOME; } diff --git a/libavcodec/utils.c b/libavcodec/utils.c index c71ddbe802..bd80d7bf13 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -2028,7 +2028,7 @@ int ff_match_2uint16(const uint16_t(*tab)[2], int size, int a, int b) void av_log_missing_feature(void *avc, const char *feature, int want_sample) { - av_log(avc, AV_LOG_WARNING, "%s not implemented. Update your Libav " + av_log(avc, AV_LOG_WARNING, "%s is not implemented. Update your Libav " "version to the newest one from Git. If the problem still " "occurs, it means that your file has a feature which has not " "been implemented.\n", feature); diff --git a/libavformat/oggparseskeleton.c b/libavformat/oggparseskeleton.c index 92841b8138..2cc63d413b 100644 --- a/libavformat/oggparseskeleton.c +++ b/libavformat/oggparseskeleton.c @@ -75,8 +75,8 @@ static int skeleton_header(AVFormatContext *s, int idx) target_idx = ogg_find_stream(ogg, AV_RL32(buf+12)); start_granule = AV_RL64(buf+36); if (os->start_granule != OGG_NOGRANULE_VALUE) { - av_log_missing_feature(s, "multiple fisbone for the " - "same stream\n", 0); + av_log_missing_feature(s, + "multiple fisbone for the same stream", 0); return 1; } if (target_idx >= 0 && start_granule != OGG_NOGRANULE_VALUE) { -- cgit v1.2.3