WOWZA到IOS-如何直播流
到目前为止,我几乎为IOS开发了一款Flash Air应用程序,完成了50%。我使用RED5媒体服务器获得了所有的实时流媒体,但当我发现iPhone摄像头显示90度时,我就陷入了死胡同,因此发送并保存到RED5服务器的流也被记录为90度。我在网上读了很多关于堆栈溢出的文章,说这是一个已知的Bug。不确定何时会修复此问题。我还尝试了一些可以在我的Air应用程序中实现相机旋转的ANE Air原生扩展,这些是DiaDraw和StarlingCamera ANE,但在网上找不到任何信息教程,因此无法实现 Flash Adobe Air for IOS代码,连接到RED5服务器并显示iPhone摄像头为90度:WOWZA到IOS-如何直播流,ios,wowza,Ios,Wowza,到目前为止,我几乎为IOS开发了一款Flash Air应用程序,完成了50%。我使用RED5媒体服务器获得了所有的实时流媒体,但当我发现iPhone摄像头显示90度时,我就陷入了死胡同,因此发送并保存到RED5服务器的流也被记录为90度。我在网上读了很多关于堆栈溢出的文章,说这是一个已知的Bug。不确定何时会修复此问题。我还尝试了一些可以在我的Air应用程序中实现相机旋转的ANE Air原生扩展,这些是DiaDraw和StarlingCamera ANE,但在网上找不到任何信息教程,因此无法实现
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.ActivityEvent;
import flash.events.MouseEvent;
import flash.media.Camera;
import flash.media.Video;
import flash.events.NetStatusEvent;
import flash.net.NetStream;
import flash.net.NetConnection;
var nc:NetConnection;
var cam:Camera;
var vid:Video;
var nsOut:NetStream;
var nsIn:NetStream;
// support autoOrients
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
cam = Camera.getCamera();
cam.setMode(320, 300, 25);
cam.setQuality(0,100);
if (!cam)
{
txt.text ="No camera is installed.";
}
else
{
nc = new NetConnection();
nc.connect("rtmp://192.168.1.5/RED5Hugt");
nc.addEventListener(NetStatusEvent.NET_STATUS,getStream);
nc.client = this;
//connectCamera();
}
function getStream(e:NetStatusEvent):void
{
connectCamera();
nsIn = new NetStream(nc);
nsOut = new NetStream(nc);
vid.attachNetStream(nsIn);
nsIn.play("tester");
nsOut=new NetStream(nc);
netOut.attachAudio(mic);
nsOut.attachCamera(cam);
nsOut.publish("tester", "live");
// add click event to record button
// add event for stage video render state
}
function connectCamera():void
{
vid = new Video();
vid.width = cam.width;
vid.height = cam.height;
vid.x = 0;
vid.y = 0;
vid.attachCamera(cam);
addChild(vid);
//stage.addEventListener(MouseEvent.CLICK, clickHandler);
}
function clickHandler(e:MouseEvent):void
{
return;
switch (cam.width) {
case 160:
cam.setMode(320, 240, 10);
break;
case 320:
cam.setMode(640, 480, 5);
break;
default:
cam.setMode(160, 120, 15);
break;
}
removeChild(vid);
connectCamera();
}
RED5服务器代码:
package com;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
import org.red5.server.adapter.ApplicationAdapter;
import org.red5.server.adapter.MultiThreadedApplicationAdapter;
import org.red5.server.api.IClient;
import org.red5.server.api.IConnection;
import org.red5.server.api.Red5;
import org.red5.server.api.scope.IScope;
import org.red5.server.api.service.IPendingServiceCall;
import org.red5.server.api.service.IPendingServiceCallback;
import org.red5.server.api.service.IServiceCapableConnection;
import org.red5.server.api.service.IServiceHandlerProvider;
import org.red5.server.api.stream.IBroadcastStream;
import org.red5.server.api.stream.IServerStream;
import org.red5.server.api.stream.support.SimplePlayItem;
import org.red5.server.api.stream.support.StreamUtils;
import org.red5.server.stream.ClientBroadcastStream;
import org.red5.server.stream.RecordingListener;
import static java.lang.System.*;
public class Application extends MultiThreadedApplicationAdapter{
//private static final Log log = LogFactory.getLog( Application.class );
private IBroadcastStream serverStream;
@Override
public boolean appStart(IScope scope)
{
if(!super.appStart(scope))
{
return false;
}
else
{
super.appStart(scope);
return true;
}
}
@Override
public void appStop(IScope scope)
{
}
//User connecting/disconnecting to/from application
@Override
public boolean appConnect(IConnection connection, Object[] parameters) {
super.appConnect(connection, parameters);
//connection.getClient().setAttribute("userName", parameters[0]);
return true;
}
@Override
public void appDisconnect(IConnection connection) {
super.appDisconnect(connection);
}
//User joining/leaving scope
@Override
public boolean appJoin(IClient client, IScope scope)
{
super.appJoin(client, scope);
return true;
}
@Override
public void appLeave(IClient client, IScope scope)
{
super.appLeave(client,scope);
}
public boolean connect(IConnection conn, IScope scope, Object[] params) {
super.connect(conn, scope, params);
return true;
}
}
于是我决定以本机方式进行流式传输,我使用objective-c中的媒体和CommLib库找到了这段代码,我将其粘贴到了Pastebin上,因为粘贴到这里时有太多的代码需要编辑:
这是成功连接到另一台PC上运行的RED5 Java应用程序适配器的RTMP客户端
当使用Xcode运行RTMP客户端时,应用程序正在进行流媒体直播,但每隔几秒钟音频就会出现故障,我无法找到任何可以解决此问题的方法,可能我需要更改一些代码,但我在线找到了此RTMP客户端代码,并修改了流名称和RTMP Url,以指向我在RED5服务器上的应用程序
为什么音频一直有问题。所以现在我想试试WOWZA媒体服务器
到目前为止,我下载了Wowza媒体服务器,然后安装了Eclipse。安装Eclipse之后,我安装了Wowza IDE,我在Eclipse中安装了该IDE,但请确保在安装Wowza IDE之前先安装Wowza媒体服务器
然后我在网上找到了一些代码,可能是在Wowza服务器上运行的服务器,新的Wowza服务器是在浏览器中运行的,我尝试在终端上运行此代码,但无法运行,因为它在终端上一直说“操作无法运行”
这是我用于服务器的代码:
package com;
import com.wowza.wms.application.*;
import com.wowza.wms.amf.*;
import com.wowza.wms.client.*;
import com.wowza.wms.module.*;
import com.wowza.wms.request.*;
import com.wowza.wms.stream.*;
import com.wowza.wms.rtp.model.*;
import com.wowza.wms.httpstreamer.model.*;
import com.wowza.wms.httpstreamer.cupertinostreaming.httpstreamer.*;
import com.wowza.wms.httpstreamer.smoothstreaming.httpstreamer.*;
public class RED5Hugt extends ModuleBase {
public void doSomething(IClient client, RequestFunction function,
AMFDataList params) {
getLogger().info("doSomething");
sendResult(client, params, "Hello Wowza");
}
public void onAppStart(IApplicationInstance appInstance) {
String fullname = appInstance.getApplication().getName() + "/"
+ appInstance.getName();
getLogger().info("onAppStart: " + fullname);
}
public void onAppStop(IApplicationInstance appInstance) {
String fullname = appInstance.getApplication().getName() + "/"
+ appInstance.getName();
getLogger().info("onAppStop: " + fullname);
}
public void onConnect(IClient client, RequestFunction function,
AMFDataList params) {
getLogger().info("onConnect: " + client.getClientId());
}
public void onConnectAccept(IClient client) {
getLogger().info("onConnectAccept: " + client.getClientId());
}
public void onConnectReject(IClient client) {
getLogger().info("onConnectReject: " + client.getClientId());
}
public void onDisconnect(IClient client) {
getLogger().info("onDisconnect: " + client.getClientId());
}
public void onStreamCreate(IMediaStream stream) {
getLogger().info("onStreamCreate: " + stream.getSrc());
}
public void onStreamDestroy(IMediaStream stream) {
getLogger().info("onStreamDestroy: " + stream.getSrc());
}
}
所以现在我运行Xcode项目RTMP客户机,发现RTMP客户机确实连接了,但没有实时流。我只是想问我需要在哪里修改代码才能让流媒体直播正常工作
另外,根据我使用AdobeAIR for IOS和使用RED5的经验,我是否应该选择这最后一条路线,因为我不确定。我做了很多研究,我真的很想找到一种免费的方式来了解如何从IPhone摄像头中播放流媒体。我试过AdobeForiOS到RED5服务器,发现有一个已知的Bug,我试过RED5的原生版本,发现了音频故障,那么Wowza是最好的选择吗
更新
我在Xcode控制台中得到一个无法找到流的输出,以下是输出:
2014-07-30 13:33:06.246 RTMPStreamComeback[340:4003] $$$$$$ <MPIMediaStreamEvent> stateChangedEvent: sender = MediaStreamPlayer, 4 = NetStream.Play.StreamNotFound
但是,就像RED5一样,音频似乎出现了故障,但除了音频,流从未中断
我怎样才能解决这个问题
这是来自Xcode的跟踪:
2014-07-30 15:19:48.296 RTMPStreamComeback[397:60b] connectControl: host = rtmp://192.168.1.4:1935/RED5Hugt
2014-07-30 15:19:49.325 RTMPStreamComeback[397:60b] Video encoding is initialized: bit_rate = 272000, rc_max_rate = 0, rc_min_rate = 0, qmin=2, qmax=31, qcompress=0.500000
2014-07-30 15:19:49.334 RTMPStreamComeback[397:60b] AudioCodec: codecID = 86050, codecType = 42, bitRate = 16000, _sampleBytes = 4
encoder supports the sample formats:
flt,
audio codec best options: sample_rate = 44100
2014-07-30 15:19:49.340 RTMPStreamComeback[397:60b] audio codec context: codec_type = 1, sample_fmt = flt, bit_rate = 16000, sample_rate = 16000, channels = 1, frame_bits = 4, channel_layout = 0, frame_size = 0, buffer_size = 256
2014-07-30 15:19:49.344 RTMPStreamComeback[397:60b] initVideoCapture -> preset AVCaptureSessionPresetLow is supported, orientation = 3
2014-07-30 15:19:49.414 RTMPStreamComeback[397:60b] BroadcastStreamClient STREAM ----> name: tester, type: 2, [socket retainCount] = 3
2014-07-30 15:19:49.789 RTMPStreamComeback[397:60b] $$$$$$ <MPIMediaStreamEvent> stateChangedEvent: sender = BroadcastStreamClient, 1 = RTMP.Client.isConnected
2014-07-30 15:19:49.831 RTMPStreamComeback[397:3f03] $$$$$$ <MPIMediaStreamEvent> stateChangedEvent: sender = BroadcastStreamClient, 2 = RTMP.Client.Stream.isCreated
2014-07-30 15:19:50.585 RTMPStreamComeback[397:3f03] $$$$$$ <MPIMediaStreamEvent> stateChangedEvent: sender = BroadcastStreamClient, 3 = NetStream.Publish.Start
[flv @ 0x1883d000] Error, Invalid timestamp=0, last=0
[flv @ 0x1883d000] Error, Invalid timestamp=0, last=0
[flv @ 0x1883d000] Error, Invalid timestamp=0, last=0
2014-07-30 15:20:01.677 RTMPStreamComeback[397:60b] publishControl: stream = slavav
2014-07-30 15:20:01.680 RTMPStreamComeback[397:60b] NellyMoserDecoder -> audio codec context: codec_type = 1, sample_fmt = flt, bit_rate = 16000, sample_rate = 16000, channels = 1, frame_bits = 4, channel_layout = 0, frame_size = 0
2014-07-30 15:20:01.681 RTMPStreamComeback[397:60b] Set Player's Framework -> 'AudioUnit'
2014-07-30 15:20:01.685 RTMPStreamComeback[397:60b] VideoStream decoding is initialized: context->pix_fmt = 0, width = 0, height = 0
2014-07-30 15:20:01.689 RTMPStreamComeback[397:60b] $$$$$$ <MPIMediaStreamEvent> stateChangedEvent: sender = MediaStreamPlayer, 1 = RTMP.Client.isConnected
2014-07-30 15:20:01.712 RTMPStreamComeback[397:3f03] $$$$$$ <MPIMediaStreamEvent> stateChangedEvent: sender = MediaStreamPlayer, 2 = RTMP.Client.Stream.isCreated
2014-07-30 15:20:01.758 RTMPStreamComeback[397:3f03] $$$$$$ <MPIMediaStreamEvent> stateChangedEvent: sender = MediaStreamPlayer, 3 = NetStream.Play.Start
[flv @ 0x1808c600] Bad picture start code
[flv @ 0x1808c600] header damaged
2014-07-30 15:20:01.764 RTMPStreamComeback[397:3f03] VideoStream -> decodeFrame: (ERROR) got_packet = 0, processed_size = -1
[swscaler @ 0x2e38000] No accelerated colorspace conversion found from yuv420p to bgra.
2014-07-30 15:20:01.775 RTMPStreamComeback[397:7a03] MPAudioUnitEngine -> nextFrame: < NO PCM - WHITE NOISE > timestamp = 11192, dropWhiteNoise = 0
2014-07-30 15:20:01.799 RTMPStreamComeback[397:7a03] MPAudioUnitEngine -> nextFrame: < NO PCM - WHITE NOISE > timestamp = 11215, dropWhiteNoise = 0
2014-07-30 15:20:01.821 RTMPStreamComeback[397:7a03] MPAudioUnitEngine -> nextFrame: < NO PCM - WHITE NOISE > timestamp = 11238, dropWhiteNoise = 0
2014-07-30 15:20:01.845 RTMPStreamComeback[397:7a03] MPAudioUnitEngine -> nextFrame: < NO PCM - WHITE NOISE > timestamp = 11261, dropWhiteNoise = 0
2014-07-30 15:20:01.867 RTMPStreamComeback[397:7a03] MPAudioUnitEngine -> nextFrame: < NO PCM - WHITE NOISE > timestamp = 11284, dropWhiteNoise = 0
[flv @ 0x1808c600] Bad picture start code
[flv @ 0x1808c600] header damaged
2014-07-30 15:20:01.888 RTMPStreamComeback[397:3f03] VideoStream -> decodeFrame: (ERROR) got_packet = 0, processed_size = -1
2014-07-30 15:23:31.088 RTMPStreamComeback[397:3f03] MPAudioUnitEngine -> dropPcm: *** DROPPED = 320, dropWhiteNoise = 8600, pcm.remaining = 16036
2014-07-30 15:23:31.090 RTMPStreamComeback[397:3f03] MPAudioUnitEngine -> dropPcm: *** DROPPED = 1024, dropWhiteNoise = 7576, pcm.remaining = 16036
2014-07-30 15:23:31.093 RTMPStreamComeback[397:3f03] MPAudioUnitEngine -> dropPcm: *** DROPPED = 2048, dropWhiteNoise = 5528, pcm.remaining = 16036
2014-07-30 15:23:31.164 RTMPStreamComeback[397:3f03] MPAudioUnitEngine -> dropPcm: *** DROPPED = 640, dropWhiteNoise = 4888, pcm.remaining = 16056
2014-07-30 15:23:31.219 RTMPStreamComeback[397:3f03] MPAudioUnitEngine -> dropPcm: *** DROPPED = 128, dropWhiteNoise = 4760, pcm.remaining = 16028
2014-07-30 15:23:31.298 RTMPStreamComeback[397:3f03] MPAudioUnitEngine -> dropPcm: *** DROPPED = 192, dropWhiteNoise = 4568, pcm.remaining = 16036
2014-07-30 15:23:31.604 RTMPStreamComeback[397:3f03] MPAudioUnitEngine -> dropPcm: *** DROPPED = 128, dropWhiteNoise = 4440, pcm.remaining = 16048
2014-07-30 15:23:31.740 RTMPStreamComeback[397:3f03] MPAudioUnitEngine -> dropPcm: *** DROPPED = 320, dropWhiteNoise = 4120, pcm.remaining = 16024
2014-07-30 15:23:32.296 RTMPStreamComeback[397:3f03] MPAudioUnitEngine -> dropPcm: *** DROPPED = 192, dropWhiteNoise = 3928, pcm.remaining = 16008
2014-07-30 15:24:47.575 RTMPStreamComeback[397:3f03] MPAudioUnitEngine -> dropPcm: *** DROPPED = 64, dropWhiteNoise = 3864, pcm.remaining = 16000
还建议:
Currently the library does not provide an instrument to control the stream quality. This is planned for a future release.
因此,我认为这不可能改变音频流格式我认为问题可能在于所选的音频编解码器;如果你有能力改变一个选择,我建议尝试mp3在44100kHzThanks Mondain我现在看看
Audio:
codec - Nelly Mozer 16KHz, mono
bitrate - 128000
Video:
codec - H.263 (Sorenson)
bitrate - 200000
resolution - 192x144px
fps = 25
intra frame - 10
Currently the library does not provide an instrument to control the stream quality. This is planned for a future release.