1/* 2 * RTP parser for DV payload format (RFC 6469) 3 * Copyright (c) 2015 Thomas Volkert <thomas@homer-conferencing.com> 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22#include "libavutil/avstring.h" 23 24#include "avio_internal.h" 25#include "rtpdec.h" 26 27struct PayloadContext { 28 AVIOContext *buf; 29 uint32_t timestamp; 30 int bundled_audio; 31}; 32 33static av_cold void dv_close_context(PayloadContext *data) 34{ 35 ffio_free_dyn_buf(&data->buf); 36} 37 38static av_cold int dv_sdp_parse_fmtp_config(AVFormatContext *s, 39 AVStream *stream, 40 PayloadContext *dv_data, 41 const char *attr, const char *value) 42{ 43 /* does the DV stream include audio? */ 44 if (!strcmp(attr, "audio") && !strcmp(value, "bundled")) 45 dv_data->bundled_audio = 1; 46 47 /* extract the DV profile */ 48 if (!strcmp(attr, "encode")) { 49 /* SD-VCR/525-60 */ 50 /* SD-VCR/625-50 */ 51 /* HD-VCR/1125-60 */ 52 /* HD-VCR/1250-50 */ 53 /* SDL-VCR/525-60 */ 54 /* SDL-VCR/625-50 */ 55 /* 314M-25/525-60 */ 56 /* 314M-25/625-50 */ 57 /* 314M-50/525-60 */ 58 /* 314M-50/625-50 */ 59 /* 370M/1080-60i */ 60 /* 370M/1080-50i */ 61 /* 370M/720-60p */ 62 /* 370M/720-50p */ 63 /* 306M/525-60 (for backward compatibility) */ 64 /* 306M/625-50 (for backward compatibility) */ 65 } 66 67 return 0; 68} 69 70static av_cold int dv_parse_sdp_line(AVFormatContext *ctx, int st_index, 71 PayloadContext *dv_data, const char *line) 72{ 73 AVStream *current_stream; 74 const char *sdp_line_ptr = line; 75 76 if (st_index < 0) 77 return 0; 78 79 current_stream = ctx->streams[st_index]; 80 81 if (av_strstart(sdp_line_ptr, "fmtp:", &sdp_line_ptr)) { 82 return ff_parse_fmtp(ctx, current_stream, dv_data, sdp_line_ptr, 83 dv_sdp_parse_fmtp_config); 84 } 85 86 return 0; 87} 88 89static int dv_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_dv_ctx, 90 AVStream *st, AVPacket *pkt, uint32_t *timestamp, 91 const uint8_t *buf, int len, uint16_t seq, 92 int flags) 93{ 94 int res = 0; 95 96 /* drop data of previous packets in case of non-continuous (lossy) packet stream */ 97 if (rtp_dv_ctx->buf && rtp_dv_ctx->timestamp != *timestamp) { 98 ffio_free_dyn_buf(&rtp_dv_ctx->buf); 99 } 100 101 /* sanity check for size of input packet: 1 byte payload at least */ 102 if (len < 1) { 103 av_log(ctx, AV_LOG_ERROR, "Too short RTP/DV packet, got %d bytes\n", len); 104 return AVERROR_INVALIDDATA; 105 } 106 107 /* start frame buffering with new dynamic buffer */ 108 if (!rtp_dv_ctx->buf) { 109 res = avio_open_dyn_buf(&rtp_dv_ctx->buf); 110 if (res < 0) 111 return res; 112 /* update the timestamp in the frame packet with the one from the RTP packet */ 113 rtp_dv_ctx->timestamp = *timestamp; 114 } 115 116 /* write the fragment to the dyn. buffer */ 117 avio_write(rtp_dv_ctx->buf, buf, len); 118 119 /* RTP marker bit means: last fragment of current frame was received; 120 otherwise, an additional fragment is needed for the current frame */ 121 if (!(flags & RTP_FLAG_MARKER)) 122 return AVERROR(EAGAIN); 123 124 /* close frame buffering and create resulting A/V packet */ 125 res = ff_rtp_finalize_packet(pkt, &rtp_dv_ctx->buf, st->index); 126 if (res < 0) 127 return res; 128 129 return 0; 130} 131 132const RTPDynamicProtocolHandler ff_dv_dynamic_handler = { 133 .enc_name = "DV", 134 .codec_type = AVMEDIA_TYPE_VIDEO, 135 .codec_id = AV_CODEC_ID_DVVIDEO, 136 .need_parsing = AVSTREAM_PARSE_FULL, 137 .parse_sdp_a_line = dv_parse_sdp_line, 138 .priv_data_size = sizeof(PayloadContext), 139 .close = dv_close_context, 140 .parse_packet = dv_handle_packet, 141}; 142