@@ -35,6 +35,8 @@ extern "C" {
35
35
#define LOG_TAG " ffmpeg_jni"
36
36
#define LOGE (...) \
37
37
((void )__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
38
+ #define LOGD (...) \
39
+ ((void )__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
38
40
39
41
#define LIBRARY_FUNC (RETURN_TYPE, NAME, ...) \
40
42
extern " C" { \
@@ -67,6 +69,8 @@ static const AVSampleFormat OUTPUT_FORMAT_PCM_FLOAT = AV_SAMPLE_FMT_FLT;
67
69
static const int AUDIO_DECODER_ERROR_INVALID_DATA = -1 ;
68
70
static const int AUDIO_DECODER_ERROR_OTHER = -2 ;
69
71
72
+ static jmethodID growOutputBufferMethod;
73
+
70
74
/* *
71
75
* Returns the AVCodec with the specified name, or NULL if it is not available.
72
76
*/
@@ -81,13 +85,21 @@ AVCodecContext *createContext(JNIEnv *env, AVCodec *codec, jbyteArray extraData,
81
85
jboolean outputFloat, jint rawSampleRate,
82
86
jint rawChannelCount);
83
87
88
+ struct GrowOutputBufferCallback {
89
+ uint8_t *operator ()(int requiredSize) const ;
90
+
91
+ JNIEnv *env;
92
+ jobject thiz;
93
+ jobject decoderOutputBuffer;
94
+ };
95
+
84
96
/* *
85
97
* Decodes the packet into the output buffer, returning the number of bytes
86
98
* written, or a negative AUDIO_DECODER_ERROR constant value in the case of an
87
99
* error.
88
100
*/
89
101
int decodePacket (AVCodecContext *context, AVPacket *packet,
90
- uint8_t *outputBuffer, int outputSize);
102
+ uint8_t *outputBuffer, int outputSize, GrowOutputBufferCallback growBuffer );
91
103
92
104
/* *
93
105
* Transforms ffmpeg AVERROR into a negative AUDIO_DECODER_ERROR constant value.
@@ -107,6 +119,17 @@ void releaseContext(AVCodecContext *context);
107
119
jint JNI_OnLoad (JavaVM *vm, void *reserved) {
108
120
JNIEnv *env;
109
121
if (vm->GetEnv (reinterpret_cast <void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
122
+ LOGE (" JNI_OnLoad: GetEnv failed" );
123
+ return -1 ;
124
+ }
125
+ jclass clazz = env->FindClass (" androidx/media3/decoder/ffmpeg/FfmpegAudioDecoder" );
126
+ if (!clazz) {
127
+ LOGE (" JNI_OnLoad: FindClass failed" );
128
+ return -1 ;
129
+ }
130
+ growOutputBufferMethod = env->GetMethodID (clazz, " growOutputBuffer" ," (Landroidx/media3/decoder/SimpleDecoderOutputBuffer;I)Ljava/nio/ByteBuffer;" );
131
+ if (!growOutputBufferMethod) {
132
+ LOGE (" JNI_OnLoad: GetMethodID failed" );
110
133
return -1 ;
111
134
}
112
135
avcodec_register_all ();
@@ -138,12 +161,12 @@ AUDIO_DECODER_FUNC(jlong, ffmpegInitialize, jstring codecName,
138
161
}
139
162
140
163
AUDIO_DECODER_FUNC (jint, ffmpegDecode, jlong context, jobject inputData,
141
- jint inputSize, jobject outputData, jint outputSize) {
164
+ jint inputSize, jobject decoderOutputBuffer, jobject outputData, jint outputSize) {
142
165
if (!context) {
143
166
LOGE (" Context must be non-NULL." );
144
167
return -1 ;
145
168
}
146
- if (!inputData || !outputData) {
169
+ if (!inputData || !decoderOutputBuffer || ! outputData) {
147
170
LOGE (" Input and output buffers must be non-NULL." );
148
171
return -1 ;
149
172
}
@@ -162,7 +185,17 @@ AUDIO_DECODER_FUNC(jint, ffmpegDecode, jlong context, jobject inputData,
162
185
packet.data = inputBuffer;
163
186
packet.size = inputSize;
164
187
return decodePacket ((AVCodecContext *)context, &packet, outputBuffer,
165
- outputSize);
188
+ outputSize, GrowOutputBufferCallback{env, thiz, decoderOutputBuffer});
189
+ }
190
+
191
+ uint8_t *GrowOutputBufferCallback::operator ()(int requiredSize) const {
192
+ jobject newOutputData = env->CallObjectMethod (thiz, growOutputBufferMethod, decoderOutputBuffer, requiredSize);
193
+ if (env->ExceptionCheck ()) {
194
+ LOGE (" growOutputBuffer() failed" );
195
+ env->ExceptionDescribe ();
196
+ return nullptr ;
197
+ }
198
+ return static_cast <uint8_t *>(env->GetDirectBufferAddress (newOutputData));
166
199
}
167
200
168
201
AUDIO_DECODER_FUNC (jint, ffmpegGetChannelCount, jlong context) {
@@ -264,7 +297,7 @@ AVCodecContext *createContext(JNIEnv *env, AVCodec *codec, jbyteArray extraData,
264
297
}
265
298
266
299
int decodePacket (AVCodecContext *context, AVPacket *packet,
267
- uint8_t *outputBuffer, int outputSize) {
300
+ uint8_t *outputBuffer, int outputSize, GrowOutputBufferCallback growBuffer ) {
268
301
int result = 0 ;
269
302
// Queue input data.
270
303
result = avcodec_send_packet (context, packet);
@@ -320,15 +353,20 @@ int decodePacket(AVCodecContext *context, AVPacket *packet,
320
353
}
321
354
context->opaque = resampleContext;
322
355
}
323
- int inSampleSize = av_get_bytes_per_sample (sampleFormat);
356
+
324
357
int outSampleSize = av_get_bytes_per_sample (context->request_sample_fmt );
325
358
int outSamples = swr_get_out_samples (resampleContext, sampleCount);
326
359
int bufferOutSize = outSampleSize * channelCount * outSamples;
327
360
if (outSize + bufferOutSize > outputSize) {
328
- LOGE (" Output buffer size (%d) too small for output data (%d)." ,
361
+ LOGD (" Output buffer size (%d) too small for output data (%d), reallocating buffer ." ,
329
362
outputSize, outSize + bufferOutSize);
330
- av_frame_free (&frame);
331
- return AUDIO_DECODER_ERROR_INVALID_DATA;
363
+ outputSize = outSize + bufferOutSize;
364
+ outputBuffer = growBuffer (outputSize);
365
+ if (!outputBuffer) {
366
+ LOGE (" Failed to reallocate output buffer." );
367
+ av_frame_free (&frame);
368
+ return AUDIO_DECODER_ERROR_OTHER;
369
+ }
332
370
}
333
371
result = swr_convert (resampleContext, &outputBuffer, bufferOutSize,
334
372
(const uint8_t **)frame->data , frame->nb_samples );
0 commit comments