static vod_status_t audio_encoder_write_packet( audio_encoder_state_t* state, AVPacket* output_packet) { input_frame_t* cur_frame; vod_status_t rc; void* data; rc = audio_filter_alloc_memory_frame( state->request_context, state->frames_array, output_packet->size, &cur_frame); if (rc != VOD_OK) { return rc; } data = (void*)(uintptr_t)cur_frame->offset; vod_memcpy(data, output_packet->data, output_packet->size); cur_frame->duration = output_packet->duration; cur_frame->pts_delay = output_packet->pts - output_packet->dts; return VOD_OK; }
static vod_status_t audio_filter_write_frame(audio_filter_state_t* state, AVPacket* output_packet) { input_frame_t* cur_frame; u_char* new_data; cur_frame = vod_array_push(&state->frames_array); if (cur_frame == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, state->request_context->log, 0, "audio_filter_write_frame: vod_array_push failed"); return VOD_ALLOC_FAILED; } new_data = vod_alloc(state->request_context->pool, output_packet->size); if (new_data == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, state->request_context->log, 0, "audio_filter_write_frame: vod_alloc failed"); return VOD_ALLOC_FAILED; } vod_memcpy(new_data, output_packet->data, output_packet->size); cur_frame->duration = output_packet->duration; cur_frame->size = output_packet->size; cur_frame->key_frame = 0; cur_frame->pts_delay = output_packet->pts - output_packet->dts; cur_frame->offset = (uintptr_t)new_data; return VOD_OK; }
static vod_status_t mp4_encrypt_video_snpf_build_auxiliary_data(mp4_encrypt_video_state_t* state) { u_char iv[MP4_AES_CTR_IV_SIZE]; uint32_t bytes_of_encrypted_data; uint16_t bytes_of_clear_data; bool_t init_track; u_char* p; state->default_auxiliary_sample_size = sizeof(cenc_sample_auxiliary_data_t) + sizeof(cenc_sample_auxiliary_data_subsample_t); state->saiz_sample_count = state->base.sequence->total_frame_count; p = vod_alloc( state->base.request_context->pool, state->default_auxiliary_sample_size * state->base.sequence->total_frame_count); if (p == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, state->base.request_context->log, 0, "mp4_encrypt_video_snpf_build_auxiliary_data: vod_alloc failed"); return VOD_ALLOC_FAILED; } state->auxiliary_data.start = p; bytes_of_clear_data = state->base.cur_clip->first_track->media_info.u.video.nal_packet_size_length + 1; vod_memcpy(iv, state->base.iv, sizeof(iv)); for (;;) { if (!mp4_encrypt_move_to_next_frame(&state->base, &init_track)) { break; } if (init_track) { bytes_of_clear_data = state->base.cur_clip->first_track->media_info.u.video.nal_packet_size_length + 1; } // cenc_sample_auxiliary_data_t p = vod_copy(p, iv, sizeof(iv)); mp4_aes_ctr_increment_be64(iv); write_be16(p, 1); // subsample count // cenc_sample_auxiliary_data_subsample_t bytes_of_encrypted_data = state->base.cur_frame->size - bytes_of_clear_data; write_be16(p, bytes_of_clear_data); write_be32(p, bytes_of_encrypted_data); state->base.cur_frame++; } state->auxiliary_data.pos = p; // reset the state state->base.cur_clip = state->base.sequence->filtered_clips; mp4_encrypt_init_track(&state->base, state->base.cur_clip->first_track); return VOD_OK; }
vod_status_t sample_aes_avc_filter_init( void** context, request_context_t* request_context, media_filter_write_t write_callback, void* write_context, u_char* key, u_char* iv) { sample_aes_avc_filter_state_t* state; vod_pool_cleanup_t *cln; state = vod_alloc(request_context->pool, sizeof(*state)); if (state == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0, "sample_aes_avc_filter_init: vod_alloc failed"); return VOD_ALLOC_FAILED; } cln = vod_pool_cleanup_add(request_context->pool, 0); if (cln == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0, "sample_aes_avc_filter_init: vod_pool_cleanup_add failed"); return VOD_ALLOC_FAILED; } cln->handler = (vod_pool_cleanup_pt)sample_aes_avc_cleanup; cln->data = state; state->request_context = request_context; state->write_callback = write_callback; state->write_context = write_context; vod_memcpy(state->iv, iv, sizeof(state->iv)); vod_memcpy(state->key, key, sizeof(state->key)); state->encrypt = FALSE; EVP_CIPHER_CTX_init(&state->cipher); *context = state; return VOD_OK; }
void mp4_aes_ctr_set_iv( mp4_aes_ctr_state_t* state, u_char* iv) { vod_memcpy(state->counter, iv, MP4_AES_CTR_IV_SIZE); vod_memzero(state->counter + MP4_AES_CTR_IV_SIZE, sizeof(state->counter) - MP4_AES_CTR_IV_SIZE); state->block_offset = 0; }
void mp4_aes_ctr_set_iv( mp4_aes_ctr_state_t* state, u_char* iv) { vod_memcpy(state->counter, iv, MP4_AES_CTR_IV_SIZE); vod_memzero(state->counter + MP4_AES_CTR_IV_SIZE, sizeof(state->counter) - MP4_AES_CTR_IV_SIZE); state->encrypted_pos = NULL; state->encrypted_end = NULL; }
u_char* mp4_encrypt_audio_write_auxiliary_data(mp4_encrypt_state_t* state, u_char* p) { u_char* end_pos = p + sizeof(state->iv) * state->sequence->total_frame_count; u_char iv[MP4_AES_CTR_IV_SIZE]; vod_memcpy(iv, state->iv, sizeof(iv)); while (p < end_pos) { p = vod_copy(p, iv, sizeof(iv)); mp4_aes_ctr_increment_be64(iv); } return p; }
vod_status_t mp4_decrypt_init( request_context_t* request_context, frames_source_t* frames_source, void* frames_source_context, u_char* key, media_encryption_t* encryption, void** result) { mp4_decrypt_state_t* state; vod_status_t rc; state = vod_alloc(request_context->pool, sizeof(*state)); if (state == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0, "mp4_decrypt_init: vod_alloc failed"); return VOD_ALLOC_FAILED; } vod_memzero(state, sizeof(*state)); rc = mp4_aes_ctr_init(&state->cipher, request_context, key); if (rc != VOD_OK) { return rc; } vod_memcpy(state->key, key, sizeof(state->key)); state->request_context = request_context; state->frames_source = frames_source; state->frames_source_context = frames_source_context; state->reuse_buffers = TRUE; state->auxiliary_info_pos = encryption->auxiliary_info; state->auxiliary_info_end = encryption->auxiliary_info_end; state->use_subsamples = encryption->use_subsamples; *result = state; return VOD_OK; }
vod_status_t audio_encoder_update_media_info( void* context, media_info_t* media_info) { audio_encoder_state_t* state = context; AVCodecContext *encoder = state->encoder; u_char* new_extra_data; if (encoder->time_base.num != 1) { vod_log_error(VOD_LOG_ERR, state->request_context->log, 0, "audio_encoder_update_media_info: unexpected encoder time base %d/%d", encoder->time_base.num, encoder->time_base.den); return VOD_UNEXPECTED; } media_info->timescale = encoder->time_base.den; media_info->bitrate = encoder->bit_rate; media_info->u.audio.object_type_id = 0x40; // ffmpeg always writes 0x40 (ff_mp4_obj_type) media_info->u.audio.channels = encoder->channels; media_info->u.audio.bits_per_sample = AUDIO_ENCODER_BITS_PER_SAMPLE; media_info->u.audio.packet_size = 0; // ffmpeg always writes 0 (mov_write_audio_tag) media_info->u.audio.sample_rate = encoder->sample_rate; new_extra_data = vod_alloc(state->request_context->pool, encoder->extradata_size); if (new_extra_data == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, state->request_context->log, 0, "audio_encoder_update_media_info: vod_alloc failed"); return VOD_ALLOC_FAILED; } vod_memcpy(new_extra_data, encoder->extradata, encoder->extradata_size); media_info->extra_data.data = new_extra_data; media_info->extra_data.len = encoder->extradata_size; return VOD_OK; }
vod_status_t audio_filter_update_stream_metadata(audio_filter_state_t* state) { mpeg_stream_metadata_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; if (state->encoder->time_base.num != 1) { vod_log_error(VOD_LOG_ERR, state->request_context->log, 0, "audio_filter_update_stream_metadata: unexpected encoder time base num %d", state->encoder->time_base.num); return VOD_UNEXPECTED; } output->frames = state->frames_array.elts; output->frame_count = state->frames_array.nelts; output->frame_offsets = state->frame_offsets_array.elts; output->total_frames_size = 0; output->total_frames_duration = 0; output->media_info.min_frame_duration = 0; output->media_info.max_frame_duration = 0; last_frame = output->frames + output->frame_count; for (cur_frame = output->frames; 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; } if (cur_frame->duration > output->media_info.max_frame_duration) { output->media_info.max_frame_duration = cur_frame->duration; } } if (output->media_info.min_frame_duration == 0) { vod_log_error(VOD_LOG_ERR, state->request_context->log, 0, "audio_filter_update_stream_metadata: min frame duration is zero"); return VOD_UNEXPECTED; } old_timescale = output->media_info.timescale; output->media_info.timescale = state->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->encoder->bit_rate; output->media_info.speed_nom = 1; output->media_info.speed_denom = 1; output->media_info.u.audio.object_type_id = 0x40; // ffmpeg always writes 0x40 (ff_mp4_obj_type) output->media_info.u.audio.channels = state->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->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->encoder->extradata_size); if (new_extra_data == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, state->request_context->log, 0, "audio_filter_update_stream_metadata: vod_alloc failed"); return VOD_ALLOC_FAILED; } vod_memcpy(new_extra_data, state->encoder->extradata, state->encoder->extradata_size); output->media_info.extra_data = new_extra_data; output->media_info.extra_data_size = state->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; } } output->frames_file_index = INVALID_FILE_INDEX; // the frames are now in memory // TODO: update raw_atoms return VOD_OK; }
static vod_status_t mp4_metadata_reader_read( void* ctx, uint64_t offset, vod_str_t* buffer, media_format_read_metadata_result_t* result) { mp4_read_metadata_state_t* state = ctx; const u_char* ftyp_ptr; size_t ftyp_size; u_char* uncomp_buffer; off_t moov_offset; size_t moov_size; vod_status_t rc; if (state->state == STATE_READ_MOOV_DATA) { // make sure we got the whole moov atom moov_size = state->parts[MP4_METADATA_PART_MOOV].len; if (buffer->len < moov_size) { vod_log_error(VOD_LOG_ERR, state->request_context->log, 0, "mp4_metadata_reader_read: buffer size %uz is smaller than moov size %uz", buffer->len, moov_size); return VOD_BAD_DATA; } moov_offset = 0; goto done; } if (state->parts[MP4_METADATA_PART_FTYP].len == 0) { // try to find the ftyp atom rc = mp4_parser_get_ftyp_atom_into( state->request_context, buffer->data, buffer->len, &ftyp_ptr, &ftyp_size); if (rc != VOD_OK) { vod_log_debug1(VOD_LOG_DEBUG_LEVEL, state->request_context->log, 0, "mp4_metadata_reader_read: mp4_parser_get_ftyp_atom_into failed %i", rc); return rc; } if (ftyp_size > 0 && ftyp_ptr + ftyp_size <= buffer->len + buffer->data) { // got a full ftyp atom state->parts[MP4_METADATA_PART_FTYP].data = vod_alloc(state->request_context->pool, ftyp_size); if (state->parts[MP4_METADATA_PART_FTYP].data == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, state->request_context->log, 0, "mp4_metadata_reader_read: vod_alloc failed"); return VOD_ALLOC_FAILED; } vod_memcpy(state->parts[MP4_METADATA_PART_FTYP].data, ftyp_ptr, ftyp_size); state->parts[MP4_METADATA_PART_FTYP].len = ftyp_size; } else { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, state->request_context->log, 0, "mp4_metadata_reader_read: ftyp atom not found"); } } // get moov atom offset and size rc = mp4_parser_get_moov_atom_info( state->request_context, buffer->data, buffer->len, &moov_offset, &moov_size); if (rc != VOD_OK) { vod_log_debug1(VOD_LOG_DEBUG_LEVEL, state->request_context->log, 0, "mp4_metadata_reader_read: mp4_parser_get_moov_atom_info failed %i", rc); return rc; } if (moov_size <= 0) { // moov not found if ((size_t)moov_offset < buffer->len) { vod_log_error(VOD_LOG_ERR, state->request_context->log, 0, "mp4_metadata_reader_read: moov start offset %O is smaller than the buffer size %uz", moov_offset, buffer->len); return VOD_BAD_DATA; } if (state->moov_start_reads <= 0) { vod_log_error(VOD_LOG_ERR, state->request_context->log, 0, "mp4_metadata_reader_read: exhausted all moov read attempts"); return VOD_BAD_DATA; } state->moov_start_reads--; // perform another read attempt result->read_req.read_offset = offset + moov_offset; result->read_req.read_size = 0; result->read_req.realloc_buffer = FALSE; return VOD_AGAIN; } // save the moov size state->parts[MP4_METADATA_PART_MOOV].len = moov_size; // check whether we already have the whole atom if (moov_offset + moov_size <= buffer->len) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, state->request_context->log, 0, "mp4_metadata_reader_read: already read the full moov atom"); goto done; } // validate the moov size if (moov_size > state->max_moov_size) { vod_log_error(VOD_LOG_ERR, state->request_context->log, 0, "mp4_metadata_reader_read: moov size %uD exceeds the max %uz", moov_size, state->max_moov_size); return VOD_BAD_DATA; } state->state = STATE_READ_MOOV_DATA; result->read_req.read_offset = offset + moov_offset; result->read_req.read_size = moov_size; result->read_req.realloc_buffer = FALSE; return VOD_AGAIN; done: state->parts[MP4_METADATA_PART_MOOV].data = buffer->data + moov_offset; // uncompress the moov atom if needed rc = mp4_parser_uncompress_moov( state->request_context, state->parts[MP4_METADATA_PART_MOOV].data, moov_size, state->max_moov_size, &uncomp_buffer, &moov_offset, &moov_size); if (rc != VOD_OK) { vod_log_debug1(VOD_LOG_DEBUG_LEVEL, state->request_context->log, 0, "mp4_metadata_reader_read: mp4_parser_uncompress_moov failed %i", rc); return rc; } if (uncomp_buffer != NULL) { state->parts[MP4_METADATA_PART_MOOV].data = uncomp_buffer + moov_offset; state->parts[MP4_METADATA_PART_MOOV].len = moov_size; } result->parts = state->parts; result->part_count = MP4_METADATA_PART_COUNT; 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; }
vod_status_t audio_filter_process(void* context) { audio_filter_state_t* state = context; audio_filter_source_t* source; u_char* read_buffer; uint32_t read_size; bool_t processed_data = FALSE; vod_status_t rc; bool_t frame_done; for (;;) { // choose a source if needed if (state->cur_source == NULL) { rc = audio_filter_choose_source(state, &source); if (rc != VOD_OK) { return rc; } if (source == NULL) { // done return audio_filter_flush_encoder(state); } state->cur_source = source; // start the frame rc = source->cur_frame_part.frames_source->start_frame( source->cur_frame_part.frames_source_context, source->cur_frame); if (rc != VOD_OK) { return rc; } } else { source = state->cur_source; } // read some data from the frame rc = source->cur_frame_part.frames_source->read( source->cur_frame_part.frames_source_context, &read_buffer, &read_size, &frame_done); if (rc != VOD_OK) { if (rc != VOD_AGAIN) { return rc; } if (!processed_data && !state->first_time) { vod_log_error(VOD_LOG_ERR, state->request_context->log, 0, "audio_filter_process: no data was handled, probably a truncated file"); return VOD_BAD_DATA; } state->first_time = FALSE; return VOD_AGAIN; } processed_data = TRUE; if (!frame_done) { // didn't finish the frame, append to the frame buffer vod_memcpy(state->frame_buffer + state->cur_frame_pos, read_buffer, read_size); state->cur_frame_pos += read_size; continue; } if (state->cur_frame_pos != 0) { // copy the remainder vod_memcpy(state->frame_buffer + state->cur_frame_pos, read_buffer, read_size); state->cur_frame_pos = 0; read_buffer = state->frame_buffer; } // process the frame rc = audio_filter_process_frame(state, read_buffer); if (rc != VOD_OK) { return rc; } // move to the next frame source->cur_frame++; state->cur_source = NULL; } }
static vod_status_t audio_filter_process_frame(audio_filter_state_t* state, u_char* buffer) { audio_filter_source_t* source = state->cur_source; input_frame_t* frame = source->cur_frame; AVPacket input_packet; u_char original_pad[VOD_BUFFER_PADDING_SIZE]; u_char* frame_end; int got_frame; int avrc; #ifdef AUDIO_FILTER_DEBUG size_t data_size; #endif // AUDIO_FILTER_DEBUG #ifdef AUDIO_FILTER_DEBUG audio_filter_append_debug_data("input", "aac", buffer, frame->size); #endif // AUDIO_FILTER_DEBUG vod_memzero(&input_packet, sizeof(input_packet)); input_packet.data = buffer; input_packet.size = frame->size; input_packet.dts = source->dts; input_packet.pts = source->dts + frame->pts_delay; input_packet.duration = frame->duration; input_packet.flags = AV_PKT_FLAG_KEY; source->dts += frame->duration; av_frame_unref(state->decoded_frame); got_frame = 0; frame_end = buffer + frame->size; vod_memcpy(original_pad, frame_end, sizeof(original_pad)); vod_memzero(frame_end, sizeof(original_pad)); avrc = avcodec_decode_audio4(source->decoder, state->decoded_frame, &got_frame, &input_packet); if (avrc < 0) { vod_log_error(VOD_LOG_ERR, state->request_context->log, 0, "audio_filter_process_frame: avcodec_decode_audio4 failed %d", avrc); return VOD_BAD_DATA; } vod_memcpy(frame_end, original_pad, sizeof(original_pad)); if (!got_frame) { return VOD_OK; } #ifdef AUDIO_FILTER_DEBUG data_size = av_samples_get_buffer_size( NULL, source->decoder->channels, state->decoded_frame->nb_samples, source->decoder->sample_fmt, 1); audio_filter_append_debug_data(source->buffer_src->name, "pcm", state->decoded_frame->data[0], data_size); #endif // AUDIO_FILTER_DEBUG avrc = av_buffersrc_add_frame_flags(source->buffer_src, state->decoded_frame, AV_BUFFERSRC_FLAG_PUSH); if (avrc < 0) { vod_log_error(VOD_LOG_ERR, state->request_context->log, 0, "audio_filter_process_frame: av_buffersrc_add_frame_flags failed %d", avrc); return VOD_ALLOC_FAILED; } return audio_filter_read_filter_sink(state); }
vod_status_t full_frame_processor_process(full_frame_processor_t* state) { u_char* read_buffer; uint32_t read_size; uint32_t cur_copy_size; uint64_t offset; bool_t processed_data = FALSE; vod_status_t rc; for (;;) { // check if we're done if (state->cur_frame >= state->last_frame) { rc = state->frame_callback(state->frame_context, NULL, NULL); if (rc != VOD_OK) { return rc; } return VOD_OK; } // read some data from the frame offset = *state->cur_frame_offset + state->cur_frame_pos; if (!read_cache_get_from_cache( state->read_cache_state, state->cur_frame->size - state->cur_frame_pos, 0, state->frames_file_index, offset, &read_buffer, &read_size)) { if (!processed_data && !state->first_time) { vod_log_error(VOD_LOG_ERR, state->request_context->log, 0, "full_frame_processor_process: no data was handled, probably a truncated file"); return VOD_BAD_DATA; } state->first_time = FALSE; return VOD_AGAIN; } processed_data = TRUE; if (state->cur_frame_pos == 0 && read_size >= state->cur_frame->size) { // have the whole frame in one piece rc = state->frame_callback(state->frame_context, state->cur_frame, read_buffer); if (rc != VOD_OK) { return rc; } // move to the next frame state->cur_frame++; state->cur_frame_offset++; continue; } // copy as much as possible from the frame cur_copy_size = MIN(state->cur_frame->size - state->cur_frame_pos, read_size); vod_memcpy(state->frame_buffer + state->cur_frame_pos, read_buffer, cur_copy_size); state->cur_frame_pos += cur_copy_size; // move to the next frame if done if (state->cur_frame_pos >= state->cur_frame->size) { rc = state->frame_callback(state->frame_context, state->cur_frame, state->frame_buffer); if (rc != VOD_OK) { return rc; } state->cur_frame++; state->cur_frame_offset++; state->cur_frame_pos = 0; } } }
vod_status_t mp4_aes_ctr_process(mp4_aes_ctr_state_t* state, u_char* dest, const u_char* src, uint32_t size) { const u_char* src_end = src + size; const u_char* cur_end_pos; u_char* encrypted_counter_pos; u_char* cur_block; u_char* next_block; u_char* end_block; size_t encrypted_size; int out_size; while (src < src_end) { if (state->encrypted_pos >= state->encrypted_end) { // find the size of the data to encrypt encrypted_size = aes_round_up_to_block_exact(src_end - src); if (encrypted_size > sizeof(state->counter)) { encrypted_size = sizeof(state->counter); } // initialize the clear counters (the first counter is already initialized) end_block = state->counter + encrypted_size - AES_BLOCK_SIZE; for (cur_block = state->counter; cur_block < end_block; cur_block = next_block) { next_block = cur_block + AES_BLOCK_SIZE; vod_memcpy(next_block, cur_block, AES_BLOCK_SIZE); mp4_aes_ctr_increment_be64(next_block + 8); } // encrypt the clear counters if (1 != EVP_EncryptUpdate( &state->cipher, state->encrypted_counter, &out_size, state->counter, encrypted_size) || out_size != (int)encrypted_size) { vod_log_error(VOD_LOG_ERR, state->request_context->log, 0, "mp4_aes_ctr_process: EVP_EncryptUpdate failed"); return VOD_UNEXPECTED; } // update the first counter if (encrypted_size > AES_BLOCK_SIZE) { vod_memcpy(state->counter, end_block, AES_BLOCK_SIZE); } mp4_aes_ctr_increment_be64(state->counter + 8); state->encrypted_end = state->encrypted_counter + encrypted_size; encrypted_counter_pos = state->encrypted_counter; cur_end_pos = src + encrypted_size; } else { encrypted_counter_pos = state->encrypted_pos; cur_end_pos = src + (state->encrypted_end - encrypted_counter_pos); } if (src_end < cur_end_pos) { cur_end_pos = src_end; } while (src < cur_end_pos) { *dest++ = *src++ ^ *encrypted_counter_pos++; } state->encrypted_pos = encrypted_counter_pos; } return VOD_OK; }
vod_status_t codec_config_hevc_get_nal_units( request_context_t* request_context, const u_char* extra_data, uint32_t extra_data_size, bool_t size_only, uint32_t* nal_packet_size_length, u_char** result, uint32_t* result_size) { hevc_config_t cfg; vod_status_t rc; const u_char* start_pos; const u_char* cur_pos; const u_char* end_pos; size_t actual_size; uint16_t unit_size; uint16_t count; uint8_t type_count; u_char* p; rc = codec_config_hevc_config_parse(request_context, extra_data, extra_data_size, &cfg, &start_pos); if (rc != VOD_OK) { return rc; } *nal_packet_size_length = cfg.nal_unit_size; end_pos = extra_data + extra_data_size; // calculate total size and validate *result_size = 0; cur_pos = start_pos; if (cur_pos >= end_pos) { vod_log_error(VOD_LOG_ERR, request_context->log, 0, "codec_config_hevc_get_nal_units: extra data overflow while reading type count"); return VOD_BAD_DATA; } for (type_count = *cur_pos++; type_count > 0; type_count--) { if (cur_pos + 3 > end_pos) { vod_log_error(VOD_LOG_ERR, request_context->log, 0, "codec_config_hevc_get_nal_units: extra data overflow while reading type header"); return VOD_BAD_DATA; } cur_pos++; read_be16(cur_pos, count); for (; count > 0; count--) { if (cur_pos + sizeof(uint16_t) > end_pos) { vod_log_error(VOD_LOG_ERR, request_context->log, 0, "codec_config_hevc_get_nal_units: extra data overflow while reading unit size"); return VOD_BAD_DATA; } read_be16(cur_pos, unit_size); cur_pos += unit_size; if (cur_pos > end_pos) { vod_log_error(VOD_LOG_ERR, request_context->log, 0, "codec_config_hevc_get_nal_units: extra data overflow while reading unit data"); return VOD_BAD_DATA; } *result_size += sizeof(uint32_t) + unit_size; } } if (size_only) { *result = NULL; return VOD_OK; } // allocate buffer p = vod_alloc(request_context->pool, *result_size); if (p == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0, "codec_config_hevc_get_nal_units: vod_alloc failed"); return VOD_ALLOC_FAILED; } *result = p; // copy data cur_pos = start_pos; for (type_count = *cur_pos++; type_count > 0; type_count--) { cur_pos++; // unit type read_be16(cur_pos, count); for (; count > 0; count--) { read_be16(cur_pos, unit_size); *((uint32_t*)p) = 0x01000000; p += sizeof(uint32_t); vod_memcpy(p, cur_pos, unit_size); p += unit_size; cur_pos += unit_size; } } // verify size actual_size = p - *result; if (actual_size != *result_size) { vod_log_error(VOD_LOG_ERR, request_context->log, 0, "codec_config_hevc_get_nal_units: actual extra data size %uz is different than calculated size %uD", actual_size, *result_size); return VOD_UNEXPECTED; } vod_log_buffer(VOD_LOG_DEBUG_LEVEL, request_context->log, 0, "codec_config_hevc_get_nal_units: parsed extra data ", *result, *result_size); return VOD_OK; }
vod_status_t codec_config_avcc_get_nal_units( request_context_t* request_context, const u_char* extra_data, uint32_t extra_data_size, bool_t size_only, uint32_t* nal_packet_size_length, u_char** result, uint32_t* result_size) { const u_char* extra_data_end = extra_data + extra_data_size; const u_char* cur_pos; u_char* p; size_t actual_size; uint16_t unit_size; int unit_count; int i; if (extra_data_size < sizeof(avcc_config_t)) { vod_log_error(VOD_LOG_ERR, request_context->log, 0, "codec_config_avcc_get_nal_units: extra data size %uD too small", extra_data_size); return VOD_BAD_DATA; } *nal_packet_size_length = (((avcc_config_t*)extra_data)->nula_length_size & 0x3) + 1; // calculate total size and validate *result_size = 0; cur_pos = extra_data + sizeof(avcc_config_t); for (i = 0; i < 2; i++) // once for SPS, once for PPS { if (cur_pos >= extra_data_end) { vod_log_error(VOD_LOG_ERR, request_context->log, 0, "codec_config_avcc_get_nal_units: extra data overflow while reading unit count"); return VOD_BAD_DATA; } for (unit_count = (*cur_pos++ & 0x1f); unit_count; unit_count--) { if (cur_pos + sizeof(uint16_t) > extra_data_end) { vod_log_error(VOD_LOG_ERR, request_context->log, 0, "codec_config_avcc_get_nal_units: extra data overflow while reading unit size"); return VOD_BAD_DATA; } read_be16(cur_pos, unit_size); if (cur_pos + unit_size > extra_data_end) { vod_log_error(VOD_LOG_ERR, request_context->log, 0, "codec_config_avcc_get_nal_units: unit size %uD overflows the extra data buffer", (uint32_t)unit_size); return VOD_BAD_DATA; } cur_pos += unit_size; *result_size += sizeof(uint32_t) + unit_size; } } if (size_only) { *result = NULL; return VOD_OK; } // allocate buffer p = vod_alloc(request_context->pool, *result_size); if (p == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0, "codec_config_avcc_get_nal_units: vod_alloc failed"); return VOD_ALLOC_FAILED; } *result = p; // copy data cur_pos = extra_data + sizeof(avcc_config_t); for (i = 0; i < 2; i++) // once for SPS, once for PPS { for (unit_count = *cur_pos++ & 0x1f; unit_count; unit_count--) { unit_size = parse_be16(cur_pos); cur_pos += sizeof(uint16_t); *((uint32_t*)p) = 0x01000000; p += sizeof(uint32_t); vod_memcpy(p, cur_pos, unit_size); cur_pos += unit_size; p += unit_size; } } actual_size = p - *result; if (actual_size != *result_size) { vod_log_error(VOD_LOG_ERR, request_context->log, 0, "codec_config_avcc_get_nal_units: actual extra data size %uz is different than calculated size %uD", actual_size, *result_size); return VOD_UNEXPECTED; } vod_log_buffer(VOD_LOG_DEBUG_LEVEL, request_context->log, 0, "codec_config_avcc_get_nal_units: parsed extra data ", *result, *result_size); return VOD_OK; }
vod_status_t audio_filter_process(void* context) { audio_filter_state_t* state = context; audio_filter_source_t* source; u_char* read_buffer; uint32_t read_size; uint64_t offset; bool_t processed_data = FALSE; vod_status_t rc; for (;;) { // choose a source if needed if (state->cur_source == NULL) { rc = audio_filter_choose_source(state, &source); if (rc != VOD_OK) { return rc; } if (source == NULL) { // done return audio_filter_flush_encoder(state); } state->cur_source = source; } else { source = state->cur_source; } // read some data from the frame offset = *source->cur_frame_offset + state->cur_frame_pos; if (!read_cache_get_from_cache( state->read_cache_state, source->cur_frame->size - state->cur_frame_pos, source->cache_slot_id, source->frames_source, offset, &read_buffer, &read_size)) { if (!processed_data && !state->first_time) { vod_log_error(VOD_LOG_ERR, state->request_context->log, 0, "audio_filter_process: no data was handled, probably a truncated file"); return VOD_BAD_DATA; } state->first_time = FALSE; return VOD_AGAIN; } processed_data = TRUE; if (state->cur_frame_pos == 0 && read_size >= source->cur_frame->size) { // have the whole frame in one piece rc = audio_filter_process_frame(state, read_buffer); if (rc != VOD_OK) { return rc; } // move to the next frame source->cur_frame++; source->cur_frame_offset++; state->cur_source = NULL; continue; } if (read_size < source->cur_frame->size - state->cur_frame_pos) { // didn't finish the frame, append to the frame buffer vod_memcpy(state->frame_buffer + state->cur_frame_pos, read_buffer, read_size); state->cur_frame_pos += read_size; continue; } // finished the frame vod_memcpy(state->frame_buffer + state->cur_frame_pos, read_buffer, source->cur_frame->size - state->cur_frame_pos); rc = audio_filter_process_frame(state, state->frame_buffer); if (rc != VOD_OK) { return rc; } source->cur_frame++; source->cur_frame_offset++; state->cur_frame_pos = 0; state->cur_source = NULL; } }