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