#二进制读取video文件然后转十六进制,输出out.txt
def hex_read_video(your_video_path,your_outfile_path):
    f = open(your_video_path, 'rb')
    outfile1 = open(your_outfile_path, "w")
    i = 0
    while 1:
        c = f.read(1)
        i = i + 1
        if not c:
            break
        if i % 33 == 0:
            outfile1.write("\n")
        else:
            if ord(c) <= 15:
                outfile1.write(("0x0" + hex(ord(c))[2:])[2:] + " ")
            else:
                outfile1.write((hex(ord(c)))[2:] + " ")
    outfile1.close()
    f.close()
    return your_outfile_path
● 80%的人都不知道,全球Python库下载前10名● 我珍藏的一些好的Python代码,技巧|上篇● 爬取300本Python书籍,用Python告诉你哪家强?● 简单几步,100行代码用Python画一个蝙蝠侠的logo● 我用Python分析了《青春有你2》109位漂亮小姐姐,真香!● 牛逼操作!用Python做了一个编程语言20年的动态排行榜!● 我打赌,学会这6招,谁再敢笑你的Python程序慢!

每天分享一些有趣的干货
#启用方法
location /status {
  stub_status;
}
flowchart TD
    Start --> Step1
    Step1 --> Step2
    Step2 --> Step3
    Step3 --> Step4
    Step4 --> End
# 安装必要的库
pip install pydub
pip install moviepy
-s size
       Set frame size. The format is wxh (avserver default = 160x128, ffmpeg default = same as source).  The following abbreviations are recognized:

       sqcif
           128x96

       qcif
           176x144

       cif 352x288

       4cif
           704x576

       16cif
           1408x1152

       qqvga
           160x120

       qvga
           320x240

       vga 640x480

       svga
           800x600

       xga 1024x768

       uxga
           1600x1200

       qxga
           2048x1536

       sxga
           1280x1024

       qsxga
           2560x2048

       hsxga
           5120x4096

       wvga
           852x480

       wxga
           1366x768

       wsxga
           1600x1024

       wuxga
           1920x1200

       woxga
           2560x1600

       wqsxga
           3200x2048

       wquxga
           3840x2400

       whsxga
           6400x4096

       whuxga
           7680x4800

       cga 320x200

       ega 640x350

       hd480
           852x480

       hd720
           1280x720

       hd1080
           1920x1080
framework/av/media/libstagefright/MPEG4Extrator.cpp
status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    ALOGV("entering parseChunk %lld/%d", *offset, depth);
    uint32_t hdr[2];
    static const char* mQTMajorBrand = "qt  ";
    if (mDataSource->readAt(*offset, hdr, 8) < 8) {
        return ERROR_IO;
    }
uint64_t chunk_size = ntohl(hdr[0]);---box size
uint32_t chunk_type = ntohl(hdr[1]);---box type
    off64_t data_offset = *offset + 8;
 
    if (chunk_size == 1) {
mDataSource->readAt(*offset + 8, &chunk_size, 8) < 8) {---读取box size的大小
            return ERROR_IO;
        }
 ntoh64(chunk_size); ---将64位的网络字节转换为主机字节
        data_offset += 8;
……….
    char chunk[5];
MakeFourCCString(chunk_type, chunk);  ----FOURCC全称Four-Character Codes,是在编程
中非常常用的东西,一般用作标示符。它是一个32位的标示符,其实就是typedef unsigned long FOURCC
 
}
…………
}
 
 
static void MakeFourCCString(uint32_t x, char *s) {
    s[0] = x >> 24;
    s[1] = (x >> 16) & 0xff;
    s[2] = (x >> 8) & 0xff;
    s[3] = x & 0xff;
    s[4] = '\0';
}
package com.onzhou.ffmpeg.decode;

public class NativeDecode {

    static {
        System.loadLibrary("native-decode");
    }

    public native void decodeMP4(String mp4Path, String yuvPath);

}
import os
import glob
from pydub import AudioSegment
AudioSegment.converter = r"D:\\ffmmg\\bin\\ffmpeg.exe" #ffmpeg位置
wenjianjia = []
path = r"C:\Users\chenquan\Desktop\p4batch" # 需要批量转换的mp4目录位置
for root, dirs, files in os.walk(path):
wenjianjia.append(root)
wjj = wenjianjia

for dir in wjj:
video_dir = dir
extension_list = ('*.mp4', '*.flv')
i = 1

os.chdir(video_dir)
for extension in extension_list:
for video in glob.glob(extension):
mp3_filename = os.path.splitext(os.path.basename(video))[0] + '.mp3'
AudioSegment.from_file(video).export(mp3_filename, format='mp3')
print('已转码', str(i), '个视频!')
i += 1

for infile in glob.glob(os.path.join(video_dir, '*.mp4')):
os.remove(infile)
  1. public void writeHeader() throws IOException{  
  2. writeFtypBox();  
  3. writeFreeBox();  
  4. }  
  5.  
  6.  
  7. private void writeFtypBox() throws IOException{  
  8. write(intTobyte(20));//box_length  
  9. write("ftyp");//box_type (4字节)  
  10. write("isom");//major_brand (4字节)  
  11. write(intTobyte(512));//minor_version (4 字节)  
  12. write("mp41");//compatible_brands (4字节)  
  13. }  
  14.  
  15. private void writeFreeBox() throws IOException{  
  16. write(intTobyte(8));  
  17. write("free");  
  18. }  
  19.  
  20.  
  21. private byte[] intTobyte(int value){  
  22. byte[] data = new byte[4];  
  23. data[3] = (byte)(value);  
  24. data[2] = (byte)(value>>8);  
  25. data[1] = (byte)(value>>16);  
  26. data[0] = (byte)(value>>24);  
  27. return data;  
  28. }  
  29.  
  30. private void write(byte[] data) throws IOException{  
  31. mOutput.write(data);  
  32. }  
  33.  
  34. private void write(String str) throws IOException{  
  35. mOutput.write(str.getBytes());  
class Video(Resource):
# @jwt_required
def get(self, video_id):
try:
range_value = request.headers.get("Range", None)
video = Videos.query.filter_by(id=video_id).first()
if not video:
raise VideoError(err_msg="No search video")
data = current_app.config['MINIO'].get_files(video.key, video.bucket)
data_length = len(data)
start = 0
end = data_length - 1
headers = {"Content-disposition": 'inline; filename=%s' % video.key}
status_code = 200
if range_value:
status_code = 206
range_re_obj = re.compile(r'bytes=([0-9]+)\-(([0-9]+)?)')
result = re.match(range_re_obj, range_value)
if result:
start_str = result.group(1)
end_str = result.group(2)
start = int(start_str)
if end_str:
end = int(end_str)
else:
end = data_length-1
headers["Content-Length"] = str(end - start + 1)
headers["Accept-Ranges"] = "bytes"
headers["Content-Range"] = "bytes %d-%d/%d" % (start, end, data_length)
headers["Connection"] = "keep-alive"
response = Response(data[start:end + 1], mimetype="video/mp4", headers=headers)
response.status_code = status_code
return response
<video controls width="250">
    <source src="https://xxxx/xxxxx/xxxx.mp4"
            type="video/mp4">
    Sorry, your browser doesn't support embedded videos.
</video>
//1\. 命令下载
wget https://ffmpeg.org/releases/ffmpeg-4.2.2.tar.bz2
//2\. 安装解压缩工具
yum -y install bzip2
//3\. 解压 FFmpeg 
tar -jxvf ffmpeg-4.2.2.tar.bz2
//1.注册所有组件
    av_register_all();
    //初始网络流
    avformat_network_init();
    //封装格式上下文,统领全局的结构体,保存了视频文件封装格式的相关信息
    pFormatCtx = avformat_alloc_context();
    //2.打开输入视频文件
    if(avformat_open_input(&pFormatCtx,input_str,NULL,NULL)!=0){
        LOGE("Couldn't open input stream.\n");
        return -1;
    }
    //3.获取视频文件信息
    if(avformat_find_stream_info(pFormatCtx,NULL)<0){
        LOGE("Couldn't find stream information.\n");
        return -1;
    }
    //获取视频流的索引位置
    //遍历所有类型的流(音频流、视频流、字幕流),找到视频流
    videoindex=-1;
    for(i=0; i<pFormatCtx->nb_streams; i++)
        if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO){
            videoindex=i;
            break;
        }
    if(videoindex==-1){
        LOGE("Couldn't find a video stream.\n");
        return -1;
    }
    //只有知道视频的编码方式,才能够根据编码方式去找到解码器
    //获取视频流中的编解码上下文
    pCodecCtx=pFormatCtx->streams[videoindex]->codec;
    //4.根据编解码上下文中的编码id查找对应的解码
    pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
    if(pCodec==NULL){
        LOGE("Couldn't find Codec.\n");
        return -1;
    }
    if(avcodec_open2(pCodecCtx, pCodec,NULL)<0){
        LOGE("Couldn't open codec.\n");
        return -1;
    }

    pFrame=av_frame_alloc();
    pFrameYUV=av_frame_alloc();
    out_buffer=(unsigned char *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P,  pCodecCtx->width, pCodecCtx->height,1));
    av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize,out_buffer,
                         AV_PIX_FMT_YUV420P,pCodecCtx->width, pCodecCtx->height,1);

    //准备读取
    //AVPacket用于存储一帧一帧的压缩数据(H264)
    //缓冲区,开辟空间
    packet=(AVPacket *)av_malloc(sizeof(AVPacket));
//用于转码(缩放)的参数,转之前的宽高,转之后的宽高,格式等
    img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
                                     pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);

//输出视频信息
    sprintf(info,   "[Input     ]%s\n", input_str);
    sprintf(info, "%s[Output    ]%s\n",info,output_str);
    sprintf(info, "%s[Format    ]%s\n",info, pFormatCtx->iformat->name);
    sprintf(info, "%s[Codec     ]%s\n",info, pCodecCtx->codec->name);
    sprintf(info, "%s[Resolution]%dx%d\n",info, pCodecCtx->width,pCodecCtx->height);


    fp_yuv=fopen(output_str,"wb+");
    if(fp_yuv==NULL){
        printf("Cannot open output file.\n");
        return -1;
    }

    frame_cnt=0;
    time_start = clock();
//6.一帧一帧的读取压缩数据
    while(av_read_frame(pFormatCtx, packet)>=0){
        //只要视频压缩数据(根据流的索引位置判断)
        if(packet->stream_index==videoindex){
            //7.解码一帧视频压缩数据,得到视频像素数据
            ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
            if(ret < 0){
                LOGE("Decode Error.\n");
                return -1;
            }
            //为0说明解码完成,非0正在解码
            if(got_picture){
                //AVFrame转为像素格式YUV420,宽高
                //2 6输入、输出数据
                //3 7输入、输出画面一行的数据的大小 AVFrame 转换是一行一行转换的
                //4 输入数据第一列要转码的位置 从0开始
                //5 输入画面的高度
                sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height,
                          pFrameYUV->data, pFrameYUV->linesize);
                //输出到YUV文件
                //AVFrame像素帧写入文件
                //data解码后的图像像素数据(音频采样数据)
                //Y 亮度 UV 色度(压缩了) 人对亮度更加敏感
                //U V 个数是Y的1/4
                y_size=pCodecCtx->width*pCodecCtx->height;
                fwrite(pFrameYUV->data[0],1,y_size,fp_yuv);    //Y
                fwrite(pFrameYUV->data[1],1,y_size/4,fp_yuv);  //U
                fwrite(pFrameYUV->data[2],1,y_size/4,fp_yuv);  //V
                //Output info
                char pictype_str[10]={0};
                switch(pFrame->pict_type){
                    case AV_PICTURE_TYPE_I:sprintf(pictype_str,"I");break;
                    case AV_PICTURE_TYPE_P:sprintf(pictype_str,"P");break;
                    case AV_PICTURE_TYPE_B:sprintf(pictype_str,"B");break;
                    default:sprintf(pictype_str,"Other");break;
                }
                LOGI("Frame Index: %5d. Type:%s",frame_cnt,pictype_str);
                //释放资源
                frame_cnt++;
            }
        }
        av_free_packet(packet);
    }
svn checkout svn://svn.ffmpeg.org/ffmpeg/trunk ffmpeg
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define PRINTF_DEBUG

#define BOX_TYPE_FTYPE "ftyp"
#define BOX_TYPE_MOOV "moov"
#define BOX_TYPE_MVHD "mvhd"
#define BOX_TYPE_TRAK "trak"
#define BOX_TYPE_TKHD "tkhd"
#define BOX_TYPE_EDTS "edts"
#define BOX_TYPE_MDIA "mdia"
#define BOX_TYPE_MDHD "mdhd"
#define BOX_TYPE_HDLR "hdlr"
#define BOX_TYPE_MINF "minf"
#define BOX_TYPE_VMHD "vmhd"
#define BOX_TYPE_DINF "dinf"
#define BOX_TYPE_DREF "dref"
#define BOX_TYPE_STBL "stbl"
#define BOX_TYPE_STSD "stsd"
#define BOX_TYPE_STTS "stts"
#define BOX_TYPE_STSS "stss"
#define BOX_TYPE_STSC "stsc"
#define BOX_TYPE_STSZ "stsz"
#define BOX_TYPE_STCO "stco"
#define BOX_TYPE_UDTA "udta"

#define MAX_BOX_SIZE_LEN 4
#define MAX_BOX_TYPE_LEN 4
#define MAX_HANDLER_TYPE_LEN 4
#define MAX_FTYP_BRABDS_LEN 4
#define MAX_FTYP_BRABDS_NUM 4
#define MAX_STTS_ENTRY_NUM 8
#define MAX_STSS_ENTRY_NUM 8
#define MAX_STSC_ENTRY_NUM 100
#define MAX_STSZ_ENTRY_NUM 100 /* now parse 100 frame */
#define MAX_STCO_ENTRY_NUM 100
#define MAX_MVHD_RESERVED_LEN 10
#define MAX_PRE_DEFINE_LEN 24
#define MAX_MATRIX_LEN 36
#define MAX_HDLR_NAME_LEN 100


typedef struct t_box_header
{
    int boxSize;

    unsigned char boxType[MAX_BOX_TYPE_LEN+1];

    long largeBoxSize; /* if boxSize=1 use, if boxSize=0, end of file */
} T_BOX_HEADER;

/********************************************************************************************
**                            File Type Box (ftyp): file type, 表明文件类型
**
--------------------------------------------------------------------------------------------
**        字段名称              |    长度(bytes)   |        有关描述
--------------------------------------------------------------------------------------------
**        boxsize               |    4            |        box的长度
**        boxtype               |    4            |        box的类型
**        major_brand           |    4            |
**        minor_version         |    4            |        版本号
**        compatible_brands     |    4 * N        |        本文件遵从的多种协议(ismo, iso2, mp41)
********************************************************************************************/
typedef struct t_box4ftyp_brand
{
    unsigned char brands[MAX_FTYP_BRABDS_LEN+1];
} T_BOX4FTYP_BRAN;

typedef struct t_box4ftyp
{
    unsigned char major_brand[MAX_FTYP_BRABDS_LEN+1];

    int minor_version;

    T_BOX4FTYP_BRAN compatible_brands[MAX_FTYP_BRABDS_NUM];
} T_BOX4FTYP;

/************************************************************************************************************
**                                            mvhd: movie header, 文件的总体信息: 时长, 创建时间等
**
--------------------------------------------------------------------------------------------
**        字段名称              |    长度(bytes)   |        有关描述
--------------------------------------------------------------------------------------------
**        boxsize               |    4            |        box的长度
**        boxtype               |    4            |        box的类型
**        version               |    1            |        box版本,0或1,一般为0(以下字节数均按version = 0)
**        flags                 |    3            |
**        creation time         |    4            |        创建时间(相对于UTC时间1904 - 01 - 01零点的秒数)
**        modification time     |    4            |        修改时间
**        time scale            |    4            |        文件媒体在1秒时间内的刻度值,可以理解为1秒长度的时间单元数
**        duration              |    4            |        该track的时间长度,用duration和time scale值可以计算track时长
**        rate                  |    4            |        推荐播放速率,高16位和低16位分别为小数点整数部分和小数部分,即[16.16] 格式.该值为1.0 (0x00010000)
**        volume                |    2            |        与rate类似,[8.8] 格式,1.0(0x0100)表示最大音量
**        reserved              |    10           |        保留位
**        matrix                |    36           |        视频变换矩阵
**        pre-defined           |    24           |
**        next track id         |    4            |        下一个track使用的id号
**
if (version==1)
{
    unsigned int(64) creation_time;
    unsigned int(64) modification_time;
    unsigned int(32) timescale;
    unsigned int(64) duration;
}
else
{
    unsigned int(32) creation_time;
    unsigned int(32) modification_time;
    unsigned int(32) timescale;
    unsigned int(32) duration;
}
************************************************************************************************************/
typedef struct t_box4mvhd
{
    int creation_time;
    int modification_time;
    int timescale;
    int duration;
    float rate;
    float volume;
    int next_track_id;
} T_BOX4MVHD;

/************************************************************************************************************
**                                        tkhd: track header, track的总体信息, 如时长, 宽高等
**
-------------------------------------------------------------------------------------------------------------
**        字段名称               |    长度(bytes)   |        有关描述
-------------------------------------------------------------------------------------------------------------
**        boxsize                |    4            |        box的长度
**        boxtype                |    4            |        box的类型
**        version                |    1            |        box版本,0或1,一般为0。(以下字节数均按version = 0)
**        flags                  |    3            |        按位或操作结果值,预定义如下;
                                                         0x000001 track_enabled,否则该track不被播放;
                                                         0x000002 track_in_movie,表示该track在播放中被引用;
                                                         0x000004 track_in_preview,表示该track在预览时被引用。
                                                         一般该值为7,如果一个媒体所有track均未设置track_in_movie和track_in_preview,将被理解为所有track均设置了这两项;
                                                         对于hint track,该值为0;
**        creation_time          |    4            |        创建时间(相对于UTC时间1904 - 01 - 01零点的秒数)
**        modification_time      |    4            |        修改时间
**        track_id               |    4            |        id号 不能重复且不能为0
**        reserved               |    4            |        保留位
**        duration               |    4            |        track的时间长度
**        reserved               |    8            |        保留位
**        layer                  |    2            |        视频层,默认为0,值小的在上层
**        alternate_group        |    2            |        track分组信息,默认为0表示该track未与其他track有群组关系
**        volume                 |    2            |        [8.8] 格式,如果为音频track,1.0(0x0100)表示最大音量;否则为0
**        reserved               |    2            |        保留位
**        matrix                 |    36           |        视频变换矩阵
**        width                  |    4            |        宽
**        height                 |    4            |        高,均为[16.16] 格式值 与sample描述中的实际画面大小比值,用于播放时的展示宽高
if (version==1)
{
    unsigned int(64) creation_time;
    unsigned int(64) modification_time;
    unsigned int(32) track_ID;
    const unsigned int(32) reserved = 0;
    unsigned int(64) duration;
}
else
{
    unsigned int(32) creation_time;
    unsigned int(32) modification_time;
    unsigned int(32) track_ID;
    const unsigned int(32) reserved = 0;
    unsigned int(32) duration;
}
************************************************************************************************************/
typedef struct t_box4tkhd
{
    int flags;
    int creation_time;
    int modification_time;
    int track_id;
    int duration;
    int layer;
    int alternate_group;
    float volume;
    float width;
    float height;
} T_BOX4TKHD;

/************************************************************************************************************
**                                        mdhd: 包含了了该track的总体信息, mdhd和tkhd 内容大致都是一样的.
**
-------------------------------------------------------------------------------------------------------------
**        字段名称              |      长度(bytes)   |        有关描述
-------------------------------------------------------------------------------------------------------------
**        boxsize               |    4                |        box的长度
**        boxtype               |    4                |        box的类型
**        version               |    1         |        box版本0或1 一般为0 (以下字节数均按version=0)
**        flags                 |    3                |
**        creation_time         |    4                |        创建时间(相对于UTC时间1904 - 01 - 01零点的秒数)
**        modification_time     |    4                |        修改时间
**        time_scale            |    4                |
**        duration              |    4               |        track的时间长度
**        language              |    2               |        媒体语言码,最高位为0 后面15位为3个字符[见ISO 639-2/T标准中定义]
**        pre-defined           |    2                |        保留位

** tkhd通常是对指定的track设定相关属性和内容, 而mdhd是针对于独立的media来设置的, 一般情况下二者相同.
************************************************************************************************************/
typedef struct t_box4mdhd
{
    int creation_time;
    int modification_time;
    int timescale;
    int duration;
    short language;
} T_BOX4MDHD;

/************************************************************************************************************
**                                        hdlr: Handler Reference Box, 媒体的播放过程信息, 该box也可以被包含在meta box(meta)中
**
-------------------------------------------------------------------------------------------------------------
**        字段名称               |    长度(bytes)    |        有关描述
-------------------------------------------------------------------------------------------------------------
**        boxsize                |    4             |        box的长度
**        boxtype                |    4             |        box的类型
**        version                |    1             |        box版本0或1 一般为0 (以下字节数均按version=0)
**        flags                  |    3             |
**        pre-defined            |    4             |
**        handler type           |    4             |        在media box中,该值为4个字符
                                                          "vide"— video track
                                                          "soun"— audio track
                                                          "hint"— hint track
**        reserved               |    12            |
**        name                   |    不定           |        track type name,以‘\0’结尾的字符串
************************************************************************************************************/
typedef struct t_box4hdlr
{
    unsigned char handler_type[MAX_HANDLER_TYPE_LEN+1];
    unsigned char name[MAX_HDLR_NAME_LEN+1];
} T_BOX4HDLR;

/************************************************************************************************************
**                                        vmhd: Video Media Header Box
**
-------------------------------------------------------------------------------------------------------------
**        字段名称            |    长度(bytes)    |        有关描述
-------------------------------------------------------------------------------------------------------------
**        boxsize                |    4            |        box的长度
**        boxtype                |    4            |        box的类型
**        version                |    1            |        box版本0或1 一般为0 (以下字节数均按version=0)
**        flags                     |    3            |
**        graphics_mode          |    4            |        视频合成模式,为0时拷贝原始图像,否则与opcolor进行合成
**        opcolor                |    2 ×3         |        {red,green,blue}

"vide"—vmhd 视频
"soun"— smhd 音频
"hint"—hmhd 忽略
************************************************************************************************************/
typedef struct t_box4vmhd
{
    int graphics_mode;
} T_BOX4VMHD;

/************************************************************************************************************
**                                        dref: data reference box
**
-------------------------------------------------------------------------------------------------------------
**        字段名称               |    长度(bytes)    |        有关描述
-------------------------------------------------------------------------------------------------------------
**        boxsize                |    4             |        box的长度
**        boxtype                |    4             |        box的类型
**        version                |    1             |        box版本0或1 一般为0 (以下字节数均按version=0)
**        flags                  |    3             |
**        entry count            |    4             |         "url"或"urn"表的元素个数
**        "url"或"urn"列表       |    不定          |

** "dref"下会包含若干个"url"或"urn", 这些box组成一个表, 用来定位track数据. 简单的说, track可以被分成若干段,
   每一段都可以根据"url"或"urn"指向的地址来获取数据, sample描述中会用这些片段的序号将这些片段组成一个完整的track.
   一般情况下, 当数据被完全包含在文件中时, "url"或"urn"中的定位字符串是空的.
************************************************************************************************************/
typedef struct t_box4dref
{
    int entry_count;
} T_BOX4DREF;

/************************************************************************************************************
**                                        stsd: Sample Description Box
**
-------------------------------------------------------------------------------------------------------------
**        字段名称               |    长度(bytes)    |        有关描述
-------------------------------------------------------------------------------------------------------------
**        boxsize                |    4             |        box的长度
**        boxtype                |    4             |        box的类型
**        version                |    1             |        box版本0或1 一般为0 (以下字节数均按version=0)
**        entry count            |    4             |         "url"或"urn"表的元素个数

** box header和version字段后会有一个entry count字段, 根据entry的个数, 每个entry会有type信息, 如"vide", "sund"等,
   根据type不同sample description会提供不同的信息, 例如对于video track, 会有"VisualSampleEntry"类型信息,
   对于audio track会有"AudioSampleEntry"类型信息. 视频的编码类型, 宽高, 长度, 音频的声道, 采样等信息都会出现在这个box中
************************************************************************************************************/
typedef struct t_box4stsd
{
    int entry_count;

    //TODO
} T_BOX4STSD;

/************************************************************************************************************
**                                        stts: Time To Sample Box
**
-------------------------------------------------------------------------------------------------------------
**        字段名称               |    长度(bytes)    |        有关描述
-------------------------------------------------------------------------------------------------------------
**        boxsize                |    4             |        box的长度
**        boxtype                |    4             |        box的类型
**        version                |    1             |        box版本,0或1,一般为0(以下字节数均按version = 0)
**        flags                  |    3             |
**        entry count            |    4             |         sample_count和sample_delta的个数
**        sample_count           |    4             |
**        sample_delta           |    4             |

** "stts”"存储了sample的duration, 描述了sample时序的映射方法, 我们通过它可以找到任何时间的sample. "stts"可以
   包含一个压缩的表来映射时间和sample序号, 用其他的表来提供每个sample的长度和指针. 表中每个条目提供了在同一个
   时间偏移量里面连续的sample序号, 以及samples的偏移量. 递增这些偏移量, 就可以建立一个完整的time to sample表.

   例: 说明该视频包含87帧数据(sample_count), 每帧包含512个采样(sample_delta). 总共512*87=44544个采样,
       和我们前面mdhd box的Duration完全一致。
       Duration/TimeScale = 44544/12288 = 3.625s, 正是我们的视频播放长度.
       12288/512 = 24 p/s (帧率)
************************************************************************************************************/
typedef struct t_box4stts_entry
{
    int sample_count;
    int sample_delta;
} T_BOX4STTS_ENTRY;

typedef struct t_box4stts
{
    int entry_count;

    T_BOX4STTS_ENTRY entrys[MAX_STTS_ENTRY_NUM];
} T_BOX4STTS;

/************************************************************************************************************
**                                        stss: Sync Sample Box
**
-------------------------------------------------------------------------------------------------------------
**        字段名称               |    长度(bytes)    |        有关描述
-------------------------------------------------------------------------------------------------------------
**        boxsize                |    4             |        box的长度
**        boxtype                |    4             |        box的类型
**        version                |    1             |        box版本,0或1,一般为0(以下字节数均按version = 0)
**        flags                  |    3             |
**        entry count            |    4             |         sample_num的个数
**        sample_num                |    4             |

** "stss"确定media中的关键帧. 对于压缩媒体数据, 关键帧是一系列压缩序列的开始帧, 其解压缩时不依赖以前的帧,
   而后续帧的解压缩将依赖于这个关键帧. "stss"可以非常紧凑的标记媒体内的随机存取点, 它包含一个sample序号表,
   表内的每一项严格按照sample的序号排列, 说明了媒体中的哪一个sample是关键帧. 如果此表不存在, 说明每一个sample
   都是一个关键帧, 是一个随机存取点.
************************************************************************************************************/
typedef struct t_box4stss_entry
{
    int sample_num;
} T_BOX4STSS_ENTRY;

typedef struct t_box4stss
{
    int entry_count;

    T_BOX4STSS_ENTRY entrys[MAX_STSS_ENTRY_NUM];
} T_BOX4STSS;

/************************************************************************************************************
**                                        stsc: Sample To Chunk Box
**
-------------------------------------------------------------------------------------------------------------
**        字段名称               |    长度(bytes)    |        有关描述
-------------------------------------------------------------------------------------------------------------
**        boxsize                |    4             |        box的长度
**        boxtype                |    4             |        box的类型
**        version                |    1             |        box版本,0或1,一般为0(以下字节数均按version = 0)
**        flags                  |    3             |
**        entry count            |    4             |         entry的个数
**        first_chunk            |    4             |
**        samples_per_chunk      |    4             |
**        sample_des_index       |    4             |

** 用chunk组织sample可以方便优化数据获取, 一个thunk包含一个或多个sample. "stsc"中用一个表描述了sample与chunk的映射关系,
   查看这张表就可以找到包含指定sample的thunk, 从而找到这个sample.
************************************************************************************************************/
typedef struct t_box4stsc_entry
{
    int first_chunk;
    int samples_per_chunk;
    int sample_description_index;
} T_BOX4STSC_ENTRY;

typedef struct t_box4stsc
{
    int entry_count;

    T_BOX4STSC_ENTRY entrys[MAX_STSC_ENTRY_NUM];
} T_BOX4STSC;

/************************************************************************************************************
**                                        stsz: Sample To Chunk Box
**
-------------------------------------------------------------------------------------------------------------
**        字段名称               |    长度(bytes)    |        有关描述
-------------------------------------------------------------------------------------------------------------
**        boxsize                |    4             |        box的长度
**        boxtype                |    4             |        box的类型
**        version                |    1             |        box版本,0或1,一般为0(以下字节数均按version = 0)
**        flags                  |    3             |
**        sample_size            |    4             |
**        sample_count           |    4             |         entry的个数
**        entry_size             |    4             |

**  "stsz"定义了每个sample的大小, 包含了媒体中全部sample的数目和一张给出每个sample大小的表. 这个box相对来说体积是比较大的.
************************************************************************************************************/
typedef struct t_box4stsz_entry
{
    int entry_size;
} T_BOX4STSZ_ENTRY;

typedef struct t_box4stsz
{
    int sample_size;
    int sample_count;

    T_BOX4STSZ_ENTRY entrys[MAX_STSZ_ENTRY_NUM];
} T_BOX4STSZ;

/************************************************************************************************************
**                                        stco: Chunk Offset Box
**
-------------------------------------------------------------------------------------------------------------
**        字段名称               |    长度(bytes)    |        有关描述
-------------------------------------------------------------------------------------------------------------
**        boxsize                |    4             |        box的长度
**        boxtype                |    4             |        box的类型
**        version                |    1             |        box版本,0或1,一般为0(以下字节数均按version = 0)
**        flags                  |    3             |
**        entry_count            |    4             |
**        chunk_offset           |    4             |

**  "stco"定义了每个thunk在媒体流中的位置, sample的偏移可以根据其他box推算出来. 位置有两种可能, 32位的和64位的,
    后者对非常大的电影很有用. 在一个表中只会有一种可能, 这个位置是在整个文件中的, 而不是在任何box中的.
    这样做就可以直接在文件中找到媒体数据, 而不用解释box. 需要注意的是一旦前面的box有了任何改变, 这张表都要重新建立, 因为位置信息已经改变了.
************************************************************************************************************/
typedef struct t_box4stco_entry
{
    int chunk_offset;
} T_BOX4STCO_ENTRY;

typedef struct t_box4stco
{
    int entry_count;

    T_BOX4STCO_ENTRY entrys[MAX_STCO_ENTRY_NUM];
} T_BOX4STCO;

typedef struct t_box
{
    T_BOX_HEADER boxHeader;

    unsigned char *boxData;
} T_BOX;

static void DealBox4ftyp(const T_BOX *box)
{
    int i = 0;
    int j = 0;
    int brandsNum = 0;

    T_BOX4FTYP box4ftyp = {0};

    memset(&box4ftyp, 0x0, sizeof(T_BOX4FTYP));

    memcpy(box4ftyp.major_brand, box->boxData, 4);
    box4ftyp.major_brand[MAX_FTYP_BRABDS_LEN] = '\0';

    box4ftyp.minor_version =  box->boxData[4] << 24 | box->boxData[5] << 16 | box->boxData[6] << 8 | box->boxData[7];

    brandsNum = (box->boxHeader.boxSize - MAX_BOX_SIZE_LEN - MAX_BOX_TYPE_LEN - MAX_FTYP_BRABDS_LEN - 4) / 4;

    /* 1. if not have '\0', 每个brands的内存是连续的, 导致打印时后面的每4个数据都会加到前面;
       2. unsigned char brands[MAX_FTYP_BRABDS_LEN+1]; 可解决, 此时也不必加'\0', 但需初始化;
       3. 因此字符串最好定义+1并赋'\0';
       4. 复现: unsigned char brands[MAX_FTYP_BRABDS_LEN]
    */
    for (i=0; i<brandsNum; i++)
    {
        memcpy(box4ftyp.compatible_brands[i].brands, box->boxData+MAX_FTYP_BRABDS_LEN+4+4*i, 4);

        box4ftyp.compatible_brands[i].brands[MAX_FTYP_BRABDS_LEN] = '\0';
    }

#ifdef PRINTF_DEBUG
    printf("\tmajor_brand: %s, minor_version: %d, compatible_brands: ", box4ftyp.major_brand, box4ftyp.minor_version);

    for (i=0; i<brandsNum; i++)
    {
        if (i==brandsNum-1)
        {
            printf("%s", box4ftyp.compatible_brands[i].brands);
        }
        else
        {
            printf("%s,", box4ftyp.compatible_brands[i].brands);
        }
    }

    printf("\n");
#endif
}

static void DealBox4mvhd(const unsigned char *mvhdData)
{
    unsigned char *data = NULL;

    T_BOX4MVHD box4mvhd = {0};

    memset(&box4mvhd, 0x0, sizeof(T_BOX4MVHD));

    data = (unsigned char *)mvhdData;

    data += 4;
    box4mvhd.creation_time = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

    data += 4;
    box4mvhd.modification_time = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

    data += 4;
    box4mvhd.timescale = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

    data += 4;
    box4mvhd.duration = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

    data += 4;
    //box4mvhd.rate = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
    box4mvhd.rate = (data[0] << 8 | data[1]) + (data[2] << 8 | data[3]);

    data += 4;
    //box4mvhd.volume = data[0] << 8 | data[1];
    box4mvhd.volume = data[0] + data[1];

    data += 2;
    data += (MAX_MVHD_RESERVED_LEN + MAX_PRE_DEFINE_LEN + MAX_MATRIX_LEN);
    box4mvhd.next_track_id = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

#ifdef PRINTF_DEBUG
    printf("\t\tcreation_time: %d, modification_time: %d, timescale: %d, duration: %d, rate: %f, volume: %f, next_track_id: %d\n",
            box4mvhd.creation_time, box4mvhd.modification_time, box4mvhd.timescale, box4mvhd.duration, box4mvhd.rate, box4mvhd.volume, box4mvhd.next_track_id);
#endif
}

static void DealBox4tkhd(const unsigned char *tkhdData)
{
    unsigned char *data = NULL;

    T_BOX4TKHD box4tkhd = {0};

    memset(&box4tkhd, 0x0, sizeof(box4tkhd));

    data = (unsigned char *)tkhdData;

    box4tkhd.flags = data[1] << 16 | data[2] << 8 | data[3];

    data += 4;
    box4tkhd.creation_time = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

    data += 4;
    box4tkhd.modification_time = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

    data += 4;
    box4tkhd.track_id = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

    data += 4;

    data += 4; /* 4 reserved */
    box4tkhd.duration = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

    data += 4;

    data += 8; /* 8 reserved */
    box4tkhd.layer = data[0] << 8 | data[1];

    data += 2;
    box4tkhd.alternate_group = data[0] << 8 | data[1];

    data += 2;
    box4tkhd.volume = data[0] + data[1];

    data += 2;

    data += 2;

    data += 36;
    box4tkhd.width = (data[0] << 8 | data[1]) + (data[2] << 8 | data[3]);

    data += 4;
    box4tkhd.height = (data[0] << 8 | data[1]) + (data[2] << 8 | data[3]);

#ifdef PRINTF_DEBUG
    printf("\t\t\tflags: %d, creation_time: %d, modification_time: %d, track_id: %d, duration: %d, layer: %d, alternate_group: %d, volume: %f, width: %f, height: %f\n",
            box4tkhd.flags, box4tkhd.creation_time, box4tkhd.modification_time, box4tkhd.track_id, box4tkhd.duration, box4tkhd.layer, box4tkhd.alternate_group, box4tkhd.volume, box4tkhd.width, box4tkhd.height);
#endif
}

static void DealBox4dref(const T_BOX *box)
{
    // TODO
}

static void DealBox4dinf(const T_BOX *box)
{    int boxSize = 0;
    int dinfDataSize = 0;

    unsigned char *dinfData = NULL;
    unsigned char *data = NULL;

    char boxType[MAX_BOX_TYPE_LEN+1] = {0};

    T_BOX drefBox = {0};

    dinfData = box->boxData;
    dinfDataSize = box->boxHeader.boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN;

    while (dinfDataSize > 0)
    {
        boxSize = dinfData[0] << 24 | dinfData[1] << 16 | dinfData[2] << 8 | dinfData[3];

        memcpy(boxType, dinfData+MAX_BOX_SIZE_LEN, 4);

#ifdef PRINTF_DEBUG
    printf("\t\t\t\t\t****BOX: Layer6****\n");
    printf("\t\t\t\t\t\tsize: %d\n", boxSize);
    printf("\t\t\t\t\t\ttype: %s\n", boxType);
#endif
        if (0 == strcmp(boxType, BOX_TYPE_DREF))
        {
            memset(&drefBox, 0x0, sizeof(T_BOX));

            drefBox.boxHeader.boxSize = boxSize;

            memcpy(drefBox.boxHeader.boxType, boxType, strlen(boxType));

            drefBox.boxData = (unsigned char*)malloc(boxSize);
            if (drefBox.boxData)
            {
                memcpy(drefBox.boxData, dinfData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);

                DealBox4dref((const T_BOX*)&drefBox);

                free(drefBox.boxData);
                drefBox.boxData = NULL;
            }
        }

        dinfData += boxSize;
        dinfDataSize -= boxSize;
    }
}

static void DealBox4stts(const unsigned char *sttsData)
{
    int i = 0;

    unsigned char *data = NULL;

    T_BOX4STTS box4stts = {0};

    memset(&box4stts, 0x0, sizeof(box4stts));

    data = (unsigned char *)sttsData;

    data += 4;

    box4stts.entry_count = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

    data += 4;

    for (i=0; i<box4stts.entry_count; i++)
    {
        if (i == MAX_STTS_ENTRY_NUM)
        {
            break;
        }

        box4stts.entrys[i].sample_count = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

        data += 4;

        box4stts.entrys[i].sample_delta = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

        data += 4;
    }

#ifdef PRINTF_DEBUG
    printf("\t\t\tentry_count: %d, [sample_count, sample_delta]: ", box4stts.entry_count);

    if (box4stts.entry_count>MAX_STTS_ENTRY_NUM)
    {
        box4stts.entry_count = MAX_STTS_ENTRY_NUM;
    }

    for (i=0; i<box4stts.entry_count; i++)
    {
        if (i>0)
        {
            printf(", ");
        }

        printf("[%d, %d]", box4stts.entrys[i].sample_count, box4stts.entrys[i].sample_delta);
    }

    if (box4stts.entry_count==MAX_STTS_ENTRY_NUM)
    {
        printf("...(just show %d now)", MAX_STTS_ENTRY_NUM);
    }

    printf("\n");
#endif
}

static void DealBox4stss(const unsigned char *stssData)
{
    int i = 0;

    unsigned char *data = NULL;

    T_BOX4STSS box4stss = {0};

    memset(&box4stss, 0x0, sizeof(box4stss));

    data = (unsigned char *)stssData;

    data += 4;

    box4stss.entry_count = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

    data += 4;

    for (i=0; i<box4stss.entry_count; i++)
    {
        if (i == MAX_STSS_ENTRY_NUM)
        {
            break;
        }

        box4stss.entrys[i].sample_num = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

        data += 4;
    }

#ifdef PRINTF_DEBUG
    printf("\t\t\tentry_count: %d, sample_num: ", box4stss.entry_count);

    if (box4stss.entry_count>MAX_STSS_ENTRY_NUM)
    {
        box4stss.entry_count = MAX_STSS_ENTRY_NUM;
    }

    for (i=0; i<box4stss.entry_count; i++)
    {
        if (i>0)
        {
            printf(", ");
        }

        printf("%d", box4stss.entrys[i].sample_num);
    }

    if (box4stss.entry_count==MAX_STSS_ENTRY_NUM)
    {
        printf("...(just show %d now)", MAX_STSS_ENTRY_NUM);
    }

    printf("\n");
#endif
}

static void DealBox4stsc(const unsigned char *stscData)
{
    int i = 0;

    unsigned char *data = NULL;

    T_BOX4STSC box4stsc = {0};

    memset(&box4stsc, 0x0, sizeof(box4stsc));

    data = (unsigned char *)stscData;

    data += 4;

    box4stsc.entry_count = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

    data += 4;

    for (i=0; i<box4stsc.entry_count; i++)
    {
        if (i == MAX_STSC_ENTRY_NUM)
        {
            break;
        }

        box4stsc.entrys[i].first_chunk = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

        data += 4;

        box4stsc.entrys[i].samples_per_chunk = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

        data += 4;

        box4stsc.entrys[i].sample_description_index = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

        data += 4;
    }

#ifdef PRINTF_DEBUG
    printf("\t\t\tentry_count: %d, [first_chunk, samples_per_chunk, sample_description_index]: ", box4stsc.entry_count);

    if (box4stsc.entry_count>MAX_STSC_ENTRY_NUM)
    {
        box4stsc.entry_count = MAX_STSC_ENTRY_NUM;
    }

    for (i=0; i<box4stsc.entry_count; i++)
    {
        if (i>0)
        {
            printf(", ");
        }

        printf("[%d, %d, %d]", box4stsc.entrys[i].first_chunk, box4stsc.entrys[i].samples_per_chunk, box4stsc.entrys[i].sample_description_index);
    }

    if (box4stsc.entry_count==MAX_STSC_ENTRY_NUM)
    {
        printf("...(just show %d now)", MAX_STSC_ENTRY_NUM);
    }

    printf("\n");
#endif
}

static void DealBox4stsz(const unsigned char *stszData)
{
    int i = 0;

    unsigned char *data = NULL;

    T_BOX4STSZ box4stsz = {0};

    memset(&box4stsz, 0x0, sizeof(box4stsz));

    data = (unsigned char *)stszData;

    data += 4;

    box4stsz.sample_size = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

    data += 4;

    box4stsz.sample_count = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

    data += 4;

    for (i=0; i<box4stsz.sample_count; i++)
    {
        if (i == MAX_STSZ_ENTRY_NUM)
        {
            break;
        }

        box4stsz.entrys[i].entry_size = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

        data += 4;
    }

#ifdef PRINTF_DEBUG
    printf("\t\t\tsample_size: %d, sample_count: %d, [entry_size]: ", box4stsz.sample_size, box4stsz.sample_count);

    if (box4stsz.sample_count>MAX_STSZ_ENTRY_NUM)
    {
        box4stsz.sample_count = MAX_STSZ_ENTRY_NUM;
    }

    for (i=0; i<box4stsz.sample_count; i++)
    {
        if (i>0)
        {
            printf(", ");
        }

        printf("[%d]", box4stsz.entrys[i].entry_size);
    }

    if (box4stsz.sample_count==MAX_STSZ_ENTRY_NUM)
    {
        printf("...(just show %d now)", MAX_STSZ_ENTRY_NUM);
    }

    printf("\n");
#endif
}

static void DealBox4stco(const unsigned char *stcoData)
{
    int i = 0;

    unsigned char *data = NULL;

    T_BOX4STCO box4stco = {0};

    memset(&box4stco, 0x0, sizeof(box4stco));

    data = (unsigned char *)stcoData;

    data += 4;

    box4stco.entry_count = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

    data += 4;

    for (i=0; i<box4stco.entry_count; i++)
    {
        if (i == MAX_STCO_ENTRY_NUM)
        {
            break;
        }

        box4stco.entrys[i].chunk_offset = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

        data += 4;
    }

#ifdef PRINTF_DEBUG
    printf("\t\t\entry_count: %d, [chunk_offset]: ", box4stco.entry_count);

    if (box4stco.entry_count>MAX_STCO_ENTRY_NUM)
    {
        box4stco.entry_count = MAX_STCO_ENTRY_NUM;
    }

    for (i=0; i<box4stco.entry_count; i++)
    {
        if (i>0)
        {
            printf(", ");
        }

        printf("[%d]", box4stco.entrys[i].chunk_offset);
    }

    if (box4stco.entry_count==MAX_STCO_ENTRY_NUM)
    {
        printf("...(just show %d now)", MAX_STCO_ENTRY_NUM);
    }

    printf("\n");
#endif
}

static void DealBox4stbl(const T_BOX *box)
{
    int boxSize = 0;
    int stblDataSize = 0;

    unsigned char *stblData = NULL;
    unsigned char *data = NULL;

    char boxType[MAX_BOX_TYPE_LEN+1] = {0};

    stblData = box->boxData;
    stblDataSize = box->boxHeader.boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN;

    while (stblDataSize > 0)
    {
        boxSize = stblData[0] << 24 | stblData[1] << 16 | stblData[2] << 8 | stblData[3];

        memcpy(boxType, stblData+MAX_BOX_SIZE_LEN, 4);

#ifdef PRINTF_DEBUG
    printf("\t\t\t\t\t****BOX: Layer6****\n");
    printf("\t\t\t\t\t\tsize: %d\n", boxSize);
    printf("\t\t\t\t\t\ttype: %s\n", boxType);
#endif

        if (0 == strcmp(boxType, BOX_TYPE_STTS))
        {
            data = (unsigned char*)malloc(boxSize);
            if (data)
            {
                memcpy(data, stblData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);

                DealBox4stts(data);

                free(data);
                data = NULL;
            }
        }
        else if (0 == strcmp(boxType, BOX_TYPE_STSS))
        {
            data = (unsigned char*)malloc(boxSize);
            if (data)
            {
                memcpy(data, stblData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);

                DealBox4stss(data);

                free(data);
                data = NULL;
            }
        }
        else if (0 == strcmp(boxType, BOX_TYPE_STSC))
        {
            data = (unsigned char*)malloc(boxSize);
            if (data)
            {
                memcpy(data, stblData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);

                DealBox4stsc(data);

                free(data);
                data = NULL;
            }
        }
        else if (0 == strcmp(boxType, BOX_TYPE_STSZ))
        {
            data = (unsigned char*)malloc(boxSize);
            if (data)
            {
                memcpy(data, stblData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);

                DealBox4stsz(data);

                free(data);
                data = NULL;
            }
        }
        else if (0 == strcmp(boxType, BOX_TYPE_STCO))
        {
            data = (unsigned char*)malloc(boxSize);
            if (data)
            {
                memcpy(data, stblData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);

                DealBox4stco(data);

                free(data);
                data = NULL;
            }
        }

        stblData += boxSize;
        stblDataSize -= boxSize;
    }
}

static void DealBox4mdhd(const unsigned char *mdhdData)
{
    unsigned char *data = NULL;

    T_BOX4MDHD box4mdhd = {0};

    memset(&box4mdhd, 0x0, sizeof(box4mdhd));

    data = (unsigned char *)mdhdData;

    data += 4;
    box4mdhd.creation_time = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

    data += 4;
    box4mdhd.modification_time = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

    data += 4;
    box4mdhd.timescale = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

    data += 4;
    box4mdhd.duration = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

    data += 4;
    box4mdhd.language = data[0] << 8 | data[1];

#ifdef PRINTF_DEBUG
    //printf("\t\t\tcreation_time: %d, modification_time: %d, timescale: %d, duration: %d, language: %c%c%c\n",
            //box4mdhd.creation_time, box4mdhd.modification_time, box4mdhd.timescale, box4mdhd.duration, (box4mdhd.language>>10&0x1f), (box4mdhd.language>>5&0x1f), (box4mdhd.language&0x1f));

    printf("\t\t\t\tcreation_time: %d, modification_time: %d, timescale: %d, duration: %d, language:%d\n",
            box4mdhd.creation_time, box4mdhd.modification_time, box4mdhd.timescale, box4mdhd.duration, box4mdhd.language);
#endif
}

static void DealBox4hdlr(const unsigned char *hdlrData)
{
    int i = 0;

    unsigned char *data = NULL;

    T_BOX4HDLR box4hdlr = {0};

    memset(&box4hdlr, 0x0, sizeof(box4hdlr));

    data = (unsigned char *)hdlrData;

    data += 4;
    data += 4;

    memcpy(box4hdlr.handler_type, data, 4);

    box4hdlr.handler_type[MAX_HANDLER_TYPE_LEN] = '\0';

    data += 4;

    data += 12;

    while ('\0' != data[i])
    {
        i++;
    }

    memcpy(box4hdlr.name, data, i);

    box4hdlr.name[MAX_HDLR_NAME_LEN] = '\0';

#ifdef PRINTF_DEBUG
    printf("\t\t\t\thandler_type: %s, name: %s\n", box4hdlr.handler_type, box4hdlr.name);
#endif
}

static void DealBox4vmdhd(const unsigned char *vmdhdData)
{
    // TODO
}

static void DealBox4minf(const T_BOX *box)
{    int boxSize = 0;
    int minfDataSize = 0;

    unsigned char *minfData = NULL;
    unsigned char *data = NULL;

    char boxType[MAX_BOX_TYPE_LEN+1] = {0};

    T_BOX dinfBox = {0};
    T_BOX stblBox = {0};

    minfData = box->boxData;
    minfDataSize = box->boxHeader.boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN;

    while (minfDataSize > 0)
    {
        boxSize = minfData[0] << 24 | minfData[1] << 16 | minfData[2] << 8 | minfData[3];

        memcpy(boxType, minfData+MAX_BOX_SIZE_LEN, 4);

#ifdef PRINTF_DEBUG
    printf("\t\t\t\t********BOX: Layer5********\n");
    printf("\t\t\t\t\tsize: %d\n", boxSize);
    printf("\t\t\t\t\ttype: %s\n", boxType);
#endif
        if (0 == strcmp(boxType, BOX_TYPE_VMHD))
        {
            data = (unsigned char*)malloc(boxSize);
            if (data)
            {
                memcpy(data, minfData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);

                DealBox4vmdhd(data);

                free(data);
                data = NULL;
            }
        }
        else if (0 == strcmp(boxType, BOX_TYPE_DINF))
        {
            memset(&dinfBox, 0x0, sizeof(T_BOX));

            dinfBox.boxHeader.boxSize = boxSize;

            memcpy(dinfBox.boxHeader.boxType, boxType, strlen(boxType));

            dinfBox.boxData = (unsigned char*)malloc(boxSize);
            if (dinfBox.boxData)
            {
                memcpy(dinfBox.boxData, minfData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);

                DealBox4dinf((const T_BOX*)&dinfBox);

                free(dinfBox.boxData);
                dinfBox.boxData = NULL;
            }
        }
        else if (0 == strcmp(boxType, BOX_TYPE_STBL))
        {
            memset(&stblBox, 0x0, sizeof(T_BOX));

            stblBox.boxHeader.boxSize = boxSize;

            memcpy(stblBox.boxHeader.boxType, boxType, strlen(boxType));

            stblBox.boxData = (unsigned char*)malloc(boxSize);
            if (stblBox.boxData)
            {
                memcpy(stblBox.boxData, minfData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);

                DealBox4stbl((const T_BOX*)&stblBox);

                free(stblBox.boxData);
                stblBox.boxData = NULL;
            }
        }

        minfData += boxSize;
        minfDataSize -= boxSize;
    }
}

static void DealBox4mdia(const T_BOX *box)
{    int boxSize = 0;
    int mdiaDataSize = 0;

    unsigned char *mdiaData = NULL;
    unsigned char *data = NULL;

    char boxType[MAX_BOX_TYPE_LEN+1] = {0};

    T_BOX minfBox = {0};

    mdiaData = box->boxData;
    mdiaDataSize = box->boxHeader.boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN;

    while (mdiaDataSize > 0)
    {
        boxSize = mdiaData[0] << 24 | mdiaData[1] << 16 | mdiaData[2] << 8 | mdiaData[3];

        memcpy(boxType, mdiaData+MAX_BOX_SIZE_LEN, 4);

#ifdef PRINTF_DEBUG
    printf("\t\t\t************BOX: Layer4************\n");
    printf("\t\t\t\tsize: %d\n", boxSize);
    printf("\t\t\t\ttype: %s\n", boxType);
#endif
        if (0 == strcmp(boxType, BOX_TYPE_MDHD))
        {
            data = (unsigned char*)malloc(boxSize);
            if (data)
            {
                memcpy(data, mdiaData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);

                DealBox4mdhd(data);

                free(data);
                data = NULL;
            }
        }
        else if (0 == strcmp(boxType, BOX_TYPE_HDLR))
        {
            data = (unsigned char*)malloc(boxSize);
            if (data)
            {
                memcpy(data, mdiaData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);

                DealBox4hdlr(data);

                free(data);
                data = NULL;
            }
        }
        else if (0 == strcmp(boxType, BOX_TYPE_MINF))
        {
            memset(&minfBox, 0x0, sizeof(T_BOX));

            minfBox.boxHeader.boxSize = boxSize;

            memcpy(minfBox.boxHeader.boxType, boxType, strlen(boxType));

            minfBox.boxData = (unsigned char*)malloc(boxSize);
            if (minfBox.boxData)
            {
                memcpy(minfBox.boxData, mdiaData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);

                DealBox4minf((const T_BOX*)&minfBox);

                free(minfBox.boxData);
                minfBox.boxData = NULL;
            }
        }

        mdiaData += boxSize;
        mdiaDataSize -= boxSize;
    }
}

static void DealBox4trak(const T_BOX *box)
{
    int boxSize = 0;
    int trakDataSize = 0;

    unsigned char *trakData = NULL;
    unsigned char *data = NULL;

    char boxType[MAX_BOX_TYPE_LEN+1] = {0};

    T_BOX mdiaBox = {0};

    trakData = box->boxData;
    trakDataSize = box->boxHeader.boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN;

    while (trakDataSize > 0)
    {
        boxSize = trakData[0] << 24 | trakData[1] << 16 | trakData[2] << 8 | trakData[3];

        memcpy(boxType, trakData+MAX_BOX_SIZE_LEN, 4);

#ifdef PRINTF_DEBUG
    printf("\t\t****************BOX: Layer3****************\n");
    printf("\t\t\tsize: %d\n", boxSize);
    printf("\t\t\ttype: %s\n", boxType);
#endif

        if (0 == strcmp(boxType, BOX_TYPE_TKHD))
        {
            data = (unsigned char*)malloc(boxSize);
            if (data)
            {
                memcpy(data, trakData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);

                DealBox4tkhd(data);

                free(data);
                data = NULL;
            }
        }
        else if (0 == strcmp(boxType, BOX_TYPE_MDIA))
        {
            memset(&mdiaBox, 0x0, sizeof(T_BOX));

            mdiaBox.boxHeader.boxSize = boxSize;

            memcpy(mdiaBox.boxHeader.boxType, boxType, strlen(boxType));

            mdiaBox.boxData = (unsigned char*)malloc(boxSize);
            if (mdiaBox.boxData)
            {
                memcpy(mdiaBox.boxData, trakData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);

                DealBox4mdia((const T_BOX*)&mdiaBox);

                free(mdiaBox.boxData);
                mdiaBox.boxData = NULL;
            }
        }

        trakData += boxSize;
        trakDataSize -= boxSize;
    }
}

static void DealBox4moov(const T_BOX *box)
{
    int boxSize = 0;
    int moovDataSize = 0;

    unsigned char *moovData = NULL;
    unsigned char *data = NULL;

    char boxType[MAX_BOX_TYPE_LEN+1] = {0};

    T_BOX trakBox = {0};

    moovData = box->boxData;
    moovDataSize = box->boxHeader.boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN;

    while (moovDataSize > 0)
    {
        boxSize = moovData[0] << 24 | moovData[1] << 16 | moovData[2] << 8 | moovData[3];

        memcpy(boxType, moovData+MAX_BOX_SIZE_LEN, 4);

        boxType[MAX_BOX_TYPE_LEN] = '\0';

#ifdef PRINTF_DEBUG
    printf("\t********************BOX: Layer2********************\n");
    printf("\t\tsize: %d\n", boxSize);
    printf("\t\ttype: %s\n", boxType);
#endif

        if (0 == strcmp(boxType, BOX_TYPE_MVHD))
        {
            data = (unsigned char*)malloc(boxSize);
            if (data)
            {
                memcpy(data, moovData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);

                DealBox4mvhd(data);

                free(data);
                data = NULL;
            }
        }
        else if (0 == strcmp(boxType, BOX_TYPE_TRAK))
        {
            memset(&trakBox, 0x0, sizeof(T_BOX));

            trakBox.boxHeader.boxSize = boxSize;

            memcpy(trakBox.boxHeader.boxType, boxType, strlen(boxType));

            trakBox.boxData = (unsigned char*)malloc(boxSize);
            if (trakBox.boxData)
            {
                memcpy(trakBox.boxData, moovData+MAX_BOX_SIZE_LEN+MAX_BOX_TYPE_LEN, boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);

                DealBox4trak((const T_BOX*)&trakBox);

                free(trakBox.boxData);
                trakBox.boxData = NULL;
            }
        }

        moovData += boxSize;
        moovDataSize -= boxSize;
    }
}

static void DealBox(const T_BOX *box)
{
#ifdef PRINTF_DEBUG
    printf("****************************BOX: Layer1****************************\n");
    printf("\tsize: %d\n", box->boxHeader.boxSize);
    printf("\ttype: %s\n", box->boxHeader.boxType);
#endif

    if (0 == strcmp(box->boxHeader.boxType, BOX_TYPE_FTYPE))
    {
        DealBox4ftyp(box);
    }
    else if (0 == strcmp(box->boxHeader.boxType, BOX_TYPE_MOOV))
    {
        DealBox4moov(box);
    }
}

int main(int argc, char *argv[])
{
    unsigned char boxSize[MAX_BOX_SIZE_LEN] = {0};

    FILE *fp = NULL;

    T_BOX box = {0};

    if (2 != argc)
    {
        printf("Usage: mp4parse **.mp4\n");

        return -1;
    }

    fp = fopen(argv[1], "rb");
    if (!fp)
    {
        printf("open file[%s] error!\n", argv[1]);

        return -1;
    }


    while (1)
    {
        memset(&box, 0x0, sizeof(T_BOX));

        if (fread(boxSize, 1, 4, fp) <= 0)
        {
            break;
        }

        box.boxHeader.boxSize = boxSize[0] << 24 | boxSize[1] << 16 | boxSize[2] << 8 | boxSize[3];

        fread(box.boxHeader.boxType, 1, 4, fp);

        box.boxHeader.boxType[MAX_BOX_TYPE_LEN] = '\0';

        box.boxData = (unsigned char*)malloc(box.boxHeader.boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN);
        if (!box.boxData)
        {
            printf("malloc data error!\n");

            break;
        }

        fread(box.boxData, 1, box.boxHeader.boxSize-MAX_BOX_SIZE_LEN-MAX_BOX_TYPE_LEN, fp);

        printf("\n=====================================\n");

        /* deal box data */
        DealBox(&box);

        /* free box */
        free(box.boxData);

        box.boxData = NULL;
    }

    fclose(fp);

    printf("\n");

    return 0;
}
public class Mp4DownloadUtils {
	/** 播放MP4消息 */
	private static final int PLAYER_MP4_MSG = 0x1001;
	/** 下载MP4完成 */
	private static final int DOWNLOAD_MP4_COMPLETION = 0x1002;
	/** 下载MP4失败 */
	private static final int DOWNLOAD_MP4_FAIL = 0x1003;

	/**
	 * 下载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
	 * @param moovSize
	 */
	private static void downloadVideoToFile(final String url, final File dstFile, final Handler handler) {
		Thread thread = new Thread() {
			
			@Override
			public void run() {
				super.run();
				try {
					URL request = new URL(url);
					HttpURLConnection httpConn = (HttpURLConnection) request.openConnection();
					httpConn.setConnectTimeout(3000);
					httpConn.setDoInput(true);
					httpConn.setDoOutput(true);
					httpConn.setDefaultUseCaches(false);
					
					httpConn.setRequestMethod("GET");
					httpConn.setRequestProperty("Charset", "UTF-8");
					httpConn.setRequestProperty("Accept-Encoding", "identity");
					
					int responseCode = httpConn.getResponseCode();
					if ((responseCode == HttpURLConnection.HTTP_OK)) {
						// 获取文件总长度
						int totalLength = httpConn.getContentLength();
						InputStream is = httpConn.getInputStream();
						
						if (dstFile.exists()) {
							dstFile.delete();
						}
						dstFile.createNewFile();
						RandomAccessFile raf = new RandomAccessFile(dstFile, "rw");
						BufferedInputStream bis = new BufferedInputStream(is);
						int readSize = 0;
						
						int mdatSize = 0;// mp4的mdat长度
						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);
						
						while (!boxType.equalsIgnoreCase("moov")) {
							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);
							} else if (boxType.equalsIgnoreCase("mdat")) {
								// 标记mdat数据流位置,在后面reset时读取
								bis.mark(totalLength - headSize);
								// 跳过mdat数据
								skip(bis, count);
								mdatSize = count;
								byte[] mdatBuf = new byte[mdatSize];
								raf.write(mdatBuf);
							} else if (boxType.equalsIgnoreCase("free")) {
								headSize += boxSize;
							}
							
							boxSize = readBoxSize(bis, boxSizeBuf);
							boxType = readBoxType(bis, boxTypeBuf);
							raf.write(boxSizeBuf);
							raf.write(boxTypeBuf);
						}
						
						// 读取moov数据
						byte[] buffer = new byte[4096];
						int moovSize = 0;
						while ((readSize = bis.read(buffer)) != -1) {
							moovSize += readSize;
							raf.write(buffer, 0, readSize);
						}
						
						// 返回到mdat数据开始
						bis.reset();
						// 设置文件指针偏移到mdat位置
						long offset = raf.getFilePointer() - moovSize - mdatSize - 8;
						raf.seek(offset);
						
						// 读取mdat数据,设置mp4初始mdat的缓存大小
						int buf_size = 56 * 1024;// 56kb
						int downloadCount = 0;
						boolean viable = false;
						while (mdatSize > 0) {
							readSize = bis.read(buffer);
							raf.write(buffer, 0, readSize);
							mdatSize -= readSize;
							downloadCount += readSize;
							if (handler != null && !viable && downloadCount >= buf_size) {
								viable = true;
								// 发送开始播放视频消息
								sendMessage(handler, PLAYER_MP4_MSG, null);
							}
						}
						// 发送下载消息
						if (handler != null) {
							sendMessage(handler, DOWNLOAD_MP4_COMPLETION, null);
						}
						
						bis.close();
						is.close();
						raf.close();
						httpConn.disconnect();
					}
				} catch (Exception e) {
					e.printStackTrace();
					sendMessage(handler, DOWNLOAD_MP4_FAIL, null);
				}
			}
			
		};
		thread.start();
		thread = null;
	}
	
	/**
	 * 发送下载消息
	 * @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;
	}
}
# 导入相关包或模块
import threading, queue
import time, os, subprocess
import requests, urllib, parsel
import random, re
from Crypto.Cipher import AES

# 下载ts文件
def download_ts(urlQueue,aes,headers): 
    while True:
        try: 
            #不阻塞的读取队列数据 
            temp = urlQueue.get_nowait()
            url=temp[0]
            n=temp[1]
        except Exception as e:
            break
        response=requests.get(url,stream=True,headers=headers)
        ts_path = "./ts/%04d.ts"%n  # 注意这里的ts文件命名规则
        with open(ts_path,"wb+") as file:
            for chunk in response.iter_content(chunk_size=1024):
                if chunk:
                    after=aes.decrypt(chunk)
                    file.write(after)
        print("%04d.ts OK..."%n)

if __name__ == '__main__':
    url='https://mahua-kb.com/20200330/2q4zN34n/2000kb/hls/index.m3u8' # 驱魔神医粤语版第一集
    headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3741.400 QQBrowser/10.5.3863.400'}
    r=requests.get(url,headers=headers)
    urlQueue = queue.Queue()  # 存储ts文件的网址
    for i in r.text.split('\n'):
        if i.endswith('.ts'):
            urlQueue.put([urllib.parse.urljoin(url,i),urlQueue.qsize()])
        elif 'URI' in i:
            URI=urllib.parse.urljoin(url,re.findall('URI="(.*?)"',i)[0]) # 秘钥的网址
            key=requests.get(URI,headers=headers).text  # 得到秘钥
            aes=AES.new(key,AES.MODE_CBC,key)  # 通过秘钥新建解密器
    # 下面开始多线程下载
    startTime = time.time()
    threads = []
    # 可以适当调节线程数,进而控制抓取速度
    threadNum = 4
    for i in range(threadNum):
        t = threading.Thread(target=download_ts, args=(urlQueue,aes,headers,))
        threads.append(t)
    for t in threads:
        t.start()
    for t in threads:
        t.join()
    endTime = time.time()
    print ('Done, Time cost: %s ' %  (endTime - startTime))

    # 下面是执行cmd命令来合成mp4视频
    command=r'copy/b D:\python3.7\HEHE\爬虫\ts\*.ts D:\python3.7\HEHE\爬虫\mp4\驱魔神医-第一集.mp4'
    output=subprocess.getoutput(command)
    print('驱魔神医-第一集.mp4  OK...'

    # 下面是把这一集所有的ts文件给删除
    file_list = []
    for root, dirs, files in os.walk('D:/python3.7/HEHE/爬虫/ts'):
        for fn in files:
            p = str(root+'/'+fn)
            file_list.append(p)
    for i in file_list:
        os.remove(i)
private static final String PATH_STRING = "/mnt/sdcard/test.mp4";//定义视频文件的路径,test.mp4文件我们已经事先放在sdcard中
	VideoView videoView; 
	MediaPlayer mediaPlayer;
  • 1
  • 2
  • 3
  • 4
  • 5