static vod_status_t mp4_encrypt_write_encrypted( mp4_encrypt_state_t* state, u_char* cur_pos, uint32_t write_size) { uint32_t cur_write_size; size_t alloc_size; u_char* write_end; u_char* output; vod_status_t rc; write_end = cur_pos + write_size; while (cur_pos < write_end) { rc = write_buffer_get_bytes(&state->write_buffer, MIN_ALLOC_SIZE, &alloc_size, &output); if (rc != VOD_OK) { return rc; } cur_write_size = write_end - cur_pos; cur_write_size = vod_min(cur_write_size, alloc_size); rc = mp4_aes_ctr_process(&state->cipher, output, cur_pos, cur_write_size); if (rc != VOD_OK) { return rc; } cur_pos += cur_write_size; state->write_buffer.cur_pos += cur_write_size; } return VOD_OK; }
static vod_status_t hds_muxer_end_frame(hds_muxer_state_t* state) { uint32_t packet_size = state->frame_header_size + state->cur_frame->size; vod_status_t rc; u_char* p; // write the frame size rc = write_buffer_get_bytes(&state->write_buffer_state, sizeof(uint32_t), NULL, &p); if (rc != VOD_OK) { vod_log_debug1(VOD_LOG_DEBUG_LEVEL, state->request_context->log, 0, "hds_muxer_end_frame: write_buffer_get_bytes failed %i", rc); return rc; } write_be32(p, packet_size); return VOD_OK; }
static vod_status_t hds_muxer_start_frame(hds_muxer_state_t* state) { hds_muxer_stream_state_t* selected_stream; uint64_t cur_frame_offset; uint64_t cur_frame_dts; size_t alloc_size; u_char* p; vod_status_t rc; rc = hds_muxer_choose_stream(state, &selected_stream); if (rc != VOD_OK) { return rc; } // init the frame state->cur_frame = selected_stream->cur_frame; state->frames_source = selected_stream->frames_source; state->frames_source_context = selected_stream->frames_source_context; selected_stream->cur_frame++; cur_frame_offset = *selected_stream->cur_frame_input_offset; selected_stream->cur_frame_input_offset++; selected_stream->cur_frame_output_offset++; selected_stream->next_frame_time_offset += state->cur_frame->duration; cur_frame_dts = selected_stream->next_frame_dts + selected_stream->clip_start_time; selected_stream->next_frame_dts = rescale_time(selected_stream->next_frame_time_offset, selected_stream->timescale, HDS_TIMESCALE); state->cache_slot_id = selected_stream->media_type; // allocate room for the mux packet header state->frame_header_size = tag_size_by_media_type[selected_stream->media_type]; alloc_size = state->frame_header_size; if (selected_stream->media_type == MEDIA_TYPE_VIDEO && state->cur_frame->key_frame) { alloc_size += state->codec_config_size; } rc = write_buffer_get_bytes(&state->write_buffer_state, alloc_size, NULL, &p); if (rc != VOD_OK) { vod_log_debug1(VOD_LOG_DEBUG_LEVEL, state->request_context->log, 0, "hds_muxer_start_frame: write_buffer_get_bytes failed %i", rc); return rc; } // write the mux packet header and optionally codec config if (selected_stream->media_type == MEDIA_TYPE_VIDEO && state->cur_frame->key_frame) { p = hds_muxer_write_codec_config(p, state, cur_frame_dts); } switch (selected_stream->media_type) { case MEDIA_TYPE_VIDEO: hds_write_video_tag_header( p, state->cur_frame->size, cur_frame_dts, state->cur_frame->key_frame ? FRAME_TYPE_KEY_FRAME : FRAME_TYPE_INTER_FRAME, AVC_PACKET_TYPE_NALU, rescale_time(state->cur_frame->pts_delay, selected_stream->timescale, HDS_TIMESCALE)); break; case MEDIA_TYPE_AUDIO: hds_write_audio_tag_header( p, state->cur_frame->size, cur_frame_dts, selected_stream->sound_info, AAC_PACKET_TYPE_RAW); } rc = state->frames_source->start_frame(state->frames_source_context, state->cur_frame, cur_frame_offset); if (rc != VOD_OK) { return rc; } return VOD_OK; }
static vod_status_t mp4_encrypt_video_write_buffer(void* context, u_char* buffer, uint32_t size) { mp4_encrypt_video_state_t* state = (mp4_encrypt_video_state_t*)context; vod_str_t fragment_header; u_char* buffer_end = buffer + size; u_char* cur_pos = buffer; u_char* output; uint32_t write_size; int32_t cur_shift; size_t ignore; bool_t init_track; vod_status_t rc; while (cur_pos < buffer_end) { switch (state->cur_state) { case STATE_PACKET_SIZE: if (state->base.frame_size_left <= 0) { rc = mp4_encrypt_video_start_frame(state); if (rc != VOD_OK) { return rc; } if (state->base.frame_size_left <= 0) { state->cur_state = STATE_PACKET_DATA; break; } } for (; state->length_bytes_left && cur_pos < buffer_end; state->length_bytes_left--) { state->packet_size_left = (state->packet_size_left << 8) | *cur_pos++; } if (cur_pos >= buffer_end) { break; } if (state->base.frame_size_left < state->nal_packet_size_length + state->packet_size_left) { vod_log_error(VOD_LOG_ERR, state->base.request_context->log, 0, "mp4_encrypt_video_write_buffer: frame size %uD too small, nalu size %uD packet size %uD", state->base.frame_size_left, state->nal_packet_size_length, state->packet_size_left); return VOD_BAD_DATA; } state->base.frame_size_left -= state->nal_packet_size_length + state->packet_size_left; state->cur_state++; // fall through case STATE_NAL_TYPE: // write the packet size and nal type rc = write_buffer_get_bytes(&state->base.write_buffer, state->nal_packet_size_length + 1, NULL, &output); if (rc != VOD_OK) { return rc; } for (cur_shift = (state->nal_packet_size_length - 1) * 8; cur_shift >= 0; cur_shift -= 8) { *output++ = (state->packet_size_left >> cur_shift) & 0xff; } *output++ = *cur_pos++; // nal type // update the packet size if (state->packet_size_left <= 0) { vod_log_error(VOD_LOG_ERR, state->base.request_context->log, 0, "mp4_encrypt_video_write_buffer: zero size packet"); return VOD_BAD_DATA; } state->packet_size_left--; // add the subsample rc = mp4_encrypt_video_add_subsample(state, state->nal_packet_size_length + 1, state->packet_size_left); if (rc != VOD_OK) { return rc; } state->cur_state++; // fall through case STATE_PACKET_DATA: write_size = (uint32_t)(buffer_end - cur_pos); write_size = vod_min(write_size, state->packet_size_left); rc = mp4_encrypt_write_encrypted(&state->base, cur_pos, write_size); if (rc != VOD_OK) { return rc; } cur_pos += write_size; state->packet_size_left -= write_size; if (state->packet_size_left > 0) { break; } // finished a packet state->cur_state = STATE_PACKET_SIZE; state->length_bytes_left = state->nal_packet_size_length; state->packet_size_left = 0; if (state->base.frame_size_left > 0) { break; } // finished a frame rc = mp4_encrypt_video_end_frame(state); if (rc != VOD_OK) { return rc; } // move to the next frame if (mp4_encrypt_move_to_next_frame(&state->base, &init_track)) { if (init_track) { rc = mp4_encrypt_video_init_track(state, state->base.cur_clip->first_track); if (rc != VOD_OK) { return rc; } } break; } // finished all frames rc = write_buffer_flush(&state->base.write_buffer, FALSE); if (rc != VOD_OK) { return rc; } mp4_encrypt_video_prepare_saiz_saio(state); rc = state->build_fragment_header(state, &fragment_header, &ignore); if (rc != VOD_OK) { return rc; } rc = state->base.segment_writer.write_head( state->base.segment_writer.context, fragment_header.data, fragment_header.len); if (rc != VOD_OK) { vod_log_debug1(VOD_LOG_DEBUG_LEVEL, state->base.request_context->log, 0, "mp4_encrypt_video_write_buffer: write_head failed %i", rc); return rc; } break; } } return VOD_OK; }
static vod_status_t mp4_encrypt_video_snpf_write_buffer(void* context, u_char* buffer, uint32_t size) { mp4_encrypt_video_state_t* state = (mp4_encrypt_video_state_t*)context; u_char* buffer_end = buffer + size; u_char* cur_pos = buffer; u_char* cur_end_pos; u_char* output; uint32_t write_size; bool_t init_track; vod_status_t rc; while (cur_pos < buffer_end) { switch (state->cur_state) { case STATE_CLEAR_BYTES: // start a new frame if needed if (state->base.frame_size_left <= 0) { rc = mp4_encrypt_start_frame(&state->base); if (rc != VOD_OK) { return rc; } if (state->base.frame_size_left <= 0) { state->cur_state = STATE_ENCRYPTED_BYTES; break; } } // copy the clear bytes write_size = (uint32_t)(buffer_end - cur_pos); write_size = vod_min(write_size, state->length_bytes_left + 1); rc = write_buffer_get_bytes(&state->base.write_buffer, write_size, NULL, &output); if (rc != VOD_OK) { return rc; } // copy the nalu length if (write_size >= state->length_bytes_left) { cur_end_pos = cur_pos + state->length_bytes_left; state->length_bytes_left = 0; } else { cur_end_pos = cur_pos + write_size; state->length_bytes_left -= write_size; } while (cur_pos < cur_end_pos) { state->packet_size_left = (state->packet_size_left << 8) | *cur_pos; *output++ = *cur_pos++; } if (cur_pos >= buffer_end) { break; } // copy the nalu type *output++ = *cur_pos++; if (state->base.frame_size_left < state->nal_packet_size_length + 1) { vod_log_error(VOD_LOG_ERR, state->base.request_context->log, 0, "mp4_encrypt_video_snpf_write_buffer: frame size %uD too small, nalu size %uD", state->base.frame_size_left, state->nal_packet_size_length); return VOD_BAD_DATA; } state->base.frame_size_left -= state->nal_packet_size_length; if (state->packet_size_left != state->base.frame_size_left && !state->single_nalu_warning_printed) { vod_log_error(VOD_LOG_WARN, state->base.request_context->log, 0, "mp4_encrypt_video_snpf_write_buffer: frame does not contain a single nalu, " "consider changing vod_min_single_nalu_per_frame_segment, " "packet size=%uD, frame size=%uD", state->packet_size_left, state->base.frame_size_left); state->single_nalu_warning_printed = TRUE; } state->base.frame_size_left--; state->cur_state++; // fall through case STATE_ENCRYPTED_BYTES: write_size = (uint32_t)(buffer_end - cur_pos); write_size = vod_min(write_size, state->base.frame_size_left); rc = mp4_encrypt_write_encrypted(&state->base, cur_pos, write_size); if (rc != VOD_OK) { return rc; } cur_pos += write_size; state->base.frame_size_left -= write_size; if (state->base.frame_size_left > 0) { break; } // finished a packet state->cur_state = STATE_CLEAR_BYTES; state->length_bytes_left = state->nal_packet_size_length; state->packet_size_left = 0; // move to the next frame if (mp4_encrypt_move_to_next_frame(&state->base, &init_track)) { if (init_track) { rc = mp4_encrypt_video_init_track(state, state->base.cur_clip->first_track); if (rc != VOD_OK) { return rc; } } break; } // finished all frames rc = write_buffer_flush(&state->base.write_buffer, FALSE); if (rc != VOD_OK) { return rc; } break; } } return VOD_OK; }