hb_audio_remap_t* hb_audio_remap_init(uint64_t channel_layout, hb_chan_map_t *map_out, hb_chan_map_t *map_in) { hb_audio_remap_t *remap = malloc(sizeof(hb_audio_remap_t)); if (remap == NULL) return NULL; remap->remap_table = hb_audio_remap_build_table(channel_layout, map_out, map_in); if (remap->remap_table == NULL) { hb_audio_remap_free(remap); return NULL; } int ii; remap->nchannels = av_get_channel_layout_nb_channels(channel_layout); remap->sample_size = remap->nchannels * sizeof(hb_sample_t); remap->remap_needed = 0; for (ii = 0; ii < remap->nchannels; ii++) { if (remap->remap_table[ii] != ii) { remap->remap_needed = 1; break; } } return remap; }
void hb_audio_remap_set_channel_layout(hb_audio_remap_t *remap, uint64_t channel_layout, int channels) { if (remap != NULL) { int ii; remap->remap_needed = 0; // in some cases, remapping is not necessary and/or supported if (channels > HB_AUDIO_REMAP_MAX_CHANNELS) { hb_log("hb_audio_remap_set_channel_layout: too many channels (%d)", channels); return; } if (remap->channel_map_in == remap->channel_map_out) { return; } // sanitize the layout channel_layout = hb_ff_layout_xlat(channel_layout, channels); if (channel_layout == AV_CH_LAYOUT_STEREO_DOWNMIX) { channel_layout = AV_CH_LAYOUT_STEREO; } remap->nchannels = av_get_channel_layout_nb_channels(channel_layout); // build the table and check whether remapping is necessary hb_audio_remap_build_table(remap->channel_map_out, remap->channel_map_in, channel_layout, remap->table); for (ii = 0; ii < remap->nchannels; ii++) { if (remap->table[ii] != ii) { remap->remap_needed = 1; break; } } } }
/*********************************************************************** * hb_work_encfaac_init *********************************************************************** * **********************************************************************/ int encfaacInit( hb_work_object_t * w, hb_job_t * job ) { hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) ); hb_audio_t * audio = w->audio; faacEncConfigurationPtr cfg; uint8_t * bytes; unsigned long length; w->private_data = pv; pv->job = job; /* pass the number of channels used into the private work data */ pv->out_discrete_channels = hb_mixdown_get_discrete_channel_count(audio->config.out.mixdown); pv->faac = faacEncOpen( audio->config.out.samplerate, pv->out_discrete_channels, &pv->input_samples, &pv->output_bytes ); pv->buf = malloc( pv->input_samples * sizeof( float ) ); pv->obuf = malloc( pv->output_bytes ); pv->framedur = 90000.0 * pv->input_samples / ( audio->config.out.samplerate * pv->out_discrete_channels ); audio->config.out.samples_per_frame = pv->input_samples / pv->out_discrete_channels; cfg = faacEncGetCurrentConfiguration( pv->faac ); cfg->mpegVersion = MPEG4; cfg->aacObjectType = LOW; cfg->allowMidside = 1; /* channel configuration & remapping */ uint64_t layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, NULL); hb_audio_remap_build_table(&hb_aac_chan_map, audio->config.in.channel_map, layout, cfg->channel_map); switch (audio->config.out.mixdown) { case HB_AMIXDOWN_7POINT1: cfg->channelConfiguration = 0; cfg->numFrontChannels = 3; cfg->numSideChannels = 2; cfg->numBackChannels = 2; cfg->numLFEChannels = 1; break; case HB_AMIXDOWN_6POINT1: cfg->channelConfiguration = 0; cfg->numFrontChannels = 3; cfg->numSideChannels = 0; cfg->numBackChannels = 3; cfg->numLFEChannels = 1; break; case HB_AMIXDOWN_5_2_LFE: cfg->channelConfiguration = 7; break; default: cfg->channelConfiguration = hb_mixdown_get_discrete_channel_count(audio->config.out.mixdown); break; } cfg->useTns = 0; cfg->bitRate = audio->config.out.bitrate * 1000 / pv->out_discrete_channels; /* Per channel */ cfg->bandWidth = 0; cfg->outputFormat = 0; cfg->inputFormat = FAAC_INPUT_FLOAT; if( !faacEncSetConfiguration( pv->faac, cfg ) ) { hb_log( "faacEncSetConfiguration failed" ); *job->done_error = HB_ERROR_INIT; *job->die = 1; return 0; } if( faacEncGetDecoderSpecificInfo( pv->faac, &bytes, &length ) < 0 ) { hb_log( "faacEncGetDecoderSpecificInfo failed" ); *job->done_error = HB_ERROR_INIT; *job->die = 1; return 0; } memcpy( w->config->extradata.bytes, bytes, length ); w->config->extradata.length = length; free( bytes ); pv->list = hb_list_init(); return 0; }
/*********************************************************************** * hb_work_encfaac_init *********************************************************************** * **********************************************************************/ int encfaacInit( hb_work_object_t * w, hb_job_t * job ) { hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) ); hb_audio_t * audio = w->audio; faacEncConfigurationPtr cfg; uint8_t * bytes; unsigned long length; w->private_data = pv; pv->job = job; /* pass the number of channels used into the private work data */ pv->out_discrete_channels = hb_mixdown_get_discrete_channel_count(audio->config.out.mixdown); /* if the sample rate is 'auto' and that has given us an invalid output */ /* rate, map it to the next highest output rate or 48K if above the highest. */ int rate_index = find_samplerate(audio->config.out.samplerate); if ( audio->config.out.samplerate != valid_rates[rate_index] ) { int rate = valid_rates[valid_rates[rate_index]? rate_index : rate_index - 1]; hb_log( "encfaac changing output samplerate from %d to %d", audio->config.out.samplerate, rate ); audio->config.out.samplerate = rate; /* if the new rate is over the max bandwidth per channel limit */ /* lower the bandwidth. */ double bw = audio->config.out.bitrate * 1000 / pv->out_discrete_channels; if ( bw > (double)rate * (6144./1024.) ) { int newbr = (double)rate * (6.144/1024.) * pv->out_discrete_channels; hb_log( "encfaac changing output bitrate from %d to %d", audio->config.out.bitrate, newbr ); audio->config.out.bitrate = newbr; } } pv->faac = faacEncOpen( audio->config.out.samplerate, pv->out_discrete_channels, &pv->input_samples, &pv->output_bytes ); pv->buf = malloc( pv->input_samples * sizeof( float ) ); pv->obuf = malloc( pv->output_bytes ); pv->framedur = 90000.0 * pv->input_samples / ( audio->config.out.samplerate * pv->out_discrete_channels ); audio->config.out.samples_per_frame = pv->input_samples / pv->out_discrete_channels; cfg = faacEncGetCurrentConfiguration( pv->faac ); cfg->mpegVersion = MPEG4; cfg->aacObjectType = LOW; cfg->allowMidside = 1; // channel remapping, LFE uint64_t layout; int *remap_table; layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, NULL); remap_table = hb_audio_remap_build_table(layout, &hb_aac_chan_map, audio->config.in.channel_map); if (remap_table != NULL) { // faac does its own remapping memcpy(cfg->channel_map, remap_table, pv->out_discrete_channels * sizeof(int)); free(remap_table); } cfg->useLfe = !!(layout & AV_CH_LOW_FREQUENCY); cfg->useTns = 0; cfg->bitRate = audio->config.out.bitrate * 1000 / pv->out_discrete_channels; /* Per channel */ cfg->bandWidth = 0; cfg->outputFormat = 0; cfg->inputFormat = FAAC_INPUT_FLOAT; if( !faacEncSetConfiguration( pv->faac, cfg ) ) { hb_log( "faacEncSetConfiguration failed" ); *job->die = 1; return 0; } if( faacEncGetDecoderSpecificInfo( pv->faac, &bytes, &length ) < 0 ) { hb_log( "faacEncGetDecoderSpecificInfo failed" ); *job->die = 1; return 0; } memcpy( w->config->extradata.bytes, bytes, length ); w->config->extradata.length = length; free( bytes ); pv->list = hb_list_init(); return 0; }
int encvorbisInit(hb_work_object_t *w, hb_job_t *job) { hb_work_private_t *pv = calloc(1, sizeof(hb_work_private_t)); hb_audio_t *audio = w->audio; w->private_data = pv; pv->job = job; int i; ogg_packet header[3]; hb_log("encvorbis: opening libvorbis"); /* init */ for (i = 0; i < 3; i++) { // Zero vorbis headers so that we don't crash in mk_laceXiph // when vorbis_encode_setup_managed fails. memset(w->config->vorbis.headers[i], 0, sizeof(ogg_packet)); } vorbis_info_init(&pv->vi); pv->out_discrete_channels = hb_mixdown_get_discrete_channel_count(audio->config.out.mixdown); if (audio->config.out.bitrate > 0) { if (vorbis_encode_setup_managed(&pv->vi, pv->out_discrete_channels, audio->config.out.samplerate, -1, audio->config.out.bitrate * 1000, -1)) { hb_error("encvorbis: vorbis_encode_setup_managed() failed"); *job->die = 1; return -1; } } else if (audio->config.out.quality != HB_INVALID_AUDIO_QUALITY) { // map VBR quality to Vorbis API (divide by 10) if (vorbis_encode_setup_vbr(&pv->vi, pv->out_discrete_channels, audio->config.out.samplerate, audio->config.out.quality / 10)) { hb_error("encvorbis: vorbis_encode_setup_vbr() failed"); *job->die = 1; return -1; } } if (vorbis_encode_ctl(&pv->vi, OV_ECTL_RATEMANAGE2_SET, NULL) || vorbis_encode_setup_init(&pv->vi)) { hb_error("encvorbis: vorbis_encode_ctl(ratemanage2_set) OR vorbis_encode_setup_init() failed"); *job->die = 1; return -1; } /* add a comment */ vorbis_comment_init(&pv->vc); vorbis_comment_add_tag(&pv->vc, "Encoder", "HandBrake"); vorbis_comment_add_tag(&pv->vc, "LANGUAGE", w->config->vorbis.language); /* set up the analysis state and auxiliary encoding storage */ vorbis_analysis_init(&pv->vd, &pv->vi); vorbis_block_init(&pv->vd, &pv->vb); /* get the 3 headers */ vorbis_analysis_headerout(&pv->vd, &pv->vc, &header[0], &header[1], &header[2]); for (i = 0; i < 3; i++) { memcpy(w->config->vorbis.headers[i], &header[i], sizeof(ogg_packet)); memcpy(w->config->vorbis.headers[i] + sizeof(ogg_packet), header[i].packet, header[i].bytes); } pv->input_samples = pv->out_discrete_channels * OGGVORBIS_FRAME_SIZE; audio->config.out.samples_per_frame = OGGVORBIS_FRAME_SIZE; pv->buf = malloc(pv->input_samples * sizeof(float)); pv->list = hb_list_init(); // channel remapping uint64_t layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, NULL); pv->remap_table = hb_audio_remap_build_table(layout, &hb_vorbis_chan_map, audio->config.in.channel_map); if (pv->remap_table == NULL) { hb_error("encvorbisInit: hb_audio_remap_build_table() failed"); *job->die = 1; return -1; } return 0; }