1

我正在尝试使用 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;
        }
    }
}

媒体记录器

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();
4

3 回答 3

1

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

检查 Spydroid,它做类似的事情

于 2014-01-09T06:05:52.307 回答
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 中使用的库相同。

于 2014-06-10T12:00:45.677 回答
1

这个问题有点老了,但我目前正在这方面做一些工作,所以我想我会尝试添加一个答案,这可能会帮助那些以这种方式绊倒的人。

这里的根本问题是 3GPP(如 MP4)不是实时的、可流式传输的格式,因此即使通过套接字捕获数据,通常在音频或视频捕获结束时写入的关键文件头也会丢失(因为套接字不像本地文件那样是可搜索的) - 因此是不可播放的数据。

AMR 没有此文件头限制,这就是为什么 OP 的录音可以与上面的代码一起正常工作的原因。

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

  1. 不要使用 3GPP 或 MP4 作为录制格式
  2. 编写一个类似于Spydroid 项目中使用的打包器

希望这可以帮助。

于 2013-08-30T05:10:28.560 回答