Exemplo n.º 1
0
static vod_status_t 
hls_muxer_init_base(
	hls_muxer_state_t* state,
	request_context_t* request_context,
	hls_muxer_conf_t* conf,
	hls_encryption_params_t* encryption_params,
	uint32_t segment_index,
	media_set_t* media_set,
	write_callback_t write_callback,
	void* write_context,
	bool_t* simulation_supported, 
	vod_str_t* response_header)
{
	mpegts_encoder_init_streams_state_t init_streams_state;
	media_track_t* track;
	hls_muxer_stream_state_t* cur_stream;
	const media_filter_t* next_filter;
	void* next_filter_context;
	vod_status_t rc;
	bool_t reuse_buffers;

	*simulation_supported = hls_muxer_simulation_supported(media_set, encryption_params);

	state->request_context = request_context;
	state->cur_frame = NULL;
	state->video_duration = 0;
	state->first_time = TRUE;

	state->media_set = media_set;
	state->use_discontinuity = media_set->use_discontinuity;

	if (encryption_params->type == HLS_ENC_AES_128)
	{
		rc = aes_cbc_encrypt_init(
			&state->encrypted_write_context,
			request_context,
			write_callback,
			write_context,
			encryption_params->key,
			encryption_params->iv);

		write_callback = (write_callback_t)aes_cbc_encrypt_write;
		write_context = state->encrypted_write_context;
		reuse_buffers = TRUE;		// aes_cbc_encrypt allocates new buffers
	}
	else
	{
		state->encrypted_write_context = NULL;
		reuse_buffers = FALSE;
	}

	// init the write queue
	write_buffer_queue_init(
		&state->queue,
		request_context,
		write_callback,
		write_context,
		reuse_buffers);

	// init the packetizer streams and get the packet ids / stream ids
	rc = mpegts_encoder_init_streams(
		request_context,
		encryption_params,
		&state->queue,
		&init_streams_state,
		segment_index);
	if (rc != VOD_OK)
	{
		return rc;
	}

	// allocate the streams
	state->first_stream = vod_alloc(request_context->pool, 
		sizeof(*state->first_stream) * (media_set->total_track_count + 1));
	if (state->first_stream == NULL)
	{
		vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0,
			"hls_muxer_init_base: vod_alloc failed (1)");
		return VOD_ALLOC_FAILED;
	}

	state->last_stream = state->first_stream + media_set->total_track_count;

	track = media_set->filtered_tracks;
	for (cur_stream = state->first_stream; cur_stream < state->last_stream; cur_stream++, track++)
	{
		cur_stream->segment_limit = ULLONG_MAX;

		rc = mpegts_encoder_init(
			&cur_stream->mpegts_encoder_state,
			&init_streams_state,
			track,
			&state->queue,
			conf->interleave_frames,
			conf->align_frames);
		if (rc != VOD_OK)
		{
			return rc;
		}

		switch (track->media_info.media_type)
		{
		case MEDIA_TYPE_VIDEO:
			if (track->media_info.duration_millis > state->video_duration)
			{
				state->video_duration = track->media_info.duration_millis;
			}

			cur_stream->buffer_state = NULL;
			cur_stream->top_filter_context = vod_alloc(request_context->pool, sizeof(mp4_to_annexb_state_t));
			if (cur_stream->top_filter_context == NULL)
			{
				vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0,
					"hls_muxer_init_base: vod_alloc failed (2)");
				return VOD_ALLOC_FAILED;
			}

			rc = mp4_to_annexb_init(
				cur_stream->top_filter_context,
				request_context,
				encryption_params,
				&mpegts_encoder,
				&cur_stream->mpegts_encoder_state);
			if (rc != VOD_OK)
			{
				return rc;
			}

			cur_stream->top_filter = &mp4_to_annexb;
			break;

		case MEDIA_TYPE_AUDIO:
			if (conf->interleave_frames)
			{
				// frame interleaving enabled, just join several audio frames according to timestamp
				cur_stream->buffer_state = NULL;

				next_filter_context = vod_alloc(request_context->pool, sizeof(frame_joiner_t));
				if (next_filter_context == NULL)
				{
					vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0,
						"hls_muxer_init_base: vod_alloc failed (3)");
					return VOD_ALLOC_FAILED;
				}

				frame_joiner_init(next_filter_context, &mpegts_encoder, &cur_stream->mpegts_encoder_state);

				next_filter = &frame_joiner;
			}
			else
			{
				// no frame interleaving, buffer the audio until it reaches a certain size / delay from video
				cur_stream->buffer_state = vod_alloc(request_context->pool, sizeof(buffer_filter_t));
				if (cur_stream->buffer_state == NULL)
				{
					vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0,
						"hls_muxer_init_base: vod_alloc failed (4)");
					return VOD_ALLOC_FAILED;
				}

				rc = buffer_filter_init(
					cur_stream->buffer_state,
					request_context,
					&mpegts_encoder,
					&cur_stream->mpegts_encoder_state,
					conf->align_frames,
					DEFAULT_PES_PAYLOAD_SIZE);
				if (rc != VOD_OK)
				{
					return rc;
				}

				next_filter = &buffer_filter;
				next_filter_context = cur_stream->buffer_state;
			}

			if (track->media_info.codec_id == VOD_CODEC_ID_AAC)
			{
				cur_stream->top_filter_context = vod_alloc(request_context->pool, sizeof(adts_encoder_state_t));
				if (cur_stream->top_filter_context == NULL)
				{
					vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0,
						"hls_muxer_init_base: vod_alloc failed (5)");
					return VOD_ALLOC_FAILED;
				}

				rc = adts_encoder_init(
					cur_stream->top_filter_context,
					request_context,
					encryption_params,
					next_filter,
					next_filter_context);
				if (rc != VOD_OK)
				{
					return rc;
				}

				cur_stream->top_filter = &adts_encoder;
			}
			else
			{
				if (encryption_params->type == HLS_ENC_SAMPLE_AES)
				{
					vod_log_error(VOD_LOG_ERR, request_context->log, 0,
						"hls_muxer_init_base: sample aes encryption is supported only for aac");
					return VOD_BAD_REQUEST;
				}

				cur_stream->top_filter = next_filter;
				cur_stream->top_filter_context = next_filter_context;
			}
			break;
		}

		rc = hls_muxer_init_track(cur_stream, track);
		if (rc != VOD_OK)
		{
			return rc;
		}
	}

	state->first_clip_track = track;

	// init the id3 stream
	rc = hls_muxer_init_id3_stream(state, conf, &init_streams_state);
	if (rc != VOD_OK)
	{
		return rc;
	}

	mpegts_encoder_finalize_streams(&init_streams_state, response_header);

	if (media_set->timing.durations != NULL)
	{
		state->video_duration = media_set->timing.total_duration;
	}

	return VOD_OK;
}
Exemplo n.º 2
0
off_t
buffer_filter(const void *input, void *output, int type, off_t limit)
{
	struct buffer_data data = { .arg.ptr = output, .type = type };
	off_t ret;

	buffer_filter_init(&data);
	ret = buffer_filter_update(&data, input, limit);
	buffer_filter_done(&data);

	return ret;
}

static off_t
buffer_copy(struct buffer_data *read_data,
            struct buffer_data *filter,
            struct buffer_data *write_data,
            off_t limit, struct dpkg_error *err)
{
	char *buf;
	int bufsize = 32768;
	off_t bytesread = 0, byteswritten = 0;
	off_t totalread = 0, totalwritten = 0;

	if ((limit != -1) && (limit < bufsize))
		bufsize = limit;
	if (bufsize == 0)
		buf = NULL;
	else
		buf = m_malloc(bufsize);

	buffer_filter_init(filter);

	while (bufsize > 0) {
		bytesread = buffer_read(read_data, buf, bufsize, err);
		if (bytesread < 0)
			break;
		if (bytesread == 0)
			break;

		totalread += bytesread;

		if (limit != -1) {
			limit -= bytesread;
			if (limit < bufsize)
				bufsize = limit;
		}

		buffer_filter_update(filter, buf, bytesread);

		byteswritten = buffer_write(write_data, buf, bytesread, err);
		if (byteswritten < 0)
			break;
		if (byteswritten == 0)
			break;

		totalwritten += byteswritten;
	}

	buffer_filter_done(filter);

	free(buf);

	if (bytesread < 0 || byteswritten < 0)
		return -1;
	if (limit > 0)
		return dpkg_put_error(err, _("unexpected end of file or stream"));

	return totalread;
}