Ejemplo n.º 1
0
static int encavcodecaInit(hb_work_object_t *w, hb_job_t *job)
{
    AVCodec *codec;
    AVCodecContext *context;
    hb_audio_t *audio = w->audio;

    hb_work_private_t *pv = calloc(1, sizeof(hb_work_private_t));
    w->private_data       = pv;
    pv->job               = job;
    pv->list              = hb_list_init();

    // channel count, layout and matrix encoding
    int matrix_encoding;
    uint64_t channel_layout   = hb_ff_mixdown_xlat(audio->config.out.mixdown,
                                                   &matrix_encoding);
    pv->out_discrete_channels =
        hb_mixdown_get_discrete_channel_count(audio->config.out.mixdown);

    // default settings and options
    AVDictionary *av_opts          = NULL;
    const char *codec_name         = NULL;
    enum AVCodecID codec_id        = AV_CODEC_ID_NONE;
    enum AVSampleFormat sample_fmt = AV_SAMPLE_FMT_FLTP;
    int bits_per_raw_sample        = 0;
    int profile                    = FF_PROFILE_UNKNOWN;

    // override with encoder-specific values
    switch (audio->config.out.codec)
    {
        case HB_ACODEC_AC3:
            codec_id = AV_CODEC_ID_AC3;
            if (matrix_encoding != AV_MATRIX_ENCODING_NONE)
                av_dict_set(&av_opts, "dsur_mode", "on", 0);
            break;

        case HB_ACODEC_FDK_AAC:
        case HB_ACODEC_FDK_HAAC:
            codec_name          = "libfdk_aac";
            sample_fmt          = AV_SAMPLE_FMT_S16;
            bits_per_raw_sample = 16;
            switch (audio->config.out.codec)
            {
                case HB_ACODEC_FDK_HAAC:
                    profile = FF_PROFILE_AAC_HE;
                    break;
                default:
                    profile = FF_PROFILE_AAC_LOW;
                    break;
            }
            // Libav's libfdk-aac wrapper expects back channels for 5.1
            // audio, and will error out unless we translate the layout
            if (channel_layout == AV_CH_LAYOUT_5POINT1)
                channel_layout  = AV_CH_LAYOUT_5POINT1_BACK;
            break;

        case HB_ACODEC_FFAAC:
            codec_name = "aac";
            av_dict_set(&av_opts, "stereo_mode", "ms_off", 0);
            break;

        case HB_ACODEC_FFFLAC:
        case HB_ACODEC_FFFLAC24:
            codec_id = AV_CODEC_ID_FLAC;
            switch (audio->config.out.codec)
            {
                case HB_ACODEC_FFFLAC24:
                    sample_fmt          = AV_SAMPLE_FMT_S32;
                    bits_per_raw_sample = 24;
                    break;
                default:
                    sample_fmt          = AV_SAMPLE_FMT_S16;
                    bits_per_raw_sample = 16;
                    break;
            }
            break;

        default:
            hb_error("encavcodecaInit: unsupported codec (0x%x)",
                     audio->config.out.codec);
            return 1;
    }
    if (codec_name != NULL)
    {
        codec = avcodec_find_encoder_by_name(codec_name);
        if (codec == NULL)
        {
            hb_error("encavcodecaInit: avcodec_find_encoder_by_name(%s) failed",
                     codec_name);
            return 1;
        }
    }
    else
    {
        codec = avcodec_find_encoder(codec_id);
        if (codec == NULL)
        {
            hb_error("encavcodecaInit: avcodec_find_encoder(%d) failed",
                     codec_id);
            return 1;
        }
    }
    // allocate the context and apply the settings
    context                      = avcodec_alloc_context3(codec);
    hb_ff_set_sample_fmt(context, codec, sample_fmt);
    context->bits_per_raw_sample = bits_per_raw_sample;
    context->profile             = profile;
    context->channel_layout      = channel_layout;
    context->channels            = pv->out_discrete_channels;
    context->sample_rate         = audio->config.out.samplerate;

    if (audio->config.out.bitrate > 0)
    {
        context->bit_rate = audio->config.out.bitrate * 1000;
    }
    else if (audio->config.out.quality >= 0)
    {
        context->global_quality = audio->config.out.quality * FF_QP2LAMBDA;
        context->flags |= CODEC_FLAG_QSCALE;
    }

    if (audio->config.out.compression_level >= 0)
    {
        context->compression_level = audio->config.out.compression_level;
    }

    // For some codecs, libav requires the following flag to be set
    // so that it fills extradata with global header information.
    // If this flag is not set, it inserts the data into each
    // packet instead.
    context->flags |= CODEC_FLAG_GLOBAL_HEADER;

    if (hb_avcodec_open(context, codec, &av_opts, 0))
    {
        hb_error("encavcodecaInit: hb_avcodec_open() failed");
        return 1;
    }
    // avcodec_open populates the opts dictionary with the
    // things it didn't recognize.
    AVDictionaryEntry *t = NULL;
    while ((t = av_dict_get(av_opts, "", t, AV_DICT_IGNORE_SUFFIX)))
    {
        hb_log("encavcodecaInit: Unknown avcodec option %s", t->key);
    }
    av_dict_free(&av_opts);

    pv->context           = context;
    audio->config.out.samples_per_frame =
    pv->samples_per_frame = context->frame_size;
    pv->input_samples     = context->frame_size * context->channels;
    pv->input_buf         = malloc(pv->input_samples * sizeof(float));
    pv->max_output_bytes  = (pv->input_samples *
                             av_get_bytes_per_sample(context->sample_fmt));

    // sample_fmt conversion
    if (context->sample_fmt != AV_SAMPLE_FMT_FLT)
    {
        pv->output_buf = malloc(pv->max_output_bytes);
        pv->avresample = avresample_alloc_context();
        if (pv->avresample == NULL)
        {
            hb_error("encavcodecaInit: avresample_alloc_context() failed");
            return 1;
        }
        av_opt_set_int(pv->avresample, "in_sample_fmt",
                       AV_SAMPLE_FMT_FLT, 0);
        av_opt_set_int(pv->avresample, "out_sample_fmt",
                       context->sample_fmt, 0);
        av_opt_set_int(pv->avresample, "in_channel_layout",
                       context->channel_layout, 0);
        av_opt_set_int(pv->avresample, "out_channel_layout",
                       context->channel_layout, 0);
        if (hb_audio_dither_is_supported(audio->config.out.codec))
        {
            // dithering needs the sample rate
            av_opt_set_int(pv->avresample, "in_sample_rate",
                           context->sample_rate, 0);
            av_opt_set_int(pv->avresample, "out_sample_rate",
                           context->sample_rate, 0);
            av_opt_set_int(pv->avresample, "dither_method",
                           audio->config.out.dither_method, 0);
        }
        if (avresample_open(pv->avresample))
        {
            hb_error("encavcodecaInit: avresample_open() failed");
            avresample_free(&pv->avresample);
            return 1;
        }
    }
    else
    {
        pv->avresample = NULL;
        pv->output_buf = pv->input_buf;
    }

    if (context->extradata != NULL)
    {
        memcpy(w->config->extradata.bytes, context->extradata,
               context->extradata_size);
        w->config->extradata.length = context->extradata_size;
    }

    return 0;
}
Ejemplo n.º 2
0
static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i )
{
    hb_work_object_t  * w;
    hb_work_private_t * pv;
    hb_sync_audio_t   * sync;

    pv = calloc( 1, sizeof( hb_work_private_t ) );
    sync = &pv->type.audio;
    sync->index = i;
    pv->job    = job;
    pv->common = common;
    pv->common->ref++;
    pv->common->pts_count++;

    w = hb_get_work( WORK_SYNC_AUDIO );
    w->private_data = pv;
    w->audio = hb_list_item( job->list_audio, i );
    w->fifo_in = w->audio->priv.fifo_raw;

    if ( w->audio->config.out.codec & HB_ACODEC_PASS_FLAG )
    {
        w->fifo_out = w->audio->priv.fifo_out;
    }
    else
    {
        w->fifo_out = w->audio->priv.fifo_sync;
    }

    if( w->audio->config.out.codec == HB_ACODEC_AC3_PASS ||
        w->audio->config.out.codec == HB_ACODEC_AAC_PASS )
    {
        /* Have a silent AC-3/AAC frame ready in case we have to fill a
           gap */
        AVCodec        * codec;
        AVCodecContext * c;

        switch ( w->audio->config.out.codec )
        {
            case HB_ACODEC_AC3_PASS:
            {
                codec = avcodec_find_encoder( AV_CODEC_ID_AC3 );
            } break;
            case HB_ACODEC_AAC_PASS:
            {
                codec = avcodec_find_encoder( AV_CODEC_ID_AAC );
            } break;
            default:
            {
                // Never gets here
                codec = NULL; // Silence compiler warning
            } break;
        }

        c              = avcodec_alloc_context3(codec);
        c->bit_rate    = w->audio->config.in.bitrate;
        c->sample_rate = w->audio->config.in.samplerate;
        c->channels    =
            av_get_channel_layout_nb_channels(w->audio->config.in.channel_layout);
        hb_ff_set_sample_fmt(c, codec, AV_SAMPLE_FMT_FLT);

        if (w->audio->config.in.channel_layout == AV_CH_LAYOUT_STEREO_DOWNMIX)
        {
            c->channel_layout = AV_CH_LAYOUT_STEREO;
        }
        else
        {
            c->channel_layout = w->audio->config.in.channel_layout;
        }

        if( hb_avcodec_open( c, codec, NULL, 0 ) < 0 )
        {
            hb_log( "sync: avcodec_open failed" );
            return;
        }

        // Prepare input frame
        AVFrame frame = { .nb_samples = c->frame_size, .pts = 0, };
        int input_size = av_samples_get_buffer_size(NULL, c->channels,
                                                    frame.nb_samples,
                                                    c->sample_fmt, 1);
        uint8_t *zeros = calloc(1, input_size);
        avcodec_fill_audio_frame(&frame, c->channels, c->sample_fmt, zeros,
                                 input_size, 1);

        // Allocate enough space for the encoded silence
        // The output should be < the input
        sync->silence_buf  = malloc( input_size );

        // There is some delay in getting output from some audio encoders.
        // So encode a few packets till we get output.
        int ii;
        for ( ii = 0; ii < 10; ii++ )
        {
            // Prepare output packet
            AVPacket pkt;
            int got_packet;
            av_init_packet(&pkt);
            pkt.data = sync->silence_buf;
            pkt.size = input_size;

            int ret = avcodec_encode_audio2( c, &pkt, &frame, &got_packet);
            if ( ret < 0 )
            {
                hb_log( "sync: avcodec_encode_audio failed" );
                break;
            }

            if ( got_packet )
            {
                sync->silence_size = pkt.size;
                break;
            }
        }
        free( zeros );
        hb_avcodec_close( c );
        av_free( c );
    }
    else
    {
        if( w->audio->config.out.codec & HB_ACODEC_PASS_FLAG )
Ejemplo n.º 3
0
static int encavcodecaInit( hb_work_object_t * w, hb_job_t * job )
{
    AVCodec * codec;
    AVCodecContext * context;
    hb_audio_t * audio = w->audio;

    hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
    w->private_data = pv;

    pv->job = job;

    pv->out_discrete_channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown);

    codec = avcodec_find_encoder( w->codec_param );
    if( !codec )
    {
        hb_log( "encavcodecaInit: avcodec_find_encoder "
                "failed" );
        return 1;
    }
    context = avcodec_alloc_context3(codec);

    AVDictionary *av_opts = NULL;
    if ( w->codec_param == CODEC_ID_AAC )
    {
        av_dict_set( &av_opts, "stereo_mode", "ms_off", 0 );
    }
    if ( w->codec_param == CODEC_ID_AC3 )
    {
        if( audio->config.out.mixdown == HB_AMIXDOWN_DOLBY ||
            audio->config.out.mixdown == HB_AMIXDOWN_DOLBYPLII )
        {
            av_dict_set( &av_opts, "dsur_mode", "on", 0 );
        }
    }

    context->channel_layout = AV_CH_LAYOUT_STEREO;
    switch( audio->config.out.mixdown )
    {
        case HB_AMIXDOWN_MONO:
            context->channel_layout = AV_CH_LAYOUT_MONO;
            pv->layout = HB_INPUT_CH_LAYOUT_MONO;
            break;

        case HB_AMIXDOWN_STEREO:
        case HB_AMIXDOWN_DOLBY:
        case HB_AMIXDOWN_DOLBYPLII:
            context->channel_layout = AV_CH_LAYOUT_STEREO;
            pv->layout = HB_INPUT_CH_LAYOUT_STEREO;
            break;

        case HB_AMIXDOWN_6CH:
            context->channel_layout = AV_CH_LAYOUT_5POINT1;
            pv->layout = HB_INPUT_CH_LAYOUT_3F2R | HB_INPUT_CH_LAYOUT_HAS_LFE;
            break;

        default:
            hb_log("encavcodecaInit: bad mixdown" );
            break;
    }

    if( audio->config.out.bitrate > 0 )
        context->bit_rate = audio->config.out.bitrate * 1000;
    else if( audio->config.out.quality >= 0 )
    {
        context->global_quality = audio->config.out.quality * FF_QP2LAMBDA;
        context->flags |= CODEC_FLAG_QSCALE;
    }

    if( audio->config.out.compression_level >= 0 )
        context->compression_level = audio->config.out.compression_level;

    context->sample_rate = audio->config.out.samplerate;
    context->channels = pv->out_discrete_channels;
    // Try to set format to float.  Fallback to whatever is supported.
    hb_ff_set_sample_fmt( context, codec );

    if( hb_avcodec_open( context, codec, &av_opts, 0 ) )
    {
        hb_log( "encavcodecaInit: avcodec_open failed" );
        return 1;
    }
    // avcodec_open populates the opts dictionary with the
    // things it didn't recognize.
    AVDictionaryEntry *t = NULL;
    while( ( t = av_dict_get( av_opts, "", t, AV_DICT_IGNORE_SUFFIX ) ) )
    {
        hb_log( "encavcodecaInit: Unknown avcodec option %s", t->key );
    }
    av_dict_free( &av_opts );

    pv->context = context;

    audio->config.out.samples_per_frame = pv->samples_per_frame = context->frame_size;
    pv->input_samples = pv->samples_per_frame * pv->out_discrete_channels;

    // Set a reasonable maximum output size
    pv->output_bytes = context->frame_size * 
        av_get_bytes_per_sample(context->sample_fmt) * 
        context->channels;

    pv->buf = malloc( pv->input_samples * sizeof( float ) );

    pv->list = hb_list_init();

    if ( context->extradata )
    {
        memcpy( w->config->extradata.bytes, context->extradata, context->extradata_size );
        w->config->extradata.length = context->extradata_size;
    }

    return 0;
}