1 from __future__ 
import unicode_literals
 
   7 from .fragment 
import FragmentFD
 
  14 u8 
= compat_Struct('>B') 
  15 u88 
= compat_Struct('>Bx') 
  16 u16 
= compat_Struct('>H') 
  17 u1616 
= compat_Struct('>Hxx') 
  18 u32 
= compat_Struct('>I') 
  19 u64 
= compat_Struct('>Q') 
  21 s88 
= compat_Struct('>bx') 
  22 s16 
= compat_Struct('>h') 
  23 s1616 
= compat_Struct('>hxx') 
  24 s32 
= compat_Struct('>i') 
  26 unity_matrix 
= (s32
.pack(0x10000) + s32
.pack(0) * 3) * 2 + s32
.pack(0x40000000) 
  30 TRACK_IN_PREVIEW 
= 0x4 
  35 def box(box_type
, payload
): 
  36     return u32
.pack(8 + len(payload
)) + box_type 
+ payload
 
  39 def full_box(box_type
, version
, flags
, payload
): 
  40     return box(box_type
, u8
.pack(version
) + u32
.pack(flags
)[1:] + payload
) 
  43 def write_piff_header(stream
, params
): 
  44     track_id 
= params
['track_id'] 
  45     fourcc 
= params
['fourcc'] 
  46     duration 
= params
['duration'] 
  47     timescale 
= params
.get('timescale', 10000000) 
  48     language 
= params
.get('language', 'und') 
  49     height 
= params
.get('height', 0) 
  50     width 
= params
.get('width', 0) 
  51     is_audio 
= width 
== 0 and height 
== 0 
  52     creation_time 
= modification_time 
= int(time
.time()) 
  54     ftyp_payload 
= b
'isml'  # major brand 
  55     ftyp_payload 
+= u32
.pack(1)  # minor version 
  56     ftyp_payload 
+= b
'piff' + b
'iso2'  # compatible brands 
  57     stream
.write(box(b
'ftyp', ftyp_payload
))  # File Type Box 
  59     mvhd_payload 
= u64
.pack(creation_time
) 
  60     mvhd_payload 
+= u64
.pack(modification_time
) 
  61     mvhd_payload 
+= u32
.pack(timescale
) 
  62     mvhd_payload 
+= u64
.pack(duration
) 
  63     mvhd_payload 
+= s1616
.pack(1)  # rate 
  64     mvhd_payload 
+= s88
.pack(1)  # volume 
  65     mvhd_payload 
+= u16
.pack(0)  # reserved 
  66     mvhd_payload 
+= u32
.pack(0) * 2  # reserved 
  67     mvhd_payload 
+= unity_matrix
 
  68     mvhd_payload 
+= u32
.pack(0) * 6  # pre defined 
  69     mvhd_payload 
+= u32
.pack(0xffffffff)  # next track id 
  70     moov_payload 
= full_box(b
'mvhd', 1, 0, mvhd_payload
)  # Movie Header Box 
  72     tkhd_payload 
= u64
.pack(creation_time
) 
  73     tkhd_payload 
+= u64
.pack(modification_time
) 
  74     tkhd_payload 
+= u32
.pack(track_id
)  # track id 
  75     tkhd_payload 
+= u32
.pack(0)  # reserved 
  76     tkhd_payload 
+= u64
.pack(duration
) 
  77     tkhd_payload 
+= u32
.pack(0) * 2  # reserved 
  78     tkhd_payload 
+= s16
.pack(0)  # layer 
  79     tkhd_payload 
+= s16
.pack(0)  # alternate group 
  80     tkhd_payload 
+= s88
.pack(1 if is_audio 
else 0)  # volume 
  81     tkhd_payload 
+= u16
.pack(0)  # reserved 
  82     tkhd_payload 
+= unity_matrix
 
  83     tkhd_payload 
+= u1616
.pack(width
) 
  84     tkhd_payload 
+= u1616
.pack(height
) 
  85     trak_payload 
= full_box(b
'tkhd', 1, TRACK_ENABLED | TRACK_IN_MOVIE | TRACK_IN_PREVIEW
, tkhd_payload
)  # Track Header Box 
  87     mdhd_payload 
= u64
.pack(creation_time
) 
  88     mdhd_payload 
+= u64
.pack(modification_time
) 
  89     mdhd_payload 
+= u32
.pack(timescale
) 
  90     mdhd_payload 
+= u64
.pack(duration
) 
  91     mdhd_payload 
+= u16
.pack(((ord(language
[0]) - 0x60) << 10) | 
((ord(language
[1]) - 0x60) << 5) | 
(ord(language
[2]) - 0x60)) 
  92     mdhd_payload 
+= u16
.pack(0)  # pre defined 
  93     mdia_payload 
= full_box(b
'mdhd', 1, 0, mdhd_payload
)  # Media Header Box 
  95     hdlr_payload 
= u32
.pack(0)  # pre defined 
  96     hdlr_payload 
+= b
'soun' if is_audio 
else b
'vide'  # handler type 
  97     hdlr_payload 
+= u32
.pack(0) * 3  # reserved 
  98     hdlr_payload 
+= (b
'Sound' if is_audio 
else b
'Video') + b
'Handler\0'  # name 
  99     mdia_payload 
+= full_box(b
'hdlr', 0, 0, hdlr_payload
)  # Handler Reference Box 
 102         smhd_payload 
= s88
.pack(0)  # balance 
 103         smhd_payload 
+= u16
.pack(0)  # reserved 
 104         media_header_box 
= full_box(b
'smhd', 0, 0, smhd_payload
)  # Sound Media Header 
 106         vmhd_payload 
= u16
.pack(0)  # graphics mode 
 107         vmhd_payload 
+= u16
.pack(0) * 3  # opcolor 
 108         media_header_box 
= full_box(b
'vmhd', 0, 1, vmhd_payload
)  # Video Media Header 
 109     minf_payload 
= media_header_box
 
 111     dref_payload 
= u32
.pack(1)  # entry count 
 112     dref_payload 
+= full_box(b
'url ', 0, SELF_CONTAINED
, b
'')  # Data Entry URL Box 
 113     dinf_payload 
= full_box(b
'dref', 0, 0, dref_payload
)  # Data Reference Box 
 114     minf_payload 
+= box(b
'dinf', dinf_payload
)  # Data Information Box 
 116     stsd_payload 
= u32
.pack(1)  # entry count 
 118     sample_entry_payload 
= u8
.pack(0) * 6  # reserved 
 119     sample_entry_payload 
+= u16
.pack(1)  # data reference index 
 121         sample_entry_payload 
+= u32
.pack(0) * 2  # reserved 
 122         sample_entry_payload 
+= u16
.pack(params
.get('channels', 2)) 
 123         sample_entry_payload 
+= u16
.pack(params
.get('bits_per_sample', 16)) 
 124         sample_entry_payload 
+= u16
.pack(0)  # pre defined 
 125         sample_entry_payload 
+= u16
.pack(0)  # reserved 
 126         sample_entry_payload 
+= u1616
.pack(params
['sampling_rate']) 
 129             sample_entry_box 
= box(b
'mp4a', sample_entry_payload
) 
 131         sample_entry_payload 
+= u16
.pack(0)  # pre defined 
 132         sample_entry_payload 
+= u16
.pack(0)  # reserved 
 133         sample_entry_payload 
+= u32
.pack(0) * 3  # pre defined 
 134         sample_entry_payload 
+= u16
.pack(width
) 
 135         sample_entry_payload 
+= u16
.pack(height
) 
 136         sample_entry_payload 
+= u1616
.pack(0x48)  # horiz resolution 72 dpi 
 137         sample_entry_payload 
+= u1616
.pack(0x48)  # vert resolution 72 dpi 
 138         sample_entry_payload 
+= u32
.pack(0)  # reserved 
 139         sample_entry_payload 
+= u16
.pack(1)  # frame count 
 140         sample_entry_payload 
+= u8
.pack(0) * 32  # compressor name 
 141         sample_entry_payload 
+= u16
.pack(0x18)  # depth 
 142         sample_entry_payload 
+= s16
.pack(-1)  # pre defined 
 144         codec_private_data 
= binascii
.unhexlify(params
['codec_private_data'].encode('utf-8')) 
 145         if fourcc 
in ('H264', 'AVC1'): 
 146             sps
, pps 
= codec_private_data
.split(u32
.pack(1))[1:] 
 147             avcc_payload 
= u8
.pack(1)  # configuration version 
 148             avcc_payload 
+= sps
[1:4]  # avc profile indication + profile compatibility + avc level indication 
 149             avcc_payload 
+= u8
.pack(0xfc | 
(params
.get('nal_unit_length_field', 4) - 1))  # complete representation (1) + reserved (11111) + length size minus one 
 150             avcc_payload 
+= u8
.pack(1)  # reserved (0) + number of sps (0000001) 
 151             avcc_payload 
+= u16
.pack(len(sps
)) 
 153             avcc_payload 
+= u8
.pack(1)  # number of pps 
 154             avcc_payload 
+= u16
.pack(len(pps
)) 
 156             sample_entry_payload 
+= box(b
'avcC', avcc_payload
)  # AVC Decoder Configuration Record 
 157             sample_entry_box 
= box(b
'avc1', sample_entry_payload
)  # AVC Simple Entry 
 158     stsd_payload 
+= sample_entry_box
 
 160     stbl_payload 
= full_box(b
'stsd', 0, 0, stsd_payload
)  # Sample Description Box 
 162     stts_payload 
= u32
.pack(0)  # entry count 
 163     stbl_payload 
+= full_box(b
'stts', 0, 0, stts_payload
)  # Decoding Time to Sample Box 
 165     stsc_payload 
= u32
.pack(0)  # entry count 
 166     stbl_payload 
+= full_box(b
'stsc', 0, 0, stsc_payload
)  # Sample To Chunk Box 
 168     stco_payload 
= u32
.pack(0)  # entry count 
 169     stbl_payload 
+= full_box(b
'stco', 0, 0, stco_payload
)  # Chunk Offset Box 
 171     minf_payload 
+= box(b
'stbl', stbl_payload
)  # Sample Table Box 
 173     mdia_payload 
+= box(b
'minf', minf_payload
)  # Media Information Box 
 175     trak_payload 
+= box(b
'mdia', mdia_payload
)  # Media Box 
 177     moov_payload 
+= box(b
'trak', trak_payload
)  # Track Box 
 179     mehd_payload 
= u64
.pack(duration
) 
 180     mvex_payload 
= full_box(b
'mehd', 1, 0, mehd_payload
)  # Movie Extends Header Box 
 182     trex_payload 
= u32
.pack(track_id
)  # track id 
 183     trex_payload 
+= u32
.pack(1)  # default sample description index 
 184     trex_payload 
+= u32
.pack(0)  # default sample duration 
 185     trex_payload 
+= u32
.pack(0)  # default sample size 
 186     trex_payload 
+= u32
.pack(0)  # default sample flags 
 187     mvex_payload 
+= full_box(b
'trex', 0, 0, trex_payload
)  # Track Extends Box 
 189     moov_payload 
+= box(b
'mvex', mvex_payload
)  # Movie Extends Box 
 190     stream
.write(box(b
'moov', moov_payload
))  # Movie Box 
 193 def extract_box_data(data
, box_sequence
): 
 194     data_reader 
= io
.BytesIO(data
) 
 196         box_size 
= u32
.unpack(data_reader
.read(4))[0] 
 197         box_type 
= data_reader
.read(4) 
 198         if box_type 
== box_sequence
[0]: 
 199             box_data 
= data_reader
.read(box_size 
- 8) 
 200             if len(box_sequence
) == 1: 
 202             return extract_box_data(box_data
, box_sequence
[1:]) 
 203         data_reader
.seek(box_size 
- 8, 1) 
 206 class IsmFD(FragmentFD
): 
 208     Download segments in a ISM manifest 
 213     def real_download(self
, filename
, info_dict
): 
 214         segments 
= info_dict
['fragments'][:1] if self
.params
.get( 
 215             'test', False) else info_dict
['fragments'] 
 218             'filename': filename
, 
 219             'total_frags': len(segments
), 
 222         self
._prepare
_and
_start
_frag
_download
(ctx
) 
 224         fragment_retries 
= self
.params
.get('fragment_retries', 0) 
 225         skip_unavailable_fragments 
= self
.params
.get('skip_unavailable_fragments', True) 
 227         track_written 
= False 
 229         for i
, segment 
in enumerate(segments
): 
 231             if frag_index 
<= ctx
['fragment_index']: 
 234             while count 
<= fragment_retries
: 
 236                     success
, frag_content 
= self
._download
_fragment
(ctx
, segment
['url'], info_dict
) 
 239                     if not track_written
: 
 240                         tfhd_data 
= extract_box_data(frag_content
, [b
'moof', b
'traf', b
'tfhd']) 
 241                         info_dict
['_download_params']['track_id'] = u32
.unpack(tfhd_data
[4:8])[0] 
 242                         write_piff_header(ctx
['dest_stream'], info_dict
['_download_params']) 
 244                     self
._append
_fragment
(ctx
, frag_content
) 
 246                 except compat_urllib_error
.HTTPError 
as err
: 
 248                     if count 
<= fragment_retries
: 
 249                         self
.report_retry_fragment(err
, frag_index
, count
, fragment_retries
) 
 250             if count 
> fragment_retries
: 
 251                 if skip_unavailable_fragments
: 
 252                     self
.report_skip_fragment(frag_index
) 
 254                 self
.report_error('giving up after %s fragment retries' % fragment_retries
) 
 257         self
._finish
_frag
_download
(ctx
)