Beispiel #1
0
/**
 * Initialize our main context FFAudioIO, so that SwrContext, decode buffers and the encoder are set
 * to reasonable values.
 *
 * @param JNIEnv    env
 * @param aio       our context, FFAudioIO
 * @return a negative value, if something went wrong
 */
int ff_init_audioio(JNIEnv *env, FFAudioIO *aio) {
    int res = 0;
    int nb_planes;
    AVCodec *codec = NULL;

    aio->timestamp = 0;

    // allocate pointer to the audio buffers, i.e. the multiple planes/channels.
    nb_planes = av_sample_fmt_is_planar(aio->stream->codecpar->format)
        ? aio->stream->codecpar->channels
        : 1;

    // always init SWR to keep code simpler
    res = init_swr(env, aio);
    if (res < 0) {
        // exception is already thrown
        goto bail;
    }
    // if for some reason the codec delivers 24bit, we need to encode its output to little endian
    if (aio->stream->codecpar->bits_per_coded_sample == 24) {
        codec = ff_find_encoder(aio->stream->codecpar->format, aio->stream->codecpar->bits_per_coded_sample, ff_big_endian(aio->stream->codecpar->codec_id), 1);
        if (!codec) {
            res = AVERROR(EINVAL);
            throwIOExceptionIfError(env, res, "Could not find suitable encoder codec.");
            goto bail;
        }
        res = ff_init_encoder(env, aio, codec);
        if (res<0) {
            throwIOExceptionIfError(env, res, "Could not initialize encoder codec.");
            goto bail;
        }
    }

    // allocate the buffer the codec decodes to
    aio->audio_data = av_mallocz(sizeof(uint8_t *) * nb_planes);
    if (!aio->audio_data) {
        res = AVERROR(ENOMEM);
        throwIOExceptionIfError(env, res, "Could not allocate audio data buffers.");
        goto bail;
    }

    aio->decode_frame = av_frame_alloc();
    if (!aio->decode_frame) {
        res = AVERROR(ENOMEM);
        throwIOExceptionIfError(env, res, "Could not allocate frame.");
        goto bail;
    }

    // initialize packet
    av_init_packet(&(aio->decode_packet));
    aio->decode_packet.data = NULL;
    aio->decode_packet.size = 0;

bail:

    return res;
}
Beispiel #2
0
/**
 * Re-configures SwrContext and Encoder to match the provided target_format.
 *
 * @param env           JNIEnv
 * @param object        stream instance this call stems from, i.e. a FFCodecInputStream
 * @param target_format target AudioFormat
 * @param aio_pointer   Pointer to the FFAudioIO struct of the FFNativePeerInputStream that opened the file/stream
 * @return pointer to the FFAudioIO struct that was given as parameter
 */
JNIEXPORT jlong JNICALL Java_com_tagtraum_ffsampledsp_FFCodecInputStream_open(JNIEnv *env, jobject object, jobject target_format, jlong aio_pointer) {
    int res = 0;
    enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_NONE;
    int out_channel_layout = AV_CH_LAYOUT_STEREO;
    int is_float = 0;
    int is_signed = 0;
    AVCodec *encoder = NULL;
    int dither_method = SWR_DITHER_NONE;
    int output_sample_bits = 0;

    init_ids(env);

    FFAudioIO *aio = (FFAudioIO*)(intptr_t)aio_pointer;

    jfloat sample_rate = (*env)->CallFloatMethod(env, target_format, getSampleRate_MID);
    jint sample_size_in_bits = (*env)->CallIntMethod(env, target_format, getSampleSizeInBits_MID);
    jint channels = (*env)->CallIntMethod(env, target_format, getChannels_MID);
    jboolean big_endian = (*env)->CallBooleanMethod(env, target_format, isBigEndian_MID);
    jobject encoding = (*env)->CallObjectMethod(env, target_format, getEncoding_MID);
    jstring jencoding_name = (jstring)(*env)->CallObjectMethod(env, encoding, toString_MID);

    const char *encoding_name = (*env)->GetStringUTFChars(env, jencoding_name, NULL);
    is_float = strcmp("PCM_FLOAT", encoding_name) == 0;
    is_signed = strcmp("PCM_SIGNED", encoding_name) == 0;
    (*env)->ReleaseStringUTFChars(env, jencoding_name, encoding_name);

#ifdef DEBUG
    fprintf(stderr, "encoding = %s\n", encoding_name);
    fprintf(stderr, "signed   = %d\n", is_signed);
    fprintf(stderr, "float    = %d\n", is_float);
    fprintf(stderr, "bits     = %d\n", (int)sample_size_in_bits);
#endif

    if (sample_size_in_bits <= 8) {
        out_sample_fmt = AV_SAMPLE_FMT_U8;
    } else if (sample_size_in_bits <=16) {
        out_sample_fmt = AV_SAMPLE_FMT_S16;
    } else if (sample_size_in_bits <= 32 && is_float) {
        out_sample_fmt = AV_SAMPLE_FMT_FLT;
    } else if (sample_size_in_bits <=32) {
        out_sample_fmt = AV_SAMPLE_FMT_S32;
    } else if (sample_size_in_bits <= 64 && is_float) {
        out_sample_fmt = AV_SAMPLE_FMT_DBL;
    } else {
        fprintf(stderr, "Will use 64 bit PCM_FLOAT even though it might not have been desired.\n");
        out_sample_fmt = AV_SAMPLE_FMT_DBL;
    }

    if (aio->stream->codecpar->channels == channels) {
        out_channel_layout = aio->stream->codecpar->channel_layout;
    } else if (channels == 1) {
        out_channel_layout = AV_CH_LAYOUT_MONO;
    } else if (channels == 2) {
        out_channel_layout = AV_CH_LAYOUT_STEREO;
    } else {
        fprintf(stderr, "Undetermined channel layout, will use stereo.\n");
        channels = 2;
    }

    if (aio->stream->codecpar->bits_per_coded_sample > sample_size_in_bits) {
        dither_method = SWR_DITHER_TRIANGULAR;
        output_sample_bits = sample_size_in_bits;
    }

#ifdef DEBUG
    fprintf(stderr, "setting out format to: %d\n", out_sample_fmt);
#endif

    // remove default setup
    if (aio->swr_context) {
        swr_free(&aio->swr_context);
    }
    // allocate new
    aio->swr_context = swr_alloc();
    if (!aio->swr_context) {
        res = AVERROR(ENOMEM);
        throwIOExceptionIfError(env, res, "Could not allocate swr context.");
        goto bail;
    }

    // standard stuff from input
    av_opt_set_sample_fmt(aio->swr_context, "in_sample_fmt",  aio->stream->codecpar->format, 0);
    av_opt_set_int(aio->swr_context, "in_channel_count",  aio->stream->codecpar->channels, 0);
    av_opt_set_int(aio->swr_context, "in_channel_layout",  aio->stream->codecpar->channel_layout, 0);
    av_opt_set_int(aio->swr_context, "in_sample_rate",     aio->stream->codecpar->sample_rate, 0);
    // custom stuff
    av_opt_set_int(aio->swr_context, "out_channel_layout", out_channel_layout, 0);
    av_opt_set_int(aio->swr_context, "out_channel_count", channels, 0);
    av_opt_set_int(aio->swr_context, "out_sample_rate", (int)round(sample_rate), 0);
    av_opt_set_sample_fmt(aio->swr_context, "out_sample_fmt", out_sample_fmt, 0);
    av_opt_set_int(aio->swr_context, "dither_method", dither_method, 0);
    av_opt_set_int(aio->swr_context, "output_sample_bits", output_sample_bits, 0);

    res = swr_init(aio->swr_context);
    if (res < 0) {
        res = AVERROR(ENOMEM);
        throwIOExceptionIfError(env, res, "Could not re-initialize swr context.");
        goto bail;
    }

#ifdef DEBUG
    fprintf(stderr, "open codec: dither method     : %d\n", dither_method);
    fprintf(stderr, "open codec: output sample bits: %d\n", aio->swr_context->dither.output_sample_bits);
#endif

    // re-adjust encoder
    encoder = ff_find_encoder(out_sample_fmt, sample_size_in_bits, big_endian, is_signed);
    if (!encoder) {
        res = AVERROR(EINVAL);
        throwIOExceptionIfError(env, res, "Could not find suitable encoder.");
        goto bail;
    }
    res = ff_init_encoder(env, aio, encoder);
    if (res < 0) {
        goto bail;
    }

    bail:

    return (jlong)(intptr_t)aio;
}