请教个问题:我对网上的一个jfm的rtp视频聊天稍微改了点,在接收端就无法接受视频信息了,请问是怎么回事?如下:

RanShW RanShW 墨衍会员 · AI 创作全网分发 墨衍智能分发 通过墨衍一键同步至各平台 可同步平台 CSDN微信公众号微博知乎掘金百家号博客园抖音小红书 你的文章也可以这样分发 墨衍会员 ¥399起/年,写一次发全网 我也要 + 加入社区
我觉得问题可能出在Receiver的获取播放器的VisualComponent上,因为当前获取到的是空值,无法将播放器组件添加到面板上,是么?
Sender.java
package testRTP2;



import java.awt.Dimension;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Vector;

import javax.media.CaptureDeviceInfo;
import javax.media.CaptureDeviceManager;
import javax.media.Codec;
import javax.media.Control;
import javax.media.Format;
import javax.media.Manager;
import javax.media.NoProcessorException;
import javax.media.Owned;
import javax.media.Processor;
import javax.media.control.FormatControl;
import javax.media.control.QualityControl;
import javax.media.control.TrackControl;
import javax.media.format.AudioFormat;
import javax.media.format.UnsupportedFormatException;
import javax.media.format.VideoFormat;
import javax.media.protocol.ContentDescriptor;
import javax.media.protocol.DataSource;
import javax.media.protocol.PushBufferDataSource;
import javax.media.protocol.PushBufferStream;
import javax.media.rtp.InvalidSessionAddressException;
import javax.media.rtp.RTPManager;
import javax.media.rtp.SendStream;
import javax.media.rtp.SessionAddress;

public class Sender {

public static void main(String[] args) {
try {//设置本地地址和远端地址都为本机地址,自己传给自己,试验用
SessionAddress local = new SessionAddress(InetAddress.getLocalHost(),50000);
SessionAddress target = new SessionAddress(InetAddress.getLocalHost(),60000);
new Sender(local,target);
} catch (UnknownHostException e) {
e.printStackTrace();
}
}

public Sender(SessionAddress local,SessionAddress target) {

Vector<CaptureDeviceInfo> deviceList = CaptureDeviceManager.getDeviceList(null);
CaptureDeviceInfo info = (CaptureDeviceInfo) deviceList.firstElement();

// CaptureDeviceInfo info=CaptureDeviceManager.getDevice(str);

//CaptureDeviceInfo info = (CaptureDeviceInfo) CaptureDeviceManager.getDeviceList(null).get(0);
// CaptureDeviceInfo info = (CaptureDeviceInfo) CaptureDeviceManager.getDeviceList(new AudioFormat(null)).get(0);用这一句替换上一句可改成音频传输
Processor p = null;
try {
p = Manager.createProcessor(info.getLocator());
} catch (NoProcessorException | IOException e) {
e.printStackTrace();
}
StateHelper sh = new StateHelper(p);

doSomeVideoProcess(p,sh);
// doSomeAudioProcess(p,sh);用这一句替换上一句可改成音频传输
RTPManager mgr = RTPManager.newInstance();//RTP管理器实例化
try {//分别将本机和目的机IP地址加入至RTP会话管理器
mgr.initialize(local);
mgr.addTarget(target);
} catch (InvalidSessionAddressException | IOException e) {
e.printStackTrace();
}

DataSource ds = p.getDataOutput();
PushBufferDataSource pbds = (PushBufferDataSource)ds;
PushBufferStream pbss[] = pbds.getStreams();

for(int i=0;i<pbss.length;i++) {
try {
SendStream ss = mgr.createSendStream(ds, i);//产生第i条轨道的传输流
ss.start();//传输流开始
} catch (UnsupportedFormatException | IOException e) {
e.printStackTrace();
}
}
p.start();
try {
Thread.sleep(60000);//传送一分钟后关闭
} catch (InterruptedException e) {
e.printStackTrace();
}
if(p!=null) {
p.stop();
p.close();
}
if(mgr!=null) {
mgr.removeTargets("client disconnnected");
mgr.dispose();
mgr = null;
}
}
private static void doSomeVideoProcess(Processor p,StateHelper sh) {
sh.configure(5000);
p.setContentDescriptor(new ContentDescriptor(ContentDescriptor.RAW_RTP));
setVideoTrackFormat(p.getTrackControls());
sh.realize(5000);
setJPEGQuality(p, 0.5f);
}
private static void doSomeAudioProcess(Processor p,StateHelper sh) {
sh.configure(5000);
p.setContentDescriptor(new ContentDescriptor(ContentDescriptor.RAW));
setAudioTrackFormat(p.getTrackControls());
sh.realize(5000);
}
private static Format checkForVideoSizes(Format original, Format supported) {
int width, height;
Dimension size = ((VideoFormat)original).getSize();
Format jpegFmt = new Format(VideoFormat.JPEG_RTP);
Format h263Fmt = new Format(VideoFormat.H263_RTP);
if (supported.matches(jpegFmt)) {
// For JPEG, make sure width and height are divisible by 8.
width = (size.width % 8 == 0 ? size.width :
(int)(size.width / 8) * 8);
height = (size.height % 8 == 0 ? size.height :
(int)(size.height / 8) * 8);
} else if (supported.matches(h263Fmt)) {
// For H.263, we only support some specific sizes.
if (size.width < 128) {
width = 128;
height = 96;
} else if (size.width < 176) {
width = 176;
height = 144;
} else {
width = 352;
height = 288;
}
} else {
// We don't know this particular format. We'll just
// leave it alone then.
return supported;
}
return (new VideoFormat(null,
new Dimension(width, height),
Format.NOT_SPECIFIED,
null,
Format.NOT_SPECIFIED)).intersects(supported);
}
private static void setAudioTrackFormat(TrackControl[] trackControls) {
boolean ok = false;
for(TrackControl t:trackControls){
if(!ok && t instanceof FormatControl) {
if(((FormatControl)t).setFormat(new AudioFormat(AudioFormat.ULAW_RTP,8000,8,1))==null)
t.setEnabled(false);
else
ok = true;
} else {
t.setEnabled(false);
}
}
}
private static boolean setVideoTrackFormat(TrackControl[] tracks) {
if(tracks==null || tracks.length<1)
return false;
boolean atLeastOneTrack = false;
for(TrackControl t:tracks) {
if(t.isEnabled()) {
Format[] supported = t.getSupportedFormats();
Format chosen = null;
if(supported.length>0) {
if(supported[0] instanceof VideoFormat)
chosen = checkForVideoSizes(t.getFormat(),supported[0]);
else
chosen = supported[0];
t.setFormat(chosen);
atLeastOneTrack = true;
} else {
t.setEnabled(false);
}
} else {
t.setEnabled(false);
}
}
return atLeastOneTrack;
}
private static void setJPEGQuality(Processor p, float val) {
Control cs[] = p.getControls();
QualityControl qc = null;
VideoFormat jpegFmt = new VideoFormat(VideoFormat.JPEG);
// Loop through the controls to find the Quality control for
// the JPEG encoder.
for (int i = 0; i < cs.length; i++) {
if (cs[i] instanceof QualityControl && cs[i] instanceof Owned) {
Object owner = ((Owned)cs[i]).getOwner();
// Check to see if the owner is a Codec.
// Then check for the output format.
if (owner instanceof Codec) {
Format fmts[] = ((Codec)owner).getSupportedOutputFormats(null);
for (int j = 0; j < fmts.length; j++) {
if (fmts[j].matches(jpegFmt)) {
qc = (QualityControl)cs[i];
qc.setQuality(val);
break;
}
}
}
if (qc != null)
break;
}
}
}

}
...全文

相关推荐

CheckOutOfDateMrpSteps.py00000

CheckOutOfDateMrpSteps.py00000

大助794

驱动精灵(驱动精灵家用标准版)

1. 硬件扫描 + 驱动匹配 识别声卡、网卡、显卡、芯片组、打印机、外设,找出缺失 / 异常 / 旧驱动,按硬件 ID 匹配驱动包;适合新装系统、设备管理器黄感叹号。 2. 驱动备份 & 一键还原 装机前备份整套驱动,重装系统后直接恢复,不用重新下载;支持导出独立备份包。 3. 驱动卸载、回滚、清理 删掉冲突旧驱动、残留驱动文件;更新翻车可以回退上一版驱动,解决蓝屏、花屏、无声音。 4. 硬件信息查看 CPU、主板、硬盘、内存、显卡基础信息,附带简单温度监控。 5. 附带小工具 网卡修复、音频修复、DirectX 修复、系统组件修复。

YYcsdn56

产业园区运营负责人如何利用数智工具提升企业创新服务能力?.docx

产业园区运营负责人如何利用数智工具提升企业创新服务能力?

BIZKEEN

年会抽奖网页程序2026

用于年会抽奖

洲上渔者

基于模糊PID与传统PID控制无刷直流电机对比仿真模型【说明文档+参考文献等】

内容概要:本文介绍了一套基于Simulink的无刷直流电机(BLDC)控制系统仿真模型资源,重点对比了模糊PID与传统PID控制策略在电机调速中的性能差异。资源包含多个仿真模型,涵盖模糊PID控制、传统PID控制、无位置传感器控制、滑模观测器以及转速电流双闭环PI控制等,总计三个核心仿真系统。通过建模仿真,用户可深入理解不同控制算法在无刷直流电机系统中的动态响应、抗干扰能力、稳定性及控制精度表现。文档提供了详尽的说明材料、参考文献和实现代码,尤其突出了模糊PID相较于传统PID在非线性、时变系统中更强的自适应调节能力。此外,资源还涉及无感控制与滑模观测器的设计,有助于掌握现代电机控制中的先进观测与估算技术,适用于电力电子、电机控制及相关领域的科研与教学实践。 适合人群:从事电机控制、电力电子、自动化、电气工程等专业的科研人员、研究生及高年级本科生,以及工业界从事电机驱动系统开发的工程师和技术人员。 使用场景及目标:①研究模糊PID与传统PID在无刷直流电机调速系统中的控制性能差异,分析其超调量、响应速度与稳态精度;②学习并掌握无位置传感器控制与滑模观测器的设计原理与实现方法,提升对电机状态估计技术的理解;③开展转速电流双闭环控制系统的建模与仿真,支持学术论文复现、课程设计与创新控制算法的验证与优化。 阅读建议:建议结合提供的说明文档与参考文献,按照模块逐步运行各仿真模型,重点关注控制参数调节对系统动态性能的影响;通过对比模糊PID与传统PID的仿真结果,深入理解智能控制策略的优势;在学习过程中应动手修改参数、尝试算法改进,并通过示波器观察波形变化,以增强对控制理论与工程实践结合的理解。

梦想科研社_研学
评论 2
收藏 已收藏
分享
返回顶部
RanShW
Java 51,407 成员 86,133 内容