24 #include "com_tagtraum_ffsampledsp_FFAudioFileReader.h" 27 static int CALLBACK_BUFFERSIZE = 32*1024;
29 static jmethodID limit_MID = NULL;
30 static jmethodID ffAudioFileFormat_MID = NULL;
37 static void init_ids(JNIEnv *env) {
39 fprintf(stderr,
"FFAudioFileReader.c init_ids(env)\n");
43 jclass bufferClass = NULL;
44 jclass ffAudioFileFormat_class = NULL;
46 bufferClass = (*env)->FindClass(env,
"java/nio/Buffer");
47 ffAudioFileFormat_class = (*env)->FindClass(env,
"com/tagtraum/ffsampledsp/FFAudioFileFormat");
50 if (!bufferClass) fprintf(stderr,
"Failed to find java/nio/Buffer\n");
51 if (!ffAudioFileFormat_class) fprintf(stderr,
"Failed to find com/tagtraum/ffsampledsp/FFAudioFileFormat\n");
54 limit_MID = (*env)->GetMethodID(env, bufferClass,
"limit",
"()I");
55 ffAudioFileFormat_MID = (*env)->GetMethodID(env, ffAudioFileFormat_class,
"<init>",
"(Ljava/lang/String;IFIIIFZJILjava/lang/Boolean;)V");
57 if (!limit_MID) fprintf(stderr,
"Failed to find limit method\n");
58 if (!ffAudioFileFormat_MID) fprintf(stderr,
"Failed to find constructor of AudioFileFormat\n");
80 static int read_callback(
void *opaque, uint8_t *buf,
int size) {
83 uint8_t *java_buffer = NULL;
89 java_buffer = (uint8_t *)(*callback->
env)->GetDirectBufferAddress(callback->
env, callback->
byte_buffer);
96 availableData = (*callback->
env)->CallIntMethod(callback->
env, callback->
byte_buffer, limit_MID);
98 memcpy(buf, (
const uint8_t *)java_buffer, availableData);
113 static int is_pcm(
enum AVCodecID
id) {
116 case AV_CODEC_ID_PCM_S8:
117 case AV_CODEC_ID_PCM_U8:
118 case AV_CODEC_ID_PCM_S16BE:
119 case AV_CODEC_ID_PCM_S16LE:
120 case AV_CODEC_ID_PCM_U16BE:
121 case AV_CODEC_ID_PCM_U16LE:
122 case AV_CODEC_ID_PCM_S24BE:
123 case AV_CODEC_ID_PCM_S24LE:
124 case AV_CODEC_ID_PCM_S32BE:
125 case AV_CODEC_ID_PCM_S32LE:
126 case AV_CODEC_ID_PCM_U32BE:
127 case AV_CODEC_ID_PCM_U32LE:
128 case AV_CODEC_ID_PCM_F32BE:
129 case AV_CODEC_ID_PCM_F32LE:
130 case AV_CODEC_ID_PCM_F64BE:
131 case AV_CODEC_ID_PCM_F64LE:
147 static jlong duration(AVFormatContext *format_context, AVStream *stream) {
148 jlong duration_in_microseconds = -1;
150 if (format_context->duration != AV_NOPTS_VALUE) {
151 int64_t micro_seconds_base = AV_TIME_BASE / 1000000;
152 duration_in_microseconds = (jlong)(format_context->duration / micro_seconds_base);
155 if (stream->nb_frames != 0 && duration_in_microseconds <=0 && stream->codecpar->sample_rate > 0) {
156 duration_in_microseconds = stream->nb_frames * 1000000L / stream->codecpar->sample_rate;
158 return duration_in_microseconds;
168 static jfloat get_frame_rate(AVStream *stream, jlong duration) {
169 jfloat frame_rate = -1;
171 if (frame_rate <=0 && stream->nb_frames > 0 && duration > 0) {
172 frame_rate = stream->nb_frames * 1000000LL / (jfloat)duration;
175 if (frame_rate <=0 && stream->codecpar->frame_size > 0 && stream->codecpar->sample_rate > 0) {
176 frame_rate = (jfloat)stream->codecpar->sample_rate/(jfloat)stream->codecpar->frame_size;
179 if (frame_rate <=0 && stream->codecpar->frame_size == 0 && stream->codecpar->sample_rate > 0) {
180 frame_rate = (jfloat)stream->codecpar->sample_rate;
185 if (stream->nb_frames > 0 && duration > 0) {
186 fprintf(stderr,
"1 frame rate : %f\n", stream->nb_frames * 1000000LL / (jfloat)duration);
188 if (stream->codecpar->frame_size > 0 && stream->codecpar->sample_rate > 0) {
189 fprintf(stderr,
"2 frame rate : %f\n", (jfloat)stream->codecpar->sample_rate/(jfloat)stream->codecpar->frame_size);
191 if (stream->codecpar->frame_size == 0 && stream->codecpar->sample_rate > 0) {
192 fprintf(stderr,
"3 frame rate : %f\n", (jfloat)stream->codecpar->sample_rate);
204 static jobject create_ffaudiofileformat(JNIEnv *env, jstring url, jint codecId, jfloat sampleRate, jint sampleSize,
205 jint channels, jint frame_size, jfloat frame_rate, jboolean big_endian, jlong duration,
206 jint bitRate, jobject vbr) {
207 jclass ffAudioFileFormat_class = NULL;
209 ffAudioFileFormat_class = (*env)->FindClass(env,
"com/tagtraum/ffsampledsp/FFAudioFileFormat");
212 return (*env)->NewObject(env, ffAudioFileFormat_class, ffAudioFileFormat_MID, url, codecId, sampleRate, sampleSize,
213 channels, frame_size, frame_rate, big_endian, duration, bitRate, vbr);
216 static int create_ffaudiofileformats(JNIEnv *env, AVFormatContext *format_context, jobjectArray *array, jstring url) {
218 jlong duration_in_microseconds = -1;
219 jfloat frame_rate = -1;
221 jboolean big_endian = 1;
222 jobject audio_format = NULL;
223 jint frame_size = -1;
224 jint sample_size = -1;
225 int audio_stream_count = 0;
226 int audio_stream_number = 0;
230 for (i=0; i<format_context->nb_streams; i++) {
231 AVStream* stream = format_context->streams[i];
232 if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
233 audio_stream_count++;
238 fprintf(stderr,
"Found %i audio streams.\n", audio_stream_count);
242 if (audio_stream_count == 0) {
248 *array = (*env)->NewObjectArray(env, audio_stream_count, (*env)->FindClass(env,
"javax/sound/sampled/AudioFileFormat"), NULL);
254 fprintf(stderr,
"Created audio file format array.\n");
258 for (i=0; i<format_context->nb_streams; i++) {
259 AVStream* stream = format_context->streams[i];
260 if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
269 duration_in_microseconds = duration(format_context, stream);
270 frame_rate = get_frame_rate(stream, duration_in_microseconds);
272 if (is_pcm(stream->codecpar->codec_id)) {
273 frame_size = (stream->codecpar->bits_per_coded_sample / 8) * stream->codecpar->channels;
277 sample_size = stream->codecpar->bits_per_raw_sample
278 ? stream->codecpar->bits_per_raw_sample
279 : stream->codecpar->bits_per_coded_sample;
282 fprintf(stderr,
"stream->codecpar->bits_per_coded_sample: %i\n", stream->codecpar->bits_per_coded_sample);
283 fprintf(stderr,
"stream->codecpar->bits_per_raw_sample : %i\n", stream->codecpar->bits_per_raw_sample);
284 fprintf(stderr,
"stream->codecpar->bit_rate : %lli\n", stream->codecpar->bit_rate);
285 fprintf(stderr,
"format_context->packet_size : %i\n", format_context->packet_size);
286 fprintf(stderr,
"frames : %" PRId64
"\n", stream->nb_frames);
287 fprintf(stderr,
"sample_rate: %i\n", stream->codecpar->sample_rate);
288 fprintf(stderr,
"sampleSize : %i\n", stream->codecpar->bits_per_coded_sample);
289 fprintf(stderr,
"channels : %i\n", stream->codecpar->channels);
290 fprintf(stderr,
"frame_size : %i\n", (
int)frame_size);
291 fprintf(stderr,
"codec_id : %i\n", stream->codecpar->codec_id);
292 fprintf(stderr,
"duration : %" PRId64
"\n", (int64_t)duration_in_microseconds);
293 fprintf(stderr,
"frame_rate : %f\n", frame_rate);
295 fprintf(stderr,
"big_endian : true\n");
297 fprintf(stderr,
"big_endian : false\n");
300 audio_format = create_ffaudiofileformat(env, url,
301 stream->codecpar->codec_id,
302 (jfloat)stream->codecpar->sample_rate,
304 stream->codecpar->channels,
308 duration_in_microseconds,
309 stream->codecpar->bit_rate,
312 (*env)->SetObjectArrayElement(env, *array, audio_stream_number, audio_format);
313 audio_stream_number++;
339 fprintf(stderr,
"openFromUrl_1\n");
343 AVFormatContext *format_context = NULL;
344 jobjectArray array = NULL;
350 const char *input_url = (*env)->GetStringUTFChars(env, url, NULL);
356 res = create_ffaudiofileformats(env, format_context, &array, url);
362 if (format_context) {
363 avformat_close_input(&format_context);
365 (*env)->ReleaseStringUTFChars(env, url, input_url);
380 AVFormatContext *format_context = NULL;
382 jobjectArray array = NULL;
384 unsigned char* callbackBuffer = NULL;
386 AVIOContext *io_context;
392 res = AVERROR(ENOMEM);
400 format_context = avformat_alloc_context();
401 if (!format_context) {
402 res = AVERROR(ENOMEM);
408 format_context->probesize = 8*1024;
409 format_context->max_analyze_duration = 5*AV_TIME_BASE;
411 callbackBuffer = (
unsigned char*)av_malloc(CALLBACK_BUFFERSIZE *
sizeof(uint8_t));
412 if (!callbackBuffer) {
413 res = AVERROR(ENOMEM);
418 io_context = avio_alloc_context(
428 res = AVERROR(ENOMEM);
433 io_context->seekable = 0;
435 format_context->pb = io_context;
442 res = create_ffaudiofileformats(env, format_context, &array, NULL);
454 if (format_context) {
455 AVFormatContext *s = format_context;
456 if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) || (s->flags & AVFMT_FLAG_CUSTOM_IO)) {
459 av_free(s->pb->buffer);
464 avformat_close_input(&format_context);
void throwIOExceptionIfError(JNIEnv *env, int err, const char *message)
Throws an IOException.
jobject byte_buffer
byte buffer passed in (read only once)
int ff_big_endian(enum AVCodecID codec_id)
Indicates whether the given id belongs to a big endian codec.
void throwUnsupportedAudioFileExceptionIfError(JNIEnv *env, int err, const char *message)
Throws an UnsupportedAudioFileException.
JNIEXPORT jobjectArray JNICALL Java_com_tagtraum_ffsampledsp_FFAudioFileReader_getAudioFileFormatsFromBuffer(JNIEnv *env, jobject instance, jobject byte_buffer)
Opens the byte buffer to determine its AudioFileFormat.
int ff_open_format_context(JNIEnv *env, AVFormatContext **format_context, const char *url)
Opens the input file/url and allocates a AVFormatContext for it, but does not open the audio stream w...
JNIEXPORT jobjectArray JNICALL Java_com_tagtraum_ffsampledsp_FFAudioFileReader_getAudioFileFormatsFromURL(JNIEnv *env, jobject instance, jstring url)
Opens the given URL to determine its AudioFileFormat.
JNIEnv * env
JNI environment.
Simple struct used for the read_callback of stream data.
int call_count
number of times the read_callback was called