• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
27 struct PayloadContext {
28     AVIOContext *buf;
29     uint32_t    timestamp;
30     int         bundled_audio;
31 };
32 
dv_close_context(PayloadContext * data)33 static av_cold void dv_close_context(PayloadContext *data)
34 {
35     ffio_free_dyn_buf(&data->buf);
36 }
37 
dv_sdp_parse_fmtp_config(AVFormatContext * s,AVStream * stream,PayloadContext * dv_data,const char * attr,const char * value)38 static 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 
dv_parse_sdp_line(AVFormatContext * ctx,int st_index,PayloadContext * dv_data,const char * line)70 static 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 
dv_handle_packet(AVFormatContext * ctx,PayloadContext * rtp_dv_ctx,AVStream * st,AVPacket * pkt,uint32_t * timestamp,const uint8_t * buf,int len,uint16_t seq,int flags)89 static 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 
132 const 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