ExifInterface: Use FileDescriptors whenever we can.

This avoids a complex cyclic dependency between MediaProvider,
mediacodec and media.extractor.

Bug: 199822700
Bug: 260950919
Test: manual
Change-Id: I8863c539c7bded77fef24dfcedf28bdc59568940
This commit is contained in:
Martijn Coenen 2023-03-03 13:37:39 +00:00
parent 08f7735fca
commit e69a12f356

View File

@ -1566,7 +1566,7 @@ public class ExifInterface {
FileInputStream in = null; FileInputStream in = null;
try { try {
in = new FileInputStream(fileDescriptor); in = new FileInputStream(fileDescriptor);
loadAttributes(in); loadAttributes(in, fileDescriptor);
} finally { } finally {
closeQuietly(in); closeQuietly(in);
if (isFdDuped) { if (isFdDuped) {
@ -1637,7 +1637,7 @@ public class ExifInterface {
mSeekableFileDescriptor = null; mSeekableFileDescriptor = null;
} }
} }
loadAttributes(inputStream); loadAttributes(inputStream, null);
} }
/** /**
@ -1963,7 +1963,7 @@ public class ExifInterface {
* This function decides which parser to read the image data according to the given input stream * This function decides which parser to read the image data according to the given input stream
* type and the content of the input stream. * type and the content of the input stream.
*/ */
private void loadAttributes(@NonNull InputStream in) { private void loadAttributes(@NonNull InputStream in, @Nullable FileDescriptor fd) {
if (in == null) { if (in == null) {
throw new NullPointerException("inputstream shouldn't be null"); throw new NullPointerException("inputstream shouldn't be null");
} }
@ -1993,7 +1993,7 @@ public class ExifInterface {
break; break;
} }
case IMAGE_TYPE_HEIF: { case IMAGE_TYPE_HEIF: {
getHeifAttributes(inputStream); getHeifAttributes(inputStream, fd);
break; break;
} }
case IMAGE_TYPE_ORF: { case IMAGE_TYPE_ORF: {
@ -2580,7 +2580,7 @@ public class ExifInterface {
} else if (isSeekableFD(in.getFD())) { } else if (isSeekableFD(in.getFD())) {
mSeekableFileDescriptor = in.getFD(); mSeekableFileDescriptor = in.getFD();
} }
loadAttributes(in); loadAttributes(in, null);
} finally { } finally {
closeQuietly(in); closeQuietly(in);
if (modernFd != null) { if (modernFd != null) {
@ -3068,59 +3068,66 @@ public class ExifInterface {
} }
} }
private void getHeifAttributes(ByteOrderedDataInputStream in) throws IOException { private void getHeifAttributes(ByteOrderedDataInputStream in, @Nullable FileDescriptor fd)
throws IOException {
MediaMetadataRetriever retriever = new MediaMetadataRetriever(); MediaMetadataRetriever retriever = new MediaMetadataRetriever();
try { try {
retriever.setDataSource(new MediaDataSource() { if (fd != null) {
long mPosition; retriever.setDataSource(fd);
} else {
retriever.setDataSource(new MediaDataSource() {
long mPosition;
@Override @Override
public void close() throws IOException {} public void close() throws IOException {}
@Override @Override
public int readAt(long position, byte[] buffer, int offset, int size) public int readAt(long position, byte[] buffer, int offset, int size)
throws IOException { throws IOException {
if (size == 0) { if (size == 0) {
return 0; return 0;
} }
if (position < 0) { if (position < 0) {
return -1;
}
try {
if (mPosition != position) {
// We don't allow seek to positions after the available bytes,
// the input stream won't be able to seek back then.
// However, if we hit an exception before (mPosition set to -1),
// let it try the seek in hope it might recover.
if (mPosition >= 0 && position >= mPosition + in.available()) {
return -1;
}
in.seek(position);
mPosition = position;
}
// If the read will cause us to go over the available bytes,
// reduce the size so that we stay in the available range.
// Otherwise the input stream may not be able to seek back.
if (size > in.available()) {
size = in.available();
}
int bytesRead = in.read(buffer, offset, size);
if (bytesRead >= 0) {
mPosition += bytesRead;
return bytesRead;
}
} catch (IOException e) {
// absorb the exception and fall through to the 'failed read' path below
}
mPosition = -1; // need to seek on next read
return -1; return -1;
} }
try {
if (mPosition != position) {
// We don't allow seek to positions after the available bytes,
// the input stream won't be able to seek back then.
// However, if we hit an exception before (mPosition set to -1),
// let it try the seek in hope it might recover.
if (mPosition >= 0 && position >= mPosition + in.available()) {
return -1;
}
in.seek(position);
mPosition = position;
}
// If the read will cause us to go over the available bytes, @Override
// reduce the size so that we stay in the available range. public long getSize() throws IOException {
// Otherwise the input stream may not be able to seek back. return -1;
if (size > in.available()) { }
size = in.available(); });
} }
int bytesRead = in.read(buffer, offset, size);
if (bytesRead >= 0) {
mPosition += bytesRead;
return bytesRead;
}
} catch (IOException e) {}
mPosition = -1; // need to seek on next read
return -1;
}
@Override
public long getSize() throws IOException {
return -1;
}
});
String exifOffsetStr = retriever.extractMetadata( String exifOffsetStr = retriever.extractMetadata(
MediaMetadataRetriever.METADATA_KEY_EXIF_OFFSET); MediaMetadataRetriever.METADATA_KEY_EXIF_OFFSET);