X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fcodec%2Favcodec%2Fencoder.c;h=acf9f28bf5475ac79289fe77800fda03d549d7fa;hb=6d6342b47ebfa8fdad36cbae84ab81fad8bdca9b;hp=54b7fed93e39211f2e0bcac4a0a1cebab0d8f002;hpb=52707967341dd264d6422c8186dfa1d3c833965a;p=vlc diff --git a/modules/codec/avcodec/encoder.c b/modules/codec/avcodec/encoder.c index 54b7fed93e..acf9f28bf5 100644 --- a/modules/codec/avcodec/encoder.c +++ b/modules/codec/avcodec/encoder.c @@ -94,7 +94,7 @@ struct encoder_sys_t AVCodecContext *p_context; /* - * Common properties + * Common buffer mainly for audio as frame size in there needs usually be constant */ char *p_buffer; size_t i_buffer_out; @@ -294,11 +294,9 @@ int OpenEncoder( vlc_object_t *p_this ) if( ( p_sys = calloc( 1, sizeof(encoder_sys_t) ) ) == NULL ) return VLC_ENOMEM; p_enc->p_sys = p_sys; + p_sys->i_samples_delay = 0; p_sys->p_codec = p_codec; - p_enc->pf_encode_video = EncodeVideo; - p_enc->pf_encode_audio = EncodeAudio; - p_sys->p_buffer = NULL; p_sys->i_buffer_out = 0; @@ -595,7 +593,8 @@ int OpenEncoder( vlc_object_t *p_this ) p_context->sample_fmt = p_codec->sample_fmts ? p_codec->sample_fmts[0] : AV_SAMPLE_FMT_S16; - p_enc->fmt_in.i_codec = VLC_CODEC_S16N; + p_enc->fmt_in.i_codec = GetVlcAudioFormat( p_context->sample_fmt ); + p_context->sample_rate = p_enc->fmt_out.audio.i_rate; p_context->time_base.num = 1; p_context->time_base.den = p_context->sample_rate; @@ -807,9 +806,9 @@ int OpenEncoder( vlc_object_t *p_this ) if( p_enc->fmt_in.i_cat == AUDIO_ES ) { - GetVlcAudioFormat( &p_enc->fmt_in.i_codec, - &p_enc->fmt_in.audio.i_bitspersample, - p_sys->p_context->sample_fmt ); + p_enc->fmt_in.i_codec = GetVlcAudioFormat( p_sys->p_context->sample_fmt ); + p_enc->fmt_in.audio.i_bitspersample = aout_BitsPerSample( p_enc->fmt_in.i_codec ); + p_sys->i_sample_bytes = (p_enc->fmt_in.audio.i_bitspersample / 8) * p_context->channels; p_sys->i_frame_size = p_context->frame_size > 1 ? @@ -821,7 +820,7 @@ int OpenEncoder( vlc_object_t *p_this ) goto error; } p_enc->fmt_out.audio.i_blockalign = p_context->block_align; - p_enc->fmt_out.audio.i_bitspersample = aout_BitsPerSample( vlc_fourcc_GetCodec( AUDIO_ES, p_enc->fmt_out.i_codec ) ); + p_enc->fmt_out.audio.i_bitspersample = aout_BitsPerSample( p_enc->fmt_out.i_codec ); if( p_context->frame_size > 1 ) p_sys->i_buffer_out = 8 * AVCODEC_MAX_AUDIO_FRAME_SIZE; @@ -830,6 +829,9 @@ int OpenEncoder( vlc_object_t *p_this ) } msg_Dbg( p_enc, "found encoder %s", psz_namecodec ); + p_enc->pf_encode_video = EncodeVideo; + p_enc->pf_encode_audio = EncodeAudio; + return VLC_SUCCESS; error: @@ -1026,64 +1028,164 @@ static block_t *EncodeAudio( encoder_t *p_enc, block_t *p_aout_buf ) encoder_sys_t *p_sys = p_enc->p_sys; block_t *p_block, *p_chain = NULL; - AVFrame *frame; - AVPacket packet; - int got_packet,i_out; + AVFrame *frame=NULL; + int got_packet,i_out,i_samples_left=0,i_data_offset = 0; + + //i_samples_left is amount of samples we get + i_samples_left = p_aout_buf ? p_aout_buf->i_nb_samples : 0; + + if( p_sys->i_samples_delay > 0 ) + { + AVPacket packet; + //How much we need to copy from new packet + const int leftover = __MAX(0,__MIN(i_samples_left, (p_sys->i_frame_size - p_sys->i_samples_delay))); + + frame = avcodec_alloc_frame(); + frame->nb_samples = p_sys->i_samples_delay + leftover; + frame->format = p_sys->p_context->sample_fmt; + + //Copy samples from new packet to buffer to get frame size + if( likely( leftover ) ) + memcpy( p_sys->p_buffer+(p_sys->i_samples_delay*p_sys->i_sample_bytes), p_aout_buf->p_buffer, leftover*p_sys->i_sample_bytes*p_enc->fmt_in.audio.i_channels); + + if( avcodec_fill_audio_frame( frame, p_enc->fmt_in.audio.i_channels, + p_sys->p_context->sample_fmt, + p_sys->p_buffer, + (p_sys->i_samples_delay + leftover) * p_sys->i_sample_bytes * p_enc->fmt_in.audio.i_channels, + 0) < 0 ) + msg_Err( p_enc, "Filling on leftovers error i_leftover %d i_samples_left %d samples_delay %d frame size %d", leftover, i_samples_left, p_sys->i_samples_delay, p_sys->i_frame_size ); + + if( likely( p_aout_buf ) ) + frame->pts = p_aout_buf->i_pts - + (mtime_t)1000000 * (mtime_t)p_sys->i_samples_delay / + (mtime_t)p_enc->fmt_in.audio.i_rate; + + p_sys->i_samples_delay = 0; + i_data_offset += leftover * p_sys->i_sample_bytes * p_enc->fmt_in.audio.i_channels; + i_samples_left -= leftover; + + p_block = block_Alloc( p_sys->i_buffer_out ); + av_init_packet( &packet ); + packet.data = p_block->p_buffer; + packet.size = p_block->i_buffer; + + i_out = avcodec_encode_audio2( p_sys->p_context, &packet, frame, &got_packet ); + p_block->i_buffer = packet.size; + + + /*FIXME: same as avcodec_free_frame, but we don't require so new avcodec that has it*/ + if( frame->extended_data != frame->data ) + av_freep( frame->extended_data ); + av_freep( &frame ); + if( unlikely( !got_packet || ( i_out < 0 ) ) ) + { + if( i_out < 0 ) + { + msg_Err( p_enc,"Encoding problem..."); + return p_chain; + } + } else { + p_block->i_buffer = packet.size; + + p_block->i_length = (mtime_t)1000000 * + (mtime_t)p_sys->i_frame_size / + (mtime_t)p_sys->p_context->sample_rate; + + p_block->i_dts = p_block->i_pts = packet.pts; + + block_ChainAppend( &p_chain, p_block ); + } + } - /*FIXME: change to use avcodec_encode_audio2 to be able to flush*/ if( unlikely( !p_aout_buf ) ) { msg_Dbg(p_enc,"Flushing.."); do { + AVPacket packet; p_block = block_Alloc( p_sys->i_buffer_out ); av_init_packet( &packet ); packet.data = p_block->p_buffer; packet.size = p_block->i_buffer; i_out = avcodec_encode_audio2( p_sys->p_context, &packet, NULL, &got_packet ); + p_block->i_buffer = packet.size; + + p_block->i_length = (mtime_t)1000000 * + (mtime_t)p_sys->i_frame_size / + (mtime_t)p_sys->p_context->sample_rate; + + p_block->i_dts = p_block->i_pts = packet.pts; + if( !i_out && got_packet ) block_ChainAppend( &p_chain, p_block ); } while( got_packet && !i_out ); return p_chain; } - frame = avcodec_alloc_frame(); + while( i_samples_left >= p_sys->i_frame_size ) + { + AVPacket packet = {0}; + frame = avcodec_alloc_frame(); - frame->nb_samples = p_aout_buf->i_nb_samples; - avcodec_fill_audio_frame( frame, p_enc->fmt_in.audio.i_channels, - p_sys->p_context->sample_fmt, - p_aout_buf->p_buffer, p_aout_buf->i_buffer, - 0); + frame->nb_samples = p_sys->i_frame_size; + frame->format = p_sys->p_context->sample_fmt; + if( avcodec_fill_audio_frame( frame, p_enc->fmt_in.audio.i_channels, + p_sys->p_context->sample_fmt, + p_aout_buf->p_buffer+i_data_offset, + p_sys->i_frame_size * p_sys->i_sample_bytes * p_enc->fmt_in.audio.i_channels, + 0) < 0 ) + msg_Err( p_enc, "filling error on encode" ); - frame->pts = p_aout_buf->i_pts; + i_samples_left -= p_sys->i_frame_size; + i_data_offset += p_sys->i_frame_size * p_sys->i_sample_bytes * p_enc->fmt_in.audio.i_channels; - p_block = block_Alloc( p_sys->i_buffer_out ); - av_init_packet( &packet ); - packet.data = p_block->p_buffer; - packet.size = p_block->i_buffer; + frame->pts = p_aout_buf->i_pts; - i_out = avcodec_encode_audio2( p_sys->p_context, &packet, frame, &got_packet ); - p_block->i_buffer = packet.size; - - av_freep( &frame ); - if( unlikely( !got_packet || i_out ) ) - { - if( i_out ) - msg_Err( p_enc,"Encoding problem.."); - block_Release( p_block ); - return NULL; - } + p_block = block_Alloc( p_sys->i_buffer_out ); + av_init_packet( &packet ); + packet.data = p_block->p_buffer; + packet.size = p_block->i_buffer; - p_block->i_buffer = packet.size; + i_out = avcodec_encode_audio2( p_sys->p_context, &packet, frame, &got_packet ); + p_block->i_buffer = packet.size; - p_block->i_length = (mtime_t)1000000 * - (mtime_t)p_sys->i_frame_size / - (mtime_t)p_sys->p_context->sample_rate; + if( frame->extended_data != frame->data ) + av_freep( frame->extended_data ); + av_freep( &frame ); + if( unlikely( !got_packet || ( i_out < 0 ) ) ) + { + if( i_out < 0 ) + { + msg_Err( p_enc,"Encoding problem.."); + return p_chain; + } + block_Release( p_block ); + continue; + } - p_block->i_dts = p_block->i_pts = packet.pts; + p_block->i_buffer = packet.size; - return p_block; + p_block->i_length = (mtime_t)1000000 * + (mtime_t)p_sys->i_frame_size / + (mtime_t)p_sys->p_context->sample_rate; + + p_block->i_dts = p_block->i_pts = packet.pts; + + block_ChainAppend( &p_chain, p_block ); + } + if( i_samples_left < 0 ) + msg_Err( p_enc, "I_data_left overflow"); + + // We have leftover samples that don't fill frame_size, and libavcodec doesn't seem to like + // that frame has more data than p_sys->i_frame_size most of the cases currently. + if( i_samples_left > 0 ) + { + memcpy( p_sys->p_buffer, p_aout_buf->p_buffer+i_data_offset , i_samples_left*p_sys->i_sample_bytes*p_enc->fmt_in.audio.i_channels); + p_sys->i_samples_delay = i_samples_left; + } + + return p_chain; } /*****************************************************************************