Merge Issue: google/ExoPlayer#10762: Fix ffmpeg jni wrapper returning invalid result codes

Imported from GitHub PR Issue: google/ExoPlayer#10762

This ensure that ffmpeg error code are properly translated to values that the ExoPlayer decoder understand.
The main gain is that it allows the decoder to properly ignore more cases of invalid data and recover.
The second gain is that the other errors are now proper ExoPlayer errors and no more obscure buffer ones.

Fixes: Issue: google/ExoPlayer#10760
Merge 82ceeb77d6df71f5ffb0474db66a36fd6eb8e51a into 972e169bd85b14848dcae75e34f9e95fe87e1f4b
COPYBARA_INTEGRATE_REVIEW=go/exoghi/10762 from Tolriq:ffmpeg_error_code 82ceeb77d6df71f5ffb0474db66a36fd6eb8e51a
PiperOrigin-RevId: 487189910
This commit is contained in:
Tolriq 2022-11-09 10:53:52 +00:00 committed by microkatz
parent 714e556505
commit a1c04cd473

View File

@ -89,6 +89,11 @@ AVCodecContext *createContext(JNIEnv *env, AVCodec *codec, jbyteArray extraData,
int decodePacket(AVCodecContext *context, AVPacket *packet,
uint8_t *outputBuffer, int outputSize);
/**
* Transforms ffmpeg AVERROR into a negative AUDIO_DECODER_ERROR constant value.
*/
int transformError(const char *functionName, int errorNumber);
/**
* Outputs a log message describing the avcodec error number.
*/
@ -265,8 +270,7 @@ int decodePacket(AVCodecContext *context, AVPacket *packet,
result = avcodec_send_packet(context, packet);
if (result) {
logError("avcodec_send_packet", result);
return result == AVERROR_INVALIDDATA ? AUDIO_DECODER_ERROR_INVALID_DATA
: AUDIO_DECODER_ERROR_OTHER;
return transformError(result);
}
// Dequeue output data until it runs out.
@ -275,7 +279,7 @@ int decodePacket(AVCodecContext *context, AVPacket *packet,
AVFrame *frame = av_frame_alloc();
if (!frame) {
LOGE("Failed to allocate output frame.");
return -1;
return AUDIO_DECODER_ERROR_INVALID_DATA;
}
result = avcodec_receive_frame(context, frame);
if (result) {
@ -284,7 +288,7 @@ int decodePacket(AVCodecContext *context, AVPacket *packet,
break;
}
logError("avcodec_receive_frame", result);
return result;
return transformError(result);
}
// Resample output.
@ -312,7 +316,7 @@ int decodePacket(AVCodecContext *context, AVPacket *packet,
if (result < 0) {
logError("swr_init", result);
av_frame_free(&frame);
return -1;
return transformError(result);
}
context->opaque = resampleContext;
}
@ -324,20 +328,20 @@ int decodePacket(AVCodecContext *context, AVPacket *packet,
LOGE("Output buffer size (%d) too small for output data (%d).",
outputSize, outSize + bufferOutSize);
av_frame_free(&frame);
return -1;
return AUDIO_DECODER_ERROR_INVALID_DATA;
}
result = swr_convert(resampleContext, &outputBuffer, bufferOutSize,
(const uint8_t **)frame->data, frame->nb_samples);
av_frame_free(&frame);
if (result < 0) {
logError("swr_convert", result);
return result;
return AUDIO_DECODER_ERROR_INVALID_DATA;
}
int available = swr_get_out_samples(resampleContext, 0);
if (available != 0) {
LOGE("Expected no samples remaining after resampling, but found %d.",
available);
return -1;
return AUDIO_DECODER_ERROR_INVALID_DATA;
}
outputBuffer += bufferOutSize;
outSize += bufferOutSize;
@ -345,6 +349,11 @@ int decodePacket(AVCodecContext *context, AVPacket *packet,
return outSize;
}
int transformError(int result) {
return result == AVERROR_INVALIDDATA ? AUDIO_DECODER_ERROR_INVALID_DATA
: AUDIO_DECODER_ERROR_OTHER;
}
void logError(const char *functionName, int errorNumber) {
char *buffer = (char *)malloc(ERROR_STRING_BUFFER_LENGTH * sizeof(char));
av_strerror(errorNumber, buffer, ERROR_STRING_BUFFER_LENGTH);