精华内容
下载资源
问答
  • 1、通过网址读取mp4流来判断ftyp、free、mdat、moov。新建文件destFile,然后: a、下载ftyp的全部到newFile b、下载moov全部到newFile c、写mdat大小的数据到newFIle d、等b和c都完成之后(因b和c这两步的先后...

    解决思路:
    1、通过网址读取mp4流的关键字来判断ftyp、free、mdat、moov。新建文件destFile,然后:
    a、下载ftyp的全部到newFile
    b、下载moov全部到newFile
    c、写mdat大小的空白数据到newFIle
    d、等b和c都完成之后(因b和c这两步的先后不确定),再重新定位mp4流到mdat部分,下载56k(大小可以自行设定,这里我设的是56k)的数据到newFile,然后通知播放端开始播放视频(就用MediaPlayer.setDataSource(newfile)方法),后台下载端继续将最后部分mdat数据完全下载到newFile,即完成mp4数据的下载

    代码如下

    import java.io.BufferedInputStream;
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.RandomAccessFile;
    import java.io.UnsupportedEncodingException;
    import java.net.HttpURLConnection;
    import java.net.URL;
    
    /**
     * Created by Administrator on 2017/11/16.
     */
    
    public class Mp4DownloadUtils {
        /**
         * 播放MP4消息
         */
        public static final int PLAYER_MP4_MSG = 0x1001;
        /**
         * 下载MP4完成
         */
        public static final int DOWNLOAD_MP4_COMPLETION = 0x1002;
        /**
         * 下载MP4失败
         */
        public static final int DOWNLOAD_MP4_FAIL = 0x1003;
        /**
         * 下载MP4进度
         */
        public static final int DOWNLOAD_MP4_LOADING_PROCESS = 0x1004;
    
        /**
         * 下载MP4文件
         *
         * @param url
         * @param fileName
         * @param handler
         * @return
         */
        public static File downloadMp4File(final String url, final String fileName,
                                           final Handler handler) {
            final File mp4File = new File(fileName);
            downloadVideoToFile(url, mp4File, handler);
            return mp4File;
        }
    
        /**
         * 下载视频数据到文件
         *
         * @param url
         * @param dstFile
         */
        private static final int BUFFER_SIZE = 4 * 1024;
    
        static boolean isRunning = true;
        static Thread thread;
        public static void kill(){
            if (thread!=null){
                isRunning = false;
                thread.interrupt();
            }
        }
    
        /**
         * @param url:mp4文件url
         * @param dstFile:下载后缓存文件
         * @param handler: 通知UI主线程的handler
         */
        private static void downloadVideoToFile(final String url, final File dstFile, final Handler handler) {
             isRunning = true;
             thread = new Thread() {
                 InputStream is = null;
                 RandomAccessFile raf = null;
                 BufferedInputStream bis = null;
                @Override
                public void run() {
                    super.run();
                    try {
                        URL request = new URL(url);
                        HttpURLConnection httpConn = (HttpURLConnection) request.openConnection();
                        httpConn.setConnectTimeout(3000);
                        httpConn.setDefaultUseCaches(false);
                        httpConn.setRequestMethod("GET");
    //                    httpConn.setRequestProperty("Charset", "UTF-8");
    //                    httpConn.setRequestProperty("Accept-Encoding", "identity");
    
                        int responseCode = httpConn.getResponseCode();
                        Log.d("chy", responseCode + "");
                        if ((responseCode == HttpURLConnection.HTTP_OK)) {//链接成功
                            // 获取文件总长度
    //                        int totalLength = httpConn.getContentLength();
                            is = httpConn.getInputStream();
    
                            if (dstFile.exists()) {
                                dstFile.delete();
                            }
                            //新建缓存文件
                            dstFile.createNewFile();
                            raf = new RandomAccessFile(dstFile, "rw");
                            bis = new BufferedInputStream(is);
                            int readSize;
    
    
                            //读取Mp4流
                            int mdatSize = 0;// mp4的mdat长度
                            int headSize = 0;// mp4从流里已经读取的长度
                            int mdatMark = 0;//mdat的标记位置
                            byte[] boxSizeBuf = new byte[4];
                            byte[] boxTypeBuf = new byte[4];
                            // 由MP4的文件格式读取
                            int boxSize = readBoxSize(bis, boxSizeBuf);
                            String boxType = readBoxType(bis, boxTypeBuf);
                            raf.write(boxSizeBuf);
                            raf.write(boxTypeBuf);
    
                            boolean isMoovRead = false;
                            boolean isMdatRead = false;
                            boolean isftypRead = false;
                            byte[] buffer = new byte[BUFFER_SIZE];
                            //判断ftyp、free、mdat、moov 并下载
                            while (isRunning &&!Thread.currentThread().isInterrupted()) {
                                int count = boxSize - 8;
                                if (boxType.equalsIgnoreCase("ftyp")) {
                                    headSize += boxSize;
                                    byte[] ftyps = new byte[count];
                                    bis.read(ftyps, 0, count);
                                    raf.write(ftyps, 0, count);
                                    isftypRead = true;
                                    LogUtils.getInstance().i("ftyp ok");
                                } else if (boxType.equalsIgnoreCase("mdat")) {
                                    headSize += boxSize;
                                    //正常模式
                                    mdatSize = boxSize - 8;
                                    int dealSize = mdatSize;
                                    //填充mdata大小的空白数据到dstFile,先填充destFile的大小
                                    while (dealSize > 0) {
                                        if (dealSize > BUFFER_SIZE)
                                            raf.write(buffer);
                                        else
                                            raf.write(buffer, 0, dealSize);
                                        dealSize -= BUFFER_SIZE;
                                    }
    
                                    if(isMoovRead){//moov在mdat的前面,已经下载
                                        //下载mdat到dest
                                        downLoadMadta(bis,mdatSize,raf,headSize - boxSize+ 8,handler);
                                        bis.close();
                                        is.close();
                                        raf.close();
                                        httpConn.disconnect();
                                        return;
                                    }else {//moov在mdat的后面
                                        //下载moov到dest 与mp4服务器端重新连接一个通道,专门下载moov部分
                                        downLoadMoov(url,headSize,raf);
                                        //从destFile的起点开始,下载mdat到destFile
                                        downLoadMadta(bis,mdatSize,raf,headSize - boxSize+ 8,handler);
                                        bis.close();
                                        is.close();
                                        raf.close();
                                        httpConn.disconnect();
                                        return;
                                    }
                                } else if (boxType.equalsIgnoreCase("free")) {
                                    headSize += boxSize;
                                } else if (boxType.equalsIgnoreCase("moov")) {
                                    Log.d("chy","moov size:"+boxSize);
                                    headSize += boxSize;
                                    int moovSize = count;
                                    while (moovSize > 0) {
                                        if (moovSize > BUFFER_SIZE) {
                                            readSize = bis.read(buffer);
                                        } else {
                                            readSize = bis.read(buffer, 0, moovSize);
                                        }
                                        if (readSize == -1) break;
                                        raf.write(buffer, 0, readSize);
                                        moovSize -= readSize;
                                    }
                                    isMoovRead = true;
                                    LogUtils.getInstance().i("moov ok");
                                }
                                if (isftypRead && isMoovRead && isMdatRead) {
                                    break;
                                }
                                boxSize = readBoxSize(bis, boxSizeBuf);
                                boxType = readBoxType(bis, boxTypeBuf);
                                LogUtils.getInstance().i("boxSize:"+boxSize+" boxType:"+boxType);
                                raf.write(boxSizeBuf);
                                raf.write(boxTypeBuf);
                            }
                        }else {
                            sendMessage(handler, DOWNLOAD_MP4_FAIL, null);
                            is.close();
                            bis.close();
                            raf.close();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        this.interrupt();  //中断这个分线程
                        sendMessage(handler, DOWNLOAD_MP4_FAIL, null);
    
                        try {
                            if (is!=null && bis != null && raf != null){
                                is.close();
                                bis.close();
                                raf.close();
                            }
                        } catch (IOException e1) {
                            e1.printStackTrace();
                        }
    
                    }
                }
    
            };
            thread.start();
    //        thread = null;
        }
    
        /** 此函数只有在确定moov在mdat的后面才可以调用
         * @param url:mp4服务器地址
         * @param begin:mdat的末点,也就是moov的起点。
         * */
        private static void downLoadMoov(final String url, int begin, RandomAccessFile raf){
            HttpURLConnection httpConn = null;
            InputStream is = null;
            BufferedInputStream bis = null;
            try {
                LogUtils.getInstance().i("downLoadMoov");
                URL request = new URL(url);
                httpConn = (HttpURLConnection) request.openConnection();
                httpConn.setConnectTimeout(3000);
                httpConn.setDefaultUseCaches(false);
                httpConn.setRequestMethod("GET");
                httpConn.setRequestProperty("range", "bytes=" + begin + "-");
                is = httpConn.getInputStream();
                bis = new BufferedInputStream(is);
                int readSize =0;
                int headSize = 0;// mp4从流里已经读取的长度
                byte[] boxSizeBuf = new byte[4];
                byte[] boxTypeBuf= new byte[4];
                // 由MP4的文件格式读取
                int boxSize = readBoxSize(bis, boxSizeBuf);
                String boxType = readBoxType(bis, boxTypeBuf);
                raf.write(boxSizeBuf);
                raf.write(boxTypeBuf);
                int count =0;
                byte[] buffer = new byte[4*1024];
                while(true) {
                    count = boxSize - 8;
                    if (boxType.equalsIgnoreCase("free")) {
                        headSize += boxSize;
                    } else if (boxType.equalsIgnoreCase("moov")) {
                        Log.d("chy", "moov size:" + boxSize);
                        headSize += boxSize;
                        int moovSize = count;
                        while (moovSize > 0) {
                            if (moovSize > BUFFER_SIZE) {
                                readSize = bis.read(buffer);
                            } else {
                                readSize = bis.read(buffer, 0, moovSize);
                            }
                            if (readSize == -1) break;
                            raf.write(buffer, 0, readSize);
                            moovSize -= readSize;
                        }
                        LogUtils.getInstance().i("moov ok");
                        break;
                    }
                    boxSize = readBoxSize(bis, boxSizeBuf);
                    boxType = readBoxType(bis, boxTypeBuf);
                    LogUtils.getInstance().i("boxSizeMoov:" + boxSize + " boxTypeMoov:" + boxType);
                    raf.write(boxSizeBuf);
                    raf.write(boxTypeBuf);
                }
                bis.close();
                is.close();
                httpConn.disconnect();
            }catch (Exception e){
                try {
                    bis.close();
                    is.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
                if (httpConn!=null)
                httpConn.disconnect();
            }
    
        }
    
        /**
         *  此方法直接定位到mdat的起点开始下载mdata。1、下载部分通知前端 2、下载完成也通知前端
         *  @param bis:服务器流
         *  @param mdatSize:mdat的大小
         *  @param raf:目标文件的句柄
         *  @param wirteSeek:让目标文件指针跳过ftyp等部分
         * */
        private static void downLoadMadta(BufferedInputStream bis,int mdatSize,RandomAccessFile raf,long wirteSeek,Handler handler) throws IOException {
            LogUtils.getInstance().i("downLoadMadta");
            final int buf_size = 56 * 1024;// 56kb
            int downloadCount = 0;
            boolean viable = false;
            byte[] buffer = new byte[BUFFER_SIZE];
            int readSize = 0;
    
            if(wirteSeek>0){
                raf.seek(wirteSeek);
            }
    
            int totalMdatSize = mdatSize;
            while (mdatSize > 0) {
                readSize = bis.read(buffer);
                if(readSize < 0) break;
                raf.write(buffer, 0, readSize);
                mdatSize -= readSize;
                downloadCount += readSize;
                if (handler != null && !viable && downloadCount >= buf_size) {
                    LogUtils.getInstance().i("PLAYER_MP4_MSG");
                    viable = true;
                    // 发送开始播放视频消息,通知前台可以播放视频了
                    sendMessage(handler, PLAYER_MP4_MSG, null);
                }
    
                if (viable){
                    sendMessage(handler,DOWNLOAD_MP4_LOADING_PROCESS,1000L*downloadCount/totalMdatSize);
                }
            }
            LogUtils.getInstance().i("下载完成");
            // 发送下载消息 通知前台已经下载完成
            if (handler != null) {
                sendMessage(handler, DOWNLOAD_MP4_COMPLETION, null);
                handler.removeMessages(PLAYER_MP4_MSG);
                handler.removeMessages(DOWNLOAD_MP4_COMPLETION);
            }
        }
        /**
         * 发送下载消息
         *
         * @param handler
         * @param what
         * @param obj
         */
        private static void sendMessage(Handler handler, int what, Object obj) {
            if (handler != null) {
                Message msg = new Message();
                msg.what = what;
                msg.obj = obj;
                handler.sendMessage(msg);
            }
        }
    
        /**
         * 跳转
         *
         * @param is
         * @param count 跳转长度
         * @throws IOException
         */
        private static void skip(BufferedInputStream is, long count) throws IOException {
            while (count > 0) {
                long amt = is.skip(count);
                if (amt == -1) {
                    throw new RuntimeException("inputStream skip exception");
                }
                count -= amt;
            }
        }
    
        /**
         * 读取mp4文件box大小
         *
         * @param is
         * @param buffer
         * @return
         */
        private static int readBoxSize(InputStream is, byte[] buffer) {
            int sz = fill(is, buffer);
            if (sz == -1) {
                return 0;
            }
    
            return bytesToInt(buffer, 0, 4);
        }
    
        /**
         * 读取MP4文件box类型
         *
         * @param is
         * @param buffer
         * @return
         */
        private static String readBoxType(InputStream is, byte[] buffer) {
            fill(is, buffer);
    
            return byteToString(buffer);
        }
    
        /**
         * byte转换int
         *
         * @param buffer
         * @param pos
         * @param bytes
         * @return
         */
        private static int bytesToInt(byte[] buffer, int pos, int bytes) {
            /*
             * int intvalue = (buffer[pos + 0] & 0xFF) << 24 | (buffer[pos + 1] &
             * 0xFF) << 16 | (buffer[pos + 2] & 0xFF) << 8 | buffer[pos + 3] & 0xFF;
             */
            int retval = 0;
            for (int i = 0; i < bytes; ++i) {
                retval |= (buffer[pos + i] & 0xFF) << (8 * (bytes - i - 1));
            }
            return retval;
        }
    
        /**
         * byte数据转换String
         *
         * @param buffer
         * @return
         */
        private static String byteToString(byte[] buffer) {
            assert buffer.length == 4;
            String retval = new String();
            try {
                retval = new String(buffer, 0, buffer.length, "ascii");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
    
            return retval;
        }
    
        private static int fill(InputStream stream, byte[] buffer) {
            return fill(stream, 0, buffer.length, buffer);
        }
    
        /**
         * 读取流数据
         *
         * @param stream
         * @param pos
         * @param len
         * @param buffer
         * @return
         */
        private static int fill(InputStream stream, int pos, int len, byte[] buffer) {
            int readSize = 0;
            try {
                readSize = stream.read(buffer, pos, len);
                if (readSize == -1) {
                    return -1;
                }
                assert readSize == len : String.format("len %d readSize %d", len,
                        readSize);
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            return readSize;
        }
    }
    

    上述代码让moov无论是在mdat前面还是在moov的后面都可以播放。
    作者:陈宇、茆文涛

    展开全文
  • 19.人工神经网络.mp4

    2021-04-09 22:31:54
    19.人工神经网络.mp4
  • Java__网络.mp4

    2021-07-09 15:15:06
    Java__网络.mp4
  • 005 Docker容器网络.mp4

    2021-05-07 19:57:17
    005 Docker容器网络.mp4
  • android MP4网络播放源码

    热门讨论 2013-07-06 15:12:25
    MP4网络播放源码,肯定可以运行的。 适合于制作在线播放MP4的应用的开发者进行参考。
  • 讲一下七层模型的基础,视频来自于网络
  • 028 配置网络插件flannel.mp4
  • 029 基于canel的网络策略.mp4
  • 004 容器虚拟化网络概述.mp4
  • 计算机网络也称计算机通信网。关于计算机网络的最简单定义是:一些相互连接的、以共享资源为目的的、 自治的计算机的集合。若按此定义,则早期的面向终端的网络都不能算是计算机网络,而只能称为联机系统(因为那时...
  • 长短期记忆网络,基于长短期记忆网络的文本分类模型
  • AI主播说网络安全 _ 如何认识并规避网络赌博 安全运营 安全众测 攻防实训与靶场 业务安全 网络安全
  • 随着Web2.0、社交网络、微博等等一系列新型的互联网产品的诞生,基于Web环境的互联网应用越来越广泛,企业信息化的过程中各种应用都架设在Web平台上,Web业务的迅速发展也引起黑客们的强烈关注,接踵而至的就是Web...
  • 15.3、网络产品.mp4

    2021-09-17 21:09:29
    Python零基础10天进阶班【15课程:网站开发基础(上)】
  • python爬MP4网络视频

    2019-04-27 11:43:28
    用python爬虫抓取网络视频
    #!/usr/bin/python
    import re
    import urllib
    import os
    def getHtml(url):
            page=urllib.urlopen(url)
            html=page.read()
            return html
    
    def getMp4(html):
            filePath = './'
            downloaded = os.listdir(filePath)
            r=r"href=\"(clip.*\.mp4)\""
            re_mp4=re.compile(r)
            print html
            mp4List=re.findall(re_mp4,html)
            print mp4List
            filename=0
            dest = "https://www-nlpir.nist.gov/projects/tv2019/active/INS/topics/actions.examples/"
            for mp4name in mp4List:
                    if mp4name in downloaded:
                        pass
                    else:
                        mp4url = dest+mp4name
                        urllib.urlretrieve(mp4url,"%s" %mp4name)
                        print 'file "%s" done' %mp4name
                    filename+=1
            print 'totally "%s" files have been dowloaded' %filename
    url = "https://www-nlpir.nist.gov/projects/tv2019/active/INS/topics/actions.examples/"
    html=getHtml(url)
    getMp4(html)
                                  
    
    展开全文
  • 88-网络架构.mp4

    2021-07-14 10:35:23
    西门子200PLC入门视频教程
  • 83-网络架构.mp4

    2021-07-14 10:34:32
    西门子200PLC入门视频教程
  • 78-网络架构.mp4

    2021-07-14 10:33:30
    西门子200PLC入门视频教程
  • 大飞哥网络安全第一阶段课程,适合0基础/初学者体系化学习,也适合老手巩固基础观看,希望大家在学习过程中理解技术原理,为更深层次的防御攻击等学习打好基础。最好别用mac,好多工具不兼容。
  • Apsara Clouder云安全专项技能认证:web网络安全考试全录屏,里面可以看到真题,所选答案并不是全对。得分刚好60分,通过考试,发出来仅供参考!侵权即删!
  • 9.1、网络数据获取.mp4

    2021-09-17 20:47:56
    Python零基础10天进阶班【09网络数据获取(爬虫实战)】
  • 大飞哥网络安全第一阶段课程,适合0基础/初学者体系化学习,也适合老手巩固基础观看,希望大家在学习过程中理解技术原理,为更深层次的防御攻击等学习打好基础。最好别用mac,好多工具不兼容。
  • 大飞哥网络安全第一阶段课程,适合0基础/初学者体系化学习,也适合老手巩固基础观看,希望大家在学习过程中理解技术原理,为更深层次的防御攻击等学习打好基础。最好别用mac,好多工具不兼容。
  • 方法一:通过查看端口流量发现环路风暴,判断环路。 方法二:通过持续MAC地址漂移判断环路。 方法三:配置Loopback Detection功能检测环路。
  • 大飞哥网络安全第一阶段课程,适合0基础/初学者体系化学习,也适合老手巩固基础观看,希望大家在学习过程中理解技术原理,为更深层次的防御攻击等学习打好基础。最好别用mac,好多工具不兼容。
  • Windows网络安全精讲 网络安全:01-破解系统密码01.mp4 系统密码破解windows密码Windows登录密码
  • VoLTE是通过LTE网络作为业务接入、IMS网络实现业务控制的语音解决方案 业务接入:LTE网络是全IP网络,没有CS域,数据业务和语音多媒体业务都承载在LTE上 业务控制:EPC网络不具备语音和多媒体业务的呼叫控制功能,...
  • 大飞哥网络安全第一阶段课程,适合0基础/初学者体系化学习,也适合老手巩固基础观看,希望大家在学习过程中理解技术原理,为更深层次的防御攻击等学习打好基础。最好别用mac,好多工具不兼容。
  • 深度学习---RNN网络细节视频教程,希望能够学习者提供帮助,实现对RNN网络细节基础知识的掌握与理解,为后续学习做好铺垫,实现RNN网络细节知识的灵活运用
  • 人工神经网络是生物神经网络在某种简化意义下的技术复现,作为一门学科,它的主要任务是根据生物神经网络的原理和实际应用的需要建造实用的人工神经网络模型,设计相应的学习算法,模拟人脑的某种智能活动,然后在...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 35,858
精华内容 14,343
关键字:

网络mp4