android 录像本地网络传输保存成mp4文件

Posted 红尘六欲

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android 录像本地网络传输保存成mp4文件相关的知识,希望对你有一定的参考价值。

android 录像本地网络传输保存成mp4文件

说明

通过MediaRecorder加LocalSocket实现本地网络传输,再通过其它硬件接口(非网络接口)将mp4数据传送到PC端稍微处理一下
保存成播放器能正常播放的mp4文件,如果设备与服务器有网络连接可以直接跳过本记录使用android-libstreaming
通过libstreaming的例子1设置目标地址为本机127.0.0.1测试了一两次好像不行,放弃了。
本记录只适合录像时间比较固定,同时录像时间不能太长的应用

系统源码修改

源码路径frameworks/av/media/libstagefright/MPEG4Writer.cpp
1.函数MPEG4Writer::MPEG4Writer(int fd)

// Verify mFd is seekable
off64_t off = lseek64(mFd, 0, SEEK_SET);
if (off < 0) 
    ALOGE("cannot seek mFd: %s (%d)", strerror(errno), errno);
    //release();

注释掉其中的release,android5以下没有这个判断可以不用管

2.函数int64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate)

static const int64_t MAX_MOOV_BOX_SIZE = (3000000 * 6LL / 8000) * 1800;//(180 * 3000000 * 6LL / 8000); modify 3minutes to 30 minutes

修改MAX_MOOV_BOX_SIZE最大为30分钟计算的大小
如果只改第1个地方,针对录像时间小于15秒左右最后保存的文件经过处理能正常播放,但大于15秒后,时间越长moovbox内容越多,最后回写的次数无法确定,不好处理。

应用软件

有些变量,可自行定义

public final static String SOCKET_ADDR = "com.gzease.camera";

1.mediarecorder设置,部分代码

  mMediaRecorder.setCamera(mCamera);
  CamcorderProfile mProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_480P);
  mMediaRecorder.setAudiosource(MediaRecorder.AudioSource.MIC);
  mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
  mMediaRecorder.setOutputFormat(mProfile.fileFormat);
  mMediaRecorder.setVideoEncodingBitRate(mProfile.videoBitRate);
  mMediaRecorder.setVideoEncoder(mProfile.videoCodec);
  mMediaRecorder.setVideoSize(mProfile.videoFrameWidth, mProfile.videoFrameHeight);
  mMediaRecorder.setVideoFrameRate(mProfile.videoFrameRate);
  mMediaRecorder.setAudioEncodingBitRate(mProfile.audioBitRate);
  mMediaRecorder.setAudioChannels(mProfile.audioChannels);
  mMediaRecorder.setAudioSamplingRate(mProfile.audioSampleRate);
  mMediaRecorder.setAudioEncoder(mProfile.audioCodec);
  mMediaRecorder.setMaxDuration(0);
  mMediaRecorder.setMaxFileSize(300*1024*1024);
  mMediaRecorder.setOrientationHint(90);
  mMediaRecorder.setPreviewDisplay(mSurfaceHolder != null ? mSurfaceHolder.getSurface() : null);
  if(DataBase.hasCamEnCodeStream) 
      DataBase.CamFileSize = 0;
      if(usbLocalSocket)
          mMediaRecorder.setOutputFile(localServer.getLocalSocket().getFileDescriptor());
      else
          mMediaRecorder.setOutputFile(mParcelWrite.getFileDescriptor());
   else 
      File file = new File(DataBase.PATH_VIDEOFILE);
      if (file.exists())
          file.delete();
      try 
          fos = new FileOutputStream(DataBase.PATH_VIDEOFILE);
          //mMediaRecorder.setOutputFile(DataBase.PATH_VIDEOFILE);
          mMediaRecorder.setOutputFile(fos.getFD());
       catch (FileNotFoundException e) 
          e.printStackTrace();
       catch (IOException e) 
          e.printStackTrace();
      
  

  new LogTools(TAG, "startVideoRecording setOutputFile : " + DataBase.PATH_VIDEOFILE);
  try 
      mMediaRecorder.prepare();
      mMediaRecorder.start();
   catch (IOException e) 
      e.printStackTrace();
      new LogTools().e(TAG, "startVideoRecording exception : " + e.getMessage());
      releaseVideoRecorder();
  

一定要调用setMaxFileSize设置文件最大大小,不然系统mpeg4write中moovBox是按最小值处理,会影响最终处理流程

2.localserver

package com.gzease.CameraTools;

import android.net.LocalServerSocket;
import android.net.LocalSocket;

import com.gzease.tools.DataBase;
import com.gzease.tools.LogTools;

import java.io.IOException;
import java.io.InputStream;

public class LocalServer extends Thread
    private final String TAG = "LocalServer";
    private final int debug = DataBase.D_LEVEL_OUT;

    private LocalServerSocket server;
    private boolean isRun = true;
    private boolean isConnect = false;
    private LocalSocket localSocket;
    @Override
    public void run() 
        super.run();
        try 
            server = new LocalServerSocket(DataBase.SOCKET_ADDR);
            new LogTools(TAG," accept start",debug);
            localSocket = server.accept();
            new LogTools(TAG," accept end",debug);
            isConnect = true;
         catch (IOException e) 
            e.printStackTrace();
        

    

    public LocalSocket getLocalSocket() 
        new LogTools(TAG," getLocalSocket isConnect:" + isConnect,debug);
        if(isConnect)
            return localSocket;
        else
            return null;
    

    @Override
    public void interrupt() 
        super.interrupt();
        isRun = false;
    

3.localclient

package com.gzease.CameraTools;

import android.net.LocalSocket;
import android.net.LocalSocketAddress;

import com.gzease.tools.DataBase;
import com.gzease.tools.LogTools;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;

public class LocalClient extends Thread
    private static final String TAG = "LocalClient";
    private static final int debug = DataBase.D_LEVEL_OUT;
    private InputStream mInStream=null;
    private LocalSocket localSocket;
    private ReadThread readThread;
    private boolean hasWriteFile = false;
    private static String fileName = "/sdcard/test.mp4";
    private static String destFileName = "/sdcard/test1.mp4";
    @Override
    public void run() 
        super.run();
        try 
            Thread.sleep(1000);
            localSocket = new LocalSocket();
            new LogTools(TAG, "connect start",debug);
            localSocket.connect(new LocalSocketAddress(DataBase.SOCKET_ADDR));
            new LogTools(TAG, "connect end",debug);
            mInStream = localSocket.getInputStream();
            if(mInStream != null) 
                readThread = new ReadThread();
                readThread.start();
            
         catch (IOException e) 
            e.printStackTrace();
         catch (InterruptedException e) 
            e.printStackTrace();
        

    

    public LocalSocket getLocalSocket() 
        if(mInStream != null)
            return  localSocket;
        else
            return null;
    

    @Override
    public void interrupt() 
        super.interrupt();
        if(readThread != null)
            readThread.interrupt();
    

    class ReadThread extends Thread 
        private boolean isRun = true;
        @Override
        public void run() 
            super.run();
            try 
                while (isRun) 
                    //byte[] buffer = new byte[1024 * 1024];
                    byte[] buffer = new byte[5 * 1024];
                    int size = mInStream.read(buffer);
                    if(size > 0) 
                        if(hasWriteFile) 
                            if(DataBase.CamFileSize == 0) 
                                File file = new File(fileName);
                                if(file.exists())
                                    file.delete();
                            
                            toFile(buffer,size);
                         else
                            sendtoPc(buffer,size);
                        DataBase.CamFileSize += size;
                        new LogTools(TAG," DataBase.CamFileSize:" + DataBase.CamFileSize,debug);
                     else 
                        this.interrupt();
                    
                
             catch (IOException e) 
                e.printStackTrace();
            
        

        @Override
        public void interrupt() 
            super.interrupt();
            isRun = false;
        
    

    private void sendtoPc(byte[] buf,int size) 
    

    private void toFile(byte[] buf,int size) 
        try 
            // 打开一个随机访问文件流,按读写方式
            RandomAccessFile randomFile = new RandomAccessFile(fileName, "rw");
            // 文件长度,字节数
            long fileLength = randomFile.length();
            // 将写文件指针移到文件尾。
            randomFile.seek(fileLength);
            randomFile.write(buf,0,size);
            randomFile.close();
         catch (IOException e) 
            e.printStackTrace();
        
    

    public static void DealFile() 
        RandomAccessFile srcfile = null;
        RandomAccessFile destfile = null;
        long starttime,endtime;
        starttime = System.currentTimeMillis();
        new LogTools(TAG,"start time :" + starttime,debug);
        try 
            File file = new File(fileName);
            File file1 = new File(destFileName);
            if(file1.exists())
                file1.delete();
            srcfile = new RandomAccessFile(fileName, "r");
            destfile = new RandomAccessFile(destFileName, "rw");
            new LogTools(TAG,"filelen :" + file.length(),debug);
            srcfile.seek(24);//rewrite head
            destfile.writeInt(srcfile.readInt());
            srcfile.seek(4);
            byte[] dat = new byte[20];//writeFtypBox ftyp+mp42+0000+isom+mp42
            srcfile.read(dat);
            destfile.write(dat);
            long moovStart = searchEndStr(fileName,"moov");
            new LogTools(TAG,"moovStart:" + moovStart,debug);
            srcfile.seek(moovStart - 4);
            int moovSize = srcfile.readInt();
            destfile.writeInt(moovSize);
            dat = new byte[moovSize - 4];
            srcfile.read(dat);
            destfile.write(dat);
            srcfile.seek(file.length() - 8);
            int freeSize = srcfile.readInt();
            new LogTools(TAG,"freeSize:" + Integer.toHexString(freeSize),debug);
            destfile.writeInt(freeSize);//4
            destfile.write("free".getBytes());//4
            dat = new byte[freeSize - 4 - 4];
            destfile.write(dat);
            srcfile.seek(moovStart - 8);//media data size
            int mediaDataSize = srcfile.readInt();
            destfile.writeInt(mediaDataSize);//write media data size
            srcfile.seek(40);
            mediaDataSize -= 4;//start from mdat
            while (true) 
                byte[] mdat = new byte[100*1024];
                srcfile.read(mdat);
                if(mediaDataSize > mdat.length) 
                    mediaDataSize -= mdat.length;
                    destfile.write(mdat);
                 else 
                    destfile.write(mdat,0,mediaDataSize);
                    mediaDataSize = 0;
                
                new LogTools(TAG,"media size1:" + mediaDataSize,debug);
                if(mediaDataSize <= 0)
                    break;
            
            srcfile.android 录像本地网络传输保存成mp4文件

android 录像本地网络传输保存成mp4文件优化

android 录像本地网络传输保存成mp4文件优化

android 录像本地网络传输保存成mp4文件优化

5.3Android Studio录像

VLC拉网络流保存成本地视频