vod_status_t mp4_builder_frame_writer_init( request_context_t* request_context, media_sequence_t* sequence, write_callback_t write_callback, void* write_context, bool_t reuse_buffers, fragment_writer_state_t** result) { fragment_writer_state_t* state; state = vod_alloc(request_context->pool, sizeof(fragment_writer_state_t)); if (state == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0, "mp4_builder_frame_writer_init: vod_alloc failed"); return VOD_ALLOC_FAILED; } state->request_context = request_context; state->write_callback = write_callback; state->write_context = write_context; state->reuse_buffers = reuse_buffers; state->frame_started = FALSE; state->sequence = sequence; state->cur_clip = sequence->filtered_clips; mp4_builder_init_track(state, state->cur_clip->first_track); *result = state; return VOD_OK; }
static bool_t mp4_builder_move_to_next_frame(fragment_writer_state_t* state) { while (state->cur_frame >= state->cur_frame_part.last_frame) { if (state->cur_frame_part.next != NULL) { state->cur_frame_part = *state->cur_frame_part.next; state->cur_frame = state->cur_frame_part.first_frame; state->first_time = TRUE; break; } state->cur_clip++; if (state->cur_clip >= state->sequence->filtered_clips_end) { return FALSE; } mp4_builder_init_track(state, state->cur_clip->first_track); } return TRUE; }
vod_status_t mp4_builder_frame_writer_process(fragment_writer_state_t* state) { u_char* read_buffer; uint32_t read_size; u_char* write_buffer = NULL; uint32_t write_buffer_size = 0; vod_status_t rc; bool_t frame_done; if (!state->frame_started) { while (state->cur_frame >= state->last_frame) { state->cur_clip++; if (state->cur_clip >= state->sequence->filtered_clips_end) { return VOD_OK; } mp4_builder_init_track(state, state->cur_clip->first_track); } rc = state->frames_source->start_frame(state->frames_source_context, state->cur_frame, *state->cur_frame_offset); if (rc != VOD_OK) { return rc; } state->frame_started = TRUE; } for (;;) { // read some data from the frame rc = state->frames_source->read(state->frames_source_context, &read_buffer, &read_size, &frame_done); if (rc != VOD_OK) { if (rc != VOD_AGAIN) { return rc; } if (write_buffer != NULL) { // flush the write buffer rc = state->write_callback(state->write_context, write_buffer, write_buffer_size); if (rc != VOD_OK) { return rc; } } else if (!state->first_time) { vod_log_error(VOD_LOG_ERR, state->request_context->log, 0, "mp4_builder_frame_writer_process: no data was handled, probably a truncated file"); return VOD_BAD_DATA; } state->first_time = FALSE; return VOD_AGAIN; } if (write_buffer != NULL) { // if the buffers are contiguous, just increment the size if (!state->reuse_buffers && write_buffer + write_buffer_size == read_buffer) { write_buffer_size += read_size; } else { // buffers not contiguous, flush the write buffer rc = state->write_callback(state->write_context, write_buffer, write_buffer_size); if (rc != VOD_OK) { return rc; } // reset the write buffer write_buffer = read_buffer; write_buffer_size = read_size; } } else { // reset the write buffer write_buffer = read_buffer; write_buffer_size = read_size; } if (!frame_done) { continue; } // move to the next frame state->cur_frame++; state->cur_frame_offset++; while (state->cur_frame >= state->last_frame) { if (write_buffer != NULL) { // flush the write buffer rc = state->write_callback(state->write_context, write_buffer, write_buffer_size); if (rc != VOD_OK) { return rc; } write_buffer = NULL; } state->cur_clip++; if (state->cur_clip >= state->sequence->filtered_clips_end) { return VOD_OK; } mp4_builder_init_track(state, state->cur_clip->first_track); } rc = state->frames_source->start_frame(state->frames_source_context, state->cur_frame, *state->cur_frame_offset); if (rc != VOD_OK) { return rc; } } }