/** Find the track associated with a PS stream_id */ static VC_CONTAINER_TRACK_T *ps_find_track( VC_CONTAINER_T *ctx, uint32_t stream_id, uint32_t substream_id, bool b_create ) { VC_CONTAINER_TRACK_T *track = 0; unsigned int i; for(i = 0; i < ctx->tracks_num; i++) if(ctx->tracks[i]->priv->module->stream_id == stream_id && ctx->tracks[i]->priv->module->substream_id == substream_id) break; if(i < ctx->tracks_num) /* We found it */ track = ctx->tracks[i]; if(!track && b_create && i < PS_TRACKS_MAX) { /* Allocate and initialise a new track */ ctx->tracks[i] = track = vc_container_allocate_track(ctx, sizeof(*ctx->tracks[0]->priv->module)); if(track) { track->priv->module->stream_id = stream_id; track->priv->module->substream_id = substream_id; ctx->tracks_num++; } } if(!track && b_create) LOG_DEBUG(ctx, "could not create track for stream id: %i", stream_id); return track; }
static VC_CONTAINER_STATUS_T dummy_writer_control( VC_CONTAINER_T *p_ctx, VC_CONTAINER_CONTROL_T operation, va_list args ) { VC_CONTAINER_TRACK_T *track; VC_CONTAINER_PARAM_UNUSED(args); switch(operation) { case VC_CONTAINER_CONTROL_TRACK_ADD: if(p_ctx->tracks_num >= 2) return VC_CONTAINER_ERROR_OUT_OF_RESOURCES; /* Allocate and initialise track data */ p_ctx->tracks[p_ctx->tracks_num] = track = vc_container_allocate_track(p_ctx, 0); if(!track) return VC_CONTAINER_ERROR_OUT_OF_MEMORY; p_ctx->tracks_num++; return VC_CONTAINER_SUCCESS; case VC_CONTAINER_CONTROL_TRACK_ADD_DONE: return VC_CONTAINER_SUCCESS; default: return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION; } }
VC_CONTAINER_STATUS_T binary_reader_open( VC_CONTAINER_T *p_ctx ) { const char *extension = vc_uri_path_extension(p_ctx->priv->uri); VC_CONTAINER_MODULE_T *module = 0; VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_INVALID; VC_CONTAINER_ES_TYPE_T es_type = 0; VC_CONTAINER_FOURCC_T codec = 0; unsigned int i; /* Check if the user has specified a container */ vc_uri_find_query(p_ctx->priv->uri, 0, "container", &extension); /* Check if the extension is supported */ if(!extension || !vc_uri_path(p_ctx->priv->uri)) return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED; for(i = 0; extension_to_format_table[i].ext; i++) { if(strcasecmp(extension, extension_to_format_table[i].ext)) continue; es_type = extension_to_format_table[i].type; codec = extension_to_format_table[i].codec; break; } if(!extension_to_format_table[i].ext) return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED; /* If this a .bin file we look in our bin list */ for(i = 0; !codec && bin_extension_to_format_table[i].ext; i++) { if(!strstr(vc_uri_path(p_ctx->priv->uri), bin_extension_to_format_table[i].ext) && !strstr(extension, bin_extension_to_format_table[i].ext)) continue; es_type = bin_extension_to_format_table[i].type; codec = bin_extension_to_format_table[i].codec; break; } if(!codec) return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED; /* Allocate our context */ module = malloc(sizeof(*module)); if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; } memset(module, 0, sizeof(*module)); p_ctx->priv->module = module; p_ctx->tracks_num = 1; p_ctx->tracks = &module->track; p_ctx->tracks[0] = vc_container_allocate_track(p_ctx, 0); if(!p_ctx->tracks[0]) return VC_CONTAINER_ERROR_OUT_OF_MEMORY; p_ctx->tracks[0]->format->es_type = es_type; p_ctx->tracks[0]->format->codec = codec; p_ctx->tracks[0]->is_enabled = true; module->default_block_size = DEFAULT_BLOCK_SIZE; if(codec == VC_CONTAINER_CODEC_JPEG) module->default_block_size = DEFAULT_JPEG_BLOCK_SIZE; module->block_size = module->default_block_size; module->init = 1; /* * We now have all the information we really need to start playing the stream */ p_ctx->priv->pf_close = binary_reader_close; p_ctx->priv->pf_read = binary_reader_read; p_ctx->priv->pf_seek = binary_reader_seek; return VC_CONTAINER_SUCCESS; error: LOG_DEBUG(p_ctx, "binary: error opening stream (%i)", status); return status; }
/**************************************************************************//** * Open the container. * Uses the I/O URI and/or data to configure the container. * * @param p_ctx The reader context. * @return The resulting status of the function. */ VC_CONTAINER_STATUS_T rtp_reader_open( VC_CONTAINER_T *p_ctx ) { VC_CONTAINER_MODULE_T *module = 0; VC_CONTAINER_TRACK_T *track = 0; VC_CONTAINER_TRACK_MODULE_T *t_module = 0; VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS; VC_CONTAINERS_LIST_T *parameters = NULL; uint32_t payload_type; uint32_t initial_seq_num; /* Check the URI scheme looks valid */ if (!vc_uri_scheme(p_ctx->priv->uri) || (strcasecmp(vc_uri_scheme(p_ctx->priv->uri), RTP_SCHEME) && strcasecmp(vc_uri_scheme(p_ctx->priv->uri), RTP_PKT_SCHEME))) return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED; /* Make the query/parameter list more easily searchable */ parameters = fill_parameter_list(p_ctx->priv->uri); if (!parameters) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; } /* Payload type parameter is mandatory and must fit in 7 bits */ if (!rtp_get_parameter_u32(parameters, PAYLOAD_TYPE_NAME, &payload_type) || payload_type > 127) { status = VC_CONTAINER_ERROR_FORMAT_INVALID; goto error; } /* Allocate our context */ module = (VC_CONTAINER_MODULE_T *)malloc(sizeof(VC_CONTAINER_MODULE_T)); if (!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; } memset(module, 0, sizeof(*module)); p_ctx->priv->module = module; p_ctx->tracks = &module->track; /* Allocate the track, including space for reading an RTP packet on the end */ track = vc_container_allocate_track(p_ctx, sizeof(VC_CONTAINER_TRACK_MODULE_T) + MAXIMUM_PACKET_SIZE); if (!track) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; } module->track = track; p_ctx->tracks_num = 1; t_module = track->priv->module; /* Initialise the track data */ t_module->buffer = (uint8_t *)(t_module + 1); status = decode_payload_type(p_ctx, track, parameters, payload_type); if (status != VC_CONTAINER_SUCCESS) goto error; vc_container_assert(t_module->timestamp_clock != 0); /* Default to a generic, unstructured payload handler */ if (!t_module->payload_handler) t_module->payload_handler = generic_payload_handler; if (rtp_get_parameter_x32(parameters, SSRC_NAME, &t_module->expected_ssrc)) SET_BIT(t_module->flags, TRACK_SSRC_SET); t_module->probation = MIN_SEQUENTIAL; if (rtp_get_parameter_u32(parameters, SEQ_NAME, &initial_seq_num)) { /* If an initial sequence number is provided, avoid probation period */ t_module->max_seq_num = (uint16_t)initial_seq_num; t_module->probation = 0; } track->is_enabled = true; vc_containers_list_destroy(parameters); p_ctx->priv->pf_close = rtp_reader_close; p_ctx->priv->pf_read = rtp_reader_read; p_ctx->priv->pf_seek = rtp_reader_seek; p_ctx->priv->pf_control = rtp_reader_control; return VC_CONTAINER_SUCCESS; error: if (parameters) vc_containers_list_destroy(parameters); if(status == VC_CONTAINER_SUCCESS || status == VC_CONTAINER_ERROR_EOS) status = VC_CONTAINER_ERROR_FORMAT_INVALID; LOG_DEBUG(p_ctx, "error opening RTP (%i)", status); rtp_reader_close(p_ctx); return status; }