1 from __future__ 
import unicode_literals
 
   8 from .fragment 
import FragmentFD
 
   9 from ..compat 
import compat_urllib_error
 
  12 u8 
= struct
.Struct(b
'>B') 
  13 u88 
= struct
.Struct(b
'>Bx') 
  14 u16 
= struct
.Struct(b
'>H') 
  15 u1616 
= struct
.Struct(b
'>Hxx') 
  16 u32 
= struct
.Struct(b
'>I') 
  17 u64 
= struct
.Struct(b
'>Q') 
  19 s88 
= struct
.Struct(b
'>bx') 
  20 s16 
= struct
.Struct(b
'>h') 
  21 s1616 
= struct
.Struct(b
'>hxx') 
  22 s32 
= struct
.Struct(b
'>i') 
  24 unity_matrix 
= (s32
.pack(0x10000) + s32
.pack(0) * 3) * 2 + s32
.pack(0x40000000) 
  28 TRACK_IN_PREVIEW 
= 0x4 
  33 def box(box_type
, payload
): 
  34     return u32
.pack(8 + len(payload
)) + box_type 
+ payload
 
  37 def full_box(box_type
, version
, flags
, payload
): 
  38     return box(box_type
, u8
.pack(version
) + u32
.pack(flags
)[1:] + payload
) 
  41 def write_piff_header(stream
, params
): 
  42     track_id 
= params
['track_id'] 
  43     fourcc 
= params
['fourcc'] 
  44     duration 
= params
['duration'] 
  45     timescale 
= params
.get('timescale', 10000000) 
  46     language 
= params
.get('language', 'und') 
  47     height 
= params
.get('height', 0) 
  48     width 
= params
.get('width', 0) 
  49     is_audio 
= width 
== 0 and height 
== 0 
  50     creation_time 
= modification_time 
= int(time
.time()) 
  52     ftyp_payload 
= b
'isml'  # major brand 
  53     ftyp_payload 
+= u32
.pack(1)  # minor version 
  54     ftyp_payload 
+= b
'piff' + b
'iso2'  # compatible brands 
  55     stream
.write(box(b
'ftyp', ftyp_payload
))  # File Type Box 
  57     mvhd_payload 
= u64
.pack(creation_time
) 
  58     mvhd_payload 
+= u64
.pack(modification_time
) 
  59     mvhd_payload 
+= u32
.pack(timescale
) 
  60     mvhd_payload 
+= u64
.pack(duration
) 
  61     mvhd_payload 
+= s1616
.pack(1)  # rate 
  62     mvhd_payload 
+= s88
.pack(1)  # volume 
  63     mvhd_payload 
+= u16
.pack(0)  # reserved 
  64     mvhd_payload 
+= u32
.pack(0) * 2  # reserved 
  65     mvhd_payload 
+= unity_matrix
 
  66     mvhd_payload 
+= u32
.pack(0) * 6  # pre defined 
  67     mvhd_payload 
+= u32
.pack(0xffffffff)  # next track id 
  68     moov_payload 
= full_box(b
'mvhd', 1, 0, mvhd_payload
)  # Movie Header Box 
  70     tkhd_payload 
= u64
.pack(creation_time
) 
  71     tkhd_payload 
+= u64
.pack(modification_time
) 
  72     tkhd_payload 
+= u32
.pack(track_id
)  # track id 
  73     tkhd_payload 
+= u32
.pack(0)  # reserved 
  74     tkhd_payload 
+= u64
.pack(duration
) 
  75     tkhd_payload 
+= u32
.pack(0) * 2  # reserved 
  76     tkhd_payload 
+= s16
.pack(0)  # layer 
  77     tkhd_payload 
+= s16
.pack(0)  # alternate group 
  78     tkhd_payload 
+= s88
.pack(1 if is_audio 
else 0)  # volume 
  79     tkhd_payload 
+= u16
.pack(0)  # reserved 
  80     tkhd_payload 
+= unity_matrix
 
  81     tkhd_payload 
+= u1616
.pack(width
) 
  82     tkhd_payload 
+= u1616
.pack(height
) 
  83     trak_payload 
= full_box(b
'tkhd', 1, TRACK_ENABLED | TRACK_IN_MOVIE | TRACK_IN_PREVIEW
, tkhd_payload
)  # Track Header Box 
  85     mdhd_payload 
= u64
.pack(creation_time
) 
  86     mdhd_payload 
+= u64
.pack(modification_time
) 
  87     mdhd_payload 
+= u32
.pack(timescale
) 
  88     mdhd_payload 
+= u64
.pack(duration
) 
  89     mdhd_payload 
+= u16
.pack(((ord(language
[0]) - 0x60) << 10) | 
((ord(language
[1]) - 0x60) << 5) | 
(ord(language
[2]) - 0x60)) 
  90     mdhd_payload 
+= u16
.pack(0)  # pre defined 
  91     mdia_payload 
= full_box(b
'mdhd', 1, 0, mdhd_payload
)  # Media Header Box 
  93     hdlr_payload 
= u32
.pack(0)  # pre defined 
  94     hdlr_payload 
+= b
'soun' if is_audio 
else b
'vide'  # handler type 
  95     hdlr_payload 
+= u32
.pack(0) * 3  # reserved 
  96     hdlr_payload 
+= (b
'Sound' if is_audio 
else b
'Video') + b
'Handler\0'  # name 
  97     mdia_payload 
+= full_box(b
'hdlr', 0, 0, hdlr_payload
)  # Handler Reference Box 
 100         smhd_payload 
= s88
.pack(0)  # balance 
 101         smhd_payload 
= u16
.pack(0)  # reserved 
 102         media_header_box 
= full_box(b
'smhd', 0, 0, smhd_payload
)  # Sound Media Header 
 104         vmhd_payload 
= u16
.pack(0)  # graphics mode 
 105         vmhd_payload 
+= u16
.pack(0) * 3  # opcolor 
 106         media_header_box 
= full_box(b
'vmhd', 0, 1, vmhd_payload
)  # Video Media Header 
 107     minf_payload 
= media_header_box
 
 109     dref_payload 
= u32
.pack(1)  # entry count 
 110     dref_payload 
+= full_box(b
'url ', 0, SELF_CONTAINED
, b
'')  # Data Entry URL Box 
 111     dinf_payload 
= full_box(b
'dref', 0, 0, dref_payload
)  # Data Reference Box 
 112     minf_payload 
+= box(b
'dinf', dinf_payload
)  # Data Information Box 
 114     stsd_payload 
= u32
.pack(1)  # entry count 
 116     sample_entry_payload 
= u8
.pack(0) * 6  # reserved 
 117     sample_entry_payload 
+= u16
.pack(1)  # data reference index 
 119         sample_entry_payload 
+= u32
.pack(0) * 2  # reserved 
 120         sample_entry_payload 
+= u16
.pack(params
.get('channels', 2)) 
 121         sample_entry_payload 
+= u16
.pack(params
.get('bits_per_sample', 16)) 
 122         sample_entry_payload 
+= u16
.pack(0)  # pre defined 
 123         sample_entry_payload 
+= u16
.pack(0)  # reserved 
 124         sample_entry_payload 
+= u1616
.pack(params
['sampling_rate']) 
 127             sample_entry_box 
= box(b
'mp4a', sample_entry_payload
) 
 129         sample_entry_payload 
= sample_entry_payload
 
 130         sample_entry_payload 
+= u16
.pack(0)  # pre defined 
 131         sample_entry_payload 
+= u16
.pack(0)  # reserved 
 132         sample_entry_payload 
+= u32
.pack(0) * 3  # pre defined 
 133         sample_entry_payload 
+= u16
.pack(width
) 
 134         sample_entry_payload 
+= u16
.pack(height
) 
 135         sample_entry_payload 
+= u1616
.pack(0x48)  # horiz resolution 72 dpi 
 136         sample_entry_payload 
+= u1616
.pack(0x48)  # vert resolution 72 dpi 
 137         sample_entry_payload 
+= u32
.pack(0)  # reserved 
 138         sample_entry_payload 
+= u16
.pack(1)  # frame count 
 139         sample_entry_payload 
+= u8
.pack(0) * 32  # compressor name 
 140         sample_entry_payload 
+= u16
.pack(0x18)  # depth 
 141         sample_entry_payload 
+= s16
.pack(-1)  # pre defined 
 143         codec_private_data 
= binascii
.unhexlify(params
['codec_private_data']) 
 144         if fourcc 
in ('H264', 'AVC1'): 
 145             sps
, pps 
= codec_private_data
.split(u32
.pack(1))[1:] 
 146             avcc_payload 
= u8
.pack(1)  # configuration version 
 147             avcc_payload 
+= sps
[1:4]  # avc profile indication + profile compatibility + avc level indication 
 148             avcc_payload 
+= u8
.pack(0xfc | 
(params
.get('nal_unit_length_field', 4) - 1))  # complete represenation (1) + reserved (11111) + length size minus one 
 149             avcc_payload 
+= u8
.pack(1)  # reserved (0) + number of sps (0000001) 
 150             avcc_payload 
+= u16
.pack(len(sps
)) 
 152             avcc_payload 
+= u8
.pack(1)  # number of pps 
 153             avcc_payload 
+= u16
.pack(len(pps
)) 
 155             sample_entry_payload 
+= box(b
'avcC', avcc_payload
)  # AVC Decoder Configuration Record 
 156             sample_entry_box 
= box(b
'avc1', sample_entry_payload
)  # AVC Simple Entry 
 157     stsd_payload 
+= sample_entry_box
 
 159     stbl_payload 
= full_box(b
'stsd', 0, 0, stsd_payload
)  # Sample Description Box 
 161     stts_payload 
= u32
.pack(0)  # entry count 
 162     stbl_payload 
+= full_box(b
'stts', 0, 0, stts_payload
)  # Decoding Time to Sample Box 
 164     stsc_payload 
= u32
.pack(0)  # entry count 
 165     stbl_payload 
+= full_box(b
'stsc', 0, 0, stsc_payload
)  # Sample To Chunk Box 
 167     stco_payload 
= u32
.pack(0)  # entry count 
 168     stbl_payload 
+= full_box(b
'stco', 0, 0, stco_payload
)  # Chunk Offset Box 
 170     minf_payload 
+= box(b
'stbl', stbl_payload
)  # Sample Table Box 
 172     mdia_payload 
+= box(b
'minf', minf_payload
)  # Media Information Box 
 174     trak_payload 
+= box(b
'mdia', mdia_payload
)  # Media Box 
 176     moov_payload 
+= box(b
'trak', trak_payload
)  # Track Box 
 178     mehd_payload 
= u64
.pack(duration
) 
 179     mvex_payload 
= full_box(b
'mehd', 1, 0, mehd_payload
)  # Movie Extends Header Box 
 181     trex_payload 
= u32
.pack(track_id
)  # track id 
 182     trex_payload 
+= u32
.pack(1)  # default sample description index 
 183     trex_payload 
+= u32
.pack(0)  # default sample duration 
 184     trex_payload 
+= u32
.pack(0)  # default sample size 
 185     trex_payload 
+= u32
.pack(0)  # default sample flags 
 186     mvex_payload 
+= full_box(b
'trex', 0, 0, trex_payload
)  # Track Extends Box 
 188     moov_payload 
+= box(b
'mvex', mvex_payload
)  # Movie Extends Box 
 189     stream
.write(box(b
'moov', moov_payload
))  # Movie Box 
 192 def extract_box_data(data
, box_sequence
): 
 193     data_reader 
= io
.BytesIO(data
) 
 195         box_size 
= u32
.unpack(data_reader
.read(4))[0] 
 196         box_type 
= data_reader
.read(4) 
 197         if box_type 
== box_sequence
[0]: 
 198             box_data 
= data_reader
.read(box_size 
- 8) 
 199             if len(box_sequence
) == 1: 
 201             return extract_box_data(box_data
, box_sequence
[1:]) 
 202         data_reader
.seek(box_size 
- 8, 1) 
 205 class IsmFD(FragmentFD
): 
 207     Download segments in a ISM manifest 
 212     def real_download(self
, filename
, info_dict
): 
 213         segments 
= info_dict
['fragments'][:1] if self
.params
.get( 
 214             'test', False) else info_dict
['fragments'] 
 217             'filename': filename
, 
 218             'total_frags': len(segments
), 
 221         self
._prepare
_and
_start
_frag
_download
(ctx
) 
 223         fragment_retries 
= self
.params
.get('fragment_retries', 0) 
 224         skip_unavailable_fragments 
= self
.params
.get('skip_unavailable_fragments', True) 
 226         track_written 
= False 
 228         for i
, segment 
in enumerate(segments
): 
 230             if frag_index 
<= ctx
['fragment_index']: 
 233             while count 
<= fragment_retries
: 
 235                     success
, frag_content 
= self
._download
_fragment
(ctx
, segment
['url'], info_dict
) 
 238                     if not track_written
: 
 239                         tfhd_data 
= extract_box_data(frag_content
, [b
'moof', b
'traf', b
'tfhd']) 
 240                         info_dict
['_download_params']['track_id'] = u32
.unpack(tfhd_data
[4:8])[0] 
 241                         write_piff_header(ctx
['dest_stream'], info_dict
['_download_params']) 
 243                     self
._append
_fragment
(ctx
, frag_content
) 
 245                 except compat_urllib_error
.HTTPError 
as err
: 
 247                     if count 
<= fragment_retries
: 
 248                         self
.report_retry_fragment(err
, frag_index
, count
, fragment_retries
) 
 249             if count 
> fragment_retries
: 
 250                 if skip_unavailable_fragments
: 
 251                     self
.report_skip_fragment(frag_index
) 
 253                 self
.report_error('giving up after %s fragment retries' % fragment_retries
) 
 256         self
._finish
_frag
_download
(ctx
)