通过android来录制视频并通过socket方式传到服务器上保存文件(3gp文件)不能播放。
需求:通过android来录制视频并通过socket方式传到服务器上保存文件(3gp文件)。
问题:保存到服务器的3gp文件,手机播放器打不开,3gp文件编码不正确。
备注:保存在手机的本地系统中,3gp文件编码格式正确,手机播放器能打开。
并通过AtomicParsley工具还查看已录制视频文件编码格式:
android录制视频的代码:
try
{
socket = new Socket(InetAddress.getByName(hostname), port);
}
catch (UnknownHostException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
mMediaRecorder = new MediaRecorder();
// 设置以流方式输出
mMediaRecorder.setOutputFile(pfd.getFileDescriptor());
mMediaRecorder.setPreviewDisplay(mSu易做图ceHolder.getSu易做图ce());
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mMediaRecorder.setVideoSize(176, 144);
mMediaRecorder.setVideoFrameRate(15);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mMediaRecorder.setMaxDuration(10000);
服务端代码:
public MultiThreadServer() throws IOException
{
serverSocket = new ServerSocket(port);
// Runtime的availableProcessor()方法返回当前系统的CPU数目.
executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * POOL_SIZE);
System.out.println("服务器启动");
}
public void service()
{
while (true)
{
Socket socket = null;
try
{
// 接收客户连接,只要客户进行了连接,就会触发accept();从而建立连接
socket = serverSocket.accept();
//executorService.execute(new Handler(socket));
new Thread(new Handler(socket)).start();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
Handler代码:
public Handler(Socket socket)
{
this.socket = socket;
d = new File("D:/ds");
if (!d.exists())
{
d.mkdirs();
}
try
{
store = File.createTempFile("sdsd", ".3gp", d);
fos = new FileOutputStream(store);
socketIn = socket.getInputStream();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void run()
{
try
{
System.out.println("New connection accepted " + socket.getInetAddress() + ":" + socket.getPort());
while ((length = socketIn.read(buffer)) != -1)
{
fos.write(buffer, 0, length);
fos.flush();
System.out.println("正在写入中。。。。" + length);
}
fos.flush();
store = null;
socketIn.close();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
try
{
fos.close();
fos = null;
store = null;
if (socket != null)
socket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
System.out.println("-----------------------------完毕");
}
大家帮我看看是什么原因造成的,在此谢谢了。给于高分!!!
--------------------------------------------------------------------------------
引用地址http://www.iteye.com/problems/27244
本人也是这个问题。具体原因在网上找了很多的关于这个问题的。知道问题的原因但是没有具体解决方案和代码例子
问题的原因总结如下:
通过socket接收的视频流与直接写在本地文件的视频流数据有点不一样,因为是通过socket传输,就无法对视频文件的回写,
通常MediaRecorder结束录像的时候都会对视频文件进行回写处理,这样才可以被播放器播放。所以通过socket接受到的数
据,保存下来是无法播放的。16进制方式查看了一下其输出文件,发现其前32byte都是00,紧接着就是mdat。问题就出现在这
了:缺少了一个ftyp box 的描述(28 bytes)以及mdat的长度描述(4 bytes).网上已经有人顺利解决这样的问题,在数据中
查找moov的起始位置,发现前面会有ftyp的描述,长度刚刚好28bytes。你可以copy这28bytes到文件开始的28byte中。这ftyp
的描述是从moov的起始位置 的前32byte开始一直到前4byte(后面4byte是moov的长度描述)。然后mdat的长度就是 moov的起始
位置 减去 0x20,道理就不解释了。然后把这个值写到mdat的前面4byte。刚刚好填满32byte,之后就能顺利播放了。
本篇文章来源于 Linux公社网站(www.linuxidc.com) 原文链接:http://www.linuxidc.com/Linux/2011-04/34467.htm --------------------编程问答-------------------- 自己顶起,有那位高手给出具体解决办法和例子。本人在这里谢过。大家一起交流 --------------------编程问答--------------------
楼主问题解决了么?我现在也在纠结 --------------------编程问答-------------------- mMediaRecorder.setOutputFile(pfd.getFileDescriptor());
mMediaRecorder.setPreviewDisplay(mSu易做图ceHolder.getSu易做图ce());
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mMediaRecorder.setVideoSize(176, 144);
mMediaRecorder.setVideoFrameRate(15);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mMediaRecorder.setMaxDuration(10000);
楼主干嘛要以这样转换成流的形式传输呢?
直接用File函数得到一个文件,用getByte方法得到比特流,dos.write写入就行了。服务器再用dis.read接收,完全没问题,只不过要自己重新命名。 --------------------编程问答--------------------
你这样的话其实效率会减低很多啊,因为你还要写到文件中去,增加了一个过程。 --------------------编程问答-------------------- 楼主你好,请问你这个问题解决了吗我也遇到这个问题,请赐教
补充:移动开发 , Android