2012-05-23 115 views
6

我试图通过本地Socket从Android的MediaRecorder发送h264/AAC视频。目标是通过RTMP或RTSP将视频发送到WOWZA服务器,但它给我带来了很多麻烦,现在我只是试图从LocalServerSocket将数据写入文件。从MediaRecorder通过LocalSocket流式传输视频

这是一些代码。对不起,它不是很干净,但我花了几个小时来测试很多事情,现在我的项目很混乱。

在摄像头活动,将输出文件设置:

LocalSocket outSocket = new LocalSocket(); 

try { 
    outSocket.connect(new LocalSocketAddress(LOCAL_SOCKET)); 
} catch (Exception e) { 
    Log.i(LOG_TAG, "Error connecting socket: "+e); 
} 
mMediaRecorder.setOutputFile(outSocket.getFileDescriptor()); 

的LocalServerSocket实现:

try { 
    mLocalServerSocket = new LocalServerSocket(mName); 
} catch (Exception e) { 
    Log.e(LOG_TAG, "Error creating server socket: "+e); 
    return; 
} 

while (true) { 

    File out = null; 
    FileOutputStream fop = null; 
    try { 
     mLocalClientSocket = mLocalServerSocket.accept(); 

     InputStream in = mLocalClientSocket.getInputStream(); 

     out = new File(mContext.getExternalFilesDir(null), "testfile.mp4"); 
     fop = new FileOutputStream(out); 

     int len = 0; 
     byte[] buffer = new byte[1024]; 
     while ((len = in.read(buffer)) >= 0) { 

      Log.i(LOG_TAG, "Writing "+len+" bytes"); 
      fop.write(buffer, 0, len); 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    finally{ 
     try { 
      fop.close(); 
      mLocalClientSocket.close(); 
     } catch (Exception e2) {} 
    } 
} 

的问题是,由此产生的文件是不会被任何媒体播放器可读。你认为这是由于编码问题?如果我理解得很好,这段代码应该生成一个二进制文件?!

在此先感谢,欢呼声。

+0

如果您没有得到错误,它可能是由编码/文件名问题引起的。你设置了什么[OutputFormat](http://developer.android.com/reference/android/media/MediaRecorder.OutputFormat.html)?也许将其重命名为'.3gp'或者帮助 - 请参阅[这里](http://stackoverflow.com/questions/9110711/android-mediarecorder-getting-3gp-instead-of-mpeg4) – zapl

+0

输出格式是MPEG_4,所以我想应该用.mp4扩展名来确定。此外,如果我直接写入mMediaRecorder.setOutputFile()中的.mp4文件,它可以很好地工作。 – Simon

+0

是否检查过像[mediainfo](http://mediainfo.sourceforge.net/en)这样的内容是否可以读取已创建视频的属性?你也可以尝试直接生成的文件的二进制比较(至少是头文件),并通过本地套接字发送文件以检查生成的文件是否正确。 – zapl

回答

2

好的,我找到了文件无法播放的原因。在MP4和3GPP文件,存在含有该字节的头部:

ftyp3gp4 3gp43gp6宽的mdat之前

在HEX

0000001866747970336770340000030033677034336770360000000877696465000392D86D6461740000

的4个字节'mdat'标签代表位于其他'moov'标签的位置文件结尾。位置通常是在录制结束时设置的,但由于MediaRecorder无法查找套接字,因此无法将这些字节设置为正确的值。

我现在的问题是要找到一种方法来制作这样的文件流式传输,因为它涉及它在录制结束之前播放。

+3

你有没有找到一个解决方案,使其流传? – Houf

+0

嗨西蒙,你有没有找到一些解决方法..请分享它,我在同一问题stucking –

+0

嗨Ankita。对不起,我们现在放弃了这个项目,所以我停止了解这个问题。祝你好运,欢呼。 – Simon

1

你可以尝试使用mp4box来重构你的文件。 moov框给出了每个音频和视频样本的索引。如果该文件位于文件末尾,则很难传输。

这可能帮助: http://boliston.wordpress.com/tag/moov-box/

或者这样: mp4box -inter 0.5 some_file.mp4

(我没有目前有尝试的机会),如果您需要这

与您的应用程序一起工作,我不知道任何将mp4box移植到Android的活动。

+0

BTW mp4box是GPAC项目的一部分。至少在Ubuntu中有一个包。 http://gpac.wp.mines-telecom.fr/ –

0

我今天尝试做同样的事情,但mp4不是很容易流(如前所述,一些部分写在最后)。我没有说这是不可能的,但似乎至少很难。

因此,解决更新的Android API(4。3)可能是这一个:

  • 将相机预览到表面纹理:camera.setPreviewTexture
  • 记录此纹理使用OpenGL和MediaCodex +复用器

这种解决方案的缺点是相机的预览大小可能小于视频大小。这意味着取决于您的设备,您无法以最高分辨率录制。提示:有些相机说他们不支持更高的预览尺寸,但是他们可以,并且您可以尝试配置相机以将预览尺寸设置为视频尺寸。如果这样做,请捕获camera.setParameters的RuntimeException,如果失败,则只使用支持的预览大小。

一些链接如何从表面纹理记录:

Bigflage: great examples for MediaCodec stuff.

The VideoRecorder class from Lablet.

也可能是有用的:spydroid-IPCAMERA从MediaRecorder插座为RTP流流中的数据,但我没有发现任何将其提供给MediaCodec的方法。 (我已经被困在读取正确的NAL单元大小,因为他们这样做...)