首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android平台GB28181设备接入端实现实时快照

Android平台GB28181设备接入端实现实时快照

原创
作者头像
音视频牛哥
发布2022-10-04 02:12:10
2450
发布2022-10-04 02:12:10
举报

Android平台GB28181设计开发的时候,有个功能必不可少的:实时快照,特别是用于执法记录仪等场景下,用于图像留底或分析等考量。

实时快照的实现并不难,目前实现有两种方式,一种是拿到数据(比如摄像头数据)后,直接上层编码,存取快照;另一种模式是,数据投递到JNI层,底层针对投递过来的编码前数据,做png编码,并保存到设定的目录下,今天我们主要探讨第二种实现模式。

我们在publisher实例初始化的时候,设置是否启用快照:

private void InitAndSetConfig() {

	int audio_opt = 1;

	int fps = 18;
	int gop = fps * 2;

	Log.i(TAG, "InitAndSetConfig video_width: " + video_width_ + " cur_video_height" + video_height_ + " imageRotationDegree:" + cameraImageRotationDegree_);

	publisherHandle = libPublisher.SmartPublisherOpen(context_, audio_opt, 3,  video_width_, video_height_);

	if (publisherHandle == 0) {
		Log.e(TAG, "sdk open failed!");
		return;
	}

	Log.i(TAG, "publisherHandle=" + publisherHandle);

	if(videoEncodeType == 1)  {
		int h264HWKbps = setHardwareEncoderKbps(true, video_width_, video_height_);
		h264HWKbps = h264HWKbps*fps/25;

		Log.i(TAG, "h264HWKbps: " + h264HWKbps);

		int isSupportH264HWEncoder = libPublisher
				.SetSmartPublisherVideoHWEncoder(publisherHandle, h264HWKbps);

		if (isSupportH264HWEncoder == 0) {
			libPublisher.SetNativeMediaNDK(publisherHandle, 1);
			Log.i(TAG, "Great, it supports h.264 hardware encoder!");
		}
	}
	else if (videoEncodeType == 2) {
		int hevcHWKbps = setHardwareEncoderKbps(false, video_width_, video_height_);
		hevcHWKbps = hevcHWKbps*fps/25;
		Log.i(TAG, "hevcHWKbps: " + hevcHWKbps);

		int isSupportHevcHWEncoder = libPublisher
				.SetSmartPublisherVideoHevcHWEncoder(publisherHandle, hevcHWKbps);

		if (isSupportHevcHWEncoder == 0) {
			libPublisher.SetNativeMediaNDK(publisherHandle, 1);
			Log.i(TAG, "Great, it supports hevc hardware encoder!");
		}
	}

	boolean is_sw_vbr_mode = true;
	if(is_sw_vbr_mode)	//H.264 software encoder
	{
		int is_enable_vbr = 1;
		int video_quality = CalVideoQuality(video_width_, video_height_, true);
		int vbr_max_bitrate = CalVbrMaxKBitRate(video_width_, video_height_);

		libPublisher.SmartPublisherSetSwVBRMode(publisherHandle, is_enable_vbr, video_quality, vbr_max_bitrate);
	}

	if (is_pcma_) {
		libPublisher.SmartPublisherSetAudioCodecType(publisherHandle, 3);
	} else {
		libPublisher.SmartPublisherSetAudioCodecType(publisherHandle, 1);
	}

	libPublisher.SetSmartPublisherEventCallbackV2(publisherHandle, new EventHandePublisherV2());

	libPublisher.SmartPublisherSetSWVideoEncoderProfile(publisherHandle, 3);

	libPublisher.SmartPublisherSetSWVideoEncoderSpeed(publisherHandle, 2);

	libPublisher.SmartPublisherSetGopInterval(publisherHandle, gop);

	libPublisher.SmartPublisherSetFPS(publisherHandle, fps);

	// libPublisher.SmartPublisherSetSWVideoBitRate(publisherHandle, 600, 1200);

	boolean is_noise_suppression = true;
	libPublisher.SmartPublisherSetNoiseSuppression(publisherHandle, is_noise_suppression ? 1 : 0);

	boolean is_agc = false;
	libPublisher.SmartPublisherSetAGC(publisherHandle, is_agc ? 1 : 0);

	int echo_cancel_delay = 0;
	libPublisher.SmartPublisherSetEchoCancellation(publisherHandle, 1, echo_cancel_delay);

	libPublisher.SmartPublisherSaveImageFlag(publisherHandle, 1);
}

记得留意最后一句:libPublisher.SmartPublisherSaveImageFlag(publisherHandle, 1);

相关接口说明如下:

 /**
  * Set if needs to save image during publishing stream(设置是否启用快照)
  *
  * @param is_save_image: if with 1, it will save current image via the interface of SmartPlayerSaveImage(), if with 0: does not it
  *
  * @return {0} if successful
  */
 public native int SmartPublisherSaveImageFlag(long handle,  int is_save_image);

设置后,页面有需要实时快照的数据时,点击“实时快照”按钮即可,需要注意的是,实时快照需要存储路径和保存下来的快照文件名称。具体实现如下:

class ButtonCaptureImageListener implements View.OnClickListener {
	@SuppressLint("SimpleDateFormat")
	public void onClick(View v) {
		if(isPushingRtmp || isRecording || isRTSPPublisherRunning || isGB28181StreamRunning)
		{
			String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
			String imageFileName = "dn_" + timeStamp;    //创建以时间命名的文件名称

			String imagePath = imageSavePath + "/" + imageFileName + ".png";

			Log.i(TAG, "imagePath:" + imagePath);

			libPublisher.SmartPublisherSaveCurImage(publisherHandle, imagePath);
		}
		else
		{
			Log.e(TAG, "快照失败,请确保在推送、录像、GB28181推送或内置RTSP服务发布状态..");
		}
	}
}

快照截取成功后,publisher实例会回调以下事件:

case NTSmartEventID.EVENT_DANIULIVE_ERC_PUBLISHER_CAPTURE_IMAGE:
	publisher_event = "快照: " + param1 + " 路径:" + param3;

	if (param1 == 0) {
		publisher_event = publisher_event + "截取快照成功..";
	} else {
		publisher_event = publisher_event + "截取快照失败..";
	}
	break;

由于实时快照,功能复杂度不高,而且也可以在上层实现,很容易被忽略,如果做的精细的话,还是需要开发者花费一定的心思。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云直播
云直播(Cloud Streaming Services,CSS)为您提供极速、稳定、专业的云端直播处理服务,根据业务的不同直播场景需求,云直播提供了标准直播、快直播、云导播台三种服务,分别针对大规模实时观看、超低延时直播、便捷云端导播的场景,配合腾讯云视立方·直播 SDK,为您提供一站式的音视频直播解决方案。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档