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