Logo Search packages:      
Sourcecode: aften version File versions  Download package

AFTEN_API int aften_encode_init ( AftenContext s  ) 

Initializes an encoding context. This must be called before any calls to aften_encode_frame

Parameters:
s The encoding context
Returns:
Returns 0 on success, non-zero on failure.

Definition at line 230 of file a52enc.c.

References a52_common_init(), AftenContext::acmod, AftenEncParams::bitrate, AftenEncParams::bwcode, AftenContext::channels, exponent_init(), AftenContext::initial_samples, AftenContext::lfe, AftenContext::meta, AftenContext::mode, AftenSystemParams::n_threads, AftenContext::params, AftenContext::private_context, AftenEncParams::quality, AftenContext::sample_format, AftenContext::samplerate, AftenContext::system, and AftenSystemParams::wanted_simd_instructions.

{
    A52Context *ctx;
    int i, j, brate;
    int last_quality;

    if (s == NULL) {
        fprintf(stderr, "NULL parameter passed to aften_encode_init\n");
        return -1;
    }
    cpu_caps_detect();
    apply_simd_restrictions(&s->system.wanted_simd_instructions);

    ctx = calloc(sizeof(A52Context), 1);
    if (!ctx) {
        fprintf(stderr, "error allocating memory for A52Context\n");
        return -1;
    }
    mdct_init(ctx);
    s->private_context = ctx;
    ctx->params = s->params;
    ctx->meta = s->meta;

    a52_common_init();

    switch (s->mode) {
    case AFTEN_TRANSCODE: {
        fprintf(stderr, "Sorry, trancoding support is not complete, yet.");
        return -1;
#if 0
        A52ThreadContext *tctx;

        if (!s->initial_samples) {
            fprintf(stderr, "At least one initial frame must be provided via initial_samples when transcoding.");
            return -1;
        }//FIXME: must specify amount of bytes
        ctx->halfratecod = 0;
        tctx = calloc(sizeof(A52ThreadContext), 1);
        ctx->tctx = tctx;
        ctx->tctx->ctx = ctx;
        tctx->dctx = calloc(sizeof(A52DecodeContext), 1);
        mdct_thread_init(ctx->tctx);

        a52_decode_init();
        a52_decode_init_thread(ctx->tctx);
        memcpy(tctx->dctx->input_frame_buffer, s->initial_samples, A52_MAX_CODED_FRAME_SIZE);
        tctx->dctx->input_frame_buffer_size = A52_MAX_CODED_FRAME_SIZE;
        a52_decode_frame(ctx->tctx);
        mdct_thread_close(ctx->tctx);

        ctx->acmod = tctx->dctx->channel_mode;
        ctx->lfe = tctx->dctx->lfe_on;
        ctx->n_channels = tctx->dctx->fbw_channels;
        ctx->n_all_channels = ctx->n_channels + ctx->lfe;
        ctx->lfe_channel = s->lfe ? ctx->n_channels : -1;

        ctx->sample_rate = tctx->dctx->sample_rate;
        ctx->fscod =  tctx->dctx->bit_alloc_params.fscod;
        ctx->halfratecod =  tctx->dctx->bit_alloc_params.halfratecod;
        ctx->bsid = tctx->dctx->bsid;
        ctx->bsmod = tctx->dctx->bsmod;

        ctx->meta.cmixlev = tctx->dctx->cmixlev;
        ctx->meta.surmixlev = tctx->dctx->surmixlev;
        ctx->meta.dsurmod = tctx->dctx->dsurmod;
        a52_decode_deinit_thread(tctx);
        free(tctx->dctx);
        free(ctx->tctx);
        break;
#endif
    }
    case AFTEN_ENCODE:
        set_converter(ctx, s->sample_format);

    // channel configuration
        if (s->channels < 1 || s->channels > 6) {
            fprintf(stderr, "invalid number of channels\n");
            return -1;
        }
        if (s->acmod < 0 || s->acmod > 7) {
            fprintf(stderr, "invalid acmod\n");
            return -1;
        }
        if (s->channels == 6 && !s->lfe) {
            fprintf(stderr, "6-channel audio must have LFE channel\n");
            return -1;
        }
        if (s->channels == 1 && s->lfe) {
            fprintf(stderr, "cannot encode stand-alone LFE channel\n");
            return -1;
        }
        ctx->acmod = s->acmod;
        ctx->lfe = s->lfe;
        ctx->n_all_channels = s->channels;
        ctx->n_channels = s->channels - s->lfe;
        ctx->lfe_channel = s->lfe ? (s->channels - 1) : -1;

        // frequency
        for (i=0;i<3;i++) {
            for (j=0;j<3;j++)
                if ((a52_sample_rate_tab[j] >> i) == s->samplerate)
                    goto found;
        }
        fprintf(stderr, "invalid sample rate\n");
        return -1;
found:
        ctx->sample_rate = s->samplerate;
        ctx->halfratecod = i;
        ctx->fscod = j;
        if (ctx->halfratecod) {
            // DolbyNet
            ctx->bsid = 8 + ctx->halfratecod;
        } else if (ctx->meta.xbsi1e || ctx->meta.xbsi2e) {
            // alternate bit stream syntax
            ctx->bsid = 6;
        } else {
            // normal AC-3
            ctx->bsid = 8;
        }
        ctx->bsmod = 0;
        break;
    default:
        fprintf(stderr, "Unknown opertion mode specified.\n");
        return -1;
    }

    ctx->last_samples_count = -1;

    // bitrate & frame size
    brate = s->params.bitrate;
    if (ctx->params.encoding_mode == AFTEN_ENC_MODE_CBR) {
        if (brate == 0) {
            switch (ctx->n_channels) {
                case 1: brate =  96; break;
                case 2: brate = 192; break;
                case 3: brate = 256; break;
                case 4: brate = 384; break;
                case 5: brate = 448; break;
            }
        }
    } else if (ctx->params.encoding_mode == AFTEN_ENC_MODE_VBR) {
        if (s->params.quality < 0 || s->params.quality > 1023) {
            fprintf(stderr, "invalid quality setting\n");
            return -1;
        }
    } else {
        return -1;
    }

    for (i = 0; i < 19; i++) {
        if ((a52_bitrate_tab[i] >> ctx->halfratecod) == brate)
            break;
    }
    if (i == 19) {
        if (ctx->params.encoding_mode == AFTEN_ENC_MODE_CBR) {
            fprintf(stderr, "invalid bitrate\n");
            return -1;
        }
        i = 18;
    }
    ctx->frmsizecod = i*2;
    ctx->target_bitrate = a52_bitrate_tab[i] >> ctx->halfratecod;

    if (ctx->params.expstr_search < 1 || ctx->params.expstr_search > 32) {
        fprintf(stderr, "invalid exponent strategy search size: %d\n",
                ctx->params.expstr_search);
        return -1;
    }

    crc_init();
    a52_window_init(&ctx->winf);
    exponent_init(&ctx->expf);
    dynrng_init();

    last_quality = 240;
    if (ctx->params.encoding_mode == AFTEN_ENC_MODE_VBR)
        last_quality = ctx->params.quality;
    else if (ctx->params.encoding_mode == AFTEN_ENC_MODE_CBR)
        last_quality = ((((ctx->target_bitrate/ctx->n_channels)*35)/24)+95)+(25*ctx->halfratecod);

    if (s->params.bwcode < -2 || s->params.bwcode > 60) {
        fprintf(stderr, "invalid bandwidth code\n");
        return -1;
    }
    if (ctx->params.bwcode < 0) {
        int cutoff = ((last_quality-120) * 120) + 4000;
        ctx->fixed_bwcode = ((cutoff * 512 / ctx->sample_rate) - 73) / 3;
        if (ctx->params.bwcode == -2) {
            if (ctx->params.min_bwcode < 0 || ctx->params.min_bwcode > 60 ||
               ctx->params.max_bwcode < 0 || ctx->params.max_bwcode > 60 ||
               ctx->params.min_bwcode > ctx->params.max_bwcode) {
                fprintf(stderr, "invalid min/max bandwidth code\n");
                return -1;
            }
            if (ctx->params.encoding_mode == AFTEN_ENC_MODE_VBR) {
                fprintf(stderr, "variable bandwidth mode cannot be used with variable bitrate mode\n");
                return -1;
            }
        }
        ctx->fixed_bwcode = CLIP(ctx->fixed_bwcode, ctx->params.min_bwcode,
                                 ctx->params.max_bwcode);
    } else {
        ctx->fixed_bwcode = ctx->params.bwcode;
    }

    if (s->mode == AFTEN_ENCODE) {
        // can't do block switching with low sample rate due to the high-pass filter
        if (ctx->sample_rate <= 16000)
            ctx->params.use_block_switching = 0;

        // initialize transient-detect filters (one for each channel)
        // cascaded biquad direct form I high-pass w/ cutoff of 8 kHz
        if (ctx->params.use_block_switching) {
            for (i = 0; i < ctx->n_all_channels; i++) {
                ctx->bs_filter[i].type = FILTER_TYPE_HIGHPASS;
                ctx->bs_filter[i].cascaded = 1;
                ctx->bs_filter[i].cutoff = 8000;
                ctx->bs_filter[i].samplerate = (FLOAT)ctx->sample_rate;
                if (filter_init(&ctx->bs_filter[i], FILTER_ID_BIQUAD_I)) {
                    fprintf(stderr, "error initializing transient-detect filter\n");
                    return -1;
                }
            }
        }

        // initialize DC filters (one for each channel)
        // one-pole high-pass w/ cutoff of 3 Hz
        if (ctx->params.use_dc_filter) {
            for (i = 0; i < ctx->n_all_channels; i++) {
                ctx->dc_filter[i].type = FILTER_TYPE_HIGHPASS;
                ctx->dc_filter[i].cascaded = 0;
                ctx->dc_filter[i].cutoff = 3;
                ctx->dc_filter[i].samplerate = (FLOAT)ctx->sample_rate;
                if (filter_init(&ctx->dc_filter[i], FILTER_ID_ONEPOLE)) {
                    fprintf(stderr, "error initializing dc filter\n");
                    return -1;
                }
            }
        }

        // initialize bandwidth filters (one for each channel)
        // butterworth 2nd order cascaded direct form II low-pass
        if (ctx->params.use_bw_filter) {
            int cutoff;
            int bwcode = ctx->params.bwcode == -2 ? ctx->params.max_bwcode :
                                                    ctx->fixed_bwcode;
            cutoff = (((bwcode * 3) + 73) * ctx->sample_rate) / 512;
            if (cutoff < 4000) {
                // disable bandwidth filter if cutoff is below 4000 Hz
                ctx->params.use_bw_filter = 0;
            } else {
                for (i = 0; i < ctx->n_channels; i++) {
                    ctx->bw_filter[i].type = FILTER_TYPE_LOWPASS;
                    ctx->bw_filter[i].cascaded = 1;
                    ctx->bw_filter[i].cutoff = (FLOAT)cutoff;
                    ctx->bw_filter[i].samplerate = (FLOAT)ctx->sample_rate;
                    if (filter_init(&ctx->bw_filter[i], FILTER_ID_BUTTERWORTH_II)) {
                        fprintf(stderr, "error initializing bandwidth filter\n");
                        return -1;
                    }
                }
            }
        }

        // initialize LFE filter
        // butterworth 2nd order cascaded direct form II low-pass w/ cutoff of 120 Hz
        if (ctx->params.use_lfe_filter) {
            if (!ctx->lfe) {
                fprintf(stderr, "cannot use lfe filter. no lfe channel\n");
                return -1;
            }
            ctx->lfe_filter.type = FILTER_TYPE_LOWPASS;
            ctx->lfe_filter.cascaded = 1;
            ctx->lfe_filter.cutoff = 120;
            ctx->lfe_filter.samplerate = (FLOAT)ctx->sample_rate;
            if (filter_init(&ctx->lfe_filter, FILTER_ID_BUTTERWORTH_II)) {
                fprintf(stderr, "error initializing lfe filter\n");
                return -1;
            }
        }
    }

    // Initialize thread specific contexts
    ctx->n_threads = (s->system.n_threads > 0) ? s->system.n_threads : get_ncpus();
    ctx->n_threads = MIN(ctx->n_threads, MAX_NUM_THREADS);
    s->system.n_threads = ctx->n_threads;
    ctx->tctx = calloc(sizeof(A52ThreadContext), ctx->n_threads);

    for (j = 0; j < ctx->n_threads; j++) {
        A52ThreadContext *cur_tctx = &ctx->tctx[j];
        cur_tctx->ctx = ctx;
        cur_tctx->thread_num = j;

        mdct_thread_init(cur_tctx);

        cur_tctx->bit_cnt = 0;
        cur_tctx->sample_cnt = 0;

        cur_tctx->last_quality = last_quality;

        if (ctx->n_threads > 1) {
            cur_tctx->state = START;

            posix_cond_init(&cur_tctx->ts.enter_cond);
            posix_cond_init(&cur_tctx->ts.confirm_cond);
            posix_cond_init(&cur_tctx->ts.samples_cond);

            posix_mutex_init(&cur_tctx->ts.enter_mutex);
            posix_mutex_init(&cur_tctx->ts.confirm_mutex);

            windows_event_init(&cur_tctx->ts.ready_event);
            windows_event_init(&cur_tctx->ts.enter_event);
            windows_event_init(&cur_tctx->ts.samples_event);

            posix_mutex_lock(&cur_tctx->ts.enter_mutex);
            thread_create(&cur_tctx->ts.thread, threaded_worker, cur_tctx);
            posix_cond_wait(&cur_tctx->ts.enter_cond, &cur_tctx->ts.enter_mutex);
            posix_mutex_unlock(&cur_tctx->ts.enter_mutex);
            windows_event_wait(&cur_tctx->ts.ready_event);
            windows_event_set(&cur_tctx->ts.ready_event);
        }
    }
    for (j = 0; j < ctx->n_threads; j++) {
#ifdef HAVE_POSIX_THREADS
        ctx->tctx[j].ts.next_samples_cond = &ctx->tctx[(j + 1) % ctx->n_threads].ts.samples_cond;
#endif
#ifdef HAVE_WINDOWS_THREADS
        ctx->tctx[j].ts.next_samples_event = &ctx->tctx[(j + 1) % ctx->n_threads].ts.samples_event;
#endif
    }
    if (ctx->n_threads > 1) {
        posix_mutex_init(&ctx->ts.samples_mutex);
        windows_cs_init(&ctx->ts.samples_cs);
    }

    switch(s->mode) {
    case AFTEN_ENCODE:
#ifndef NO_THREADS
        ctx->prepare_work = prepare_encode;
#endif
        ctx->begin_process_frame = begin_encode_frame;
        // copy initial samples
        if (s->initial_samples) {
            FLOAT *samples = malloc(A52_SAMPLES_PER_FRAME * ctx->n_all_channels * sizeof(FLOAT));
            memset(samples, 0, (A52_SAMPLES_PER_FRAME - 256) * ctx->n_all_channels * sizeof(FLOAT));
            memcpy(samples + (A52_SAMPLES_PER_FRAME - 256) * ctx->n_all_channels, s->initial_samples, 256 * ctx->n_all_channels * sizeof(FLOAT));
            convert_samples_from_src(&ctx->tctx[0], samples, A52_SAMPLES_PER_FRAME);
            free(samples);
            // copy samples with filters applied
            // HACK: set threads temporarily to 1 to avoid locking
            ctx->n_threads = 1;
            copy_samples(&ctx->tctx[0]);
            ctx->n_threads = s->system.n_threads;
        }
        break;
    case AFTEN_TRANSCODE:
#ifndef NO_THREADS
        ctx->prepare_work = prepare_transcode;
#endif
        ctx->begin_process_frame = begin_transcode_frame;
        for (j = 0; j < ctx->n_threads; j++) {
            A52ThreadContext *tctx = ctx->tctx + j;
            tctx->dctx = calloc(sizeof(A52DecodeContext), 1);
            a52_decode_init_thread(tctx);
        }
        break;
    }

    return 0;
}


Generated by  Doxygen 1.6.0   Back to index