1/*
2Copyright (c) 2012, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the copyright holder nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27#include <stdlib.h>
28#include <stdio.h>
29#include <string.h>
30
31#define CONTAINER_IS_BIG_ENDIAN
32//#define ENABLE_CONTAINERS_LOG_FORMAT
33//#define ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
34#define CONTAINER_HELPER_LOG_INDENT(a) 0
35#include "containers/core/containers_private.h"
36#include "containers/core/containers_io_helpers.h"
37#include "containers/core/containers_utils.h"
38#include "containers/core/containers_uri.h"
39#include "containers/core/containers_logging.h"
40#include "containers/core/containers_bits.h"
41#include "containers/core/containers_list.h"
42
43#include "rtp_priv.h"
44#include "rtp_mpeg4.h"
45#include "rtp_h264.h"
46
47#ifdef _DEBUG
48/* Validates static sorted lists are correctly constructed */
49#define RTP_DEBUG 1
50#endif
51
52/******************************************************************************
53Configurable defines and constants.
54******************************************************************************/
55
56/** Maximum size of an RTP packet */
57#define MAXIMUM_PACKET_SIZE 2048
58
59/** Maximum number of RTP packets that can be missed without restarting. */
60#define MAX_DROPOUT 3000
61/** Maximum number of out of sequence RTP packets that are accepted. */
62#define MAX_MISORDER 0
63/** Minimum number of sequential packets required for an acceptable connection
64 * when restarting. */
65#define MIN_SEQUENTIAL 2
66
67/******************************************************************************
68Defines and constants.
69******************************************************************************/
70
71#define RTP_SCHEME "rtp:"
72
73/** The RTP PKT scheme is used with test pkt files */
74#define RTP_PKT_SCHEME "rtppkt:"
75
76/** \name RTP URI parameter names
77 * @{ */
78#define PAYLOAD_TYPE_NAME "rtppt"
79#define MIME_TYPE_NAME "mime-type"
80#define CHANNELS_NAME "channels"
81#define RATE_NAME "rate"
82#define SSRC_NAME "ssrc"
83#define SEQ_NAME "seq"
84/* @} */
85
86/** A sentinel codec that is not supported */
87#define UNSUPPORTED_CODEC VC_FOURCC(0,0,0,0)
88
89/** Evaluates to true if the given payload type is in the supported static audio range. */
90#define IS_STATIC_AUDIO_TYPE(PT) ((PT) < countof(static_audio_payload_types))
91
92/** Payload type number for the first static video type */
93#define FIRST_STATIC_VIDEO_TYPE 24
94/** Evaluates to true if the given payload type is in the supported static video range. */
95#define IS_STATIC_VIDEO_TYPE(PT) ((PT) >= FIRST_STATIC_VIDEO_TYPE && \
96 (PT) < (FIRST_STATIC_VIDEO_TYPE + countof(static_video_payload_types)))
97
98/** Evaluates to true if the given payload type is in the dynamic range. */
99#define IS_DYNAMIC_TYPE(PT) ((PT) >= 96 && (PT) < 128)
100
101/** All sequence numbers are modulo this value. */
102#define RTP_SEQ_MOD (1 << 16)
103
104/** All the static video payload types use a 90kHz timestamp clock */
105#define STATIC_VIDEO_TIMESTAMP_CLOCK 90000
106
107/** Number of microseconds in a second, used to convert RTP timestamps to microseconds */
108#define MICROSECONDS_PER_SECOND 1000000
109
110/******************************************************************************
111Type definitions
112******************************************************************************/
113
114/** \name MIME type parameter handlers
115 * Function prototypes for payload parameter handlers */
116/* @{ */
117static VC_CONTAINER_STATUS_T audio_parameter_handler(VC_CONTAINER_T *p_ctx, VC_CONTAINER_TRACK_T *track, const VC_CONTAINERS_LIST_T *params);
118static VC_CONTAINER_STATUS_T l8_parameter_handler(VC_CONTAINER_T *p_ctx, VC_CONTAINER_TRACK_T *track, const VC_CONTAINERS_LIST_T *params);
119static VC_CONTAINER_STATUS_T l16_parameter_handler(VC_CONTAINER_T *p_ctx, VC_CONTAINER_TRACK_T *track, const VC_CONTAINERS_LIST_T *params);
120/* @} */
121
122/** \name MIME type payload handlers */
123/* @{ */
124static VC_CONTAINER_STATUS_T l16_payload_handler(VC_CONTAINER_T *p_ctx, VC_CONTAINER_TRACK_T *track,
125 VC_CONTAINER_PACKET_T *p_packet, uint32_t flags);
126/* @} */
127
128/** Static audio payload type data */
129typedef struct audio_payload_type_data_tag
130{
131 VC_CONTAINER_FOURCC_T codec; /**< FourCC codec for this payload type */
132 uint32_t channels; /**< Number of audio channels */
133 uint32_t sample_rate; /**< Sample rate */
134 uint32_t bits_per_sample; /**< Bits per sample, or 1 if not applicable */
135 PARAMETER_HANDLER_T param_handler; /**< Optional parameter handler */
136 PAYLOAD_HANDLER_T payload_handler; /**< Optional payload handler */
137} AUDIO_PAYLOAD_TYPE_DATA_T;
138
139/** The details for the statically defined audio payload types from RFC3551 */
140static AUDIO_PAYLOAD_TYPE_DATA_T static_audio_payload_types[] =
141{
142 { VC_CONTAINER_CODEC_MULAW, 1, 8000, 8, audio_parameter_handler, NULL }, /* 0 - PCMU */
143 { UNSUPPORTED_CODEC }, /* 1 - reserved */
144 { UNSUPPORTED_CODEC }, /* 2 - reserved */
145 { UNSUPPORTED_CODEC, 1, 8000, 1, NULL, NULL }, /* 3 - GSM */
146 { UNSUPPORTED_CODEC, 1, 8000, 1, NULL, NULL }, /* 4 - G723 */
147 { UNSUPPORTED_CODEC, 1, 8000, 4, NULL, NULL }, /* 5 - DVI4 */
148 { UNSUPPORTED_CODEC, 1, 16000, 4, NULL, NULL }, /* 6 - DVI4 */
149 { UNSUPPORTED_CODEC, 1, 8000, 1, NULL, NULL }, /* 7 - LPC */
150 { VC_CONTAINER_CODEC_ALAW, 1, 8000, 8, audio_parameter_handler, NULL }, /* 8 - PCMA */
151 { UNSUPPORTED_CODEC, 1, 8000, 8, NULL, NULL }, /* 9 - G722 */
152 { VC_CONTAINER_CODEC_PCM_SIGNED, 2, 44100, 16, audio_parameter_handler, l16_payload_handler }, /* 10 - L16 */
153 { VC_CONTAINER_CODEC_PCM_SIGNED, 1, 44100, 16, audio_parameter_handler, l16_payload_handler }, /* 11 - L16 */
154 { VC_CONTAINER_CODEC_QCELP, 1, 8000, 16, NULL, NULL }, /* 12 - QCELP */
155 { UNSUPPORTED_CODEC, 1, 8000, 1, NULL, NULL }, /* 13 - CN */
156 { VC_CONTAINER_CODEC_MPGA, 1, 90000, 1, NULL, NULL }, /* 14 - MPA */
157 { UNSUPPORTED_CODEC, 1, 8000, 1, NULL, NULL }, /* 15 - G728 */
158 { UNSUPPORTED_CODEC, 1, 11025, 4, NULL, NULL }, /* 16 - DVI4 */
159 { UNSUPPORTED_CODEC, 1, 22050, 4, NULL, NULL }, /* 17 - DVI4 */
160 { UNSUPPORTED_CODEC, 1, 8000, 1, NULL, NULL }, /* 18 - G729 */
161};
162
163/** Static video payload type data */
164typedef struct video_payload_type_data_tag
165{
166 VC_CONTAINER_FOURCC_T codec; /**< FourCC codec for this payload type */
167 PARAMETER_HANDLER_T param_handler; /**< Optional parameter handler */
168 PAYLOAD_HANDLER_T payload_handler; /**< Optional payload handler */
169} VIDEO_PAYLOAD_TYPE_DATA_T;
170
171/** The details for the statically defined video payload types from RFC3551 */
172static VIDEO_PAYLOAD_TYPE_DATA_T static_video_payload_types[] =
173{
174 { UNSUPPORTED_CODEC }, /* 24 - unassigned */
175 { UNSUPPORTED_CODEC }, /* 25 - CelB */
176 { UNSUPPORTED_CODEC }, /* 26 - JPEG */
177 { UNSUPPORTED_CODEC }, /* 27 - unassigned */
178 { UNSUPPORTED_CODEC }, /* 28 - nv */
179 { UNSUPPORTED_CODEC }, /* 29 - unassigned */
180 { UNSUPPORTED_CODEC }, /* 30 - unassigned */
181 { UNSUPPORTED_CODEC }, /* 31 - H261 */
182 { VC_CONTAINER_CODEC_MP2V, NULL, NULL }, /* 32 - MPV */
183 { UNSUPPORTED_CODEC }, /* 33 - MP2T */
184 { VC_CONTAINER_CODEC_H263, NULL, NULL } /* 34 - H263 */
185};
186
187/** MIME type details */
188typedef struct mime_type_data_tag
189{
190 const char *name; /**< Name of MIME type */
191 VC_CONTAINER_ES_TYPE_T es_type; /**< Elementary stream type */
192 VC_CONTAINER_FOURCC_T codec; /**< Codec to be used */
193 PARAMETER_HANDLER_T param_handler; /**< Parameter handler for this MIME type */
194} MIME_TYPE_DATA_T;
195
196/** Comparator for MIME type details. */
197static int mime_type_data_comparator(const MIME_TYPE_DATA_T *a, const MIME_TYPE_DATA_T *b);
198
199/** Dynamic audio payload details
200 * Note: case-insensitive sort by name */
201static MIME_TYPE_DATA_T dynamic_mime_details[] = {
202 { "audio/l16", VC_CONTAINER_ES_TYPE_AUDIO, VC_CONTAINER_CODEC_PCM_SIGNED, l16_parameter_handler },
203 { "audio/l8", VC_CONTAINER_ES_TYPE_AUDIO, VC_CONTAINER_CODEC_PCM_SIGNED, l8_parameter_handler },
204 { "audio/mpeg4-generic", VC_CONTAINER_ES_TYPE_AUDIO, VC_CONTAINER_CODEC_MP4A, mp4_parameter_handler },
205 { "video/h264", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_H264, h264_parameter_handler },
206 { "video/mpeg4-generic", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_MP4V, mp4_parameter_handler },
207};
208
209/** Sorted list of dynamic MIME type details */
210VC_CONTAINERS_STATIC_LIST(dynamic_mime, dynamic_mime_details, mime_type_data_comparator);
211
212/** RTP reader data. */
213typedef struct VC_CONTAINER_MODULE_T
214{
215 VC_CONTAINER_TRACK_T *track;
216} VC_CONTAINER_MODULE_T;
217
218/******************************************************************************
219Function prototypes
220******************************************************************************/
221VC_CONTAINER_STATUS_T rtp_reader_open( VC_CONTAINER_T * );
222
223/******************************************************************************
224Local Functions
225******************************************************************************/
226
227/**************************************************************************//**
228 * Parameter comparison function.
229 * Compare two parameter structures and return whether the first is less than,
230 * equal to or greater than the second.
231 *
232 * @param first The first structure to be compared.
233 * @param second The second structure to be compared.
234 * @return Negative if first is less than second, positive if first is greater
235 * and zero if they are equal.
236 */
237static int parameter_comparator(const PARAMETER_T *first, const PARAMETER_T *second)
238{
239 return strcasecmp(first->name, second->name);
240}
241
242/**************************************************************************//**
243 * Creates and populates a parameter list from a URI structure.
244 * The list does not copy the parameter strings themselves, so the URI structure
245 * must be retained (and its parameters unmodified) while the list is in use.
246 *
247 * @param uri The URI containing the parameters.
248 * @return List created from the parameters of the URI, or NULL on error.
249 */
250static VC_CONTAINERS_LIST_T *fill_parameter_list(VC_URI_PARTS_T *uri)
251{
252 uint32_t num_parameters = vc_uri_num_queries(uri);
253 VC_CONTAINERS_LIST_T *parameters;
254 uint32_t ii;
255
256 parameters = vc_containers_list_create(num_parameters, sizeof(PARAMETER_T), (VC_CONTAINERS_LIST_COMPARATOR_T)parameter_comparator);
257 if (!parameters)
258 return NULL;
259
260 for (ii = 0; ii < num_parameters; ii++)
261 {
262 PARAMETER_T param;
263
264 vc_uri_query(uri, ii, &param.name, &param.value);
265 if (!vc_containers_list_insert(parameters, &param, false))
266 {
267 vc_containers_list_destroy(parameters);
268 return NULL;
269 }
270 }
271
272#ifdef RTP_DEBUG
273 vc_containers_list_validate(parameters);
274#endif
275
276 return parameters;
277}
278
279/**************************************************************************//**
280 * Decodes a static audio payload type into track information.
281 * The static parameters may be overridden by URI parameters.
282 *
283 * @param p_ctx The reader context.
284 * @param track The track to be populated.
285 * @param param_list The URI parameter list.
286 * @param payload_type The static payload type.
287 * @return The resulting status of the function.
288 */
289static VC_CONTAINER_STATUS_T decode_static_audio_type(VC_CONTAINER_T *p_ctx,
290 VC_CONTAINER_TRACK_T *track,
291 const VC_CONTAINERS_LIST_T *param_list,
292 uint32_t payload_type)
293{
294 VC_CONTAINER_ES_FORMAT_T *format = track->format;
295 AUDIO_PAYLOAD_TYPE_DATA_T *data = &static_audio_payload_types[payload_type];
296
297 VC_CONTAINER_PARAM_UNUSED(p_ctx);
298 VC_CONTAINER_PARAM_UNUSED(param_list);
299
300 vc_container_assert(payload_type < countof(static_audio_payload_types));
301
302 if (data->codec == UNSUPPORTED_CODEC)
303 return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
304
305 format->es_type = VC_CONTAINER_ES_TYPE_AUDIO;
306 format->codec = data->codec;
307 format->type->audio.channels = data->channels;
308 format->type->audio.sample_rate = data->sample_rate;
309 format->type->audio.bits_per_sample = data->bits_per_sample;
310 format->type->audio.block_align = data->channels * BITS_TO_BYTES(data->bits_per_sample);
311 track->priv->module->timestamp_clock = format->type->audio.sample_rate;
312 track->priv->module->payload_handler = data->payload_handler;
313
314 if (data->param_handler)
315 data->param_handler(p_ctx, track, param_list);
316
317 return VC_CONTAINER_SUCCESS;
318}
319
320/**************************************************************************//**
321 * Decodes a static video payload type into track information.
322 * The static parameters may be overridden by URI parameters.
323 *
324 * @param p_ctx The reader context.
325 * @param track The track to be populated.
326 * @param param_list The URI parameter list.
327 * @param payload_type The static payload type.
328 * @return The resulting status of the function.
329 */
330static VC_CONTAINER_STATUS_T decode_static_video_type(VC_CONTAINER_T *p_ctx,
331 VC_CONTAINER_TRACK_T *track,
332 const VC_CONTAINERS_LIST_T *param_list,
333 uint32_t payload_type)
334{
335 VC_CONTAINER_ES_FORMAT_T *format = track->format;
336 VIDEO_PAYLOAD_TYPE_DATA_T *data = &static_video_payload_types[payload_type - FIRST_STATIC_VIDEO_TYPE];
337
338 VC_CONTAINER_PARAM_UNUSED(p_ctx);
339 VC_CONTAINER_PARAM_UNUSED(param_list);
340
341 vc_container_assert(payload_type >= FIRST_STATIC_VIDEO_TYPE);
342 vc_container_assert(payload_type < FIRST_STATIC_VIDEO_TYPE + countof(static_video_payload_types));
343
344 if (data->codec == UNSUPPORTED_CODEC)
345 return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
346
347 format->es_type = VC_CONTAINER_ES_TYPE_VIDEO;
348 format->codec = data->codec;
349 track->priv->module->timestamp_clock = STATIC_VIDEO_TIMESTAMP_CLOCK;
350 track->priv->module->payload_handler = data->payload_handler;
351
352 if (data->param_handler)
353 data->param_handler(p_ctx, track, param_list);
354
355 return VC_CONTAINER_SUCCESS;
356}
357
358/**************************************************************************//**
359 * Compare two MIME type structures and return whether the first is less than,
360 * equal to or greater than the second.
361 *
362 * @param a The first parameter structure to be compared.
363 * @param b The second parameter structure to be compared.
364 * @return Negative if a is less than b, positive if a is greater and zero if
365 * they are equal.
366 */
367static int mime_type_data_comparator(const MIME_TYPE_DATA_T *a, const MIME_TYPE_DATA_T *b)
368{
369 return strcasecmp(a->name, b->name);
370}
371
372/**************************************************************************//**
373 * Generic audio parameter handler.
374 * Updates the track information with generic audio parameters, such as "rate"
375 * and "channels".
376 *
377 * @param p_ctx The reader context.
378 * @param track The track to be updated.
379 * @param params The URI parameter list.
380 * @return The resulting status of the function.
381 */
382static VC_CONTAINER_STATUS_T audio_parameter_handler(VC_CONTAINER_T *p_ctx,
383 VC_CONTAINER_TRACK_T *track,
384 const VC_CONTAINERS_LIST_T *params)
385{
386 VC_CONTAINER_AUDIO_FORMAT_T *audio = &track->format->type->audio;
387
388 VC_CONTAINER_PARAM_UNUSED(p_ctx);
389
390 /* See RFC3555. Generic audio parameters that can override static payload
391 * type defaults. */
392 if (rtp_get_parameter_u32(params, RATE_NAME, &audio->sample_rate))
393 track->priv->module->timestamp_clock = audio->sample_rate;
394 if (rtp_get_parameter_u32(params, CHANNELS_NAME, &audio->channels))
395 audio->block_align = audio->channels * BITS_TO_BYTES(audio->bits_per_sample);
396
397 return VC_CONTAINER_SUCCESS;
398}
399
400/**************************************************************************//**
401 * L8 specific audio parameter handler.
402 * Updates the track information with audio parameters needed by the audio/L8
403 * MIME type. For example, the "rate" parameter is mandatory.
404 *
405 * @param p_ctx The reader context.
406 * @param track The track to be updated.
407 * @param params The URI parameter list.
408 * @return The resulting status of the function.
409 */
410static VC_CONTAINER_STATUS_T l8_parameter_handler(VC_CONTAINER_T *p_ctx,
411 VC_CONTAINER_TRACK_T *track,
412 const VC_CONTAINERS_LIST_T *params)
413{
414 VC_CONTAINER_AUDIO_FORMAT_T *audio = &track->format->type->audio;
415
416 VC_CONTAINER_PARAM_UNUSED(p_ctx);
417
418 /* See RFC3555, section 4.1.14, for parameter names and details. */
419 if (!rtp_get_parameter_u32(params, RATE_NAME, &audio->sample_rate))
420 return VC_CONTAINER_ERROR_FORMAT_INVALID;
421 if (!rtp_get_parameter_u32(params, CHANNELS_NAME, &audio->channels))
422 audio->channels = 1;
423 audio->bits_per_sample = 8;
424 audio->block_align = audio->channels;
425 track->priv->module->timestamp_clock = audio->sample_rate;
426
427 return VC_CONTAINER_SUCCESS;
428}
429
430/**************************************************************************//**
431 * L16 specific audio parameter handler.
432 * Updates the track information with audio parameters needed by the audio/L16
433 * MIME type. For example, the "rate" parameter is mandatory.
434 *
435 * @param p_ctx The reader context.
436 * @param track The track to be updated.
437 * @param params The URI parameter list.
438 * @return The resulting status of the function.
439 */
440static VC_CONTAINER_STATUS_T l16_parameter_handler(VC_CONTAINER_T *p_ctx,
441 VC_CONTAINER_TRACK_T *track,
442 const VC_CONTAINERS_LIST_T *params)
443{
444 VC_CONTAINER_AUDIO_FORMAT_T *audio = &track->format->type->audio;
445
446 VC_CONTAINER_PARAM_UNUSED(p_ctx);
447
448 /* See RFC3555, section 4.1.15, for parameter names and details. */
449 if (!rtp_get_parameter_u32(params, RATE_NAME, &audio->sample_rate))
450 return VC_CONTAINER_ERROR_FORMAT_INVALID;
451 if (!rtp_get_parameter_u32(params, CHANNELS_NAME, &audio->channels))
452 audio->channels = 1;
453 audio->bits_per_sample = 16;
454 audio->block_align = audio->channels * 2;
455 track->priv->module->timestamp_clock = audio->sample_rate;
456 track->priv->module->payload_handler = l16_payload_handler;
457
458 /* TODO: add support for "channel-order" to set channel mapping */
459
460 return VC_CONTAINER_SUCCESS;
461}
462
463/**************************************************************************//**
464 * Decode a dynamic payload type from parameters.
465 * Populates the track information with data for supported dynamic media types.
466 *
467 * @param p_ctx The reader context.
468 * @param track The track to be updated.
469 * @param param_list The URI parameter list.
470 * @return The resulting status of the function.
471 */
472static VC_CONTAINER_STATUS_T decode_dynamic_type(VC_CONTAINER_T *p_ctx,
473 VC_CONTAINER_TRACK_T *track,
474 const VC_CONTAINERS_LIST_T *param_list)
475{
476 VC_CONTAINER_ES_FORMAT_T *format = track->format;
477 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
478 PARAMETER_T mime_type;
479 MIME_TYPE_DATA_T mime_details;
480
481 /* Get MIME type parameter */
482 mime_type.name = MIME_TYPE_NAME;
483 if (!vc_containers_list_find_entry(param_list, &mime_type))
484 return VC_CONTAINER_ERROR_FORMAT_INVALID;
485
486#ifdef RTP_DEBUG
487 vc_containers_list_validate(&dynamic_mime);
488#endif
489
490 /* Look up MIME type to see if it can be handled */
491 mime_details.name = mime_type.value;
492 if (!vc_containers_list_find_entry(&dynamic_mime, &mime_details))
493 return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
494
495 format->codec = mime_details.codec;
496 format->es_type = mime_details.es_type;
497
498 /* Default number of channels for audio is one */
499 if (mime_details.es_type == VC_CONTAINER_ES_TYPE_AUDIO)
500 format->type->audio.channels = 1;
501
502 /* Lete MIME type specific parameter handler deal with any other parameters */
503 status = mime_details.param_handler(p_ctx, track, param_list);
504
505 /* Ensure that the sample rate has been set for audio formats */
506 if (mime_details.es_type == VC_CONTAINER_ES_TYPE_AUDIO && !format->type->audio.sample_rate)
507 return VC_CONTAINER_ERROR_FORMAT_INVALID;
508
509 return status;
510}
511
512/**************************************************************************//**
513 * Decode the RTP payload type.
514 * Populates track information with data from static tables and the URI
515 * parameter list, according to the payload and MIME types.
516 *
517 * @param p_ctx The reader context.
518 * @param track The track to be updated.
519 * @param params The URI parameter list.
520 * @return The resulting status of the function.
521 */
522static VC_CONTAINER_STATUS_T decode_payload_type(VC_CONTAINER_T *p_ctx,
523 VC_CONTAINER_TRACK_T *track,
524 const VC_CONTAINERS_LIST_T *param_list,
525 uint32_t payload_type)
526{
527 VC_CONTAINER_TRACK_MODULE_T *module = track->priv->module;
528 VC_CONTAINER_STATUS_T status;
529
530 if (IS_STATIC_AUDIO_TYPE(payload_type))
531 status = decode_static_audio_type(p_ctx, track, param_list, payload_type);
532 else if (IS_STATIC_VIDEO_TYPE(payload_type))
533 status = decode_static_video_type(p_ctx, track, param_list, payload_type);
534 else if (IS_DYNAMIC_TYPE(payload_type))
535 status = decode_dynamic_type(p_ctx, track, param_list);
536 else
537 status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
538
539 module->payload_type = (uint8_t)payload_type;
540
541 return status;
542}
543
544/**************************************************************************//**
545 * Initialises the RTP sequence number algorithm with a new sequence number.
546 *
547 * @param t_module The track module.
548 * @param seq The new sequence number.
549 */
550static void init_sequence_number(VC_CONTAINER_TRACK_MODULE_T *t_module,
551 uint16_t seq)
552{
553 t_module->base_seq = seq;
554 t_module->max_seq_num = seq;
555 t_module->bad_seq = RTP_SEQ_MOD + 1; /* so seq == bad_seq is false */
556 t_module->received = 0;
557}
558
559/**************************************************************************//**
560 * Checks whether the sequence number for a packet is acceptable or not.
561 * The packet will be unacceptable if it is out of sequence by some degree, or
562 * if the packet sequence is still being established.
563 *
564 * @param t_module The track module.
565 * @param seq The new sequence number.
566 * @return True if the sequence number indicates the packet is acceptable
567 */
568static bool update_sequence_number(VC_CONTAINER_TRACK_MODULE_T *t_module,
569 uint16_t seq)
570{
571 uint16_t udelta = seq - t_module->max_seq_num;
572
573 /* NOTE: This source is derived from the example code in RFC3550, section A.1 */
574
575 /* Source is not valid until MIN_SEQUENTIAL packets with
576 * sequential sequence numbers have been received. */
577 if (t_module->probation)
578 {
579 /* packet is in sequence */
580 if (seq == t_module->max_seq_num + 1)
581 {
582 t_module->probation--;
583 t_module->max_seq_num = seq;
584 LOG_INFO(0, "RTP: Probation, %u more packet(s) to go at 0x%4.4hx", t_module->probation, seq);
585
586 if (!t_module->probation)
587 {
588 init_sequence_number(t_module, seq);
589 t_module->received++;
590 return 1;
591 }
592 } else {
593 t_module->probation = MIN_SEQUENTIAL - 1;
594 t_module->max_seq_num = seq;
595 LOG_INFO(0, "RTP: Probation reset, wait for %u packet(s) at 0x%4.4hx", t_module->probation, seq);
596 }
597 return 0;
598 } else if (udelta < MAX_DROPOUT)
599 {
600 if (!udelta)
601 {
602 /* Duplicate packet, drop it */
603 LOG_INFO(0, "RTP: Drop duplicate packet at 0x%4.4hx", seq);
604 return 0;
605 }
606 if (udelta > 1)
607 {
608 LOG_INFO(0, "RTP: Jumped by %hu packets to 0x%4.4hx", udelta, seq);
609 }
610 /* in order, with permissible gap */
611 t_module->max_seq_num = seq;
612 } else
613#if (MAX_MISORDER != 0)
614 /* When MAX_MISORDER is zero, always treat as out of order */
615 if (udelta <= RTP_SEQ_MOD - MAX_MISORDER)
616#endif
617 {
618 /* the sequence number made a very large jump */
619 if (seq == t_module->bad_seq)
620 {
621 LOG_INFO(0, "RTP: Misorder restart at 0x%4.4hx", seq);
622 /* Two sequential packets -- assume that the other side
623 * restarted without telling us so just re-sync
624 * (i.e., pretend this was the first packet). */
625 init_sequence_number(t_module, seq);
626 } else {
627 LOG_INFO(0, "RTP: Misorder at 0x%4.4hx, expected 0x%4.4hx", seq, t_module->max_seq_num);
628 t_module->bad_seq = (seq + 1) & (RTP_SEQ_MOD-1);
629 return 0;
630 }
631 }
632#if (MAX_MISORDER != 0)
633 else {
634 /* duplicate or reordered packet */
635
636 /* TODO: handle out of order packets */
637 }
638#endif
639 t_module->received++;
640 return 1;
641}
642
643/**************************************************************************//**
644 * Extract the fields of an RTP packet and validate it.
645 *
646 * @param p_ctx The reader context.
647 * @param t_module The track module.
648 * @return True if successful, false if there were not enough bits in the
649 * packet or the packet was invalid.
650 */
651static void decode_rtp_packet_header(VC_CONTAINER_T *p_ctx,
652 VC_CONTAINER_TRACK_MODULE_T *t_module)
653{
654 VC_CONTAINER_BITS_T *payload = &t_module->payload;
655 uint32_t version, has_padding, has_extension, csrc_count, has_marker;
656 uint32_t payload_type, ssrc;
657 uint16_t seq_num;
658
659 /* Break down fixed header area into component parts */
660 version = BITS_READ_U32(p_ctx, payload, 2, "Version");
661 has_padding = BITS_READ_U32(p_ctx, payload, 1, "Has padding");
662 has_extension = BITS_READ_U32(p_ctx, payload, 1, "Has extension");
663 csrc_count = BITS_READ_U32(p_ctx, payload, 4, "CSRC count");
664 has_marker = BITS_READ_U32(p_ctx, payload, 1, "Has marker");
665 payload_type = BITS_READ_U32(p_ctx, payload, 7, "Payload type");
666 seq_num = BITS_READ_U16(p_ctx, payload, 16, "Sequence number");
667 t_module->timestamp = BITS_READ_U32(p_ctx, payload, 32, "Timestamp");
668 ssrc = BITS_READ_U32(p_ctx, payload, 32, "SSRC");
669
670 /* If there was only a partial header, abort immediately */
671 if (!BITS_VALID(p_ctx, payload))
672 return;
673
674 /* Validate version, payload type, sequence number and SSRC, if set */
675 if (version != 2 || payload_type != t_module->payload_type)
676 {
677 BITS_INVALIDATE(p_ctx, payload);
678 return;
679 }
680 if (BIT_IS_SET(t_module->flags, TRACK_SSRC_SET) && (ssrc != t_module->expected_ssrc))
681 {
682 LOG_DEBUG(p_ctx, "RTP: Unexpected SSRC (0x%8.8X)", ssrc);
683 BITS_INVALIDATE(p_ctx, payload);
684 return;
685 }
686
687 /* Check sequence number indicates packet is usable */
688 if (!update_sequence_number(t_module, seq_num))
689 {
690 BITS_INVALIDATE(p_ctx, payload);
691 return;
692 }
693
694 /* Adjust to account for padding, CSRCs and extension */
695 if (has_padding)
696 {
697 VC_CONTAINER_BITS_T bit_stream;
698 uint32_t available = BITS_BYTES_AVAILABLE(p_ctx, payload);
699 uint8_t padding;
700
701 BITS_COPY_STREAM(p_ctx, &bit_stream, payload);
702 /* The last byte of the payload is the number of padding bytes, including itself */
703 BITS_SKIP_BYTES(p_ctx, &bit_stream, available - 1, "Skip to padding length");
704 padding = BITS_READ_U8(p_ctx, &bit_stream, 8, "Padding length");
705
706 BITS_REDUCE_BYTES(p_ctx, payload, padding, "Remove padding");
707 }
708
709 /* Each CSRC is 32 bits, so shift count up to skip the right number of bits */
710 BITS_SKIP(p_ctx, payload, csrc_count << 5, "CSRC section");
711
712 if (has_extension)
713 {
714 uint32_t extension_bits;
715
716 /* Extension header is 16-bit ID (which isn't needed), then 16-bit length in 32-bit words */
717 BITS_SKIP(p_ctx, payload, 16, "Extension ID");
718 extension_bits = BITS_READ_U32(p_ctx, payload, 16, "Extension length") << 5;
719 BITS_SKIP(p_ctx, payload, extension_bits, "Extension data");
720 }
721
722 /* Record whether or not this RTP packet had the marker bit set */
723 if (has_marker)
724 SET_BIT(t_module->flags, TRACK_HAS_MARKER);
725 else
726 CLEAR_BIT(t_module->flags, TRACK_HAS_MARKER);
727
728 /* If it hasn't been set independently, use the first timestamp as a baseline */
729 if (!t_module->timestamp_base)
730 t_module->timestamp_base = t_module->timestamp;
731 t_module->timestamp -= t_module->timestamp_base;
732}
733
734/**************************************************************************//**
735 * Generic payload handler.
736 * Copies/skips data verbatim from the packet payload.
737 *
738 * @param p_ctx The reader context.
739 * @param track The track being read.
740 * @param p_packet The container packet information, or NULL.
741 * @param flags The container read flags.
742 * @return The resulting status of the function.
743 */
744static VC_CONTAINER_STATUS_T generic_payload_handler(VC_CONTAINER_T *p_ctx,
745 VC_CONTAINER_TRACK_T *track,
746 VC_CONTAINER_PACKET_T *p_packet,
747 uint32_t flags)
748{
749 VC_CONTAINER_TRACK_MODULE_T *t_module = track->priv->module;
750 VC_CONTAINER_BITS_T *payload = &t_module->payload;
751 uint32_t size;
752
753 VC_CONTAINER_PARAM_UNUSED(p_ctx);
754
755 if (!p_packet)
756 {
757 /* Skip the rest of this RTP packet */
758 BITS_INVALIDATE(p_ctx, payload);
759 return VC_CONTAINER_SUCCESS;
760 }
761
762 /* Copy as much as possible into the client packet buffer */
763 size = BITS_BYTES_AVAILABLE(p_ctx, payload);
764
765 if (flags & VC_CONTAINER_READ_FLAG_SKIP)
766 BITS_SKIP_BYTES(p_ctx, payload, size, "Packet data");
767 else {
768 if (!(flags & VC_CONTAINER_READ_FLAG_INFO))
769 {
770 if (size > p_packet->buffer_size)
771 size = p_packet->buffer_size;
772
773 BITS_COPY_BYTES(p_ctx, payload, size, p_packet->data, "Packet data");
774 }
775 p_packet->size = size;
776 }
777
778 return VC_CONTAINER_SUCCESS;
779}
780
781/**************************************************************************//**
782 * L16 payload handler.
783 * Copies/skips data from the packet payload. On copy, swaps consecutive bytes
784 * in the data in order to get expected byte order.
785 *
786 * @param p_ctx The reader context.
787 * @param track The track being read.
788 * @param p_packet The container packet information, or NULL.
789 * @param flags The container read flags.
790 * @return The resulting status of the function.
791 */
792static VC_CONTAINER_STATUS_T l16_payload_handler(VC_CONTAINER_T *p_ctx,
793 VC_CONTAINER_TRACK_T *track,
794 VC_CONTAINER_PACKET_T *p_packet,
795 uint32_t flags)
796{
797 VC_CONTAINER_STATUS_T status;
798
799 /* Most aspects are handled adequately by the generic handler */
800 status = generic_payload_handler(p_ctx, track, p_packet, flags);
801 if (status != VC_CONTAINER_SUCCESS)
802 return status;
803
804 if (p_packet && !(flags & (VC_CONTAINER_READ_FLAG_SKIP | VC_CONTAINER_READ_FLAG_INFO)))
805 {
806 uint8_t *ptr, *end_ptr;
807
808 /* Ensure packet size is even */
809 p_packet->size &= ~1;
810
811 /* Swap bytes of each sample, to get host order instead of network order */
812 for (ptr = p_packet->data, end_ptr = ptr + p_packet->size; ptr < end_ptr; ptr += 2)
813 {
814 uint8_t high_byte = ptr[0];
815 ptr[0] = ptr[1];
816 ptr[1] = high_byte;
817 }
818 }
819
820 return status;
821}
822
823
824/*****************************************************************************
825Utility functions for use by RTP payload handlers
826 *****************************************************************************/
827
828/**************************************************************************//**
829 * Gets the value of a parameter as an unsigned 32-bit decimal integer.
830 *
831 * @param param_list The URI parameter list.
832 * @param name The name of the parameter.
833 * @param value Pointer to the variable to receive the value.
834 * @return True if the parameter value was read and stored correctly, false
835 * otherwise.
836 */
837bool rtp_get_parameter_u32(const VC_CONTAINERS_LIST_T *param_list,
838 const char *name,
839 uint32_t *value)
840{
841 PARAMETER_T param;
842
843 param.name = name;
844 if (vc_containers_list_find_entry(param_list, &param) && param.value)
845 {
846 char *end;
847
848 *value = strtoul(param.value, &end, 10);
849 return (end != param.value) && (*end == '\0');
850 }
851
852 return false;
853}
854
855/**************************************************************************//**
856 * Gets the value of a parameter as an unsigned 32-bit hexadecimal integer.
857 *
858 * @param param_list The URI parameter list.
859 * @param name The name of the parameter.
860 * @param value Pointer to the variable to receive the value.
861 * @return True if the parameter value was read and stored correctly, false
862 * otherwise.
863 */
864bool rtp_get_parameter_x32(const VC_CONTAINERS_LIST_T *param_list,
865 const char *name,
866 uint32_t *value)
867{
868 PARAMETER_T param;
869
870 param.name = name;
871 if (vc_containers_list_find_entry(param_list, &param) && param.value)
872 {
873 char *end;
874
875 *value = strtoul(param.value, &end, 16);
876 return (end != param.value) && (*end == '\0');
877 }
878
879 return false;
880}
881
882/*****************************************************************************
883Functions exported as part of the Container Module API
884 *****************************************************************************/
885
886/**************************************************************************//**
887 * Read/skip data from the container.
888 * Can also be used to query information about the next block of data.
889 *
890 * @param p_ctx The reader context.
891 * @param p_packet The container packet information, or NULL.
892 * @param flags The container read flags.
893 * @return The resulting status of the function.
894 */
895static VC_CONTAINER_STATUS_T rtp_reader_read( VC_CONTAINER_T *p_ctx,
896 VC_CONTAINER_PACKET_T *p_packet,
897 uint32_t flags )
898{
899 VC_CONTAINER_TRACK_T *track;
900 VC_CONTAINER_TRACK_MODULE_T *t_module;
901 VC_CONTAINER_STATUS_T status;
902
903 if((flags & VC_CONTAINER_READ_FLAG_FORCE_TRACK) && p_packet->track)
904 return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
905
906 track = p_ctx->tracks[0];
907 t_module = track->priv->module;
908
909 CLEAR_BIT(t_module->flags, TRACK_NEW_PACKET);
910
911 while (!BITS_AVAILABLE(p_ctx, &t_module->payload))
912 {
913 uint32_t bytes_read;
914
915 /* No data left from last RTP packet, get another one */
916 bytes_read = READ_BYTES(p_ctx, t_module->buffer, MAXIMUM_PACKET_SIZE);
917 if (!bytes_read)
918 return STREAM_STATUS(p_ctx);
919
920 BITS_INIT(p_ctx, &t_module->payload, t_module->buffer, bytes_read);
921
922 decode_rtp_packet_header(p_ctx, t_module);
923 SET_BIT(t_module->flags, TRACK_NEW_PACKET);
924 }
925
926 if (p_packet)
927 {
928 uint32_t timestamp_top = t_module->timestamp >> 30;
929
930 /* Determine whether timestamp has wrapped forwards or backwards around zero */
931 if ((timestamp_top == 0) && (t_module->last_timestamp_top == 3))
932 t_module->timestamp_wraps++;
933 else if ((timestamp_top == 3) && (t_module->last_timestamp_top == 0))
934 t_module->timestamp_wraps--;
935 t_module->last_timestamp_top = timestamp_top;
936
937 p_packet->dts = p_packet->pts = ((int64_t)t_module->timestamp_wraps << 32) | t_module->timestamp;
938 p_packet->track = 0;
939 p_packet->flags = 0;
940 }
941
942 status = t_module->payload_handler(p_ctx, track, p_packet, flags);
943 if (p_packet && status == VC_CONTAINER_SUCCESS)
944 {
945 /* Adjust timestamps from RTP clock rate to microseconds */
946 p_packet->pts = p_packet->pts * MICROSECONDS_PER_SECOND / t_module->timestamp_clock;
947 p_packet->dts = p_packet->dts * MICROSECONDS_PER_SECOND / t_module->timestamp_clock;
948 }
949
950 STREAM_STATUS(p_ctx) = status;
951 return status;
952}
953
954/**************************************************************************//**
955 * Seek over data in the container.
956 *
957 * @param p_ctx The reader context.
958 * @param p_offset The seek offset.
959 * @param mode The seek mode.
960 * @param flags The seek flags.
961 * @return The resulting status of the function.
962 */
963static VC_CONTAINER_STATUS_T rtp_reader_seek( VC_CONTAINER_T *p_ctx,
964 int64_t *p_offset,
965 VC_CONTAINER_SEEK_MODE_T mode,
966 VC_CONTAINER_SEEK_FLAGS_T flags)
967{
968 VC_CONTAINER_PARAM_UNUSED(p_ctx);
969 VC_CONTAINER_PARAM_UNUSED(p_offset);
970 VC_CONTAINER_PARAM_UNUSED(mode);
971 VC_CONTAINER_PARAM_UNUSED(flags);
972
973 /* RTP is a non-seekable container */
974 return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
975}
976
977/**************************************************************************//**
978 * Apply a control operation to the container.
979 *
980 * @param p_ctx The reader context.
981 * @param operation The control operation.
982 * @param args Optional additional arguments for the operation.
983 * @return The resulting status of the function.
984 */
985static VC_CONTAINER_STATUS_T rtp_reader_control( VC_CONTAINER_T *p_ctx,
986 VC_CONTAINER_CONTROL_T operation,
987 va_list args)
988{
989 VC_CONTAINER_STATUS_T status;
990 VC_CONTAINER_TRACK_MODULE_T *t_module = p_ctx->tracks[0]->priv->module;
991
992 switch (operation)
993 {
994 case VC_CONTAINER_CONTROL_SET_TIMESTAMP_BASE:
995 {
996 t_module->timestamp_base = va_arg(args, uint32_t);
997 if (!t_module->timestamp_base)
998 t_module->timestamp_base = 1; /* Zero is used to mean "not set" */
999 status = VC_CONTAINER_SUCCESS;
1000 }
1001 break;
1002 case VC_CONTAINER_CONTROL_SET_NEXT_SEQUENCE_NUMBER:
1003 {
1004 init_sequence_number(t_module, (uint16_t)va_arg(args, uint32_t));
1005 t_module->probation = 0;
1006 status = VC_CONTAINER_SUCCESS;
1007 }
1008 break;
1009 case VC_CONTAINER_CONTROL_SET_SOURCE_ID:
1010 {
1011 t_module->expected_ssrc = va_arg(args, uint32_t);
1012 SET_BIT(t_module->flags, TRACK_SSRC_SET);
1013 status = VC_CONTAINER_SUCCESS;
1014 }
1015 break;
1016 default:
1017 status = VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
1018 }
1019
1020 return status;
1021}
1022
1023/**************************************************************************//**
1024 * Close the container.
1025 *
1026 * @param p_ctx The reader context.
1027 * @return The resulting status of the function.
1028 */
1029static VC_CONTAINER_STATUS_T rtp_reader_close( VC_CONTAINER_T *p_ctx )
1030{
1031 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
1032
1033 vc_container_assert(p_ctx->tracks_num < 2);
1034
1035 if (p_ctx->tracks_num)
1036 {
1037 void *payload_extra;
1038
1039 vc_container_assert(module);
1040 vc_container_assert(module->track);
1041 vc_container_assert(module->track->priv);
1042 vc_container_assert(module->track->priv->module);
1043
1044 payload_extra = module->track->priv->module->extra;
1045 if (payload_extra)
1046 free(payload_extra);
1047 vc_container_free_track(p_ctx, module->track);
1048 }
1049 p_ctx->tracks = NULL;
1050 p_ctx->tracks_num = 0;
1051 if (module) free(module);
1052 p_ctx->priv->module = 0;
1053 return VC_CONTAINER_SUCCESS;
1054}
1055
1056/**************************************************************************//**
1057 * Open the container.
1058 * Uses the I/O URI and/or data to configure the container.
1059 *
1060 * @param p_ctx The reader context.
1061 * @return The resulting status of the function.
1062 */
1063VC_CONTAINER_STATUS_T rtp_reader_open( VC_CONTAINER_T *p_ctx )
1064{
1065 VC_CONTAINER_MODULE_T *module = 0;
1066 VC_CONTAINER_TRACK_T *track = 0;
1067 VC_CONTAINER_TRACK_MODULE_T *t_module = 0;
1068 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
1069 VC_CONTAINERS_LIST_T *parameters = NULL;
1070 uint32_t payload_type;
1071 uint32_t initial_seq_num;
1072
1073 /* Check the URI scheme looks valid */
1074 if (!vc_uri_scheme(p_ctx->priv->uri) ||
1075 (strcasecmp(vc_uri_scheme(p_ctx->priv->uri), RTP_SCHEME) &&
1076 strcasecmp(vc_uri_scheme(p_ctx->priv->uri), RTP_PKT_SCHEME)))
1077 return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
1078
1079 /* Make the query/parameter list more easily searchable */
1080 parameters = fill_parameter_list(p_ctx->priv->uri);
1081 if (!parameters) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
1082
1083 /* Payload type parameter is mandatory and must fit in 7 bits */
1084 if (!rtp_get_parameter_u32(parameters, PAYLOAD_TYPE_NAME, &payload_type) || payload_type > 127)
1085 {
1086 status = VC_CONTAINER_ERROR_FORMAT_INVALID;
1087 goto error;
1088 }
1089
1090 /* Allocate our context */
1091 module = (VC_CONTAINER_MODULE_T *)malloc(sizeof(VC_CONTAINER_MODULE_T));
1092 if (!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
1093
1094 memset(module, 0, sizeof(*module));
1095 p_ctx->priv->module = module;
1096 p_ctx->tracks = &module->track;
1097
1098 /* Allocate the track, including space for reading an RTP packet on the end */
1099 track = vc_container_allocate_track(p_ctx, sizeof(VC_CONTAINER_TRACK_MODULE_T) + MAXIMUM_PACKET_SIZE);
1100 if (!track)
1101 {
1102 status = VC_CONTAINER_ERROR_OUT_OF_MEMORY;
1103 goto error;
1104 }
1105 module->track = track;
1106 p_ctx->tracks_num = 1;
1107 t_module = track->priv->module;
1108
1109 /* Initialise the track data */
1110 t_module->buffer = (uint8_t *)(t_module + 1);
1111 status = decode_payload_type(p_ctx, track, parameters, payload_type);
1112 if (status != VC_CONTAINER_SUCCESS)
1113 goto error;
1114
1115 vc_container_assert(t_module->timestamp_clock != 0);
1116
1117 /* Default to a generic, unstructured payload handler */
1118 if (!t_module->payload_handler)
1119 t_module->payload_handler = generic_payload_handler;
1120
1121 if (rtp_get_parameter_x32(parameters, SSRC_NAME, &t_module->expected_ssrc))
1122 SET_BIT(t_module->flags, TRACK_SSRC_SET);
1123
1124 t_module->probation = MIN_SEQUENTIAL;
1125 if (rtp_get_parameter_u32(parameters, SEQ_NAME, &initial_seq_num))
1126 {
1127 /* If an initial sequence number is provided, avoid probation period */
1128 t_module->max_seq_num = (uint16_t)initial_seq_num;
1129 t_module->probation = 0;
1130 }
1131
1132 track->is_enabled = true;
1133
1134 vc_containers_list_destroy(parameters);
1135
1136 p_ctx->priv->pf_close = rtp_reader_close;
1137 p_ctx->priv->pf_read = rtp_reader_read;
1138 p_ctx->priv->pf_seek = rtp_reader_seek;
1139 p_ctx->priv->pf_control = rtp_reader_control;
1140
1141 return VC_CONTAINER_SUCCESS;
1142
1143error:
1144 if (parameters) vc_containers_list_destroy(parameters);
1145 if(status == VC_CONTAINER_SUCCESS || status == VC_CONTAINER_ERROR_EOS)
1146 status = VC_CONTAINER_ERROR_FORMAT_INVALID;
1147 LOG_DEBUG(p_ctx, "error opening RTP (%i)", status);
1148 rtp_reader_close(p_ctx);
1149 return status;
1150}
1151
1152/********************************************************************************
1153 Entrypoint function
1154 ********************************************************************************/
1155
1156#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
1157# pragma weak reader_open rtp_reader_open
1158#endif
1159