/* $Id: decavcodec.c,v 1.6 2005/03/06 04:08:54 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. It may be used under the terms of the GNU General Public License. */ #include "hb.h" #include "ffmpeg/avcodec.h" int decavcodecInit( hb_work_object_t *, hb_job_t * ); int decavcodecWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** ); void decavcodecClose( hb_work_object_t * ); hb_work_object_t hb_decavcodec = { WORK_DECAVCODEC, "MPGA decoder (libavcodec)", decavcodecInit, decavcodecWork, decavcodecClose }; struct hb_work_private_s { hb_job_t * job; AVCodecContext * context; int64_t pts_last; AVCodecParserContext *parser; }; /*********************************************************************** * hb_work_decavcodec_init *********************************************************************** * **********************************************************************/ int decavcodecInit( hb_work_object_t * w, hb_job_t * job ) { AVCodec * codec; hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) ); w->private_data = pv; pv->job = job; codec = avcodec_find_decoder( CODEC_ID_MP2 ); pv->parser = av_parser_init(CODEC_ID_MP2); pv->context = avcodec_alloc_context(); avcodec_open( pv->context, codec ); pv->pts_last = -1; return 0; } /*********************************************************************** * Close *********************************************************************** * **********************************************************************/ void decavcodecClose( hb_work_object_t * w ) { hb_work_private_t * pv = w->private_data; av_parser_close(pv->parser); avcodec_close( pv->context ); } /*********************************************************************** * Work *********************************************************************** * **********************************************************************/ int decavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in, hb_buffer_t ** buf_out ) { hb_work_private_t * pv = w->private_data; hb_buffer_t * in = *buf_in, * buf, * last = NULL; int pos, len, out_size, i, uncompressed_len; short buffer[AVCODEC_MAX_AUDIO_FRAME_SIZE]; uint64_t cur; unsigned char *parser_output_buffer; int parser_output_buffer_len; *buf_out = NULL; if( in->start < 0 || ( pv->pts_last > 0 && in->start > pv->pts_last && in->start - pv->pts_last < 5000 ) ) /* Hacky */ { cur = pv->pts_last; } else { cur = in->start; } pos = 0; while( pos < in->size ) { len = av_parser_parse(pv->parser, pv->context,&parser_output_buffer,&parser_output_buffer_len,in->data + pos,in->size - pos,cur,cur); out_size = 0; uncompressed_len = 0; if (parser_output_buffer_len) uncompressed_len = avcodec_decode_audio( pv->context, buffer, &out_size, parser_output_buffer, parser_output_buffer_len ); if( out_size ) { short * s16; float * fl32; buf = hb_buffer_init( 2 * out_size ); int sample_size_in_bytes = 2; // Default to 2 bytes switch (pv->context->sample_fmt) { case SAMPLE_FMT_S16: sample_size_in_bytes = 2; break; /* We should handle other formats here - but that needs additional format conversion work below */ /* For now we'll just report the error and try to carry on */ default: hb_log("decavcodecWork - Unknown Sample Format from avcodec_decode_audio (%d) !", pv->context->sample_fmt); break; } buf->start = cur; buf->stop = cur + 90000 * ( out_size / (sample_size_in_bytes * pv->context->channels) ) / pv->context->sample_rate; cur = buf->stop; s16 = buffer; fl32 = (float *) buf->data; for( i = 0; i < out_size / 2; i++ ) { fl32[i] = s16[i]; } if( last ) { last = last->next = buf; } else { *buf_out = last = buf; } } pos += len; } pv->pts_last = cur; return HB_WORK_OK; }