android DLNA投屏

android投屏技术的基本原理就是根据DLNA以及UPNP来实现,另外还有些黑科技技术便是根据端口号或者通过广播来用adb下载本身相关的apk来间接实现投屏,当然此处不提及黑科技。原理什么的百度一堆。这里主要讲实现方式和具体实现的代码。

那么,开始开发这玩意的时候肯定要先看看有没有现成的轮子,git上是有轮子的,链接如下:

https://github.com/4thline/cling 最基础的包,main类方法中有基础的调用方式

https://github.com/offbye/DroidDLNA 在cling上改动,代码表现为当前设备的媒资资源DLNA投屏,没涉及到相关的网络媒资投屏

 

DroidDLNA 中是有bug的,具体表现在api版本为25以后,是不能投屏的,原因出自AndroidNetworkAddressFactory类中的反射问题,api版本25以后,结果与之前完全不一致,改法已经在cling中完善,代码改动如下:

@Override
protected boolean isUsableAddress(NetworkInterface networkInterface, InetAddress address) {
    boolean result = super.isUsableAddress(networkInterface, address);
    if (result) {
        // TODO: Workaround Android DNS reverse lookup issue, still a problem on ICS+?
        // http://4thline.org/projects/mailinglists.html#nabble-td3011461
        String hostName = address.getHostAddress();
        Log.e("gjh test Log", "sdk version=" + Build.VERSION.SDK_INT + "->hostName=" + hostName);
        try {
            Field field0 = null;
            Object target = null;
            try {
                field0 = InetAddress.class.getDeclaredField("holder");
                field0.setAccessible(true);
                target = field0.get(address);
                field0 = target.getClass().getDeclaredField("hostName");
            } catch( NoSuchFieldException e ) {
                // Let's try the non-OpenJDK variant
                field0 = InetAddress.class.getDeclaredField("hostName");
                target = address;
            }
            if (field0 != null && hostName != null) {
                field0.setAccessible(true);
                field0.set(target, hostName);
            } else {
                return false;
            }
        } catch (Exception ex) {
            log.log(Level.SEVERE,
                    "Failed injecting hostName to work around Android InetAddress DNS bug: " + address,
                    ex
            );
            return false;
        }
    }
    return result;
}

DLNA轮子中投屏的方法为广播,代码表现为:

private void jumpToControl(ContentItem localContentItem) {

	Intent localIntent = new Intent("com.transport.info");

	localIntent.putExtra("name", localContentItem.toString());

	localIntent.putExtra("playURI", localContentItem.getItem()

	.getFirstResource().getValue());

	localIntent.putExtra("currentContentFormatMimeType",

	currentContentFormatMimeType);

	try {

	localIntent.putExtra("metaData",

	new GenerateXml().generate(localContentItem));

	} catch (Exception e) {

	e.printStackTrace();

	}

	IndexActivity.mTabHost.setCurrentTabByTag(getString(R.string.control));

	IndexActivity.setSelect();

	this.sendBroadcast(localIntent);

	}

当然如果需求为投射本地已经存在的资源的话只要稍微改动下界面和bug即可。

下面说说如何投射网络在线视频。

从上面的DLNA播放本地资源已经大致可以猜到只要修改其中的name、playURI和metaData即可。

但实际上我们只要改动metaData,因为最终解析是根据MetaData来拿到相关的媒资数据,其他大致上没什么用处

具体实现的代码如下:

 

private AndroidUpnpService upnpService;//DLNA投屏服务
private DeviceListRegistryListener deviceListRegistryListener;//搜索设备的回调
mContext.bindService(
        new Intent(mContext, AndroidUpnpServiceImpl.class),
        serviceConnection, Context.BIND_AUTO_CREATE);
private ServiceConnection serviceConnection = new ServiceConnection() {

    public void onServiceConnected(ComponentName className, IBinder service) {
        if (mContext != null) {
            upnpService = (AndroidUpnpService) service;//本地设备服务,用于执行投屏命令
            upnpService.getRegistry().addListener(deviceListRegistryListener);//搜索设备的回调
            ThreadManager.execute(new Runnable() {
                @Override
                public void run() {
                    if (mContext != null && upnpService != null) {
                        upnpService.getControlPoint().search();//搜索相关设备
                    }
                }
            });
        }
    }

    public void onServiceDisconnected(ComponentName className) {
        upnpService = null;
    }
};

public class DeviceListRegistryListener extends DefaultRegistryListener {

    @Override
    public void remoteDeviceRemoved(Registry registry, RemoteDevice device) {
        if (device.getType().getNamespace().equals("schemas-upnp-org")
                && device.getType().getType().equals("MediaRenderer")) {
            final DeviceItem dmrDisplay = new DeviceItem(device, device
                    .getDetails().getFriendlyName(),
                    device.getDisplayString(), "(REMOTE) "
                    + device.getType().getDisplayString());
            dmrRemoved(dmrDisplay);
        }
    }

    @Override
    public void remoteDeviceAdded(Registry registry, RemoteDevice device) {
        if (device.getType().getNamespace().equals("schemas-upnp-org")
                && device.getType().getType().equals("MediaRenderer")) {
            final DeviceItem dmrDisplay = new DeviceItem(device, device
                    .getDetails().getFriendlyName(),
                    device.getDisplayString(), "(REMOTE) "
                    + device.getType().getDisplayString());
            dmrAdded(dmrDisplay);
        }
    }

    public void dmrAdded(final DeviceItem di) {
        if (mTvDataList == null) {
            mTvDataList = new ArrayList<>();
        }
        mTvDataList.add(di);
    }

    public void dmrRemoved(final DeviceItem di) {
        if (mTvDataList != null && mTvDataList.contains(di)) {
            mTvDataList.remove(di);
        }
    }
}
private void playToTv(DeviceItem deviceItem) {
    String url = "网络视频链接";
    Service avtService = deviceItem.getDevice()
            .findService(new UDAServiceType("AVTransport"));
    String metaData = TvUtil.pushMediaToRender(url, "video-item", "DLNA测试视频", "50:00", "ggg");
    upnpService.getControlPoint().execute(new SetAVTransportURI(avtService, url, metaData) {
        @Override
        public void success(ActionInvocation invocation) {
            super.success(invocation);
            LogUtil.e("playToTv", "-------success");
        }

        @Override
        public void failure(ActionInvocation invocation, UpnpResponse operation, String defaultMsg) {
            LogUtil.e("playToTv", "-------failure defaultMsg=" + defaultMsg);
        }
    });
}

当然上面的网络视频链接最好以最终的播放地址,不然会出现无法播放的情况.

具体代码 https://download.csdn.net/download/gan303/10392625

 

  • 4
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
DLNA投屏是一种流媒体技术,它允许用户将音频、视频和照片从一个设备传输到另一个设备进行播放。它基于DLNA(数字生活网络联盟)的标准协议,可实现设备之间的互通和互操作性。 DLNA投屏的demo演示了如何使用DLNA技术进行多媒体投屏。首先,我们需要有一个DLNA兼容的播放设备(如智能电视、音响系统等)作为投放目标。然后,我们需要一个DLNA服务器或媒体播放器(如手机、电脑等)作为源设备。 在demo中,源设备上的DLNA服务会扫描设备上的媒体文件,并将其展示在一个可选择的列表中。用户可以选择想要投放的视频、音频或照片。一旦选择完毕,源设备会发送一个投屏指令给目标设备,请求播放所选的媒体文件。 目标设备接收到指令后,会通过DLNA协议进行与源设备的通信,获取所需的媒体文件,并开始播放。在这个过程中,目标设备可以根据需要进行格式转换或解码操作,以确保所播放的媒体文件与设备兼容。 DLNA投屏的demo展示了如何实现设备间的无缝连接和媒体共享。通过DLNA技术,我们可以享受无线投屏的便利,将媒体文件从一个设备传输到另一个设备,实现更好的观影、听歌或观看照片的体验。 总之,DLNA投屏demo演示了DLNA技术的应用场景和工作原理,展示了设备间的互通和互操作性。它使我们能够轻松地在不同设备之间进行媒体共享和投屏,丰富了我们的数字生活体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值