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; }
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; }