技术背景

我们在做Android平台RTSP|RTMP播放器的时候,有这样的技术诉求,播放端需要支持随时实时截图快照功能。实际上,这块,我们前些年就实现了,本blog,介绍下如何实现播放端的实时截图快照。

Android平台RTSP|RTMP播放端实时截图快照功能实现,可以用很多方式,常见的方式比如:

  • 使用 TextureView:TextureView 是一个用于显示视频内容的视图,可以通过设置 SurfaceTextureListener 来监听视频帧的更新。在 onSurfaceTextureUpdated 方法中,可以获取当前的视频帧并进行截图。
  • 利用 FFmpeg 库:FFmpeg 是一个强大的开源多媒体框架,可以在 Android 上进行编译和使用。通过调用 FFmpeg 的 API,可以对 RTSP 流进行解码,并获取视频帧的数据。然后,可以将视频帧数据保存为图片文件。
  • 借助第三方播放模块:SmartPlayer可以实现 RTSP|RTMP播放器的视频截图功能,通常提供了相应的 API 和方法,可以方便地进行截图操作。

技术实现

在探讨Android平台播放器截图快照之前,我们先看保存jpeg还是png,二者区别在哪里?

图像质量差别

PNG:

  • 支持无损压缩,能够保留图像的细节和质量,尤其对于具有复杂颜色变化或渐变的图像效果更好。
  • 适合保存需要高质量图像的场景,例如截图中包含精细的图形、文本或需要进行后续的编辑处理。
  • 但是,由于无损压缩,文件大小通常比 JPEG 大。

JPEG:

  • 采用有损压缩算法,可以在一定程度上控制图像质量和文件大小的平衡。
  • 对于一般的视频截图,JPEG 的图像质量通常已经足够,特别是在颜色变化相对简单、没有过多细节的情况下。
  • 可以通过调整压缩质量参数来控制文件大小和图像质量之间的权衡。

适用场景

如果截图主要用于以下场景,可以考虑使用 PNG:

  • 需要高质量的图像,用于打印、专业设计或对图像质量要求较高的场合。
  • 截图中包含复杂的图形、文本或需要进行精确的编辑处理。
  • 需要保留透明背景或与其他具有透明元素的图像进行合成。

如果截图主要用于以下场景,可以考虑使用 JPEG:

  • 对文件大小有限制,例如在移动设备上存储大量截图或进行网络传输。
  • 图像质量要求不是特别高,主要用于一般的查看和分享。
  • 不需要透明背景或复杂的编辑处理。

接口设计

本文以大牛直播SDK的SmartPlayer播放器为例,介绍下,如何设计实时截图快照的接口。考虑到实际使用场景,我们jpeg和png两种格式,都做了支持。可以参考“拉流端快照”调用实时截图快照功能。

Android平台RTSP|RTMP播放器如何实现实时截图快照?_大牛直播SDK

/*
 * SmartPlayerJniV2.java
 * Copyright © 2014~2024 daniusdk.com All rights reserved.
 */
/**
 * 新的截图接口, 支持JPEG和PNG两种格式
 * @param compress_format: 压缩格式, 0:JPEG格式, 1:PNG格式, 其他返回错误
 * @param quality: 取值范围:[0, 100], 值越大图像质量越好, 仅对JPEG格式有效, 若是PNG格式,请填100
 * @param file_name: 图像文件名, 例如:/dirxxx/test20231113100739.jpeg, /dirxxx/test20231113100739.png
 * @param user_data_string: 用户自定义字符串
 * @return {0} if successful
 */
public native int CaptureImage(long handle, int compress_format, int quality, String file_name, String user_data_string);

针对播放端的封装设计如下:

public boolean CaptureImage(int compress_format, int quality, String file_name, String user_data_string) {
	if (!check_native_handle())
		return false;

	return OK == lib_player_.CaptureImage(get(), compress_format, quality, file_name, user_data_string);
}

外部调用:

/*
 * SmartPlayer.java
 * Copyright © 2014~2024 daniusdk.com All rights reserved.
 */
class ButtonPullCaptureImageListener implements View.OnClickListener {
	public void onClick(View v) {
		if (!stream_player_.is_player_running())
			return;

		if (null == capture_image_date_format_)
			capture_image_date_format_ = new SimpleDateFormat("yyyyMMdd_HHmmss_SSS");

		String timestamp = capture_image_date_format_.format(new Date());
		String imageFileName = timestamp;

		String image_path = imageSavePath + "/" + imageFileName;

		int quality;
		boolean is_jpeg = true;
		if (is_jpeg) {
			image_path += ".jpeg";
			quality = 100;
		}
		else {
			image_path += ".png";
			quality = 100;
		}

		boolean capture_ret = stream_player_.CaptureImage(is_jpeg?0:1, quality, image_path, "test cix");
		Log.i(TAG, "capture image ret:" + capture_ret + ", file:" + image_path);
	}
}

总结

Android平台RTSP|RTMP播放器实现实时截图快照,选择JPEG还是 PNG 格式取决于具体的需求和应用场景。如果对图像质量要求较高且不关心文件大小,可以选择 PNG;如果需要控制文件大小且对图像质量要求不是特别苛刻,可以选择 JPEG。以上抛砖引玉,对RTSP|RTMP播放模块设计和使用感兴趣的开发者,可以单独跟我沟通探讨。