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();
//        }


    }
}

 

29 Comments

  1. Obat Benjolan Di Payudara

    Thank you for the information, and healthy greetings.

    http://obatbenjolandipayudara.idkes.com/

    Reply
  2. Public Health

    Great blog right here! Additionally your web site rather a lot up fast! What web host are you the use of? Can I am getting your affiliate hyperlink in your host? I wish my website loaded up as fast as yours lol

    Reply
  3. cad

    Very good post. I will be going through some of these issues as well..|

    Reply
  4. india outsourcing

    Good day I am so thrilled I found your blog page, I really found you by error, while I was researching on Digg for something else, Nonetheless I am here now and would just like to say thank you for a tremendous post and a all round interesting blog (I also love the theme/design), I don’t have time to browse it all at the minute but I have book-marked it and also added your RSS feeds, so when I have time I will be back to read a great deal more, Please do keep up the fantastic work.

    Reply
  5. Auto Care and Service

    Fantastic beat ! I wish to apprentice while you amend your site, how could i subscribe for a blog website? The account aided me a acceptable deal. I had been tiny bit acquainted of this your broadcast provided bright clear idea

    Reply
  6. Travel International

    Excellent goods from you, man. I’ve understand your stuff previous to and you’re just extremely wonderful. I really like what you have acquired here, really like what you are stating and the way in which you say it. You make it entertaining and you still care for to keep it sensible. I can not wait to read much more from you. This is actually a tremendous web site.

    Reply
  7. Education and Training

    Great – I should certainly pronounce, impressed with your website. I had no trouble navigating through all the tabs as well as related info ended up being truly simple to do to access. I recently found what I hoped for before you know it at all. Quite unusual. Is likely to appreciate it for those who add forums or anything, website theme . a tones way for your customer to communicate. Excellent task.

    Reply
  8. buy instagram followers

    This is a topic that is near to my heart Best wishes! Exactly where are your contact details though?

    Reply
  9. kenapa bayi 1 tahun susah makan

    Greetings from Los angeles! I’m bored to death at work so I decided to browse your website on my iphone during lunch break.
    I love the knowledge you present here and can’t wait
    to take a look when I get home. I’m surprised at how fast your
    blog loaded on my cell phone .. I’m not even using WIFI, just 3G ..
    Anyways, very good site!

    Reply
  10. Used Car Dealerships

    Howdy very cool web site!! Man .. Excellent .. Superb .. I’ll bookmark your website and take the feeds also¡KI am glad to seek out numerous useful information right here within the submit, we want work out more strategies in this regard, thanks for sharing. . . . . .

    Reply
  11. buy instagram views

    I think this is a real great post.Really looking forward to read more. Will read on

    Reply
  12. quran meaning

    Wow, great blog.Really looking forward to read more. Will read on

    Reply
  13. Education and Training

    Only a smiling visitant here to share the love (:, btw great pattern .

    Reply
  14. Business & Finance

    I was just looking for this info for some time. After 6 hours of continuous Googleing, at last I got it in your website. I wonder what’s the lack of Google strategy that don’t rank this kind of informative web sites in top of the list. Usually the top web sites are full of garbage.

    Reply
  15. Business & Finance

    Great beat ! I would like to apprentice while you amend your web site, how could i subscribe for a blog web site? The account aided me a acceptable deal. I had been tiny bit acquainted of this your broadcast provided bright clear idea

    Reply
  16. Car & Automotive

    Thank you for the good writeup. It in fact was a amusement account it. Look advanced to more added agreeable from you! However, how can we communicate?

    Reply
  17. Car & Automotive

    Wow! Thank you! I constantly needed to write on my site something like that. Can I include a portion of your post to my site?

    Reply
  18. Car & Automotive

    I’m still learning from you, but I’m improving myself. I absolutely liked reading everything that is posted on your website.Keep the information coming. I enjoyed it!

    Reply
  19. Arts & Entertainments

    Thank you so much for giving everyone an extraordinarily marvellous possiblity to check tips from here. It is usually so pleasurable plus full of amusement for me personally and my office mates to search your web site the equivalent of thrice in 7 days to learn the new things you have. And of course, I am also at all times satisfied concerning the eye-popping tactics served by you. Selected 4 tips on this page are clearly the finest we’ve ever had.

    Reply
  20. Travel International

    I just couldn’t leave your website prior to suggesting that I actually enjoyed the standard information an individual supply on your guests? Is going to be back frequently to check up on new posts.

    Reply
  21. Better Health

    Its like you read my mind! You appear to know a lot about this, like you wrote the book in it or something. I think that you can do with some pics to drive the message home a little bit, but other than that, this is wonderful blog. A fantastic read. I will definitely be back.

    Reply
  22. Lawsuit

    Hi there, just became alert to your blog through Google, and found that it is really informative. I am going to watch out for brussels. I’ll be grateful if you continue this in future. Numerous people will be benefited from your writing. Cheers!

    Reply
  23. Education

    Nice read, I just passed this onto a colleague who was doing some research on that. And he actually bought me lunch as I found it for him smile Thus let me rephrase that: Thanks for lunch! “He who walks in another’s tracks leaves no footprints.” by Joan Brannon.

    Reply
  24. Education

    I really enjoy looking at on this website , it holds great posts . “Sometime they’ll give a war and nobody will come.” by Carl Sandburg.

    Reply
  25. Education

    I have been absent for a while, but now I remember why I used to love this website. Thanks, I will try and check back more frequently. How frequently you update your website?

    Reply
  26. Education

    I really enjoy looking at on this web site , it has got superb posts . “The great secret of power is never to will to do more than you can accomplish.” by Henrik Ibsen.

    Reply
  27. Education

    Utterly indited content material, Really enjoyed looking at.

    Reply
  28. chainsaw facts

    I really liked your blog.Much thanks again. Great.

    Reply

Leave a Comment

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