FFSampledSP
Loading...
Searching...
No Matches
FFUtils.c
Go to the documentation of this file.
1/*
2 * =================================================
3 * Copyright 2013 tagtraum industries incorporated
4 * This file is part of FFSampledSP.
5 *
6 * FFSampledSP is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFSampledSP is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFSampledSP; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 * =================================================
20 *
21 * @author <a href="mailto:hs@tagtraum.com">Hendrik Schreiber</a>
22 */
23
24#include "FFUtils.h"
26
27const uint32_t CODEC_TAG_DRMS = 'smrd'; // 'drms'
28
29static jfieldID nativeBuffer_FID = NULL;
30static jmethodID rewind_MID = NULL;
31static jmethodID limit_MID = NULL;
32static jmethodID capacity_MID = NULL;
33static jmethodID setNativeBufferCapacity_MID = NULL;
34static jmethodID logFine_MID = NULL;
35static jmethodID logWarning_MID = NULL;
36static const int MIN_PROBE_SCORE =
37 5; // this is fairly arbitrary, but we need to give other
38 // javax.sound.sampled impls a chance
39// Minimum bytes to fill per ff_fill_buffer() call; reduces JNI roundtrips for
40// bulk use.
41static const int FF_FILL_TARGET = 64 * 1024;
42
53JNIEXPORT void JNICALL
55 JNIEnv *env, jclass streamClass) {
56 jclass bufferClass = (*env)->FindClass(env, "java/nio/Buffer");
57 if (!bufferClass)
58 return;
59
60 nativeBuffer_FID = (*env)->GetFieldID(env, streamClass, "nativeBuffer",
61 "Ljava/nio/ByteBuffer;");
62 if (!nativeBuffer_FID)
63 return;
64 rewind_MID =
65 (*env)->GetMethodID(env, bufferClass, "rewind", "()Ljava/nio/Buffer;");
66 if (!rewind_MID)
67 return;
68 limit_MID =
69 (*env)->GetMethodID(env, bufferClass, "limit", "(I)Ljava/nio/Buffer;");
70 if (!limit_MID)
71 return;
72 capacity_MID = (*env)->GetMethodID(env, bufferClass, "capacity", "()I");
73 if (!capacity_MID)
74 return;
75 setNativeBufferCapacity_MID =
76 (*env)->GetMethodID(env, streamClass, "setNativeBufferCapacity", "(I)I");
77 if (!setNativeBufferCapacity_MID)
78 return;
79 logFine_MID =
80 (*env)->GetMethodID(env, streamClass, "logFine", "(Ljava/lang/String;)V");
81 if (!logFine_MID)
82 return;
83 logWarning_MID = (*env)->GetMethodID(env, streamClass, "logWarning",
84 "(Ljava/lang/String;)V");
85}
86
93int ff_open_stream(JNIEnv *env, AVStream *stream, AVCodecContext **context) {
94#ifdef DEBUG
95 fprintf(stderr, "Opening stream...\n");
96#endif
97
98 int res = 0;
99 AVCodec *decoder = NULL;
100
101 decoder = avcodec_find_decoder(stream->codecpar->codec_id);
102 if (!decoder) {
103 fprintf(stderr, "Failed to find %s codec\n",
104 av_get_media_type_string(AVMEDIA_TYPE_AUDIO));
105 res = AVERROR(EINVAL);
107 "Failed to find codec.");
108 goto bail;
109 }
110 *context = avcodec_alloc_context3(decoder);
111 if (!*context) {
112 fprintf(stderr, "Failed to allocate context\n");
113 res = AVERROR(ENOMEM);
115 env, res, "Failed to allocate codec context.");
116 goto bail;
117 }
118
119 /* Copy codec parameters from input stream to output codec context */
120 if ((res = avcodec_parameters_to_context(*context, stream->codecpar)) < 0) {
121 fprintf(stderr, "Failed to copy %s codec parameters to decoder context\n",
122 av_get_media_type_string(AVMEDIA_TYPE_AUDIO));
124 env, res, "Failed to copy codec parameters.");
125 goto bail;
126 }
127
128 if ((res = avcodec_open2(*context, decoder, NULL)) < 0) {
129 fprintf(stderr, "Failed to open %s codec\n",
130 av_get_media_type_string(AVMEDIA_TYPE_AUDIO));
132 "Failed to open codec.");
133 goto bail;
134 }
135
136#ifdef DEBUG
137 fprintf(stderr, "Stream was opened.\n");
138#endif
139 return res;
140
141bail:
142 return res;
143}
144
152static int open_codec_context(int *stream_index,
153 AVFormatContext *format_context,
154 enum AVMediaType type) {
155 int res = av_find_best_stream(format_context, type, -1, -1, NULL, 0);
156 if (res >= 0)
157 *stream_index = res;
158 return res;
159}
160
168static void throw_new(JNIEnv *env, const char *class_name,
169 const char *message) {
170 if ((*env)->ExceptionCheck(env))
171 return;
172 jclass excCls = (*env)->FindClass(env, class_name);
173 if (!excCls)
174 return; // FindClass threw
175 (*env)->ThrowNew(env, excCls, message);
176 (*env)->DeleteLocalRef(env, excCls);
177}
178
183 const char *message) {
184 if (err) {
185 char formattedMessage[strlen(message) + 4 + AV_ERROR_MAX_STRING_SIZE];
186 snprintf(formattedMessage, strlen(message) + 4 + AV_ERROR_MAX_STRING_SIZE,
187 "%s (%.64s)", message, av_err2str(err));
188#ifdef DEBUG
189 fprintf(stderr, "UnsupportedAudioFileException: %s\n", formattedMessage);
190#endif
191 throw_new(env, "javax/sound/sampled/UnsupportedAudioFileException",
192 formattedMessage);
193 }
194}
195
199void throwIndexOutOfBoundsExceptionIfError(JNIEnv *env, int err, int index) {
200 if (err) {
201 char formattedMessage[15];
202 snprintf(formattedMessage, 15, "%d", index);
203#ifdef DEBUG
204 fprintf(stderr, "IndexOutOfBoundsException: %d\n", index);
205#endif
206 throw_new(env, "java/lang/IndexOutOfBoundsException", formattedMessage);
207 }
208}
209
213void throwIOExceptionIfError(JNIEnv *env, int err, const char *message) {
214 if (err) {
215 char formattedMessage[strlen(message) + 4 + AV_ERROR_MAX_STRING_SIZE];
216 snprintf(formattedMessage, strlen(message) + 4 + AV_ERROR_MAX_STRING_SIZE,
217 "%s (%.64s)", message, av_err2str(err));
218#ifdef DEBUG
219 fprintf(stderr, "IOException: %s\n", formattedMessage);
220#endif
221 throw_new(env, "java/io/IOException", formattedMessage);
222 }
223}
224
228void throwFileNotFoundExceptionIfError(JNIEnv *env, int err,
229 const char *message) {
230 if (err) {
231#ifdef DEBUG
232 fprintf(stderr, "FileNotFoundException: '%s' %d (%4.4s)\n", message,
233 (int)err, (char *)&err);
234#endif
235 throw_new(env, "java/io/FileNotFoundException", message);
236 }
237}
238
246static void log_message(FFAudioIO *aio, jmethodID log_MID, int err,
247 const char *message) {
248 JNIEnv *env = aio->env;
249 jstring s = NULL;
250
251 if ((*env)->ExceptionCheck(env)) {
252#ifdef DEBUG
253 fprintf(stderr, "Not logging, exception pending: %s\n", message);
254#endif
255 return;
256 }
257 if (err) {
258 char formattedMessage[strlen(message) + 20 + AV_ERROR_MAX_STRING_SIZE];
259 snprintf(formattedMessage, strlen(message) + 20 + AV_ERROR_MAX_STRING_SIZE,
260 "%s %i (%.64s)", message, err, av_err2str(err));
261 s = (*env)->NewStringUTF(env, formattedMessage);
262 } else {
263 s = (*env)->NewStringUTF(env, message);
264 }
265 if (s) {
266 (*env)->CallVoidMethod(env, aio->java_instance, log_MID, s);
267 (*env)->DeleteLocalRef(env, s);
268 }
269 if ((*env)->ExceptionCheck(env)) {
270 (*env)->ExceptionClear(env);
271 }
272}
273
277void logWarning(FFAudioIO *aio, int err, const char *message) {
278 log_message(aio, logWarning_MID, err, message);
279}
280
284void logFine(FFAudioIO *aio, int err, const char *message) {
285 log_message(aio, logFine_MID, err, message);
286}
287
297int ff_open_format_context(JNIEnv *env, AVFormatContext **format_context,
298 const char *url, int io_buffer_size) {
299 int res = 0;
300 int probe_score = 0;
301
302 res = avformat_open_input(format_context, url, NULL, NULL);
303 if (res) {
304 if (res == AVERROR(ENOENT) || res == AVERROR_HTTP_NOT_FOUND) {
306 } else if (res == AVERROR_PROTOCOL_NOT_FOUND ||
307 res == AVERROR_HTTP_BAD_REQUEST ||
308 res == AVERROR_HTTP_UNAUTHORIZED ||
309 res == AVERROR_HTTP_FORBIDDEN || res == AVERROR_HTTP_OTHER_4XX ||
310 res == AVERROR_HTTP_SERVER_ERROR || res == AVERROR(EIO)) {
311 throwIOExceptionIfError(env, res, url);
312 } else {
314 "Failed to open audio file");
315 }
316 goto bail;
317 }
318
319 probe_score = (*format_context)->probe_score;
320
321#ifdef DEBUG
322 fprintf(stderr, "ff_open_format_context(): probe score=%i\n", probe_score);
323#endif
324
325 if (probe_score < MIN_PROBE_SCORE) {
326 res = probe_score;
328 "Probe score too low");
329 goto bail;
330 }
331
332 res = avformat_find_stream_info(*format_context, NULL);
333 if (res < 0) {
335 "Failed to find stream info");
336 goto bail;
337 }
338
339 if (io_buffer_size > 0 && (*format_context)->pb) {
340 AVIOContext *pb = (*format_context)->pb;
341 if (pb->buffer_size < io_buffer_size) {
342 unsigned char *new_buf = (unsigned char *)av_malloc(io_buffer_size);
343 if (new_buf) {
344 int valid = (int)(pb->buf_end - pb->buf_ptr);
345 if (valid > 0)
346 memcpy(new_buf, pb->buf_ptr, valid);
347 av_free(pb->buffer);
348 pb->buffer = new_buf;
349 pb->buf_ptr = new_buf;
350 pb->buf_end = new_buf + valid;
351 pb->buffer_size = io_buffer_size;
352 pb->buf_ptr_max = new_buf + valid;
353 pb->checksum_ptr = NULL;
354 pb->checksum = 0;
355 pb->update_checksum = NULL;
356 }
357 }
358 }
359
360bail:
361
362 return res;
363}
364
378int ff_open_file(JNIEnv *env, AVFormatContext **format_context,
379 AVStream **openedStream, AVCodecContext **context,
380 int *stream_index, const char *url, int io_buffer_size) {
381 int res = 0;
382 res = ff_open_format_context(env, format_context, url, io_buffer_size);
383 if (res) {
384 // exception has already been thrown
385 goto bail;
386 }
387
388#ifdef DEBUG
389 fprintf(stderr, "Desired audio stream index: %i.\n", *stream_index);
390#endif
391
392 if (*stream_index < 0) {
393 // use best audio stream
394 res = open_codec_context(stream_index, *format_context, AVMEDIA_TYPE_AUDIO);
395 if (res) {
397 env, res, "Failed to find best audio stream.");
398 goto bail;
399 }
400 *openedStream = (*format_context)->streams[*stream_index];
401 res = ff_open_stream(env, *openedStream, context);
402 if (res) {
403 goto bail;
404 }
405 } else {
406 // find xth audio stream
407 // count possible audio streams
408 int i;
409 int audio_stream_number = 0;
410 AVStream *stream = NULL;
411
412 AVFormatContext *deref_format_context = *format_context;
413 for (i = 0; i < deref_format_context->nb_streams; i++) {
414 stream = deref_format_context->streams[i];
415 if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
416 if (audio_stream_number == *stream_index) {
417 *stream_index = i;
418#ifdef DEBUG
419 fprintf(stderr, "Found desired audio stream at index: %i.\n", i);
420#endif
421 break;
422 }
423 audio_stream_number++;
424 }
425 stream = NULL;
426 }
427 if (stream == NULL) {
428 // we didn't find a stream with the given index
429 res = -1;
430 if (*stream_index == 0) {
432 "No stream found (index=0).");
433 } else {
434 throwIndexOutOfBoundsExceptionIfError(env, res, *stream_index);
435 }
436 goto bail;
437 }
438 res = ff_open_stream(env, stream, context);
439 if (res) {
440 goto bail;
441 }
442 *openedStream = stream;
443 }
444
445 if ((*openedStream)->codecpar->codec_tag == CODEC_TAG_DRMS) {
446 fprintf(stderr, "File is DRM-crippled.\n");
447 res = -1;
449 "File is DRM-crippled.");
450 goto bail;
451 }
452
453#ifdef DEBUG
454 fprintf(stderr, "Opened stream index: %i.\n", *stream_index);
455 fprintf(stderr, "Opened stream: %ld.\n", (long)*openedStream);
456#endif
457
458bail:
459
460 return res;
461}
462
471static int init_swr(JNIEnv *env, FFAudioIO *aio) {
472 int res = 0;
473 AVChannelLayout ch_layout = {0};
474
475 // If the stream has no explicit channel layout, derive a default from the
476 // channel count.
477 if (aio->stream->codecpar->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) {
478 av_channel_layout_default(&ch_layout,
479 aio->stream->codecpar->ch_layout.nb_channels);
480 } else {
481 av_channel_layout_copy(&ch_layout, &aio->stream->codecpar->ch_layout);
482 }
483
484 aio->swr_context = swr_alloc();
485 if (!aio->swr_context) {
486 res = AVERROR(ENOMEM);
487 throwIOExceptionIfError(env, res, "Could not allocate swr context.");
488 goto bail;
489 }
490
491 av_opt_set_sample_fmt(aio->swr_context, "in_sample_fmt",
492 aio->stream->codecpar->format, 0);
493 // make sure we get interleaved/packed output
494 av_opt_set_sample_fmt(aio->swr_context, "out_sample_fmt",
495 av_get_packed_sample_fmt(aio->stream->codecpar->format),
496 0);
497
498 av_opt_set_chlayout(aio->swr_context, "in_chlayout", &ch_layout, 0);
499 av_opt_set_chlayout(aio->swr_context, "out_chlayout", &ch_layout, 0);
500 av_opt_set_int(aio->swr_context, "in_sample_rate",
501 aio->stream->codecpar->sample_rate, 0);
502 av_opt_set_int(aio->swr_context, "out_sample_rate",
503 aio->stream->codecpar->sample_rate, 0);
504
505 res = swr_init(aio->swr_context);
506 if (res < 0) {
507 res = AVERROR(ENOMEM);
508 throwIOExceptionIfError(env, res, "Could not initialize swr context");
509 goto bail;
510 }
511
512bail:
513 av_channel_layout_uninit(&ch_layout);
514 return res;
515}
516
528AVCodec *ff_find_encoder(enum AVSampleFormat sampleFormat, int bits,
529 int big_endian, int signedSamples) {
530 enum AVCodecID codec_id;
531
532#ifdef DEBUG
533 fprintf(stderr, "ff_find_encoder(fmt=%d,bits=%d,big_endian=%d,signed=%d)\n",
534 sampleFormat, bits, big_endian, signedSamples);
535#endif
536
537 switch (sampleFormat) {
538 case AV_SAMPLE_FMT_U8:
539 case AV_SAMPLE_FMT_U8P:
540 if (signedSamples)
541 codec_id = AV_CODEC_ID_PCM_S8;
542 else
543 codec_id = AV_CODEC_ID_PCM_U8;
544 break;
545 case AV_SAMPLE_FMT_S16:
546 case AV_SAMPLE_FMT_S16P:
547 if (signedSamples)
548 codec_id = big_endian ? AV_CODEC_ID_PCM_S16BE : AV_CODEC_ID_PCM_S16LE;
549 else
550 codec_id = big_endian ? AV_CODEC_ID_PCM_U16BE : AV_CODEC_ID_PCM_U16LE;
551 break;
552 case AV_SAMPLE_FMT_S32:
553 case AV_SAMPLE_FMT_S32P:
554 if (bits == 24) {
555 if (signedSamples)
556 codec_id = big_endian ? AV_CODEC_ID_PCM_S24BE : AV_CODEC_ID_PCM_S24LE;
557 else
558 codec_id = big_endian ? AV_CODEC_ID_PCM_U24BE : AV_CODEC_ID_PCM_U24LE;
559 } else {
560 if (signedSamples)
561 codec_id = big_endian ? AV_CODEC_ID_PCM_S32BE : AV_CODEC_ID_PCM_S32LE;
562 else
563 codec_id = big_endian ? AV_CODEC_ID_PCM_U32BE : AV_CODEC_ID_PCM_U32LE;
564 }
565 break;
566 case AV_SAMPLE_FMT_FLT:
567 case AV_SAMPLE_FMT_FLTP:
568 codec_id = big_endian ? AV_CODEC_ID_PCM_F32BE : AV_CODEC_ID_PCM_F32LE;
569 break;
570 case AV_SAMPLE_FMT_DBL:
571 case AV_SAMPLE_FMT_DBLP:
572 codec_id = big_endian ? AV_CODEC_ID_PCM_F64BE : AV_CODEC_ID_PCM_F64LE;
573 break;
574 default:
575 codec_id = -1;
576 }
577
578 return avcodec_find_encoder(codec_id);
579}
580
591int ff_init_encoder(JNIEnv *env, FFAudioIO *aio, AVCodec *encoder) {
592 int res = 0;
593 int64_t out_sample_rate;
594 AVChannelLayout out_ch_layout = {0};
595 enum AVSampleFormat out_sample_fmt;
596
597 // make sure we clean up before resetting this
598 // in case this is called twice
599 if (aio->encode_frame) {
600 av_frame_free(&aio->encode_frame);
601 }
602 if (aio->encode_context) {
603 avcodec_free_context(&aio->encode_context);
604 }
605
606 aio->encode_context = avcodec_alloc_context3(encoder);
607 if (!aio->encode_context) {
608 res = AVERROR(ENOMEM);
609 throwIOExceptionIfError(env, res, "Could not allocate codec context.");
610 goto bail;
611 }
612
613 // init to whatever we have in SwrContext
614 av_opt_get_chlayout(aio->swr_context, "out_chlayout", 0, &out_ch_layout);
615 av_opt_get_int(aio->swr_context, "out_sample_rate", 0, &out_sample_rate);
616 av_opt_get_sample_fmt(aio->swr_context, "out_sample_fmt", 0, &out_sample_fmt);
617
618 aio->encode_context->sample_fmt = out_sample_fmt;
619 aio->encode_context->sample_rate = (int)out_sample_rate;
620 av_channel_layout_copy(&aio->encode_context->ch_layout, &out_ch_layout);
621
622 res = avcodec_open2(aio->encode_context, encoder, NULL);
623 if (res < 0) {
624 res = AVERROR(ENOMEM);
625 throwIOExceptionIfError(env, res, "Could not open encoder.");
626 goto bail;
627 }
628
629 if (!aio->encode_packet) {
630 aio->encode_packet = av_packet_alloc();
631 if (!aio->encode_packet) {
632 res = AVERROR(ENOMEM);
633 throwIOExceptionIfError(env, res, "Could not allocate encoder packet.");
634 goto bail;
635 }
636 }
637
638 aio->encode_frame = av_frame_alloc();
639 if (!aio->encode_frame) {
640 res = AVERROR(ENOMEM);
641 throwIOExceptionIfError(env, res, "Could not allocate encoder frame.");
642 goto bail;
643 }
644 aio->encode_frame->nb_samples =
645 aio->encode_context->frame_size; // will be updated per-call
646 aio->encode_frame->format = aio->encode_context->sample_fmt;
647 av_channel_layout_copy(&aio->encode_frame->ch_layout,
648 &aio->encode_context->ch_layout);
649
650bail:
651 av_channel_layout_uninit(&out_ch_layout);
652 return res;
653}
654
663int ff_init_audioio(JNIEnv *env, FFAudioIO *aio) {
664 int res = 0;
665 int nb_planes;
666 AVCodec *codec = NULL;
667
668 aio->timestamp = 0;
669
670 // allocate pointer to the audio buffers, i.e. the multiple planes/channels.
671 nb_planes = av_sample_fmt_is_planar(aio->stream->codecpar->format)
672 ? aio->stream->codecpar->ch_layout.nb_channels
673 : 1;
674
675 // always init SWR to keep code simpler
676 res = init_swr(env, aio);
677 if (res < 0) {
678 // exception is already thrown
679 goto bail;
680 }
681 // Install a PCM encoder when the decoded output needs byte-order adjustment:
682 // - 24-bit: decoder outputs S32-padded frames; encoder repacks to 24-bit
683 // - multi-byte big-endian sources: FFmpeg's PCM decoder produces native-LE
684 // frames regardless of the on-disk byte order, so without an encoder the
685 // Java buffer would receive LE bytes while the AudioFormat reports BE.
686 {
687 int src_bits = aio->stream->codecpar->bits_per_coded_sample;
688 int src_big_endian = ff_big_endian(aio->stream->codecpar->codec_id);
689 if (src_bits == 24 || (src_big_endian && src_bits > 8)) {
690 codec = ff_find_encoder(aio->stream->codecpar->format, src_bits,
691 src_big_endian, 1);
692 if (!codec) {
693 res = AVERROR(EINVAL);
695 "Could not find suitable encoder codec.");
696 goto bail;
697 }
698 res = ff_init_encoder(env, aio, codec);
699 if (res < 0) {
700 // exception is already thrown
701 goto bail;
702 }
703 }
704 }
705
706 // allocate the buffer the codec decodes to
707 aio->audio_data = av_mallocz(sizeof(uint8_t *) * nb_planes);
708 if (!aio->audio_data) {
709 res = AVERROR(ENOMEM);
710 throwIOExceptionIfError(env, res, "Could not allocate audio data buffers.");
711 goto bail;
712 }
713
714 aio->decode_frame = av_frame_alloc();
715 if (!aio->decode_frame) {
716 res = AVERROR(ENOMEM);
717 throwIOExceptionIfError(env, res, "Could not allocate frame.");
718 goto bail;
719 }
720
721 // initialize packet
722 aio->decode_packet = av_packet_alloc();
723 if (!aio->decode_packet) {
724 res = AVERROR(ENOMEM);
725 throwIOExceptionIfError(env, res, "Could not allocate decode packet.");
726 goto bail;
727 }
728
729bail:
730
731 return res;
732}
733
743static int encode_buffer(FFAudioIO *aio, const uint8_t *in_buf, int in_size,
744 const uint8_t *out_buf) {
745 int res = 0;
746 int nb_channels = aio->encode_context->ch_layout.nb_channels;
747
748 res = av_samples_get_buffer_size(NULL, nb_channels,
749 aio->encode_frame->nb_samples,
750 aio->encode_context->sample_fmt, 1);
751
752#ifdef DEBUG
753 fprintf(stderr,
754 "encode_buffer: channels=%d frame->nb_samples=%d in_size=%d\n",
755 nb_channels, aio->encode_frame->nb_samples, in_size);
756 fprintf(stderr, "encode_buffer: needed buffer=%d available=%d\n", res,
757 in_size);
758#endif
759
760 // point the AVFrame's data arrays at in_buf (no copy)
761 res = av_samples_fill_arrays(aio->encode_frame->data, NULL, in_buf,
762 nb_channels, aio->encode_frame->nb_samples,
763 aio->encode_context->sample_fmt, 1);
764 if (res < 0) {
765 throwIOExceptionIfError(aio->env, res, "Failed to fill audio frame.");
766 goto bail;
767 }
768
769 av_packet_unref(aio->encode_packet);
770
771 res = avcodec_send_frame(aio->encode_context, aio->encode_frame);
772 if (res < 0) {
774 "Failed to send audio frame for encoding.");
775 goto bail;
776 }
777 res = avcodec_receive_packet(aio->encode_context, aio->encode_packet);
778 if (res < 0 && res != AVERROR(EAGAIN) && res != AVERROR_EOF) {
779 throwIOExceptionIfError(aio->env, res, "Failed to receive encoded packet.");
780 goto bail;
781 }
782 if (res == 0) {
783 res = aio->encode_packet->size;
784 memcpy((char *)out_buf, aio->encode_packet->data, aio->encode_packet->size);
785 av_packet_unref(aio->encode_packet);
786 }
787
788bail:
789 return res;
790}
791
804static int resample(FFAudioIO *aio, uint8_t **out_buf, int out_samples,
805 const uint8_t **in_buf, const int in_samples) {
806 int res = 0;
807 AVChannelLayout out_ch_layout = {0};
808 int out_channel_count;
809 enum AVSampleFormat out_sample_format;
810
811 if (out_samples == 0)
812 goto bail; // nothing to do.
813
814 av_opt_get_chlayout(aio->swr_context, "out_chlayout", 0, &out_ch_layout);
815 out_channel_count = out_ch_layout.nb_channels;
816 av_channel_layout_uninit(&out_ch_layout);
817 av_opt_get_sample_fmt(aio->swr_context, "out_sample_fmt", 0,
818 &out_sample_format);
819
820#ifdef DEBUG
821 fprintf(
822 stderr,
823 "resample: out_samples=%d in_samples=%d, channels=%d sample_format=%d\n",
824 out_samples, in_samples, out_channel_count, out_sample_format);
825#endif
826
827 // allocate temp buffer for resampled data
828 res = av_samples_alloc(out_buf, NULL, out_channel_count, out_samples,
829 out_sample_format, 1);
830 if (res < 0) {
831 res = AVERROR(ENOMEM);
833 "Could not allocate resample buffer.");
834 goto bail;
835 }
836
837 // run the SWR conversion (even if it is not strictly necessary)
838 res = swr_convert(aio->swr_context, out_buf, out_samples, in_buf, in_samples);
839 if (res < 0) {
840 throwIOExceptionIfError(aio->env, res, "Failed to convert audio data.");
841 goto bail;
842 }
843
844bail:
845
846 return res;
847}
848
849static int copy_to_java_buffer(FFAudioIO *aio, uint32_t offset, int samples,
850 uint8_t **resample_buf) {
851 int res = 0;
852 uint32_t buffer_size = 0;
853 jobject byte_buffer = NULL;
854 uint8_t *java_buffer = NULL;
855 AVChannelLayout out_ch_layout = {0};
856 int channel_count;
857 enum AVSampleFormat format;
858
859 av_opt_get_sample_fmt(aio->swr_context, "out_sample_fmt", 0, &format);
860 av_opt_get_chlayout(aio->swr_context, "out_chlayout", 0, &out_ch_layout);
861 channel_count = out_ch_layout.nb_channels;
862 av_channel_layout_uninit(&out_ch_layout);
863
864 res = av_samples_get_buffer_size(NULL, channel_count, samples, format, 1);
865 if (res < 0)
866 goto bail;
867 else
868 buffer_size = res;
869
870 // ensure native buffer capacity
871 if (aio->java_buffer_capacity < buffer_size + offset) {
872 jint new_capacity = (*aio->env)->CallIntMethod(
873 aio->env, aio->java_instance, setNativeBufferCapacity_MID,
874 (jint)(buffer_size + offset));
875 if ((*aio->env)->ExceptionCheck(aio->env)) {
876 // let the pending exception propagate to Java
877 res = -1;
878 goto bail;
879 }
880 aio->java_buffer_capacity = new_capacity;
881 }
882 // get java-managed byte buffer reference
883 byte_buffer = (*aio->env)->GetObjectField(aio->env, aio->java_instance,
884 nativeBuffer_FID);
885 if (!byte_buffer) {
886 res = -1;
887 throwIOExceptionIfError(aio->env, 1, "Failed to get native buffer.");
888 goto bail;
889 }
890
891 // we have some samples, let's copy them to the java buffer, using the desired
892 // encoding at the desired offset
893 java_buffer =
894 (uint8_t *)(*aio->env)->GetDirectBufferAddress(aio->env, byte_buffer);
895 if (!java_buffer) {
896 res = -1;
898 "Failed to get address for native buffer.");
899 goto bail;
900 }
901 java_buffer += offset;
902 if (aio->encode_context) {
903 aio->encode_frame->nb_samples = samples;
904 res = encode_buffer(aio, resample_buf[0], buffer_size, java_buffer);
905 if (res < 0) {
906 buffer_size = 0;
907 goto bail;
908 }
909 buffer_size = res;
910 } else {
911 memcpy(java_buffer, resample_buf[0], buffer_size);
912 }
913 // we already wrote to the buffer, now we still need to
914 // set new bytebuffer limit and position to 0.
915 if (offset == 0) {
916 // only rewind, if this is the first call for this packet
917 jobject self =
918 (*aio->env)->CallObjectMethod(aio->env, byte_buffer, rewind_MID);
919 if ((*aio->env)->ExceptionCheck(aio->env)) {
920 res = -1;
921 goto bail;
922 }
923 (*aio->env)->DeleteLocalRef(aio->env, self);
924 }
925 {
926 jobject self = (*aio->env)->CallObjectMethod(
927 aio->env, byte_buffer, limit_MID, offset + buffer_size);
928 if ((*aio->env)->ExceptionCheck(aio->env)) {
929 res = -1;
930 goto bail;
931 }
932 (*aio->env)->DeleteLocalRef(aio->env, self);
933 }
934
935 aio->resampled_samples += buffer_size;
936
937bail:
938 // called once per decoded frame, don't accumulate local refs
939 if (byte_buffer)
940 (*aio->env)->DeleteLocalRef(aio->env, byte_buffer);
941 return res;
942}
943
952static int receive_and_process_frames(FFAudioIO *aio, int is_flush,
953 uint32_t initial_offset) {
954 int res = 0;
955 int total_bytes = 0;
956 uint8_t **resample_buf = NULL;
957 uint32_t java_buffer_offset = initial_offset;
958 uint32_t out_buf_size = 0;
959 int out_buf_samples = 0;
960 int64_t out_sample_rate;
961
962 av_opt_get_int(aio->swr_context, "out_sample_rate", 0, &out_sample_rate);
963
964 resample_buf = av_mallocz(sizeof(uint8_t *));
965 if (!resample_buf) {
966 throwIOExceptionIfError(aio->env, AVERROR(ENOMEM),
967 "Could not allocate resample buffer pointer.");
968 return AVERROR(ENOMEM);
969 }
970
971 while (1) {
972 res = avcodec_receive_frame(aio->decode_context, aio->decode_frame);
973 if (res == AVERROR(EAGAIN) || res == AVERROR_EOF) {
974 res = 0;
975 break;
976 }
977 if (res < 0) {
978 logWarning(aio, res, "Error receiving frame from decoder:");
979 res = 0;
980 break;
981 }
982
983 if (aio->stream->codecpar->ch_layout.nb_channels !=
984 aio->decode_frame->ch_layout.nb_channels) {
985 logWarning(aio, 0, "Skipping frame: channel count mismatch");
986 av_frame_unref(aio->decode_frame);
987 continue;
988 }
989
990 aio->decoded_samples += aio->decode_frame->nb_samples;
991
992#ifdef DEBUG
993 fprintf(
994 stderr, "samples%s n:%" PRIu64 " nb_samples:%d pts:%s\n",
995 is_flush ? "(flush)" : "", aio->decoded_samples,
996 aio->decode_frame->nb_samples,
997 av_ts2timestr(aio->decode_frame->pts, &aio->decode_context->time_base));
998#endif
999
1000 out_buf_samples = av_rescale_rnd(
1001 swr_get_delay(aio->swr_context, aio->stream->codecpar->sample_rate) +
1002 aio->decode_frame->nb_samples,
1003 out_sample_rate, aio->stream->codecpar->sample_rate, AV_ROUND_UP);
1004
1005 res = av_samples_alloc(
1006 aio->audio_data, NULL, aio->decode_frame->ch_layout.nb_channels,
1007 aio->decode_frame->nb_samples, aio->decode_frame->format, 1);
1008 if (res < 0) {
1009 throwIOExceptionIfError(aio->env, res,
1010 "Could not allocate audio buffer.");
1011 goto bail;
1012 }
1013 av_samples_copy(aio->audio_data, aio->decode_frame->data, 0, 0,
1014 aio->decode_frame->nb_samples,
1015 aio->decode_frame->ch_layout.nb_channels,
1016 aio->decode_frame->format);
1017
1018 res = resample(aio, resample_buf, out_buf_samples,
1019 (const uint8_t **)aio->audio_data,
1020 aio->decode_frame->nb_samples);
1021 if (res < 0)
1022 goto bail;
1023 out_buf_samples = res;
1024
1025 if (out_buf_samples > 0 && resample_buf[0]) {
1026 java_buffer_offset += out_buf_size;
1027 res = copy_to_java_buffer(aio, java_buffer_offset, out_buf_samples,
1028 resample_buf);
1029 if (res < 0)
1030 goto bail;
1031 total_bytes += res;
1032 out_buf_size = res;
1033 }
1034 if (resample_buf[0])
1035 av_freep(&resample_buf[0]);
1036 if (aio->audio_data[0])
1037 av_freep(&aio->audio_data[0]);
1038 av_frame_unref(aio->decode_frame);
1039 }
1040
1041 // After the decoder is fully flushed, drain any remaining SwrContext delay.
1042 if (is_flush) {
1043 int64_t delay =
1044 swr_get_delay(aio->swr_context, aio->stream->codecpar->sample_rate);
1045 if (delay > 0) {
1046#ifdef DEBUG
1047 fprintf(stderr, "Flushing SWR delay: %" PRId64 " samples\n", delay);
1048#endif
1049 res = resample(aio, resample_buf, (int)delay, NULL, 0);
1050 if (res < 0)
1051 goto bail;
1052 out_buf_samples = res;
1053 if (out_buf_samples > 0 && resample_buf[0]) {
1054 java_buffer_offset += out_buf_size;
1055 res = copy_to_java_buffer(aio, java_buffer_offset, out_buf_samples,
1056 resample_buf);
1057 if (res < 0)
1058 goto bail;
1059 total_bytes += res;
1060 out_buf_size = res;
1061 }
1062 if (resample_buf[0])
1063 av_freep(&resample_buf[0]);
1064 }
1065 }
1066
1067bail:
1068 if (resample_buf) {
1069 if (resample_buf[0])
1070 av_freep(&resample_buf[0]);
1071 av_free(resample_buf);
1072 }
1073 if (aio->audio_data[0])
1074 av_freep(&aio->audio_data[0]);
1075 return res < 0 ? res : total_bytes;
1076}
1077
1085static int decode_packet(FFAudioIO *aio, uint32_t offset) {
1086 int res = avcodec_send_packet(aio->decode_context, aio->decode_packet);
1087 if (res == AVERROR(EINVAL)) {
1089 "Invalid argument for decoder.");
1090 // stop here, we must not make further JNI calls with a pending exception
1091 return res;
1092 }
1093 if (res < 0 && res != AVERROR_EOF) {
1094 logWarning(aio, res, "Skipping packet. avcodec_send_packet failed:");
1095 return 0;
1096 }
1097 return receive_and_process_frames(aio, 0, offset);
1098}
1099
1108 int res = 0;
1109 int total_bytes = 0;
1110
1111 // Loop over packets until the buffer reaches FF_FILL_TARGET or EOF/error.
1112 // Non-audio packets (other streams) are skipped without counting toward the
1113 // target.
1114 while (total_bytes < FF_FILL_TARGET) {
1115 int read_res = av_read_frame(aio->format_context, aio->decode_packet);
1116 if ((*aio->env)->ExceptionCheck(aio->env)) {
1117 // a read callback (FFStreamInputStream) threw, e.g. an IOException
1118 // from the Java InputStream. Stop, so it propagates unchanged.
1119 av_packet_unref(aio->decode_packet);
1120 res = read_res < 0 ? read_res : -1;
1121 goto bail;
1122 }
1123 if (read_res >= 0) {
1124 if (aio->decode_packet->stream_index == aio->stream_index) {
1125 aio->timestamp += aio->decode_packet->duration;
1126#ifdef DEBUG
1127 fprintf(stderr, "duration : %lli\n", aio->decode_packet->duration);
1128 fprintf(stderr, "timestamp : %" PRId64 "\n", aio->timestamp);
1129 fprintf(stderr, "pts : %" PRId64 "\n", aio->decode_packet->pts);
1130 fprintf(stderr, "dts : %" PRId64 "\n", aio->decode_packet->dts);
1131#endif
1132 int bytes = decode_packet(aio, (uint32_t)total_bytes);
1133 if (bytes < 0) {
1134 res = bytes;
1135 av_packet_unref(aio->decode_packet);
1136 goto bail;
1137 }
1138 total_bytes += bytes;
1139 }
1140 av_packet_unref(aio->decode_packet);
1141 } else {
1142#ifdef DEBUG
1143 fprintf(stderr, "Flushing decoder at EOF\n");
1144#endif
1145 // EOF or error — flush the decoder and drain remaining frames
1146 av_packet_unref(aio->decode_packet);
1147 if (read_res == AVERROR_EOF) {
1148 avcodec_send_packet(aio->decode_context, NULL);
1149 int bytes = receive_and_process_frames(aio, 1, (uint32_t)total_bytes);
1150 if (bytes > 0)
1151 total_bytes += bytes;
1152 else if (bytes < 0)
1153 res = bytes;
1154 } else {
1155 throwIOExceptionIfError(aio->env, read_res, "Error reading frame.");
1156 res = read_res;
1157 }
1158 break;
1159 }
1160 }
1161
1162bail:
1163 return res;
1164}
1165
1170#ifdef DEBUG
1171 fprintf(stderr, "ff_audioio_free\n");
1172#endif
1173
1174 if (aio) {
1175
1176 if (aio->encode_frame) {
1177 av_frame_free(&aio->encode_frame);
1178 }
1179 if (aio->decode_context) {
1180 avcodec_free_context(&aio->decode_context);
1181 }
1182 if (aio->encode_context) {
1183 avcodec_free_context(&aio->encode_context);
1184 }
1185 if (aio->swr_context) {
1186 swr_free(&aio->swr_context);
1187 }
1188 if (aio->format_context) {
1189 AVFormatContext *s = aio->format_context;
1190 if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) ||
1191 (s->flags & AVFMT_FLAG_CUSTOM_IO)) {
1192 if (s->pb) {
1193 avio_flush(s->pb);
1194 avio_context_free(&s->pb);
1195 }
1196 }
1197 avformat_close_input(&(aio->format_context));
1198 }
1199 if (aio->decode_frame) {
1200 av_frame_free(&aio->decode_frame);
1201 }
1202 if (aio->decode_packet) {
1203 av_packet_free(&aio->decode_packet);
1204 }
1205 if (aio->encode_packet) {
1206 av_packet_free(&aio->encode_packet);
1207 }
1208 if (aio->audio_data) {
1209 av_free(aio->audio_data);
1210 }
1211 free(aio);
1212 }
1213}
1214
1221int ff_big_endian(enum AVCodecID codec_id) {
1222 int big_endian = 0;
1223 switch (codec_id) {
1224 case AV_CODEC_ID_PCM_S16BE:
1225 case AV_CODEC_ID_PCM_U16BE:
1226 case AV_CODEC_ID_PCM_S32BE:
1227 case AV_CODEC_ID_PCM_U32BE:
1228 case AV_CODEC_ID_PCM_S24BE:
1229 case AV_CODEC_ID_PCM_U24BE:
1230 case AV_CODEC_ID_PCM_F32BE:
1231 case AV_CODEC_ID_PCM_F64BE:
1232 big_endian = 1;
1233 break;
1234 default:
1235 big_endian = 0;
1236 }
1237 return big_endian;
1238}
1239
1243JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
1244 avformat_network_init();
1245 return JNI_VERSION_1_6;
1246}
void ff_audioio_free(FFAudioIO *aio)
Free all resources held by aio and then itself.
Definition FFUtils.c:1169
int ff_big_endian(enum AVCodecID codec_id)
Indicates whether the given id belongs to a big endian codec.
Definition FFUtils.c:1221
void logWarning(FFAudioIO *aio, int err, const char *message)
Log a warning.
Definition FFUtils.c:277
void throwFileNotFoundExceptionIfError(JNIEnv *env, int err, const char *message)
Throws a FileNotFoundException.
Definition FFUtils.c:228
int ff_open_file(JNIEnv *env, AVFormatContext **format_context, AVStream **openedStream, AVCodecContext **context, int *stream_index, const char *url, int io_buffer_size)
Opens the input file/url, allocates a AVFormatContext for it and opens the audio stream with an appro...
Definition FFUtils.c:378
int ff_open_format_context(JNIEnv *env, AVFormatContext **format_context, const char *url, int io_buffer_size)
Opens the input file/url and allocates a AVFormatContext for it, but does not open the audio stream w...
Definition FFUtils.c:297
AVCodec * ff_find_encoder(enum AVSampleFormat sampleFormat, int bits, int big_endian, int signedSamples)
Finds an AVCodec encoder for the given sample format, bits per sample, byte order and signed/unsigned...
Definition FFUtils.c:528
int ff_fill_buffer(FFAudioIO *aio)
Reads frames via av_read_frame, decodes them, and writes the result to the Java-side nativeBuffer.
Definition FFUtils.c:1107
void throwUnsupportedAudioFileExceptionIfError(JNIEnv *env, int err, const char *message)
Throws an UnsupportedAudioFileException.
Definition FFUtils.c:182
int ff_init_audioio(JNIEnv *env, FFAudioIO *aio)
Initialize our main context FFAudioIO, so that SwrContext, decode buffers and the encoder are set to ...
Definition FFUtils.c:663
int ff_init_encoder(JNIEnv *env, FFAudioIO *aio, AVCodec *encoder)
Allocates and initializes the encoder context and frame in FFAudioIO.
Definition FFUtils.c:591
void throwIOExceptionIfError(JNIEnv *env, int err, const char *message)
Throws an IOException.
Definition FFUtils.c:213
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
Make sure FFmpeg is initialized all the way.
Definition FFUtils.c:1243
const uint32_t CODEC_TAG_DRMS
Definition FFUtils.c:27
JNIEXPORT void JNICALL Java_com_tagtraum_ffsampledsp_FFNativePeerInputStream_initIDs(JNIEnv *env, jclass streamClass)
Init static method and field ids for Java methods/fields.
Definition FFUtils.c:54
int ff_open_stream(JNIEnv *env, AVStream *stream, AVCodecContext **context)
Opens the given stream, i.e.
Definition FFUtils.c:93
void throwIndexOutOfBoundsExceptionIfError(JNIEnv *env, int err, int index)
Throws an IndexOutOfBoundsException.
Definition FFUtils.c:199
void logFine(FFAudioIO *aio, int err, const char *message)
Log a debug message.
Definition FFUtils.c:284
Central context representing the native peer to the Java FFNativePeerInputStream object.
Definition FFUtils.h:59
uint64_t timestamp
Current timestamp (in samples, not seconds).
Definition FFUtils.h:74
AVFormatContext * format_context
Current AVFormatContext.
Definition FFUtils.h:66
int stream_index
Index of the audio stream we are using.
Definition FFUtils.h:68
AVStream * stream
Audio stream we are interested in.
Definition FFUtils.h:67
JNIEnv * env
JNI environment.
Definition FFUtils.h:61
AVPacket * encode_packet
AVPacket for encoding.
Definition FFUtils.h:82
uint64_t decoded_samples
Running count of decoded samples.
Definition FFUtils.h:73
AVFrame * decode_frame
AVFrame for decoding.
Definition FFUtils.h:71
AVFrame * encode_frame
AVFrame for encoding.
Definition FFUtils.h:83
AVPacket * decode_packet
AVPacket for decoding.
Definition FFUtils.h:70
jint java_buffer_capacity
Current capacity of the Java nativeBuffer.
Definition FFUtils.h:63
AVCodecContext * decode_context
Codec context for decoding.
Definition FFUtils.h:69
uint8_t ** audio_data
Audio data (accommodates multiple planes).
Definition FFUtils.h:72
SwrContext * swr_context
Resampling context.
Definition FFUtils.h:77
jobject java_instance
Calling Java instance.
Definition FFUtils.h:62
uint64_t resampled_samples
Count of resampled samples.
Definition FFUtils.h:78
AVCodecContext * encode_context
Codec context for encoding.
Definition FFUtils.h:81