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


    }
}

 

35 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!.

  9. I have been a yahoo individuals for some years now. I am just beginning to make use of the devices which they give, among which being article. I have actually created a blog and wants to understand if my post are being seen by others. If not then does any person recognize exactly how I obtain my blogs posts review.

  10. Where can I find reputable blog sites that are concentrated on or at the very least dig seriously into penis enlargement?

  11. Isnt it strange that these stories are only now surfacing? You folks really showed your hand by remarking on his personality. You dont like his style as a person, so you just thought that youd point out that (you think) hes a jerk.
    Burning tongue and lips

  12. Simply obtained a Blogger account, it functions excellent, yet exactly how do I discover various users blogs I like with search. I bear in mind there is a way, however I am not seeing it now. Thanks for your aid.

  13. Just how do I begin a blog under a pen-name as well as maintain my anonymity. Just how do you then get regular readers?

  14. I’ve been trying to find blogs where blog writer covers penis enhancement or a minimum of looks into the subject of penis enlargement with an independent as well as severe voice. What are the leading blogs of this type?.

  15. Reflexology sessions typically last about 30 to 60 minutes and may incorporate balls, brushes and dowels to achieve the desired effect. There is no regulation of reflexology in the United States, but there is a certification board that requires the therapist have at least 200 hours of education at a recognized institution.
    Reflexology techniques

  16. img_back_hernia. コメントを残す コメントをキャンセル. メールアドレスが公開されることはありません。 * が付いている欄は必須項目です. コメント. 名前 * メールアドレス * サイト. 最近の投
    educational attainment

  17. I’ve had the brownish/pink mucus for a few days; ovulation was last week.. it’s early for a home pregnancy test but I did anyway – couldn’t contain myself! but knew it’d likely be negative and it was. really hoping to have a positive pregnancy test in the next couple of weeks.
    Tea tree oil for yeast infection

  18. I obtained 2 networked blog site setting of a solitary blog site in facebook. I wish to delete of them. Is there any type of means to delete only one networked blog maintaining the one more as it is?.

  19. I like reviewing individual blog sites, Mommy blogs, etc. What is the very best method to find these sorts of blogs online? The most effective method I have is simply adhering to faves people have – mosting likely to one blog owners “faves” after that the following blog owners faves, etc … I have actually tried Google Blogsearch but all that offers me is old newspaper article, and so on. Nothing individual whatsoever … Exactly how do you search for individual blog sites?.

  20. 95 24/7 Support Instant Start IG Power likes Free Video Views Buy Now 500 likes $ 4. https://krootez.com Packages & Prices 100 Real views Delay your views No Password Required Instant Delivery 24/7 Support $1. Instead of manually liking other people’s Instagram videos and photos, we’ve made it fully automatic.

发表评论

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