mirror of
https://github.com/androidx/media.git
synced 2025-05-18 04:59:54 +08:00
Treat AVERROR_INVALIDDATA as non-fatal
Also configure the FFmpeg context to ignore errors as far as possible (this appears to have an effect only for certain decoders). Issue: #5293 PiperOrigin-RevId: 227851397
This commit is contained in:
parent
189e3c31be
commit
99bc13221c
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
* IMA extension: Clear ads loader listeners on release
|
* IMA extension: Clear ads loader listeners on release
|
||||||
([#4114](https://github.com/google/ExoPlayer/issues/4114)).
|
([#4114](https://github.com/google/ExoPlayer/issues/4114)).
|
||||||
|
* FFmpeg extension: Treat invalid data errors as non-fatal to match the behavior
|
||||||
|
of MediaCodec ([#5293](https://github.com/google/ExoPlayer/issues/5293)).
|
||||||
* Fix issue where sending callbacks for playlist changes may cause problems
|
* Fix issue where sending callbacks for playlist changes may cause problems
|
||||||
because of parallel player access
|
because of parallel player access
|
||||||
([#5240](https://github.com/google/ExoPlayer/issues/5240)).
|
([#5240](https://github.com/google/ExoPlayer/issues/5240)).
|
||||||
|
@ -37,6 +37,10 @@ import java.util.List;
|
|||||||
private static final int OUTPUT_BUFFER_SIZE_16BIT = 65536;
|
private static final int OUTPUT_BUFFER_SIZE_16BIT = 65536;
|
||||||
private static final int OUTPUT_BUFFER_SIZE_32BIT = OUTPUT_BUFFER_SIZE_16BIT * 2;
|
private static final int OUTPUT_BUFFER_SIZE_32BIT = OUTPUT_BUFFER_SIZE_16BIT * 2;
|
||||||
|
|
||||||
|
// Error codes matching ffmpeg_jni.cc.
|
||||||
|
private static final int DECODER_ERROR_INVALID_DATA = -1;
|
||||||
|
private static final int DECODER_ERROR_OTHER = -2;
|
||||||
|
|
||||||
private final String codecName;
|
private final String codecName;
|
||||||
private final @Nullable byte[] extraData;
|
private final @Nullable byte[] extraData;
|
||||||
private final @C.Encoding int encoding;
|
private final @C.Encoding int encoding;
|
||||||
@ -106,8 +110,14 @@ import java.util.List;
|
|||||||
int inputSize = inputData.limit();
|
int inputSize = inputData.limit();
|
||||||
ByteBuffer outputData = outputBuffer.init(inputBuffer.timeUs, outputBufferSize);
|
ByteBuffer outputData = outputBuffer.init(inputBuffer.timeUs, outputBufferSize);
|
||||||
int result = ffmpegDecode(nativeContext, inputData, inputSize, outputData, outputBufferSize);
|
int result = ffmpegDecode(nativeContext, inputData, inputSize, outputData, outputBufferSize);
|
||||||
if (result < 0) {
|
if (result == DECODER_ERROR_INVALID_DATA) {
|
||||||
return new FfmpegDecoderException("Error decoding (see logcat). Code: " + result);
|
// Treat invalid data errors as non-fatal to match the behavior of MediaCodec. No output will
|
||||||
|
// be produced for this buffer, so mark it as decode-only to ensure that the audio sink's
|
||||||
|
// position is reset when more audio is produced.
|
||||||
|
outputBuffer.setFlags(C.BUFFER_FLAG_DECODE_ONLY);
|
||||||
|
return null;
|
||||||
|
} else if (result == DECODER_ERROR_OTHER) {
|
||||||
|
return new FfmpegDecoderException("Error decoding (see logcat).");
|
||||||
}
|
}
|
||||||
if (!hasOutputFormat) {
|
if (!hasOutputFormat) {
|
||||||
channelCount = ffmpegGetChannelCount(nativeContext);
|
channelCount = ffmpegGetChannelCount(nativeContext);
|
||||||
|
@ -63,6 +63,10 @@ static const AVSampleFormat OUTPUT_FORMAT_PCM_16BIT = AV_SAMPLE_FMT_S16;
|
|||||||
// Output format corresponding to AudioFormat.ENCODING_PCM_FLOAT.
|
// Output format corresponding to AudioFormat.ENCODING_PCM_FLOAT.
|
||||||
static const AVSampleFormat OUTPUT_FORMAT_PCM_FLOAT = AV_SAMPLE_FMT_FLT;
|
static const AVSampleFormat OUTPUT_FORMAT_PCM_FLOAT = AV_SAMPLE_FMT_FLT;
|
||||||
|
|
||||||
|
// Error codes matching FfmpegDecoder.java.
|
||||||
|
static const int DECODER_ERROR_INVALID_DATA = -1;
|
||||||
|
static const int DECODER_ERROR_OTHER = -2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the AVCodec with the specified name, or NULL if it is not available.
|
* Returns the AVCodec with the specified name, or NULL if it is not available.
|
||||||
*/
|
*/
|
||||||
@ -79,7 +83,7 @@ AVCodecContext *createContext(JNIEnv *env, AVCodec *codec, jbyteArray extraData,
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Decodes the packet into the output buffer, returning the number of bytes
|
* Decodes the packet into the output buffer, returning the number of bytes
|
||||||
* written, or a negative value in the case of an error.
|
* written, or a negative DECODER_ERROR constant value in the case of an error.
|
||||||
*/
|
*/
|
||||||
int decodePacket(AVCodecContext *context, AVPacket *packet,
|
int decodePacket(AVCodecContext *context, AVPacket *packet,
|
||||||
uint8_t *outputBuffer, int outputSize);
|
uint8_t *outputBuffer, int outputSize);
|
||||||
@ -238,6 +242,7 @@ AVCodecContext *createContext(JNIEnv *env, AVCodec *codec, jbyteArray extraData,
|
|||||||
context->channels = rawChannelCount;
|
context->channels = rawChannelCount;
|
||||||
context->channel_layout = av_get_default_channel_layout(rawChannelCount);
|
context->channel_layout = av_get_default_channel_layout(rawChannelCount);
|
||||||
}
|
}
|
||||||
|
context->err_recognition = AV_EF_IGNORE_ERR;
|
||||||
int result = avcodec_open2(context, codec, NULL);
|
int result = avcodec_open2(context, codec, NULL);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
logError("avcodec_open2", result);
|
logError("avcodec_open2", result);
|
||||||
@ -254,7 +259,8 @@ int decodePacket(AVCodecContext *context, AVPacket *packet,
|
|||||||
result = avcodec_send_packet(context, packet);
|
result = avcodec_send_packet(context, packet);
|
||||||
if (result) {
|
if (result) {
|
||||||
logError("avcodec_send_packet", result);
|
logError("avcodec_send_packet", result);
|
||||||
return result;
|
return result == AVERROR_INVALIDDATA ? DECODER_ERROR_INVALID_DATA
|
||||||
|
: DECODER_ERROR_OTHER;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dequeue output data until it runs out.
|
// Dequeue output data until it runs out.
|
||||||
|
@ -366,7 +366,10 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
|
|||||||
if (outputBuffer == null) {
|
if (outputBuffer == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
decoderCounters.skippedOutputBufferCount += outputBuffer.skippedOutputBufferCount;
|
if (outputBuffer.skippedOutputBufferCount > 0) {
|
||||||
|
decoderCounters.skippedOutputBufferCount += outputBuffer.skippedOutputBufferCount;
|
||||||
|
audioSink.handleDiscontinuity();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outputBuffer.isEndOfStream()) {
|
if (outputBuffer.isEndOfStream()) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user