static vod_status_t hls_muxer_init_id3_stream( hls_muxer_state_t* state, hls_muxer_conf_t* conf, mpegts_encoder_init_streams_state_t* init_streams_state) { hls_muxer_stream_state_t* cur_stream; hls_muxer_stream_state_t* reference_stream; id3_context_t* context; vod_status_t rc; cur_stream = state->last_stream; // init the mpeg ts encoder rc = mpegts_encoder_init( &cur_stream->mpegts_encoder_state, init_streams_state, NULL, &state->queue, conf->interleave_frames, conf->align_frames); if (rc != VOD_OK) { return rc; } if (!conf->output_id3_timestamps) { return VOD_OK; } // get the stream that has the first frame rc = hls_muxer_choose_stream(state, &reference_stream); if (rc != VOD_OK) { if (rc == VOD_NOT_FOUND) { return VOD_OK; } return rc; } // allocate the context context = vod_alloc(state->request_context->pool, sizeof(*context)); if (context == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, state->request_context->log, 0, "hls_muxer_init_id3_stream: vod_alloc failed"); return VOD_ALLOC_FAILED; } // init the memory frames source rc = frames_source_memory_init(state->request_context, &cur_stream->cur_frame_part.frames_source_context); if (rc != VOD_OK) { return rc; } cur_stream->cur_frame_part.frames_source = &frames_source_memory; // base initialization cur_stream->media_type = MEDIA_TYPE_NONE; cur_stream->segment_limit = ULLONG_MAX; cur_stream->buffer_state = NULL; // init the id3 encoder id3_encoder_init(&context->encoder, &mpegts_encoder, &cur_stream->mpegts_encoder_state); cur_stream->top_filter = &id3_encoder; cur_stream->top_filter_context = &context->encoder; // copy the time stamps cur_stream->first_frame_time_offset = reference_stream->first_frame_time_offset; cur_stream->next_frame_time_offset = reference_stream->next_frame_time_offset; cur_stream->clip_from_frame_offset = reference_stream->clip_from_frame_offset; // init the frame part cur_stream->cur_frame = &context->frame; cur_stream->first_frame_part = &cur_stream->cur_frame_part; cur_stream->cur_frame_part.next = NULL; cur_stream->cur_frame_part.first_frame = &context->frame; cur_stream->cur_frame_part.last_frame = &context->frame + 1; cur_stream->source = NULL; // init the frame context->frame.size = vod_sprintf(context->data, ID3_TEXT_JSON_FORMAT, hls_rescale_to_millis(cur_stream->first_frame_time_offset)) - context->data; context->frame.duration = 0; context->frame.key_frame = 1; context->frame.pts_delay = 0; context->frame.offset = (uintptr_t)&context->data; state->last_stream++; return VOD_OK; }
static vod_status_t audio_filter_update_track(audio_filter_state_t* state) { media_track_t* output = state->output; input_frame_t* cur_frame; input_frame_t* last_frame; uint32_t old_timescale; vod_status_t rc; u_char* new_extra_data; bool_t has_frames; if (state->sink.encoder->time_base.num != 1) { vod_log_error(VOD_LOG_ERR, state->request_context->log, 0, "audio_filter_update_track: unexpected encoder time base %d/%d", state->sink.encoder->time_base.num, state->sink.encoder->time_base.den); return VOD_UNEXPECTED; } // decrement the old frame count and size state->sequence->total_frame_count -= output->frame_count; state->sequence->total_frame_size -= output->total_frames_size; output->total_frames_size = 0; output->total_frames_duration = 0; // update frames output->frame_count = state->frames_array.nelts; output->frames.first_frame = state->frames_array.elts; output->frames.last_frame = output->frames.first_frame + output->frame_count; output->frames.next = NULL; // check whether there are any frames with duration has_frames = FALSE; // Note: always a single part here last_frame = output->frames.last_frame; for (cur_frame = output->frames.first_frame; cur_frame < last_frame; cur_frame++) { if (cur_frame->duration != 0) { has_frames = TRUE; break; } } if (!has_frames) { output->frames.first_frame = NULL; output->frames.last_frame = NULL; output->frame_count = 0; return VOD_OK; } // update the frames source to memory rc = frames_source_memory_init(state->request_context, &output->frames.frames_source_context); if (rc != VOD_OK) { return rc; } output->frames.frames_source = &frames_source_memory; // calculate the total frames size and duration output->media_info.min_frame_duration = 0; for (cur_frame = output->frames.first_frame; cur_frame < last_frame; cur_frame++) { output->total_frames_size += cur_frame->size; output->total_frames_duration += cur_frame->duration; if (cur_frame->duration != 0 && (output->media_info.min_frame_duration == 0 || cur_frame->duration < output->media_info.min_frame_duration)) { output->media_info.min_frame_duration = cur_frame->duration; } } // update media info old_timescale = output->media_info.timescale; output->media_info.timescale = state->sink.encoder->time_base.den; output->media_info.duration = rescale_time(output->media_info.duration, old_timescale, output->media_info.timescale); output->media_info.bitrate = state->sink.encoder->bit_rate; output->media_info.u.audio.object_type_id = 0x40; // ffmpeg always writes 0x40 (ff_mp4_obj_type) output->media_info.u.audio.channels = state->sink.encoder->channels; output->media_info.u.audio.bits_per_sample = ENCODER_BITS_PER_SAMPLE; output->media_info.u.audio.packet_size = 0; // ffmpeg always writes 0 (mov_write_audio_tag) output->media_info.u.audio.sample_rate = state->sink.encoder->sample_rate; output->key_frame_count = 0; output->first_frame_time_offset = rescale_time(output->first_frame_time_offset, old_timescale, output->media_info.timescale); new_extra_data = vod_alloc(state->request_context->pool, state->sink.encoder->extradata_size); if (new_extra_data == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, state->request_context->log, 0, "audio_filter_update_track: vod_alloc failed"); return VOD_ALLOC_FAILED; } vod_memcpy(new_extra_data, state->sink.encoder->extradata, state->sink.encoder->extradata_size); output->media_info.extra_data.data = new_extra_data; output->media_info.extra_data.len = state->sink.encoder->extradata_size; if (output->media_info.codec_name.data != NULL) { rc = codec_config_get_audio_codec_name(state->request_context, &output->media_info); if (rc != VOD_OK) { return rc; } } // add the new frame count and size state->sequence->total_frame_count += output->frame_count; state->sequence->total_frame_size += output->total_frames_size; // TODO: update raw_atoms return VOD_OK; }