@@ -153,7 +153,7 @@ several options for controlling its behavior. The `Container` may be in an
153
153
inconsistent state after calling ` rearrange() ` if its contents violate the
154
154
Matroska specification in some way (e.g. if it has an impermissible child).
155
155
156
- The ` Segment ` Element is more intelligent in its ` rearrange ()` method. It generates
156
+ The ` Segment ` Element has a more intelligent ` normalize ()` method. It generates
157
157
a ` SeekHead ` element at the beginning of the file with links to its children. It
158
158
tries to move the more important children before the ` Clusters ` , and moves the
159
159
rest to the end of the file. Its requirements for consistency are also a bit
@@ -174,3 +174,252 @@ The output may span multiple lines, although it is not terminated by a newline.
174
174
to a specified recursion depth) and concatenates them with indentation in a
175
175
newline-terminated string. The latter returns a newline-terminated table
176
176
summarizing which child (and descendent) elements occupy which blocks of space.
177
+
178
+ ## Example
179
+
180
+ Load a Matroska file:
181
+ ``` python
182
+ from ebml.container import File
183
+ ebml_file = File(' The_Blues_Brothers.mkv' )
184
+ ```
185
+
186
+ Output:
187
+ ```
188
+ INFO:ebml.container:Read summary in 0.084 seconds
189
+ ```
190
+
191
+ ``` python
192
+ print (ebml_file.summary())
193
+ ```
194
+
195
+ Output:
196
+ ```
197
+ File: stream=<_io.BufferedReader name='The_Blues_Brothers.mkv'>, size=27147770837, 2 children
198
+ ElementSegment Segment (12+27147770785 @40): 11 children
199
+ Segment UID: CE:C4:57:4C:E0:1E:AD:7C:14:D7:2C:84:44:B4:8E:50
200
+ Title: 'The Blues Brothers'
201
+ Duration: 8866.94 seconds
202
+ Time scale: 1000000 nanoseconds
203
+ Muxing app: 'libmakemkv v1.8.9 (1.3.0/1.4.1) x86_64-linux-gnu'
204
+ Writing app: 'MakeMKV v1.8.9 linux(x64-release)'
205
+ Seek entries:
206
+ Chapters: 1907
207
+ Cues: 27147145828
208
+ Info: 2944
209
+ Tags: 27147331697
210
+ Attachments: 27147336885
211
+ Tracks: 1292
212
+ Attachments:
213
+ ElementAttachedFile: 'myth_metadata.xml' (application/xml), 21232 bytes: 'Master XML metadata'
214
+ UID: 34:4B:C9:07:67:3D:6B:E5
215
+ ElementAttachedFile: 'cover.jpg' (image/jpeg), 200376 bytes: 'Cover image'
216
+ UID: 7C:F7:FC:C9:FF:1F:F1:AD
217
+ ElementAttachedFile: 'fanart.jpg' (image/jpeg), 212080 bytes: 'Fan art image'
218
+ UID: E9:EF:E2:31:8C:12:E3:49
219
+ Tracks:
220
+ ElementTrackEntry: video lang=eng codec=V_MPEG4/ISO/AVC num=1 uid=1
221
+ Flags: enabled default !forced !lacing
222
+ ElementVideo: dims=1920x1080, display=1920x1080, aspect='free resizing'
223
+ Stereo: mono
224
+ Interlaced: False
225
+ ElementTrackEntry: audio lang=eng codec=A_DTS num=2 uid=2: 'Surround 5.1'
226
+ Flags: enabled default !forced lacing
227
+ ElementAudio: channels=6 sampling=48k
228
+ ElementTrackEntry: audio lang=fra codec=A_DTS num=3 uid=3: 'Stereo'
229
+ Flags: enabled !default !forced lacing
230
+ ElementAudio: channels=2 sampling=48k
231
+ ElementTrackEntry: subtitle lang=eng codec=S_HDMV/PGS num=4 uid=4
232
+ Flags: enabled default !forced !lacing
233
+ ElementTrackEntry: subtitle lang=spa codec=S_HDMV/PGS num=6 uid=6
234
+ Flags: enabled !default !forced !lacing
235
+ ElementTrackEntry: subtitle lang=fra codec=S_HDMV/PGS num=8 uid=8
236
+ Flags: enabled !default !forced !lacing
237
+ ElementTrackEntry: subtitle lang=fra codec=S_HDMV/PGS num=10 uid=10
238
+ Flags: enabled !default forced !lacing
239
+ Tags:
240
+ ElementTag: MOVIE (50), 67 tags
241
+ ElementSimpleTag lang=eng def=True: 'TITLE' => 'The Blues Brothers'
242
+ ElementSimpleTag lang=eng def=True: 'DIRECTOR' => 'John Landis'
243
+ ElementSimpleTag lang=eng def=True: 'GENRE' => 'Comedy'
244
+ ElementSimpleTag lang=eng def=True: 'ACTOR' => 'Dan Aykroyd'
245
+ ElementSimpleTag lang=eng def=True: 'CHARACTER' => 'Elwood Blues (as Elwood)'
246
+ ElementSimpleTag lang=eng def=True: 'ACTOR' => 'John Belushi'
247
+ ElementSimpleTag lang=eng def=True: 'CHARACTER' => "'Joliet' Jake Blues (as Jake)"
248
+ ...
249
+ ```
250
+
251
+ Get the main segment of the file:
252
+ ``` python
253
+ segment = next (ebml_file.children_named(' Segment' ))
254
+ segment
255
+ ```
256
+
257
+ Output (` __repr__() ` version):
258
+ ```
259
+ <ElementSegment [18:53:80:67] 'Segment' size=12+27147770785 @40>
260
+ ```
261
+
262
+ ``` python
263
+ str (segment)
264
+ ```
265
+
266
+ output (` __str__() ` version):
267
+ ```
268
+ 'ElementSegment Segment (12+27147770785 @40): 11 children'
269
+ ```
270
+
271
+ Add an attached file with the ` Segment.add_attachment() ` convenience function.
272
+ ``` python
273
+ with open (' banner.jpg' , ' rb' ) as f:
274
+ banner_contents = f.read()
275
+ attachment = segment.add_attachment(' banner.jpg' , ' image/jpeg' , ' Banner image' )
276
+ attachment.file_data = banner_contents
277
+ attachment.summary()
278
+ ```
279
+
280
+ Output:
281
+ ```
282
+ "ElementAttachedFile: 'banner.jpg' (image/jpeg), 104464 bytes: 'Banner image'\n UID: 07:10:12:34:11:A3:F1:43"
283
+ ```
284
+
285
+ ``` python
286
+ print (ebml_file.summary())
287
+ ```
288
+
289
+ Output (note that it lists the new attachment):
290
+ ```
291
+ File: stream=<_io.BufferedReader name='The_Blues_Brothers.mkv'>, size=27147770837, 2 children
292
+ ElementSegment Segment (12+27147770785 @40): 11 children
293
+ Segment UID: CE:C4:57:4C:E0:1E:AD:7C:14:D7:2C:84:44:B4:8E:50
294
+ Title: 'The Blues Brothers'
295
+ Duration: 8866.94 seconds
296
+ Time scale: 1000000 nanoseconds
297
+ Muxing app: 'libmakemkv v1.8.9 (1.3.0/1.4.1) x86_64-linux-gnu'
298
+ Writing app: 'MakeMKV v1.8.9 linux(x64-release)'
299
+ Seek entries:
300
+ Chapters: 1907
301
+ Cues: 27147145828
302
+ Info: 2944
303
+ Tags: 27147331697
304
+ Attachments: 27147336885
305
+ Tracks: 1292
306
+ Attachments:
307
+ ElementAttachedFile: 'myth_metadata.xml' (application/xml), 21232 bytes: 'Master XML metadata'
308
+ UID: 34:4B:C9:07:67:3D:6B:E5
309
+ ElementAttachedFile: 'cover.jpg' (image/jpeg), 200376 bytes: 'Cover image'
310
+ UID: 7C:F7:FC:C9:FF:1F:F1:AD
311
+ ElementAttachedFile: 'fanart.jpg' (image/jpeg), 212080 bytes: 'Fan art image'
312
+ UID: E9:EF:E2:31:8C:12:E3:49
313
+ ElementAttachedFile: 'banner.jpg' (image/jpeg), 104464 bytes: 'Banner image'
314
+ UID: 07:10:12:34:11:A3:F1:43
315
+ Tracks:
316
+ ElementTrackEntry: video lang=eng codec=V_MPEG4/ISO/AVC num=1 uid=1
317
+ Flags: enabled default !forced !lacing
318
+ ElementVideo: dims=1920x1080, display=1920x1080, aspect='free resizing'
319
+ Stereo: mono
320
+ Interlaced: False
321
+ ElementTrackEntry: audio lang=eng codec=A_DTS num=2 uid=2: 'Surround 5.1'
322
+ Flags: enabled default !forced lacing
323
+ ElementAudio: channels=6 sampling=48k
324
+ ElementTrackEntry: audio lang=fra codec=A_DTS num=3 uid=3: 'Stereo'
325
+ Flags: enabled !default !forced lacing
326
+ ElementAudio: channels=2 sampling=48k
327
+ ElementTrackEntry: subtitle lang=eng codec=S_HDMV/PGS num=4 uid=4
328
+ Flags: enabled default !forced !lacing
329
+ ElementTrackEntry: subtitle lang=spa codec=S_HDMV/PGS num=6 uid=6
330
+ Flags: enabled !default !forced !lacing
331
+ ElementTrackEntry: subtitle lang=fra codec=S_HDMV/PGS num=8 uid=8
332
+ Flags: enabled !default !forced !lacing
333
+ ElementTrackEntry: subtitle lang=fra codec=S_HDMV/PGS num=10 uid=10
334
+ Flags: enabled !default forced !lacing
335
+ Tags:
336
+ ElementTag: MOVIE (50), 67 tags
337
+ ElementSimpleTag lang=eng def=True: 'TITLE' => 'The Blues Brothers'
338
+ ElementSimpleTag lang=eng def=True: 'DIRECTOR' => 'John Landis'
339
+ ElementSimpleTag lang=eng def=True: 'GENRE' => 'Comedy'
340
+ ElementSimpleTag lang=eng def=True: 'ACTOR' => 'Dan Aykroyd'
341
+ ElementSimpleTag lang=eng def=True: 'CHARACTER' => 'Elwood Blues (as Elwood)'
342
+ ElementSimpleTag lang=eng def=True: 'ACTOR' => 'John Belushi'
343
+ ElementSimpleTag lang=eng def=True: 'CHARACTER' => "'Joliet' Jake Blues (as Jake)"
344
+ ...
345
+ ```
346
+
347
+ Where did the attachment go? Here's how the segment tracks its space:
348
+ ``` python
349
+ print (segment.print_space())
350
+ ```
351
+
352
+ Output:
353
+ ```
354
+ 1> 0 --131 | 0 --131 | 131 bytes: [ 0] SeekHead
355
+ 1> 131 --1292 | 131 --1292 | 1161 bytes: [ 1] Void
356
+ 1> 1292 --1877 | 1292 --1877 | 585 bytes: [ 2] Tracks
357
+ 1> 1877 --1907 | 1877 --1907 | 30 bytes: [ 3] Void
358
+ 1> 1907 --2944 | 1907 --2944 | 1037 bytes: [ 4] Chapters
359
+ 1> 2944 --3102 | 2944 --3102 | 158 bytes: [ 5] Info
360
+ 1> 3102 --3968 | 3102 --3968 | 866 bytes: [ 6] Void
361
+ 1> 3968 --27147145828 | 3968 --27147145828 | 27147141860 bytes: ***NO CHILD***
362
+ 1> 27147145828--27147331697 | 27147145828--27147331697 | 185869 bytes: [ 7] Cues
363
+ 1> 27147331697--27147336787 | 27147331697--27147336787 | 5090 bytes: [ 8] Tags
364
+ 1> 27147336787--27147336885 | 27147336787--27147336885 | 98 bytes: [ 9] Void
365
+ 1> 27147336885--27147770785 | 27147336885--27147770785 | 433900 bytes: [10] Attachments
366
+ ```
367
+
368
+ As far as the segment knows, it's still in a consistent state, because attachments are
369
+ actually grandchildren of the Segment.
370
+ ``` python
371
+ attachments = next (segment.children_named(' Attachments' ))
372
+ print (attachments.print_space())
373
+ ```
374
+
375
+ Output: you can see that it still only has 6 bytes allocated to the new attached file.
376
+ ```
377
+ 1> 0 --21313 | 0 --21313 | 21313 bytes: [ 0] AttachedFile
378
+ 1> 21313 --221749 | 21313 --221749 | 200436 bytes: [ 1] AttachedFile
379
+ 1> 221749 --433893 | 221749 --433893 | 212144 bytes: [ 2] AttachedFile
380
+ 1> 433893 --433899 | 433893 --433899 | 6 bytes: [ 3] AttachedFile
381
+ 1> 433893 --433899 | 433893 --433899 | 6 bytes: ***OVERFLOW***
382
+ ```
383
+
384
+ The call to ` segment.normalize() ` is the most intellegent, catch-all method for
385
+ recursively rearranging an mkv file without moving Cues or Clusters (i.e. the parts
386
+ that take up 99% of the file). Of course, in this case it doesn't have to work very
387
+ hard since the attachments are already at the end of the file.
388
+ ``` python
389
+ segment.normalize()
390
+ print (segment.print_space())
391
+ ```
392
+
393
+ Output: note that Attachments has grown.
394
+ ```
395
+ 1> 0 --131 | 0 --131 | 131 bytes: [ 0] SeekHead
396
+ 1> 131 --1292 | 131 --1292 | 1161 bytes: [ 1] Void
397
+ 1> 1292 --1877 | 1292 --1877 | 585 bytes: [ 2] Tracks
398
+ 1> 1877 --1907 | 1877 --1907 | 30 bytes: [ 3] Void
399
+ 1> 1907 --2944 | 1907 --2944 | 1037 bytes: [ 4] Chapters
400
+ 1> 2944 --3102 | 2944 --3102 | 158 bytes: [ 5] Info
401
+ 1> 3102 --3968 | 3102 --3968 | 866 bytes: [ 6] Void
402
+ 1> 3968 --27147145828 | 3968 --27147145828 | 27147141860 bytes: ***NO CHILD***
403
+ 1> 27147145828--27147331697 | 27147145828--27147331697 | 185869 bytes: [ 7] Cues
404
+ 1> 27147331697--27147336787 | 27147331697--27147336787 | 5090 bytes: [ 8] Tags
405
+ 1> 27147336787--27147336885 | 27147336787--27147336885 | 98 bytes: [ 9] Void
406
+ 1> 27147336885--27147875312 | 27147336885--27147875312 | 538427 bytes: [10] Attachments
407
+ ```
408
+
409
+ ``` python
410
+ print (attachments.print_space())
411
+ ```
412
+
413
+ Output: now there's enough space for the attached file.
414
+ ```
415
+ 1> 0 --21313 | 0 --21313 | 21313 bytes: [ 0] AttachedFile
416
+ 1> 21313 --221749 | 21313 --221749 | 200436 bytes: [ 1] AttachedFile
417
+ 1> 221749 --433893 | 221749 --433893 | 212144 bytes: [ 2] AttachedFile
418
+ 1> 433893 --538420 | 433893 --538420 | 104527 bytes: [ 3] AttachedFile
419
+ ```
420
+
421
+ Save the changes to the file:
422
+ ``` python
423
+ with open (' /dev/null' , ' wb' ) as f:
424
+ ebml_file.save_changes(f)
425
+ ```
0 commit comments