文章目录
一、修改记录
版本 | 修改日期 | 作者 | 修改内容 |
---|---|---|---|
v1.0 | 2021.09.03 | 罗然 | 初版 |
二、概述
用户日常拍照或者录像,在某些场景下可能会需要在图片或者视频详情下面显示具体的位置信息(经纬度),获取位置信息目前有两种比较常用的方案:
- GPS 定位
- 网络定位
GPS 定位相比于网络定位来说优缺点都很明显,优点就是定位准确度、精度比较高,缺点则是需要在室外比较空旷的环境下才能获取到位置信息,而网络定位则没有这方面的限制,只需要网络畅通就可以获取到位置信息。比较好的方案就是优先使用网络定位,网络不可用的情况下采用 GPS 定位。
三、图片位置信息存储
图片存储位置信息通常有两种方案:
- 位置信息存储在 Media 数据库中,图库通过查询数据库获取到经纬度字段进行解析
- 位置信息存储在图片的 Exif 信息里面,通过 ExifInterface 接口解析出经纬度进行解析
3.1 存储 Media 数据库
ContentValues values = new ContentValues();
values.put(MediaStore.Images.ImageColumns.LATITUDE, latitude);
values.put(MediaStore.Images.ImageColumns.LONGITUDE, longitude);
mContentResolver.insert(Images.Media.EXTERNAL_CONTENT_URI, values);
MediaStore 的内部类 Images 包含两个字段,分别是 LATITUDE 和 LONGITUDE,LATITUDE 用来存储纬度,LONGITUDE 用来存储经度,把获取到的经纬度存储到对应的字段即可。不过这个方案在 Android Q 平台后已经无效了:
/**
* The latitude where the image was captured.
*
* @deprecated location details are no longer indexed for privacy
* reasons, and this value is now always {@code null}.
* You can still manually obtain location metadata using
* {@link ExifInterface#getLatLong(float[])}.
*/
@Deprecated
@Column(value = Cursor.FIELD_TYPE_FLOAT, readOnly = true)
public static final String LATITUDE = "latitude";
/**
* The longitude where the image was captured.
*
* @deprecated location details are no longer indexed for privacy
* reasons, and this value is now always {@code null}.
* You can still manually obtain location metadata using
* {@link ExifInterface#getLatLong(float[])}.
*/
@Deprecated
@Column(value = Cursor.FIELD_TYPE_FLOAT, readOnly = true)
public static final String LONGITUDE = "longitude";
查阅 MediaStore 源码可以看到,LATITUDE 和 LONGITUDE 两个字段已经被加上了 @Deprecated 注解,也就是说谷歌已经不推荐开发者使用这两个字段了,看到这里可能还觉得有点希望,毕竟只是不推荐使用,如果使用的话应该也不会有什么问题吧,真正绝望的是 readOnly = true,也就是说字段可读不可写,最后的一点希望破灭了。难道没有别的办法了吗?应该不是,以谷歌的尿性,通常弃用一个旧方案的时候应该会提供一个新的方案,查看字段注释果不其然:
location details are no longer indexed for privacy
reasons, and this value is now always {@code null}.
You can still manually obtain location metadata using
{@link ExifInterface#getLatLong(float[])}.
也就是我们上面说的存储位置信息的第二个方案,可以通过 ExifInterface 接口存储位置信息到图片的 Exif 信息里面。
3.2 存储 Exif 信息
存储位置信息到图片的 Exif 里面有两种方法:
3.2.1 ExifInterface
ExifInterface exifInterface = new ExifInterface();
exifInterface.addGpsTags(latitude, longitude);
exifInterface.writeExif(request.mData, out);
3.2.2 CaptureRequest.JPEG_GPS_LOCATION
Location location = new Location("");
location.setLatitude(locationProxy.getCurLatitude());
location.setLongitude(locationProxy.getCurLongitude());
builder.set(CaptureRequest.JPEG_GPS_LOCATION, location);
四、视频位置信息存储
4.1 MediaRecorder 录制
Camera 应用一般都是采用 MediaRecorder 类录像,在这种场景下,只需要调用 MediaRecorder的 setLocation 方法就可以保存视频的位置信息:
mMediaRecorder.setLocation((float) spec.location.getLatitude(), (float) spec.location.getLongitude());
4.2 MediaCodec + AudioRecorder 录制
在某些场景下,Camera 会用到 MediaCodec 采集视频数据,AudioRecorder 采集音频数据,然后通过 MediaMuxer 进行音视频合成视频文件,这种场景下需要调用 MediaMuxer 类的 setLocation 方法来保存视频的位置信息:
public void setLocation(float latitude, float longitude)
需要注意的是这个方法需要在 MediaMuxer 类的 start 方法之前调用,下面是 Google 文档的说明:
Set and store the geodata (latitude and longitude) in the output file. This method should be called before start().