Android 录制的视频封包flv

public class ReadT implements Runnable {

    private String filename;
    private boolean stop;

    private FileDescriptor fd;
    private BufferedOutputStream bos;
    private String name;
    private byte[] cdata;

    public ReadT(String filename, String name, byte[] cdata) {
        this.filename = filename;
        this.name = name;
        this.cdata = cdata;
    }

    public void setBos(OutputStream os) {
        bos = new BufferedOutputStream(os);
    }

    public ReadT(FileDescriptor fd) {
        this.fd = fd;
    }

    public static byte[] int2Byte(int v) {
        byte[] b = new byte[4];
        b[0] = (byte) ((v >>> 24) & 0xFF);
        b[1] = (byte) ((v >>> 16) & 0xFF);
        b[2] = (byte) ((v >>> 8) & 0xFF);
        b[3] = (byte) ((v >>> 0) & 0xFF);
        return b;
    }

    @Override
    public void run() {
        byte[] tmp = new byte[8192];

        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            FileInputStream fi = null;

            fi = new FileInputStream(filename);

            int skip = 6152;   // android 2.2 是 0
            if(android.os.Build.VERSION.RELEASE.startsWith("2.2"))
                skip = 0;
            int len = 0;
            while (skip > 0) {
                len = fi.read(tmp, 0, skip - len);
                if (len > -1)
                    skip -= len;
                else {
                    Thread.sleep(200);
                }

            }

            bos.write(int2Byte(name.getBytes().length));    // 服务器根据这个值获取name长度
            bos.write(name.getBytes());
            bos.write(int2Byte(cdata.length));    // 服务器根据这个值获取name长度
            bos.write(cdata);


            while (!stop) {

                len = fi.read(tmp);
                if (len < 0) {
                    Thread.sleep(100);
                } else {
                    bos.write(tmp, 0, len);

                }
            }
            bos.flush();
            bos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }


    }



    public void setStop(boolean stop) {
        this.stop = stop;
    }

    private static byte[] hex2byte(String s) throws Exception {
        char c, c1;
        int x;
        if (s.length() % 2 != 0)
            throw new Exception("密钥格式不正确");
        byte[] ret = new byte[s.length() / 2];

        for (int i = 0; i < s.length(); i++) {
            c = s.charAt(i);
            c1 = s.charAt(++i);
            if (!(c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f'))
                throw new Exception("密钥格式不正确");
            if (!(c1 >= '0' && c1 <= '9' || c1 >= 'A' && c1 <= 'F' || c1 >= 'a' && c1 <= 'f'))
                throw new Exception("密钥格式不正确");
            x = Integer.decode("0x" + c + c1).intValue();
            if (x > 127) {
                ret[i / 2] = (byte) (x | 0xffffff00);
            } else {
                ret[i / 2] = (byte) (x);
            }
        }
        return ret;
    }
}

 

 

public class KernelHandler implements Runnable {
    //Local data loopback
    private Socket receiver;

    private boolean connected = true;

    public static Map<String, FlvProperties> FLV_PROPER = new HashMap<String, FlvProperties>();


    private long frameDuration;


    public TopicPublisher publisher;

    //internal video buffer and frame timing
    VideoBuffer videoBuffer = null;
    TimeStampEstimator frameTimeStamp = null;



    public FlvProperties getFlvProperties(byte[] buf) {
        MediaDetect.getHeaderData(buf);
        MediaPackage.buildVideoHeader(MediaDetect.spsData, MediaDetect.spsDataLength, MediaDetect.ppsData, MediaDetect.ppsDataLength);

        return new FlvProperties(MediaPackage.FlvHeader, MediaPackage.videoHeader);
    }

    public static int bytes2int(byte b[]) {
        int s = 0;
        s = ((((b[0] & 0xff) << 8 | (b[1] & 0xff)) << 8) | (b[2] & 0xff)) << 8
                | (b[3] & 0xff);
        return s;
    }

    public KernelHandler(Socket socket, long duration) {

        receiver = socket;
        frameDuration = duration;

        if (videoBuffer == null)
            videoBuffer = new VideoBuffer(128, 64 * 1024);                //about two seconds
        if (frameTimeStamp == null)
            frameTimeStamp = new TimeStampEstimator(frameDuration);


    }


    public void repareStreaming() {

        videoBuffer.reset();
        frameTimeStamp.reset(frameDuration);
    }


    public int getVideoFlag() {
        return videoBuffer.getVideoFlag();
    }

    public long getTimeStamp() {
        return videoBuffer.getTimeStamp();
    }

    public byte[] getReadBuffer() {
        return videoBuffer.getReadBuffer();
    }

    public int getReadLength() {
        return videoBuffer.getReadLength();
    }

    public void releaseRead() {
        videoBuffer.releaseRead();
    }


    public void run() {

        System.out.println("client  connect !");
        InputStream fis;
        final int frame_size = 64 * 1024;
        byte[] buffer = new byte[frame_size];
        int dlen;
        int package_size;

        //Create video byte stream object
        try {
            fis = receiver.getInputStream();
            fillBuffer(buffer, 0, 4, fis);   //  读取取客户端名字参数长度
            int namelength = bytes2int(buffer);
            System.out.println("--client len---" + namelength);
            fillBuffer(buffer, 0, namelength, fis);
            String clientname = new String(buffer, 0, namelength);
            System.out.println(namelength + "--clientname---" + clientname);
            fillBuffer(buffer, 0, 4, fis);   //   读取取H264参数长度
            int headlength = bytes2int(buffer);
            byte[] cdata = new byte[headlength];
            fillBuffer(cdata, 0, headlength, fis);
            //CDATA_PS.put(clientname, cdata);
            FLV_PROPER.put(clientname, getFlvProperties(cdata));
            try {
                publisher = new TopicPublisher(clientname);
                new Thread(new Distribution()).start();
            } catch (Exception e) {
                e.printStackTrace();
            }

            /*
            File targetFLV = new File("/sdcard/temp.flv");
            localFLV = new FileOutputStream(targetFLV);

            localFLV.write(MediaPackage.FlvHeader);
            MediaPackage.buildVideoHeader(MediaDetect.spsData, MediaDetect.spsDataLength, MediaDetect.ppsData, MediaDetect.ppsDataLength );
            localFLV.write(MediaPackage.videoHeader);
            */

        } catch (Exception e1) {
            System.out.println("Create video byte stream object error");
            e1.printStackTrace();
            return;
        }

        //jump header offset
        try {
            dlen = -1;
            dlen = fillBuffer(buffer, 0, 32,fis);
            if (dlen != 32) {
                fis.close();
                return;
            }
            //System.out.println("-------------header:"+dlen);
        } catch (IOException e) {
            System.out.println("header offset error");
            e.printStackTrace();
            return;
        }

        //First frame duration computing
        frameTimeStamp.setFirstFrameTiming();

        while (true) {
            dlen = fillBuffer(buffer, 0, 4, fis);
            //System.out.println("-------------header   size:"+dlen);
            if (dlen != 4) {
                break;
            }

            package_size = (buffer[1] & 0xFF) * 65536 + (buffer[2] & 0xFF) * 256 + (buffer[3] & 0xFF);
            //System.out.println("-------------package_size:"+package_size);
            dlen = fillBuffer(buffer, 4, package_size, fis);
            //System.out.println("-------------dlen = fillBuffer:"+dlen);
            if (dlen != package_size) {

                break;
            }

            while (true) {
                //System.out.println("-------------package buffer list");
                if (videoBuffer.isEmptySpace()) {
                    // System.out.println("-------------videoBuffer add");
                    addNewPackage(buffer, package_size + 4);   //每接收到一个视频包放入缓冲
                    break;
                }

                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }


            }


        }

        try {
            receiver.close();
            connected = false;
            publisher.close();
            System.out.println("connect close");
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private void addNewPackage(byte[] buf, int size) {
        videoBuffer.writeFrame(buf, size, frameTimeStamp.getSequenceTimeStamp(), 0);
        frameTimeStamp.update();
    }

    private int fillBuffer(byte[] buf, int offset, int size, InputStream fis) {
        int dlen;
        int buf_len = 0;
        int target_size = size;
        while (target_size > 0) {
            try {
                dlen = fis.read(buf, offset + buf_len, target_size);
            } catch (IOException e) {
                e.printStackTrace();
                return -1;
            }

            if (dlen >= 0) {
                buf_len += dlen;
                target_size -= dlen;
            } else {
                return -1;
            }
        }

        return size;
    }

    //Video Ring Buffer manager
    public class VideoBuffer {
        private class VideoPackage {
            byte[] data;
            int size;
            boolean flag;
            int vflag;
            long ts;
        }

        VideoPackage[] buffers;

        int readIndex = 0;
        int writeIndex = 0;

        public VideoBuffer(int bufferNum, int pkgSize) {
            buffers = new VideoPackage[bufferNum];

            for (int i = 0; i < bufferNum; i++) {
                VideoPackage vPkg = new VideoPackage();
                vPkg.data = new byte[pkgSize];
                buffers[i] = vPkg;
            }
            reset();
        }

        public void reset() {
            for (int i = 0; i < buffers.length; i++) {
                VideoPackage vPkg = buffers[i];
                vPkg.size = 0;
                vPkg.flag = false;
                vPkg.ts = 0;
            }
            readIndex = 0;
            writeIndex = 0;
        }

        private void updateWriteIndex() {
            if (writeIndex < (buffers.length - 1))
                writeIndex++;
            else
                writeIndex = 0;
        }

        public int getVideoFlag() {
            VideoPackage vPkg = buffers[readIndex];
            if (vPkg.flag == true)
                return vPkg.vflag;

            return -1;
        }

        public long getTimeStamp() {
            VideoPackage vPkg = buffers[readIndex];
            if (vPkg.flag == true)
                return vPkg.ts;

            return 0;
        }

        public byte[] getReadBuffer() {
            VideoPackage vPkg = buffers[readIndex];
            if (vPkg.flag == true)
                return vPkg.data;

            return null;
        }

        public int getReadLength() {
            VideoPackage vPkg = buffers[readIndex];
            if (vPkg.flag == true)
                return vPkg.size;

            return -1;
        }

        public void releaseRead() {
            synchronized (this) {
                VideoPackage vPkg = buffers[readIndex];
                if (vPkg.flag == false)
                    return;

                vPkg.flag = false;

                if (readIndex < (buffers.length - 1))
                    readIndex++;
                else
                    readIndex = 0;
            }
        }

        public boolean isEmptySpace() {
            VideoPackage vPkg = buffers[writeIndex];
            if (vPkg.flag == true)
                return false;

            return true;
        }

        public boolean writeFrame(byte[] newData, int size, long ts, int vflag) {

            VideoPackage vPkg = buffers[writeIndex];
            if (vPkg.flag == true)
                return false;

            System.arraycopy(newData, 0, vPkg.data, 0, size);
            vPkg.size = size;
            vPkg.ts = ts;
            vPkg.vflag = vflag;

            synchronized (this) {
                vPkg.flag = true;
                updateWriteIndex();
                return true;
            }
        }

    }


    //Frame smooth timestamp generator
    class TimeStampEstimator {
        final int durationHistoryLength = 2048;
        private long durationHistory[];
        int durationHistoryIndex = 0;
        long durationHistorySum = 0;
        long lastFrameTiming = 0;
        long sequenceDuration = 0;

        public void update() {
            long currentFrameTiming = System.currentTimeMillis();
            long newDuration = currentFrameTiming - lastFrameTiming;
            lastFrameTiming = currentFrameTiming;

            durationHistorySum -= durationHistory[durationHistoryIndex];
            durationHistorySum += newDuration;
            durationHistory[durationHistoryIndex] = newDuration;
            durationHistoryIndex++;
            if (durationHistoryIndex >= durationHistoryLength)
                durationHistoryIndex = 0;

            //毫秒为单位
            sequenceDuration += (int) ((1.0 * durationHistorySum / durationHistoryLength));
        }

        public void setFirstFrameTiming() {
            lastFrameTiming = System.currentTimeMillis() - durationHistorySum / durationHistoryLength;
            sequenceDuration = 0;
        }

        public long getSequenceTimeStamp() {
            return sequenceDuration;
        }

        public void reset(long frameDuration) {
            if (durationHistory == null)
                durationHistory = new long[durationHistoryLength];
            durationHistorySum = 0;
            for (int i = 0; i < durationHistoryLength; i++) {
                durationHistory[i] = frameDuration;            //us
                durationHistorySum += frameDuration;
            }

            lastFrameTiming = 0;
            sequenceDuration = 0;
            durationHistoryIndex = 0;
        }

        public TimeStampEstimator(long frameDuration) {
            reset(frameDuration);
        }
    }


    public class Distribution implements Runnable {

        @Override
        public void run() {
            doStreaming(null);
        }
    }




    public void doStreaming(OutputStream os) {

        // BufferedOutputStream targetOS = new BufferedOutputStream(os, 64);


        byte[] videoBuffer = new byte[1024 * 64];
        int videoLen;

        byte[] tempBuffer;
        int vflag;
        long ts;
        int tempSize;

        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        while (connected) {
//            if (oslist.size() > 0) {
            tempBuffer = getReadBuffer();   //缓冲里读取
            if (tempBuffer != null) {

                vflag = getVideoFlag();
                ts = getTimeStamp();
                tempSize = getReadLength();

                //建立 flv 视频包
                videoLen = MediaPackage.buildFlvPackage(tempBuffer, tempSize, ts, vflag, videoBuffer);

                releaseRead();

                try {
                    publisher.publish(videoBuffer, videoLen);   //视频重新打包,推送进activemq

                } catch (Exception e) {
                    e.printStackTrace();
                    break;
                }

            } else {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
//            }
        }

//        try {
//            targetOS.close();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }


    }
}

 

12 thoughts on “Android 录制的视频封包flv”

  1. I just arrived in Chiang Mai. I wanted to post on my blog, at Blogspot, but all of the headings are now in Thai, not English. Is the problem with my computer, or the hotel’s wi-fi service, or what? How can I get things back to English again?.

  2. I was thinking of starting a blog so I did some research into it on the internet and came across a lot of stuff that talks about legal issues and blogging. I’m not planning on blogging about controversial issues, (my blog would focus on posts about books, movies, culture, theater, music etc, and all material would be solely my own opinions) so what legal issues are involved with blogging? . Should I write a copyright disclaimer or are blog disclaimers actually worthless?.

  3. BittAPI permite: • Verificar su saldo de Bittrex con un solo clic • Realizar sus pedidos de compra / venta • Realizar un seguimiento de sus pedidos
    servicios de google
    El subaru forester rediseГ±ado todavГ­a pone la funciГіn antes que la forma para que todos la disfruten: las predicciones de litecoin del condado de montgomery bitcoin ethereum

  4. When you think of a facial, do you think of massage and layers of moisturizer? Many people do. What they should be thinking about is results. A medical facial
    deep chemical peel before and after
    Fabrication of a White-Light-Emitting Diode by Doping Gallium into ZnO Nanowire on a p-GaN Substrate – The Journal of Physical Chemistry C (ACS Publice Books

  5. I’m looking for out what the most prominent blog sites are when it comes to news as well as sights and mobile phone stuff.

  6. Dubai es una tierra de leche y miel que ofrece oportunidades ilimitadas para cualquiera que haga su mejor trabajo. La ciudad mГЎs poblada de los Emiratos
    social security
    UzbekistГЎn turismo audiencia de seguridad social discapacidad audiencia Obtenga una nueva tarjeta de seguridad social, nГєmero de telГ©fono de seguridad social, cambio de nombre de seguridad social, oficina de administraciГіn de seguridad social, oficinas de seguridad social

  7. A girl from pune when met an accident around five months before with four wheeler, no one expected that she would win the race against life. She met some
    pelvic tilt
    Npo bill fraught with challenges – plp leader the tribune escoliosis sintomas

  8. I am brand-new to website design as I have no prior experience and also understand little HTML. I just would like to know what the most effective software application is to acquire to develop blog sites. I have actually downloaded and install CS5 Layout Costs with Dreamweaver and Photoshop, but I realize this is a little innovative for me and also costly!!!. Does anyone have ideas of software or methods to construct blog sites and also websites quickly and also cost-effective?. MANY THANKS!.

发表评论

电子邮件地址不会被公开。 必填项已用*标注