00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00028 #include <string.h>
00029 #include "libavutil/intreadwrite.h"
00030 #include "libavcodec/avcodec.h"
00031 #include "rtp.h"
00032 #include "rtpdec.h"
00033 #include "rtpdec_formats.h"
00034
00035 struct PayloadContext {
00038 int block_type;
00039 int block_size;
00040 int subpkts_per_block;
00041
00042
00045 uint16_t len[0x80];
00046 uint8_t buf[0x80][0x800];
00047
00048 unsigned int cache;
00049 unsigned int n_pkts;
00050 uint32_t timestamp;
00051
00052 };
00053
00075 static int qdm2_parse_config(PayloadContext *qdm, AVStream *st,
00076 const uint8_t *buf, const uint8_t *end)
00077 {
00078 const uint8_t *p = buf;
00079
00080 while (end - p >= 2) {
00081 unsigned int item_len = p[0], config_item = p[1];
00082
00083 if (item_len < 2 || end - p < item_len || config_item > 4)
00084 return AVERROR_INVALIDDATA;
00085
00086 switch (config_item) {
00087 case 0:
00088 return p - buf + item_len;
00089 case 1:
00090
00091 break;
00092 case 2:
00093 if (item_len < 3)
00094 return AVERROR_INVALIDDATA;
00095 qdm->subpkts_per_block = p[2];
00096 break;
00097 case 3:
00098 if (item_len < 4)
00099 return AVERROR_INVALIDDATA;
00100 qdm->block_type = AV_RB16(p + 2);
00101 break;
00102 case 4:
00103 if (item_len < 30)
00104 return AVERROR_INVALIDDATA;
00105 av_freep(&st->codec->extradata);
00106 st->codec->extradata_size = 26 + item_len;
00107 if (!(st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE))) {
00108 st->codec->extradata_size = 0;
00109 return AVERROR(ENOMEM);
00110 }
00111 AV_WB32(st->codec->extradata, 12);
00112 memcpy(st->codec->extradata + 4, "frma", 4);
00113 memcpy(st->codec->extradata + 8, "QDM2", 4);
00114 AV_WB32(st->codec->extradata + 12, 6 + item_len);
00115 memcpy(st->codec->extradata + 16, "QDCA", 4);
00116 memcpy(st->codec->extradata + 20, p + 2, item_len - 2);
00117 AV_WB32(st->codec->extradata + 18 + item_len, 8);
00118 AV_WB32(st->codec->extradata + 22 + item_len, 0);
00119
00120 qdm->block_size = AV_RB32(p + 26);
00121 break;
00122 }
00123
00124 p += item_len;
00125 }
00126
00127 return AVERROR(EAGAIN);
00128 }
00129
00152 static int qdm2_parse_subpacket(PayloadContext *qdm, AVStream *st,
00153 const uint8_t *buf, const uint8_t *end)
00154 {
00155 const uint8_t *p = buf;
00156 unsigned int id, len, type, to_copy;
00157
00158
00159 id = *p++;
00160 type = *p++;
00161 if (type & 0x80) {
00162 len = AV_RB16(p);
00163 p += 2;
00164 type &= 0x7F;
00165 } else
00166 len = *p++;
00167
00168 if (end - p < len + (type == 0x7F) || id >= 0x80)
00169 return AVERROR_INVALIDDATA;
00170 if (type == 0x7F)
00171 type |= *p++ << 8;
00172
00173
00174 to_copy = FFMIN(len + (p - &buf[1]), 0x800 - qdm->len[id]);
00175 memcpy(&qdm->buf[id][qdm->len[id]], buf + 1, to_copy);
00176 qdm->len[id] += to_copy;
00177
00178 return p + len - buf;
00179 }
00180
00186 static int qdm2_restore_block(PayloadContext *qdm, AVStream *st, AVPacket *pkt)
00187 {
00188 int to_copy, n, res, include_csum;
00189 uint8_t *p, *csum_pos = NULL;
00190
00191
00192 assert(qdm->cache > 0);
00193 for (n = 0; n < 0x80; n++)
00194 if (qdm->len[n] > 0)
00195 break;
00196 assert(n < 0x80);
00197
00198 if ((res = av_new_packet(pkt, qdm->block_size)) < 0)
00199 return res;
00200 memset(pkt->data, 0, pkt->size);
00201 pkt->stream_index = st->index;
00202 p = pkt->data;
00203
00204
00205 if (qdm->len[n] > 0xff) {
00206 *p++ = qdm->block_type | 0x80;
00207 AV_WB16(p, qdm->len[n]);
00208 p += 2;
00209 } else {
00210 *p++ = qdm->block_type;
00211 *p++ = qdm->len[n];
00212 }
00213 if ((include_csum = (qdm->block_type == 2 || qdm->block_type == 4))) {
00214 csum_pos = p;
00215 p += 2;
00216 }
00217
00218
00219 to_copy = FFMIN(qdm->len[n], pkt->size - (p - pkt->data));
00220 memcpy(p, qdm->buf[n], to_copy);
00221 qdm->len[n] = 0;
00222
00223
00224 if (include_csum) {
00225 unsigned int total = 0;
00226 uint8_t *q;
00227
00228 for (q = pkt->data; q < &pkt->data[qdm->block_size]; q++)
00229 total += *q;
00230 AV_WB16(csum_pos, (uint16_t) total);
00231 }
00232
00233 return 0;
00234 }
00235
00237 static int qdm2_parse_packet(AVFormatContext *s, PayloadContext *qdm,
00238 AVStream *st, AVPacket *pkt,
00239 uint32_t *timestamp,
00240 const uint8_t *buf, int len, int flags)
00241 {
00242 int res = AVERROR_INVALIDDATA, n;
00243 const uint8_t *end = buf + len, *p = buf;
00244
00245 if (len > 0) {
00246 if (len < 2)
00247 return AVERROR_INVALIDDATA;
00248
00249
00250 if (*p == 0xff) {
00251 if (qdm->n_pkts > 0) {
00252 av_log(s, AV_LOG_WARNING,
00253 "Out of sequence config - dropping queue\n");
00254 qdm->n_pkts = 0;
00255 memset(qdm->len, 0, sizeof(qdm->len));
00256 }
00257
00258 if ((res = qdm2_parse_config(qdm, st, ++p, end)) < 0)
00259 return res;
00260 p += res;
00261
00262
00263
00264
00265
00266
00267 st->codec->codec_id = AV_CODEC_ID_QDM2;
00268 }
00269 if (st->codec->codec_id == AV_CODEC_ID_NONE)
00270 return AVERROR(EAGAIN);
00271
00272
00273 while (end - p >= 4) {
00274 if ((res = qdm2_parse_subpacket(qdm, st, p, end)) < 0)
00275 return res;
00276 p += res;
00277 }
00278
00279 qdm->timestamp = *timestamp;
00280 if (++qdm->n_pkts < qdm->subpkts_per_block)
00281 return AVERROR(EAGAIN);
00282 qdm->cache = 0;
00283 for (n = 0; n < 0x80; n++)
00284 if (qdm->len[n] > 0)
00285 qdm->cache++;
00286 }
00287
00288
00289 if (!qdm->cache || (res = qdm2_restore_block(qdm, st, pkt)) < 0)
00290 return res;
00291 if (--qdm->cache == 0)
00292 qdm->n_pkts = 0;
00293
00294 *timestamp = qdm->timestamp;
00295 qdm->timestamp = RTP_NOTS_VALUE;
00296
00297 return (qdm->cache > 0) ? 1 : 0;
00298 }
00299
00300 static PayloadContext *qdm2_extradata_new(void)
00301 {
00302 return av_mallocz(sizeof(PayloadContext));
00303 }
00304
00305 static void qdm2_extradata_free(PayloadContext *qdm)
00306 {
00307 av_free(qdm);
00308 }
00309
00310 RTPDynamicProtocolHandler ff_qdm2_dynamic_handler = {
00311 .enc_name = "X-QDM",
00312 .codec_type = AVMEDIA_TYPE_AUDIO,
00313 .codec_id = AV_CODEC_ID_NONE,
00314 .alloc = qdm2_extradata_new,
00315 .free = qdm2_extradata_free,
00316 .parse_packet = qdm2_parse_packet,
00317 };