1 | /* |
2 | Copyright (c) 2012, Broadcom Europe Ltd |
3 | All rights reserved. |
4 | |
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, 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 | |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY |
20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | ON 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 |
25 | SOFTWARE, 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 | /****************************************************************************** |
53 | Configurable 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 | /****************************************************************************** |
68 | Defines 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 | /****************************************************************************** |
111 | Type definitions |
112 | ******************************************************************************/ |
113 | |
114 | /** \name MIME type parameter handlers |
115 | * Function prototypes for payload parameter handlers */ |
116 | /* @{ */ |
117 | static VC_CONTAINER_STATUS_T audio_parameter_handler(VC_CONTAINER_T *p_ctx, VC_CONTAINER_TRACK_T *track, const VC_CONTAINERS_LIST_T *params); |
118 | static VC_CONTAINER_STATUS_T l8_parameter_handler(VC_CONTAINER_T *p_ctx, VC_CONTAINER_TRACK_T *track, const VC_CONTAINERS_LIST_T *params); |
119 | static 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 | /* @{ */ |
124 | static 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 */ |
129 | typedef 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 */ |
140 | static 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 */ |
164 | typedef 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 */ |
172 | static 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 */ |
188 | typedef 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. */ |
197 | static 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 */ |
201 | static 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 */ |
210 | VC_CONTAINERS_STATIC_LIST(dynamic_mime, dynamic_mime_details, mime_type_data_comparator); |
211 | |
212 | /** RTP reader data. */ |
213 | typedef struct VC_CONTAINER_MODULE_T |
214 | { |
215 | VC_CONTAINER_TRACK_T *track; |
216 | } VC_CONTAINER_MODULE_T; |
217 | |
218 | /****************************************************************************** |
219 | Function prototypes |
220 | ******************************************************************************/ |
221 | VC_CONTAINER_STATUS_T rtp_reader_open( VC_CONTAINER_T * ); |
222 | |
223 | /****************************************************************************** |
224 | Local 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 | */ |
237 | static 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 | */ |
250 | static 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, ¶m.name, ¶m.value); |
265 | if (!vc_containers_list_insert(parameters, ¶m, 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 | */ |
289 | static 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 | */ |
330 | static 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 | */ |
367 | static 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 | */ |
382 | static 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 | */ |
410 | static 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 | */ |
440 | static 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 | */ |
472 | static 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 | */ |
522 | static 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 | */ |
550 | static 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 | */ |
568 | static 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 | */ |
651 | static void (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 | */ |
744 | static 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 | */ |
792 | static 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 | /***************************************************************************** |
825 | Utility 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 | */ |
837 | bool 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, ¶m) && 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 | */ |
864 | bool 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, ¶m) && 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 | /***************************************************************************** |
883 | Functions 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 | */ |
895 | static 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 | */ |
963 | static 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 | */ |
985 | static 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 | */ |
1029 | static 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 *; |
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 | */ |
1063 | VC_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 | |
1143 | error: |
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 | |