/*********************************************************************** * Encode *********************************************************************** * **********************************************************************/ static hb_buffer_t * Encode( hb_work_object_t * w ) { hb_work_private_t * pv = w->private_data; hb_buffer_t * buf; float ** buffer; int i, j; /* Try to extract more data */ if( ( buf = Flush( w ) ) ) { return buf; } if( hb_list_bytes( pv->list ) < pv->input_samples * sizeof( float ) ) { return NULL; } /* Process more samples */ hb_list_getbytes( pv->list, pv->buf, pv->input_samples * sizeof( float ), &pv->pts, NULL ); buffer = vorbis_analysis_buffer( &pv->vd, OGGVORBIS_FRAME_SIZE ); for( i = 0; i < OGGVORBIS_FRAME_SIZE; i++ ) { for( j = 0; j < pv->out_discrete_channels; j++) { buffer[j][i] = ((float *) pv->buf)[(pv->out_discrete_channels * i + pv->channel_map[j])]; } } vorbis_analysis_wrote( &pv->vd, OGGVORBIS_FRAME_SIZE ); /* Try to extract again */ return Flush( w ); }
/*********************************************************************** * Encode *********************************************************************** * **********************************************************************/ static hb_buffer_t * Encode( hb_work_object_t * w ) { hb_work_private_t * pv = w->private_data; hb_audio_t * audio = w->audio; hb_buffer_t * buf; float samples[2][1152]; uint64_t pts, pos; int i, j; if( hb_list_bytes( pv->list ) < pv->input_samples * sizeof( float ) ) { return NULL; } hb_list_getbytes( pv->list, pv->buf, pv->input_samples * sizeof( float ), &pts, &pos); for( i = 0; i < 1152; i++ ) { for( j = 0; j < pv->out_discrete_channels; j++ ) { samples[j][i] = ((float *) pv->buf)[(pv->out_discrete_channels * i + j)]; } } buf = hb_buffer_init( pv->output_bytes ); buf->s.start = pts + 90000 * pos / pv->out_discrete_channels / sizeof( float ) / audio->config.out.samplerate; buf->s.stop = buf->s.start + 90000 * 1152 / audio->config.out.samplerate; pv->pts = buf->s.stop; buf->size = lame_encode_buffer_float( pv->lame, samples[0], samples[1], 1152, buf->data, LAME_MAXMP3BUFFER ); buf->s.type = AUDIO_BUF; buf->s.frametype = HB_FRAME_AUDIO; if( !buf->size ) { /* Encoding was successful but we got no data. Try to encode more */ hb_buffer_close( &buf ); return Encode( w ); } else if( buf->size < 0 ) { hb_log( "enclame: lame_encode_buffer failed" ); hb_buffer_close( &buf ); return NULL; } return buf; }
/* Called whenever necessary by AudioConverterFillComplexBuffer */ static OSStatus inInputDataProc( AudioConverterRef converter, UInt32 *npackets, AudioBufferList *buffers, AudioStreamPacketDescription** ignored, void *userdata ) { hb_work_private_t *pv = userdata; if( pv->ibytes == 0 ) { *npackets = 0; hb_log( "CoreAudio: no data to use in inInputDataProc" ); return noErr; } if( pv->buf != NULL ) free( pv->buf ); uint64_t pts, pos; buffers->mBuffers[0].mDataByteSize = MIN( *npackets * pv->isamplesiz, pv->ibytes ); buffers->mBuffers[0].mData = pv->buf = calloc(1 , buffers->mBuffers[0].mDataByteSize ); if( hb_list_bytes( pv->list ) >= buffers->mBuffers[0].mDataByteSize ) { hb_list_getbytes( pv->list, buffers->mBuffers[0].mData, buffers->mBuffers[0].mDataByteSize, &pts, &pos ); } else { hb_log( "CoreAudio: Not enought data, exiting inInputDataProc" ); *npackets = 0; return 1; } *npackets = buffers->mBuffers[0].mDataByteSize / pv->isamplesiz; /* transform data from [-32768,32767] to [-1.0,1.0] */ float *fdata = buffers->mBuffers[0].mData; int i; for( i = 0; i < *npackets * pv->nchannels; i++ ) { fdata[i] = fdata[i] / 32768.f; } pv->ibytes -= buffers->mBuffers[0].mDataByteSize; return noErr; }
/* Called whenever necessary by AudioConverterFillComplexBuffer */ static OSStatus inInputDataProc( AudioConverterRef converter, UInt32 *npackets, AudioBufferList *buffers, AudioStreamPacketDescription** ignored, void *userdata ) { hb_work_private_t *pv = userdata; if( pv->ibytes == 0 ) { *npackets = 0; hb_log( "CoreAudio: no data to use in inInputDataProc" ); return 1; } if( pv->buf != NULL ) free( pv->buf ); uint64_t pts, pos; buffers->mBuffers[0].mDataByteSize = MIN( *npackets * pv->isamplesiz, pv->ibytes ); buffers->mBuffers[0].mData = pv->buf = calloc( 1, buffers->mBuffers[0].mDataByteSize ); if( hb_list_bytes( pv->list ) >= buffers->mBuffers[0].mDataByteSize ) { hb_list_getbytes( pv->list, buffers->mBuffers[0].mData, buffers->mBuffers[0].mDataByteSize, &pts, &pos ); } else { hb_log( "CoreAudio: Not enough data, exiting inInputDataProc" ); *npackets = 0; return 1; } if( pv->ichanmap != &hb_qt_chan_map ) { hb_layout_remap( pv->ichanmap, &hb_qt_chan_map, pv->layout, (float*)buffers->mBuffers[0].mData, buffers->mBuffers[0].mDataByteSize / pv->isamplesiz ); } *npackets = buffers->mBuffers[0].mDataByteSize / pv->isamplesiz; pv->ibytes -= buffers->mBuffers[0].mDataByteSize; return noErr; }
/* Called whenever necessary by AudioConverterFillComplexBuffer */ static OSStatus inInputDataProc(AudioConverterRef converter, UInt32 *npackets, AudioBufferList *buffers, AudioStreamPacketDescription **ignored, void *userdata) { hb_work_private_t *pv = userdata; if (!pv->ibytes) { *npackets = 0; return 1; } if (pv->buf != NULL) { free(pv->buf); } buffers->mBuffers[0].mDataByteSize = MIN(pv->ibytes, pv->isamplesiz * *npackets); pv->buf = calloc(1, buffers->mBuffers[0].mDataByteSize); buffers->mBuffers[0].mData = pv->buf; if (hb_list_bytes(pv->list) >= buffers->mBuffers[0].mDataByteSize) { hb_list_getbytes(pv->list, buffers->mBuffers[0].mData, buffers->mBuffers[0].mDataByteSize, NULL, NULL); } else { *npackets = 0; return 1; } *npackets = buffers->mBuffers[0].mDataByteSize / pv->isamplesiz; pv->ibytes -= buffers->mBuffers[0].mDataByteSize; if (pv->ichanmap != &hb_qt_chan_map) { hb_layout_remap(pv->ichanmap, &hb_qt_chan_map, pv->layout, (float*)buffers->mBuffers[0].mData, *npackets); } return noErr; }
/*********************************************************************** * Encode *********************************************************************** * **********************************************************************/ static hb_buffer_t * Encode( hb_work_object_t * w ) { hb_work_private_t * pv = w->private_data; if( hb_list_bytes( pv->list ) < pv->input_samples * sizeof( float ) ) { /* Need more data */ return NULL; } uint64_t pts, pos; hb_list_getbytes( pv->list, pv->buf, pv->input_samples * sizeof( float ), &pts, &pos ); int i; float *fltBuf = (float*)pv->buf; for ( i = 0; i < pv->input_samples; i++ ) fltBuf[i] *= 32768.0; int size = faacEncEncode( pv->faac, (int32_t *)pv->buf, pv->input_samples, pv->obuf, pv->output_bytes ); // AAC needs four frames before it can start encoding so we'll get nothing // on the first three calls to the encoder. if ( size > 0 ) { hb_buffer_t * buf = hb_buffer_init( size ); memcpy( buf->data, pv->obuf, size ); buf->size = size; buf->s.start = pv->pts; buf->s.duration = pv->framedur; buf->s.stop = buf->s.start + buf->s.duration; buf->s.type = AUDIO_BUF; buf->s.frametype = HB_FRAME_AUDIO; pv->pts += pv->framedur; return buf; } return NULL; }
/*********************************************************************** * Decode *********************************************************************** * **********************************************************************/ static hb_buffer_t * Decode( hb_work_object_t * w ) { hb_work_private_t * pv = w->private_data; hb_buffer_t * buf; hb_audio_t * audio = w->audio; int i, j, k; int64_t pts, pos; uint64_t upts, upos; int num_blocks; /* Get a frame header if don't have one yet */ if( !pv->sync ) { while( hb_list_bytes( pv->list ) >= 14 ) { /* We have 14 bytes, check if this is a correct header */ hb_list_seebytes( pv->list, pv->frame, 14 ); pv->size = dca_syncinfo( pv->state, pv->frame, &pv->flags_in, &pv->rate, &pv->bitrate, &pv->frame_length ); if( pv->size ) { /* It is. W00t. */ if( pv->error ) { hb_log( "dca_syncinfo ok" ); } pv->error = 0; pv->sync = 1; break; } /* It is not */ if( !pv->error ) { hb_log( "dca_syncinfo failed" ); pv->error = 1; } /* Try one byte later */ hb_list_getbytes( pv->list, pv->frame, 1, NULL, NULL ); } } if( !pv->sync || hb_list_bytes( pv->list ) < pv->size ) { /* Need more data */ return NULL; } /* Get the whole frame */ hb_list_getbytes( pv->list, pv->frame, pv->size, &upts, &upos ); pts = (int64_t)upts; pos = (int64_t)upos; if ( pts != pv->last_buf_pts ) { pv->last_buf_pts = pts; } else { // spec says that the PTS is the start time of the first frame // that starts in the PES frame so we only use the PTS once then // get the following frames' PTS from the frame length. pts = -1; } // mkv files typically use a 1ms timebase which results in a lot of // truncation error in their timestamps. Also, TSMuxer or something // in the m2ts-to-mkv toolchain seems to take a very casual attitude // about time - timestamps seem to randomly offset by ~40ms for a few // seconds then recover. So, if the pts we got is within 50ms of the // pts computed from the data stream, use the data stream pts. if ( pts == -1 || ( pv->next_pts && fabs( pts - pv->next_pts ) < 50.*90. ) ) { pts = pv->next_pts; } double frame_dur = (double)(pv->frame_length & ~0xFF) / (double)pv->rate * 90000.; /* DCA passthrough: don't decode the DCA frame */ if( audio->config.out.codec == HB_ACODEC_DCA_PASS ) { buf = hb_buffer_init( pv->size ); memcpy( buf->data, pv->frame, pv->size ); buf->start = pts; pv->next_pts = pts + frame_dur; buf->stop = pv->next_pts; pv->sync = 0; return buf; } /* Feed libdca */ dca_frame( pv->state, pv->frame, &pv->flags_out, &pv->level, 0 ); /* find out how many blocks are in this frame */ num_blocks = dca_blocks_num( pv->state ); /* num_blocks blocks per frame, 256 samples per block, channelsused channels */ int nsamp = num_blocks * 256; buf = hb_buffer_init( nsamp * pv->out_discrete_channels * sizeof( float ) ); buf->start = pts; pv->next_pts = pts + (double)nsamp / (double)pv->rate * 90000.; buf->stop = pv->next_pts; for( i = 0; i < num_blocks; i++ ) { dca_sample_t * samples_in; float * samples_out; dca_block( pv->state ); samples_in = dca_samples( pv->state ); samples_out = ((float *) buf->data) + 256 * pv->out_discrete_channels * i; /* Interleave */ for( j = 0; j < 256; j++ ) { for ( k = 0; k < pv->out_discrete_channels; k++ ) { samples_out[(pv->out_discrete_channels*j)+k] = samples_in[(256*k)+j] * 32767; } } } pv->sync = 0; return buf; }
static hb_buffer_t* Encode(hb_work_object_t *w) { hb_work_private_t *pv = w->private_data; hb_audio_t *audio = w->audio; uint64_t pts, pos; if (hb_list_bytes(pv->list) < pv->input_samples * sizeof(float)) { return NULL; } hb_list_getbytes(pv->list, pv->input_buf, pv->input_samples * sizeof(float), &pts, &pos); // Prepare input frame int out_linesize; int out_size = av_samples_get_buffer_size(&out_linesize, pv->context->channels, pv->samples_per_frame, pv->context->sample_fmt, 1); AVFrame frame = { .nb_samples = pv->samples_per_frame, }; avcodec_fill_audio_frame(&frame, pv->context->channels, pv->context->sample_fmt, pv->output_buf, out_size, 1); if (pv->avresample != NULL) { int in_linesize; av_samples_get_buffer_size(&in_linesize, pv->context->channels, frame.nb_samples, AV_SAMPLE_FMT_FLT, 1); int out_samples = avresample_convert(pv->avresample, frame.extended_data, out_linesize, frame.nb_samples, &pv->input_buf, in_linesize, frame.nb_samples); if (out_samples != pv->samples_per_frame) { // we're not doing sample rate conversion, so this shouldn't happen hb_log("encavcodecaWork: avresample_convert() failed"); return NULL; } } // Libav requires that timebase of audio frames be in sample_rate units frame.pts = pts + (90000 * pos / (sizeof(float) * pv->out_discrete_channels * audio->config.out.samplerate)); frame.pts = av_rescale(frame.pts, pv->context->sample_rate, 90000); // Prepare output packet AVPacket pkt; int got_packet; hb_buffer_t *out = hb_buffer_init(pv->max_output_bytes); av_init_packet(&pkt); pkt.data = out->data; pkt.size = out->alloc; // Encode int ret = avcodec_encode_audio2(pv->context, &pkt, &frame, &got_packet); if (ret < 0) { hb_log("encavcodeca: avcodec_encode_audio failed"); hb_buffer_close(&out); return NULL; } if (got_packet && pkt.size) { out->size = pkt.size; // The output pts from libav is in context->time_base. Convert it back // to our timebase. // // Also account for the "delay" factor that libav seems to arbitrarily // subtract from the packet. Not sure WTH they think they are doing by // offsetting the value in a negative direction. out->s.start = av_rescale_q(pv->context->delay + pkt.pts, pv->context->time_base, (AVRational){1, 90000}); out->s.stop = out->s.start + (90000 * pv->samples_per_frame / audio->config.out.samplerate); out->s.type = AUDIO_BUF; out->s.frametype = HB_FRAME_AUDIO; } else { hb_buffer_close(&out); return Encode(w); } return out; } static hb_buffer_t * Flush( hb_work_object_t * w ) { hb_buffer_t *first, *buf, *last; first = last = buf = Encode( w ); while( buf ) { last = buf; buf->next = Encode( w ); buf = buf->next; } if( last ) { last->next = hb_buffer_init( 0 ); } else { first = hb_buffer_init( 0 ); } return first; }
static hb_buffer_t * Encode( hb_work_object_t * w ) { hb_work_private_t * pv = w->private_data; uint64_t pts, pos; hb_audio_t * audio = w->audio; hb_buffer_t * buf; int ii; if( hb_list_bytes( pv->list ) < pv->input_samples * sizeof( float ) ) { return NULL; } hb_list_getbytes( pv->list, pv->buf, pv->input_samples * sizeof( float ), &pts, &pos); hb_chan_map_t *map = NULL; if ( audio->config.in.codec == HB_ACODEC_AC3 ) { map = &hb_ac3_chan_map; } else if ( audio->config.in.codec == HB_ACODEC_DCA ) { map = &hb_qt_chan_map; } if ( map ) { int layout; switch (audio->config.out.mixdown) { case HB_AMIXDOWN_MONO: layout = HB_INPUT_CH_LAYOUT_MONO; break; case HB_AMIXDOWN_STEREO: case HB_AMIXDOWN_DOLBY: case HB_AMIXDOWN_DOLBYPLII: layout = HB_INPUT_CH_LAYOUT_STEREO; break; case HB_AMIXDOWN_6CH: default: layout = HB_INPUT_CH_LAYOUT_3F2R | HB_INPUT_CH_LAYOUT_HAS_LFE; break; } hb_layout_remap( map, &hb_smpte_chan_map, layout, (float*)pv->buf, AC3_SAMPLES_PER_FRAME); } for (ii = 0; ii < pv->input_samples; ii++) { // ffmpeg float samples are -1.0 to 1.0 pv->samples[ii] = ((float*)pv->buf)[ii] / 32768.0; } buf = hb_buffer_init( pv->output_bytes ); buf->size = avcodec_encode_audio( pv->context, buf->data, buf->alloc, (short*)pv->samples ); buf->start = pts + 90000 * pos / pv->out_discrete_channels / sizeof( float ) / audio->config.out.samplerate; buf->stop = buf->start + 90000 * AC3_SAMPLES_PER_FRAME / audio->config.out.samplerate; buf->frametype = HB_FRAME_AUDIO; if ( !buf->size ) { hb_buffer_close( &buf ); return Encode( w ); } else if (buf->size < 0) { hb_log( "encac3: avcodec_encode_audio failed" ); hb_buffer_close( &buf ); return NULL; } return buf; }
static hb_buffer_t* Encode(hb_work_object_t *w) { hb_work_private_t *pv = w->private_data; hb_audio_t *audio = w->audio; uint64_t pts, pos; if (hb_list_bytes(pv->list) < pv->input_samples * sizeof(float)) { return NULL; } hb_list_getbytes(pv->list, pv->input_buf, pv->input_samples * sizeof(float), &pts, &pos); // Prepare input frame int out_linesize; int out_size = av_samples_get_buffer_size(&out_linesize, pv->context->channels, pv->samples_per_frame, pv->context->sample_fmt, 1); AVFrame frame = { .nb_samples = pv->samples_per_frame, }; avcodec_fill_audio_frame(&frame, pv->context->channels, pv->context->sample_fmt, pv->output_buf, out_size, 1); if (pv->avresample != NULL) { int in_linesize; av_samples_get_buffer_size(&in_linesize, pv->context->channels, frame.nb_samples, AV_SAMPLE_FMT_FLT, 1); int out_samples = avresample_convert(pv->avresample, frame.extended_data, out_linesize, frame.nb_samples, &pv->input_buf, in_linesize, frame.nb_samples); if (out_samples != pv->samples_per_frame) { // we're not doing sample rate conversion, so this shouldn't happen hb_log("encavcodecaWork: avresample_convert() failed"); return NULL; } } // Libav requires that timebase of audio frames be in sample_rate units frame.pts = pts + (90000 * pos / (sizeof(float) * pv->out_discrete_channels * audio->config.out.samplerate)); frame.pts = av_rescale(frame.pts, pv->context->sample_rate, 90000); // Prepare output packet AVPacket pkt; int got_packet; hb_buffer_t *out = hb_buffer_init(pv->max_output_bytes); av_init_packet(&pkt); pkt.data = out->data; pkt.size = out->alloc; // Encode int ret = avcodec_encode_audio2(pv->context, &pkt, &frame, &got_packet); if (ret < 0) { hb_log("encavcodeca: avcodec_encode_audio failed"); hb_buffer_close(&out); return NULL; } if (got_packet && pkt.size) { out->size = pkt.size; // The output pts from libav is in context->time_base. Convert it back // to our timebase. out->s.start = av_rescale_q(pkt.pts, pv->context->time_base, (AVRational){1, 90000}); out->s.duration = (double)90000 * pv->samples_per_frame / audio->config.out.samplerate; out->s.stop = out->s.start + out->s.duration; out->s.type = AUDIO_BUF; out->s.frametype = HB_FRAME_AUDIO; } else { hb_buffer_close(&out); return Encode(w); } return out; } static hb_buffer_t * Flush( hb_work_object_t * w ) { hb_buffer_list_t list; hb_buffer_t *buf; hb_buffer_list_clear(&list); buf = Encode( w ); while (buf != NULL) { hb_buffer_list_append(&list, buf); buf = Encode( w ); } hb_buffer_list_append(&list, hb_buffer_eof_init()); return hb_buffer_list_clear(&list); }
static hb_buffer_t * Encode( hb_work_object_t * w ) { hb_work_private_t * pv = w->private_data; uint64_t pts, pos; hb_audio_t * audio = w->audio; hb_buffer_t * buf; if( hb_list_bytes( pv->list ) < pv->input_samples * sizeof( float ) ) { return NULL; } hb_list_getbytes( pv->list, pv->buf, pv->input_samples * sizeof( float ), &pts, &pos); // XXX: ffaac fails to remap from the internal libav* channel map (SMPTE) to the native AAC channel map // do it here - this hack should be removed if Libav fixes the bug hb_chan_map_t * out_map = ( w->codec_param == CODEC_ID_AAC ) ? &hb_qt_chan_map : &hb_smpte_chan_map; if ( audio->config.in.channel_map != out_map ) { hb_layout_remap( audio->config.in.channel_map, out_map, pv->layout, (float*)pv->buf, pv->samples_per_frame ); } // Do we need to convert our internal float format? if ( pv->context->sample_fmt != AV_SAMPLE_FMT_FLT ) { int isamp, osamp; AVAudioConvert *ctx; isamp = av_get_bytes_per_sample( AV_SAMPLE_FMT_FLT ); osamp = av_get_bytes_per_sample( pv->context->sample_fmt ); ctx = av_audio_convert_alloc( pv->context->sample_fmt, 1, AV_SAMPLE_FMT_FLT, 1, NULL, 0 ); // get output buffer size then malloc a buffer //nsamples = out_size / isamp; //buffer = av_malloc( nsamples * sizeof(hb_sample_t) ); // we're doing straight sample format conversion which // behaves as if there were only one channel. const void * const ibuf[6] = { pv->buf }; void * const obuf[6] = { pv->buf }; const int istride[6] = { isamp }; const int ostride[6] = { osamp }; av_audio_convert( ctx, obuf, ostride, ibuf, istride, pv->input_samples ); av_audio_convert_free( ctx ); } buf = hb_buffer_init( pv->output_bytes ); buf->size = avcodec_encode_audio( pv->context, buf->data, buf->alloc, (short*)pv->buf ); buf->start = pts + 90000 * pos / pv->out_discrete_channels / sizeof( float ) / audio->config.out.samplerate; buf->stop = buf->start + 90000 * pv->samples_per_frame / audio->config.out.samplerate; buf->frametype = HB_FRAME_AUDIO; if ( !buf->size ) { hb_buffer_close( &buf ); return Encode( w ); } else if (buf->size < 0) { hb_log( "encavcodeca: avcodec_encode_audio failed" ); hb_buffer_close( &buf ); return NULL; } return buf; }