无法在Android中播放从LocalSocket收到的视频

时间:2013-02-24 09:05:06

标签: android sockets video android-mediarecorder

我正在尝试使用MediaRecorder仅录制视频(H264 / 3gpp),并将LocalSocket描述符传递给MediaRecorder。我可以接收数据,但无法播放视频。相同的代码适用于音频(AMR)。

LocalSocket类

public class MediaStreamer extends MediaRecorder{

    private static int id = 0;

    private LocalServerSocket lss = null;
    private LocalSocket receiver, sender = null;

    public void prepare() throws IllegalStateException,IOException {

        receiver = new LocalSocket();
        try {
            lss = new LocalServerSocket("librtp-"+id);
            receiver.connect(new LocalSocketAddress("librtp-"+id));
            receiver.setReceiveBufferSize(4096);
            receiver.setSendBufferSize(4096);
            sender = lss.accept();
            sender.setReceiveBufferSize(4096);
            sender.setSendBufferSize(4096); 
            id++;
        } catch (IOException e1) {
            throw new IOException("Can't create local socket !");
        }

        setOutputFile(sender.getFileDescriptor());

        try {
            super.prepare();
        } catch (IllegalStateException e) {
            closeSockets();
            throw e;
        } catch (IOException e) {
            closeSockets();
            throw e;
        }

    }

    public InputStream getInputStream() {

        InputStream out = null;

        try {
            out = receiver.getInputStream();
        } catch (IOException e) {
        }

        return out;

    }


    public void stop() {
        closeSockets();
        super.stop();
    }

    private void closeSockets() {
        if (lss!=null) {
            try {
                lss.close();
                sender.close();
                receiver.close();
            }
            catch (IOException e) {

            }
            lss = null; sender = null; receiver = null;
        }
    }
}

MediaRecorder

video = new MediaStreamer();
video.reset();

video.setVideoSource(MediaRecorder.VideoSource.DEFAULT);
video.setPreviewDisplay(holder.getSurface());
video.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
video.setVideoFrameRate(VideoConstants.frameRate);
video.setVideoEncodingBitRate(VideoConstants.bitRate*1000);
video.setVideoSize(VideoConstants.resolationX, VideoConstants.resolationY);
video.setVideoEncoder(MediaRecorder.VideoEncoder.H264);

try {
   video.prepare();
   videoWriter = new Writer(Environment.getExternalStorageDirectory()+"/video.mp4",video.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
video.start();
videoWriter.startWriting();

3 个答案:

答案 0 :(得分:1)

这个问题有点陈旧,但此刻我正在这个领域做一些工作,所以我想尝试添加一个可能有助于绊倒这种方式的人的答案。

这里的基本问题是3GPP(如MP4)不是实时的可流式格式,因此即使通过套接字捕获数据,通常在音频或视频捕获结束时写入的关键文件头,缺少(因为套接字不像本地文件那样可见) - 因此无法播放数据。

AMR没有此文件头限制,这就是为什么OP的录音可以正常使用上面的代码。

没有简单的方法对数据执行后处理以手动添加文件头。所以解决方案是:

  1. 不使用3GPP或MP4作为录制格式
  2. 编写类似于Spydroid project
  3. 中使用的分组器

    希望这有帮助。

答案 1 :(得分:1)

您需要删除MPEG4格式的标头。 localscoket的输入流包含MPEG4标头,需要将其删除才能访问视频。

检查Spydroid,它做类似的事情

答案 2 :(得分:1)

您可以使用此示例删除MP4标头:

InputStream reader = video.getInputStream();
byte buffer[] = new byte[4];
while (!Thread.interrupted()) {
   while (reader.read() != 'm');
      reader.read(buffer,0,3);
      if (buffer[0] == 'd' && buffer[1] == 'a' && buffer[2] == 't') break;
}

我在lib libstreaming(VideoStream.java)中看到过这段代码。是否与Spydroid中使用的lib相同。