- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我想使用 WebRTC 将视频从安卓摄像头流式传输到 Wowza Streaming Engine (WSE)。当设备处于横向模式时,一切正常。然后我尝试通过将设备置于纵向模式来进行流式传输。
我在 WSE 播放器中注意到的第一件事是视频流已逆时针旋转 90。我发现 WebRTC 在发送到 WSE 之前不会旋转来自 onPreviewFrame API 的每个视频帧,不幸的是 WSE 不支持任何在他们身边旋转视频帧的机制至少到目前为止。
所以我检查了 WebRTC android 原生源代码并修改它以在发送到 WSE 之前旋转每个视频帧。现在我可以在 WSE 播放器中看到纵向模式的视频流。
但它有一个问题,有时视频流看起来很奇怪。请看下面的图片。
我把相机放在固定位置。 WSE 播放器第一次显示第一个,但有时会显示第二个。
这是我更改的 WebRTC 源代码中的文件。~/webrtc/src/sdk/android/src/jni/androidvideotracksource.cc
void AndroidVideoTrackSource::OnByteBufferFrameCaptured(const void* frame_data,
int length,
int width,
int height,
VideoRotation rotation,
int64_t timestamp_ns) {
RTC_DCHECK(camera_thread_checker_.CalledOnValidThread());
int64_t camera_time_us = timestamp_ns / rtc::kNumNanosecsPerMicrosec;
int64_t translated_camera_time_us =
timestamp_aligner_.TranslateTimestamp(camera_time_us, rtc::TimeMicros());
int adapted_width;
int adapted_height;
int crop_width;
int crop_height;
int crop_x;
int crop_y;
if (!AdaptFrame(width, height, camera_time_us, &adapted_width,
&adapted_height, &crop_width, &crop_height, &crop_x,
&crop_y)) {
return;
}
const uint8_t* y_plane = static_cast<const uint8_t*>(frame_data);
const uint8_t* uv_plane = y_plane + width * height;
const int uv_width = (width + 1) / 2;
RTC_CHECK_GE(length, width * height + 2 * uv_width * ((height + 1) / 2));
// Can only crop at even pixels.
crop_x &= ~1;
crop_y &= ~1;
// Crop just by modifying pointers.
y_plane += width * crop_y + crop_x;
uv_plane += uv_width * crop_y + crop_x;
rtc::scoped_refptr<I420Buffer> buffer =
buffer_pool_.CreateBuffer(adapted_width, adapted_height);
nv12toi420_scaler_.NV12ToI420Scale(
y_plane, width, uv_plane, uv_width * 2, crop_width, crop_height,
buffer->MutableDataY(), buffer->StrideY(),
// Swap U and V, since we have NV21, not NV12.
buffer->MutableDataV(), buffer->StrideV(), buffer->MutableDataU(),
buffer->StrideU(), buffer->width(), buffer->height());
// TODO: Rotate I420 frame 90 degrees clockwise.
rtc::scoped_refptr<I420Buffer> rotated_buffer =
I420Buffer::Rotate(*buffer, kVideoRotation_90);
OnFrame(VideoFrame(rotated_buffer, rotation, translated_camera_time_us));
}
我添加了这行代码来顺时针旋转 I420 框架 90 度。
// TODO: Rotate I420 frame 90 degrees clockwise.
rtc::scoped_refptr<I420Buffer> rotated_buffer =
I420Buffer::Rotate(*buffer, kVideoRotation_90);
如有任何帮助,我将不胜感激!
最佳答案
最后我想出了解决这个问题的方法。以下是我的步骤:
第 1 步:确保将流媒体 Activity 锁定为纵向
第2步:在WebRTC android native源码的文件中改这个方法~/webrtc/src/sdk/android/src/jni/androidvideotracksource.cc
原始版本:
void AndroidVideoTrackSource::OnByteBufferFrameCaptured(const void* frame_data,
int length,
int width,
int height,
VideoRotation rotation,
int64_t timestamp_ns) {
RTC_DCHECK(camera_thread_checker_.CalledOnValidThread());
int64_t camera_time_us = timestamp_ns / rtc::kNumNanosecsPerMicrosec;
int64_t translated_camera_time_us =
timestamp_aligner_.TranslateTimestamp(camera_time_us, rtc::TimeMicros());
int adapted_width;
int adapted_height;
int crop_width;
int crop_height;
int crop_x;
int crop_y;
if (!AdaptFrame(width, height, camera_time_us, &adapted_width,
&adapted_height, &crop_width, &crop_height, &crop_x,
&crop_y)) {
return;
}
const uint8_t* y_plane = static_cast<const uint8_t*>(frame_data);
const uint8_t* uv_plane = y_plane + width * height;
const int uv_width = (width + 1) / 2;
RTC_CHECK_GE(length, width * height + 2 * uv_width * ((height + 1) / 2));
// Can only crop at even pixels.
crop_x &= ~1;
crop_y &= ~1;
// Crop just by modifying pointers.
y_plane += width * crop_y + crop_x;
uv_plane += uv_width * crop_y + crop_x;
rtc::scoped_refptr<I420Buffer> buffer =
buffer_pool_.CreateBuffer(adapted_width, adapted_height);
nv12toi420_scaler_.NV12ToI420Scale(
y_plane, width, uv_plane, uv_width * 2, crop_width, crop_height,
buffer->MutableDataY(), buffer->StrideY(),
// Swap U and V, since we have NV21, not NV12.
buffer->MutableDataV(), buffer->StrideV(), buffer->MutableDataU(),
buffer->StrideU(), buffer->width(), buffer->height());
OnFrame(VideoFrame(rotated_buffer, rotation, translated_camera_time_us));
}
修改版本:
void AndroidVideoTrackSource::OnByteBufferFrameCaptured(const void* frame_data,
int length,
int width,
int height,
VideoRotation rotation,
int64_t timestamp_ns) {
RTC_DCHECK(camera_thread_checker_.CalledOnValidThread());
int64_t camera_time_us = timestamp_ns / rtc::kNumNanosecsPerMicrosec;
int64_t translated_camera_time_us =
timestamp_aligner_.TranslateTimestamp(camera_time_us, rtc::TimeMicros());
int adapted_width;
int adapted_height;
int crop_width;
int crop_height;
int crop_x;
int crop_y;
if (!AdaptFrame(width, height, camera_time_us, &adapted_width,
&adapted_height, &crop_width, &crop_height, &crop_x,
&crop_y)) {
return;
}
const uint8_t* y_plane = static_cast<const uint8_t*>(frame_data);
const uint8_t* uv_plane = y_plane + width * height;
const int uv_width = (width + 1) / 2;
RTC_CHECK_GE(length, width * height + 2 * uv_width * ((height + 1) / 2));
// Can only crop at even pixels.
crop_x &= ~1;
crop_y &= ~1;
// Crop just by modifying pointers.
y_plane += width * crop_y + crop_x;
uv_plane += uv_width * crop_y + crop_x;
rtc::scoped_refptr<I420Buffer> buffer =
buffer_pool_.CreateBuffer(adapted_width, adapted_height);
nv12toi420_scaler_.NV12ToI420Scale(
y_plane, width, uv_plane, uv_width * 2, crop_width, crop_height,
buffer->MutableDataY(), buffer->StrideY(),
// Swap U and V, since we have NV21, not NV12.
buffer->MutableDataV(), buffer->StrideV(), buffer->MutableDataU(),
buffer->StrideU(), buffer->width(), buffer->height());
// TODO: Comment out this line of code to apply custom code.
// OnFrame(VideoFrame(buffer, rotation, translated_camera_time_us));
// TODO: The custom code to rotate video frame before passing
// to next layers of WebRTC.
// Rotate I420 frame rotation degrees.
// Value of the rotation is 90 or 270 based on camera orientation.
rtc::scoped_refptr<I420Buffer> rotated_buffer =
I420Buffer::Rotate(*buffer, rotation);
// Make sure the I420 frame has valid side in portrait mode.
rtc::scoped_refptr<I420Buffer> final_buffer =
buffer_pool_.CreateBuffer(height, width);
final_buffer->ScaleFrom(*rotated_buffer);
// After rotating the I420 frame, set value of the rotation to 0.
// This mean we do not want to rotate the frame in next layers anymore.
rotation = kVideoRotation_0;
// Pass processed frame to the next layers.
OnFrame(VideoFrame(final_buffer, rotation, translated_camera_time_us));
}
现在我的流在 Streaming Wowza Engine Player 上完美显示。
关于Android - 在使用 WebRTC 发送到 Wowza Streaming Engine 之前旋转视频帧,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49869771/
是WebRTC Web 开发人员可以免费在网页上设置视频通话吗?为什么 Twilio 的视频通话定价为每分钟 25 美分,在网络托管服务器上管理视频通话对小家伙来说会不会太贵了? 任何深入 WebRT
webRTC 是根据 https://apprtc.appspot.com/ 实现的 PeerConnection webRTC 如何实现远程音视频流的同步? 最佳答案 使用 RTCP SR/RR 报
我正在尝试使用 webRTC,似乎对每条消息中可以发送的字节数有任意限制。 This guy我使用的示例选择了 100(加上一些)字节的限制。在我的测试中,它似乎接近 200 字节。但是从阅读 TCP
我目前正在测试 WebRTC 的功能,但我有一些脑逻辑问题。 WebRTC 究竟是什么? 我只读了“STUN”、“P2P”和其他...但是在技术方面什么是正确的 WebRTC(见下一个) 我需要什么
我目前正在使用 opentok 构建实时视频聊天医疗保健应用程序api,其技术主要建立在 WebRTC 上,并想知道如何处理整体安全方面。 最佳答案 简而言之,是的。所有 WebRTC 媒体流都经过加
WebRTC Reference App --> var errorMessages = []; var channelToken = 'AHRlWroGHj6YqW
我对浏览器中的点对点连接感兴趣。由于这对于 WebRTC 来说似乎是可能的,我想知道它是如何精确工作的。 我已经阅读了一些解释并看到了相关图表,现在我很清楚,连接建立是通过服务器进行的。服务器似乎在愿
我是 WebRTC 的初学者,我想知道是否需要导入任何内容才能使用 JavaScript API。 最佳答案 不,您不需要导入任何库。 webRTC 包含在 Chrome 和 Firefox 中(以及
我正在使用 WebRTC 来开发我的应用程序之一。 WebRTC 是否原生支持视频数据包的自适应比特率流,目前尚不清楚? VP8/VP9 是否支持自适应比特率编码? bitrate_controlle
是否可以通过 webRTC 捕获桌面屏幕共享。我们知道它只是捕获浏览器选项卡上的屏幕,但是否可以捕获整个桌面屏幕,例如浏览计算机上的文件或打开和查看文件,例如pdf等.. 最佳答案 目前,RTCWeb
我可以有两个单独的服务器用于托管和发送信号吗?还是仅在托管服务器中配置信令服务器更好? 最佳答案 托管 webrtc 信令服务器没有具体限制。如果需要,您可以将信令服务器与 Web 应用程序服务器分开
我想知道 WebRTC api 是否会自动更改带宽以增加体验。据我所知,WebRTC 具有更改和限制最大值的功能。带宽如我们所愿。我寻求答案的问题是我们应该手动执行此操作还是 WebRTC 无论如何都
如果在本地网络中的两个对等方之间建立了 WebRTC 连接,我们可以在失去与互联网的连接后维持它吗?这似乎是可能的,因为它是点对点的。 最佳答案 是的,有可能。对等方使用同一网络中的专用 IP 地址直
我正在尝试创建一个应用程序,该应用程序要求用户使用 webRTC 将其本地视频流发送到多个对等方。据我所知,我负责管理多个 PeerConnection 对象,因为 PeerConnection 一次
我想创建自己的视频聊天应用程序。我使用 WebRTC 框架。我阅读了一些教程,每个主题都假定存在信令 channel 。如何实现自己的信令 channel ? 最佳答案 由于目前没有为 WebRTC
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 想改进这个问题?将问题更新为 on-topic对于堆栈溢出。 6年前关闭。 Improve this qu
假设我有 2 个同行与 webRTC 交换视频。现在我需要将两个流都保存为中央服务器中的视频文件。是否可以实时进行? (存储/上传来自同行的视频不是一种选择)。 我想建立一个 3 节点 webRTC
WebRTC 信号让我发疯。我的用例非常简单:信息亭和控制室 webapp 之间的双向音频对讲。两台计算机都在同一个网络上。两者都没有互联网访问权限,所有机器都有已知的静态 IP。 我阅读的所有内容都
我知道我可以将宽度和高度设置为本地视频的约束。但是,我不确定如何通过 RTCPeerConnection 获取远程视频的宽度和高度。我用谷歌搜索了很多,但似乎没有得到任何有用的信息。我认为这应该是一个
我是 WebRTC 的新手,并试图弄清楚如何在浏览器之外创建一个程序,该程序接收 WebRTC 音频流并将其输出到扬声器上。 是否有适用于 Java 或 C# 的 WebRTC 库? 该接收器将在 l
我是一名优秀的程序员,十分优秀!