Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 5
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->block_offset = 0;
}
Ejemplo n.º 6
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;
}
Ejemplo n.º 7
0
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;
}
Ejemplo n.º 8
0
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;
}
Ejemplo n.º 9
0
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;
}
Ejemplo n.º 10
0
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;
}
Ejemplo n.º 11
0
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;
}
Ejemplo n.º 12
0
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;
}
Ejemplo n.º 13
0
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;
	}
}
Ejemplo n.º 14
0
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;
		}
	}
}
Ejemplo n.º 16
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;
}
Ejemplo n.º 17
0
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;
}
Ejemplo n.º 18
0
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;
}
Ejemplo n.º 19
0
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;
	}
}