2 * RTP Depacketization of QCELP/PureVoice, RFC 2658
3 * Copyright (c) 2010 Martin Storsjo
5 * This file is part of FFmpeg.
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.
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.
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
22 #include "rtpdec_formats.h"
24 static const uint8_t frame_sizes
[] = {
31 /* The largest frame is 35 bytes, only 10 frames are allowed per
32 * packet, and we return the first one immediately, so allocate
33 * space for 9 frames */
37 struct PayloadContext
{
40 InterleavePacket group
[6];
43 /* The maximum packet size, 10 frames of 35 bytes each, and one
44 * packet header byte. */
45 uint8_t next_data
[1 + 35*10];
47 uint32_t next_timestamp
;
50 static PayloadContext
*qcelp_new_context(void)
52 return av_mallocz(sizeof(PayloadContext
));
55 static void qcelp_free_context(PayloadContext
*data
)
60 static int return_stored_frame(AVFormatContext
*ctx
, PayloadContext
*data
,
61 AVStream
*st
, AVPacket
*pkt
, uint32_t *timestamp
,
62 const uint8_t *buf
, int len
);
64 static int store_packet(AVFormatContext
*ctx
, PayloadContext
*data
,
65 AVStream
*st
, AVPacket
*pkt
, uint32_t *timestamp
,
66 const uint8_t *buf
, int len
)
68 int interleave_size
, interleave_index
;
73 return AVERROR_INVALIDDATA
;
75 interleave_size
= buf
[0] >> 3 & 7;
76 interleave_index
= buf
[0] & 7;
78 if (interleave_size
> 5) {
79 av_log(ctx
, AV_LOG_ERROR
, "Invalid interleave size %d\n",
81 return AVERROR_INVALIDDATA
;
83 if (interleave_index
> interleave_size
) {
84 av_log(ctx
, AV_LOG_ERROR
, "Invalid interleave index %d/%d\n",
85 interleave_index
, interleave_size
);
86 return AVERROR_INVALIDDATA
;
88 if (interleave_size
!= data
->interleave_size
) {
90 /* First packet, or changed interleave size */
91 data
->interleave_size
= interleave_size
;
92 data
->interleave_index
= 0;
93 for (i
= 0; i
< 6; i
++)
94 data
->group
[i
].size
= 0;
97 if (interleave_index
< data
->interleave_index
) {
98 /* Wrapped around - missed the last packet of the previous group. */
99 if (data
->group_finished
) {
100 /* No more data in the packets in this interleaving group, just
101 * start processing the next one */
102 data
->interleave_index
= 0;
104 /* Stash away the current packet, emit everything we have of the
106 for (; data
->interleave_index
<= interleave_size
;
107 data
->interleave_index
++)
108 data
->group
[data
->interleave_index
].size
= 0;
110 if (len
> sizeof(data
->next_data
))
111 return AVERROR_INVALIDDATA
;
112 memcpy(data
->next_data
, buf
, len
);
113 data
->next_size
= len
;
114 data
->next_timestamp
= *timestamp
;
115 *timestamp
= RTP_NOTS_VALUE
;
117 data
->interleave_index
= 0;
118 return return_stored_frame(ctx
, data
, st
, pkt
, timestamp
, buf
, len
);
121 if (interleave_index
> data
->interleave_index
) {
122 /* We missed a packet */
123 for (; data
->interleave_index
< interleave_index
;
124 data
->interleave_index
++)
125 data
->group
[data
->interleave_index
].size
= 0;
127 data
->interleave_index
= interleave_index
;
129 if (buf
[1] >= FF_ARRAY_ELEMS(frame_sizes
))
130 return AVERROR_INVALIDDATA
;
131 frame_size
= frame_sizes
[buf
[1]];
132 if (1 + frame_size
> len
)
133 return AVERROR_INVALIDDATA
;
135 if (len
- 1 - frame_size
> sizeof(data
->group
[0].data
))
136 return AVERROR_INVALIDDATA
;
138 if ((ret
= av_new_packet(pkt
, frame_size
)) < 0)
140 memcpy(pkt
->data
, &buf
[1], frame_size
);
141 pkt
->stream_index
= st
->index
;
143 ip
= &data
->group
[data
->interleave_index
];
144 ip
->size
= len
- 1 - frame_size
;
146 memcpy(ip
->data
, &buf
[1 + frame_size
], ip
->size
);
147 /* Each packet must contain the same number of frames according to the
148 * RFC. If there's no data left in this packet, there shouldn't be any
149 * in any of the other frames in the interleaving group either. */
150 data
->group_finished
= ip
->size
== 0;
152 if (interleave_index
== interleave_size
) {
153 data
->interleave_index
= 0;
154 return !data
->group_finished
;
156 data
->interleave_index
++;
161 static int return_stored_frame(AVFormatContext
*ctx
, PayloadContext
*data
,
162 AVStream
*st
, AVPacket
*pkt
, uint32_t *timestamp
,
163 const uint8_t *buf
, int len
)
165 InterleavePacket
* ip
= &data
->group
[data
->interleave_index
];
168 if (data
->group_finished
&& data
->interleave_index
== 0) {
169 *timestamp
= data
->next_timestamp
;
170 ret
= store_packet(ctx
, data
, st
, pkt
, timestamp
, data
->next_data
,
177 /* No stored data for this interleave block, output an empty packet */
178 if ((ret
= av_new_packet(pkt
, 1)) < 0)
180 pkt
->data
[0] = 0; // Blank - could also be 14, Erasure
182 if (ip
->pos
>= ip
->size
)
183 return AVERROR_INVALIDDATA
;
184 if (ip
->data
[ip
->pos
] >= FF_ARRAY_ELEMS(frame_sizes
))
185 return AVERROR_INVALIDDATA
;
186 frame_size
= frame_sizes
[ip
->data
[ip
->pos
]];
187 if (ip
->pos
+ frame_size
> ip
->size
)
188 return AVERROR_INVALIDDATA
;
190 if ((ret
= av_new_packet(pkt
, frame_size
)) < 0)
192 memcpy(pkt
->data
, &ip
->data
[ip
->pos
], frame_size
);
194 ip
->pos
+= frame_size
;
195 data
->group_finished
= ip
->pos
>= ip
->size
;
197 pkt
->stream_index
= st
->index
;
199 if (data
->interleave_index
== data
->interleave_size
) {
200 data
->interleave_index
= 0;
201 if (!data
->group_finished
)
204 return data
->next_size
> 0;
206 data
->interleave_index
++;
211 static int qcelp_parse_packet(AVFormatContext
*ctx
, PayloadContext
*data
,
212 AVStream
*st
, AVPacket
*pkt
, uint32_t *timestamp
,
213 const uint8_t *buf
, int len
, uint16_t seq
,
217 return store_packet(ctx
, data
, st
, pkt
, timestamp
, buf
, len
);
219 return return_stored_frame(ctx
, data
, st
, pkt
, timestamp
, buf
, len
);
222 RTPDynamicProtocolHandler ff_qcelp_dynamic_handler
= {
223 .enc_name
= "x-Purevoice",
224 .codec_type
= AVMEDIA_TYPE_AUDIO
,
225 .codec_id
= AV_CODEC_ID_QCELP
,
226 .static_payload_id
= 12,
227 .alloc
= qcelp_new_context
,
228 .free
= qcelp_free_context
,
229 .parse_packet
= qcelp_parse_packet