项目作者: DicomJ

项目描述 :
mpeg-isobmf/mp4 profiling library
高级语言: C++
项目地址: git://github.com/DicomJ/mpeg-profiler.git
创建时间: 2018-10-21T18:15:15Z
项目社区:https://github.com/DicomJ/mpeg-profiler

开源协议:GNU Affero General Public License v3.0

下载


MPEG-PROFILER - mpeg-isobmf/mp4 profiling library

Key features

  1. Like MPEG-ISOBASE library it’s totally use-case agnostic. Provides pure MPEG-ISOBMF/MP4 profiling abilities without superfluous functionality;
  2. Simplified data model represented as Container of Tracks with Media::Samples;
  3. Simplified memory managment what results into a single user faced std::unique_ptr. No shared objects (and so responsibilities);
  4. Fine-grained access to the Box tree;
  5. Ultrasmart Media::Samples::Iterator facilitates access to the timing and data indexing information of the Media::Samples in the Track and hides all the complexity of iteration over stbl related Boxes;
  6. Seeking abilities with almost O(1) complexity by time in any scale (mvhd or mdhd) or by time in seconds;
  7. Apart and like MPEG-ISOBASE it relies only on pure C++ and C++ Standard Library.

What’s is not

It’s not a full featured media stream processing solution which does repackaging. Nevertheless, it’s very easy to build such solutions based on MPEG-PROFILER and MPEG-ISOBASE libraries. For example:

https://github.com/DicomJ/mpeg-packager

Known limitations:

It implies the same limitations as MPEG-ISOBASE library as it’s based on it.

Building

If you would like to check out and build MPEG-PROFILER library, the procedure is as follows (requires modern C++17 compiler):

  1. Check out MPEG-PROFILER

    1. git clone git@github.com:DicomJ/mpeg-profiler.git mpeg-profiler
  2. Build MPEG-PROFILER

    1. mkdir mpeg-profiler/build
    2. cd mpeg-profiler/build
    3. cmake -DCMAKE_BUILD_TYPE=Release -DCXX_STD=c++17 -DCMAKE_INSTALL_PREFIX=$(pwd)/install $(pwd)/../../mpeg-profiler
    4. make install

Usage

Profiling

All parsing hard work is done by mpeg::isobase::Parser of MPEG-ISOBASE library. Profiler is just an implementation of Parser::Observer which handles corresponding parsing events.

  1. cat ../../mpeg-profiler/demo/dump.cc
  1. bitstream::input::file::Stream stream("sample.mp4");
  2. mpeg::profiler::Profiler profiler;
  3. mpeg::isobase::Parser parser(stream, profiler);
  4. parser.parse();

Container

As the result of profiling Container object is built and could be detached as std::unique_ptr off the Profiler object:

  1. auto container_ptr = profiler.detach_container();
  2. const auto &container = *container_ptr;

Container object is a root node of Box tree starting from which all other Boxes could be obtained by the following methods (note that all returned types are weak references/pointers to the objects life time of which is determined by std::unique_ptr of detached Container object):

  • traverse to the required Box by the subscript operator []:

    1. const auto &mvhd = container['moov']['mvhd'];
  • obtain Box object casted to its type by counterpart as method:

    1. const auto &mvhd = container['moov'].as<Movie::Header>('mvhd');
  • obtain a pointer to the optional Box by get method. nullptr is returned if object is not found:

    1. assert(container.get('foo ') == nullptr);
  • obtain optional object but casted to its type:

    1. const Foo *foo = container.get<Foo>('bar ');
  • if there’re more than one Box all method should be used to iterate over them:

    1. for (const auto &track: container['moov'].all<Track>('trak')) {
    2. track['mdia'].as<Media::Header>('mdhd');
    3. // ...
    4. }

Tracks

Container object itself has a built in methods to iterate over tracks, even though technically tracks are stored under moov Box:

  1. container.tracks(); // all tracks
  2. container.video_tracks();
  3. container.audio_tracks();

In its turn Track object has handy methods to figure out the type of track:

  1. track.is_audio();
  2. track.is_video();

Samples

Conceptually Track comprises Media::Samples, mostly defined by stbl Box. So Track object has corresponding method to obtain the Media::Samples object:

  1. const auto &samples = track.samples();

Media::Samples object encapsulates all the details of traversing over stbl Box by exposing very simple Sample::Iterator interface.

  1. assert(samples.count() == (samples.end() - samples.begin()));
  2. for (auto it = samples.begin(); it != samples.end(); ++it) {
  3. // ...
  4. }

Samples::Iterator can be obtained at any Media::Sample by its index in the following range [0, samples.count()) :

  1. const auto &it = samples.at(i);

Then a Media::Sample itself can be obtained by dereferencing Sample::Iterator:

  1. const auto &sample = *it;

The Media::Sample object provides all the time and data indexing infomation defined by the following interface:

  1. struct Media::Sample {
  2. // Timing information
  3. Time decoding_time() const;
  4. Time composition_time() const;
  5. // Offset in bytes within media defined by the DataReferenceBox
  6. uint64_t offset() const;
  7. // Size of sample in bytes
  8. uint32_t size() const;
  9. // Sample's metadata
  10. const SampleEntry &sample_entry() const;
  11. const DependencyType::Entry *dependency() const; // optional
  12. // The rest technical indexes and metadata there's no real reason to care about
  13. ...
  14. }

Seeking

Media::Samples object exposes methods which allow to seek by time in mdhd or mvhd timescales or by time in seconds. As the result index of the Media::Sample is returned. The following example demonstrates how to iterate over all Media::samples in all Tracks from 5.7s up to 6.3s:

  1. for (const auto &track: container.tracks()) {
  2. const auto begin = samples.seek(5.7), end = samples.seek(6.3);
  3. auto i = 0;
  4. for (auto it = samples.at(begin); it != end; ++it) {
  5. const auto &sample = *it;
  6. std::cout
  7. << "#" << std::setw(3) << std::left << i++ << ": ["
  8. << "time: " << sample.decoding_time().seconds() << "s, "
  9. << "size: " << sample.size() << " bytes, "
  10. << "offset: " << sample.offset() << " bytes]" << std::endl;
  11. }
  12. }

Note that by default Sync Sample Table is used to locate real random access point (RAP) prior sample determined by given time. What means that unlike in this example and first of all seeking should happen on the video Track to determine the time boundaries of the segment aligned by random access points of the video Track, and only then do seeking on the rest required audio and other Tracks which has more fine-grained alignment of RAPs. Checkout the output of this example:

  1. soun: 26 samples:
  2. #0 : [time: 5.69s, size: 213 bytes, offset: 392953 bytes]
  3. #1 : [time: 5.71s, size: 206 bytes, offset: 393166 bytes]
  4. #2 : [time: 5.74s, size: 194 bytes, offset: 393372 bytes]
  5. #3 : [time: 5.76s, size: 209 bytes, offset: 393566 bytes]
  6. #4 : [time: 5.78s, size: 201 bytes, offset: 393775 bytes]
  7. ...
  8. #21 : [time: 6.18s, size: 206 bytes, offset: 443427 bytes]
  9. #22 : [time: 6.20s, size: 231 bytes, offset: 443633 bytes]
  10. #23 : [time: 6.22s, size: 193 bytes, offset: 443864 bytes]
  11. #24 : [time: 6.25s, size: 202 bytes, offset: 444057 bytes]
  12. #25 : [time: 6.27s, size: 220 bytes, offset: 444259 bytes]
  13. vide: 24 samples:
  14. #0 : [time: 4.99s, size: 22215 bytes, offset: 327198 bytes]
  15. #1 : [time: 5.03s, size: 3488 bytes, offset: 349413 bytes]
  16. #2 : [time: 5.08s, size: 1373 bytes, offset: 352901 bytes]
  17. #3 : [time: 5.12s, size: 1604 bytes, offset: 354274 bytes]
  18. #4 : [time: 5.16s, size: 1707 bytes, offset: 355878 bytes]
  19. ...
  20. #18 : [time: 5.74s, size: 2913 bytes, offset: 399832 bytes]
  21. #19 : [time: 5.78s, size: 1939 bytes, offset: 402745 bytes]
  22. #20 : [time: 5.82s, size: 2232 bytes, offset: 404684 bytes]
  23. #21 : [time: 5.87s, size: 2316 bytes, offset: 406916 bytes]
  24. #22 : [time: 5.91s, size: 2383 bytes, offset: 409232 bytes]
  25. #23 : [time: 5.95s, size: 2374 bytes, offset: 411615 bytes]

no_sync=true could be specified while seeking to avoid alignment on RAPs:

  1. const auto begin = samples.seek(5.7, no_sync=true), end = samples.seek(6.3, no_sync=true);

The result is still the same 26 audio samples, and only 14 video samples, started from and ended with not aligned RAPs in the video Track:

  1. soun: 26 samples:
  2. #0 : [time: 5.69s, size: 213 bytes, offset: 392953 bytes]
  3. #1 : [time: 5.71s, size: 206 bytes, offset: 393166 bytes]
  4. #2 : [time: 5.74s, size: 194 bytes, offset: 393372 bytes]
  5. #3 : [time: 5.76s, size: 209 bytes, offset: 393566 bytes]
  6. #4 : [time: 5.78s, size: 201 bytes, offset: 393775 bytes]
  7. ...
  8. #21 : [time: 6.18s, size: 206 bytes, offset: 443427 bytes]
  9. #22 : [time: 6.20s, size: 231 bytes, offset: 443633 bytes]
  10. #23 : [time: 6.22s, size: 193 bytes, offset: 443864 bytes]
  11. #24 : [time: 6.25s, size: 202 bytes, offset: 444057 bytes]
  12. #25 : [time: 6.27s, size: 220 bytes, offset: 444259 bytes]
  13. vide: 14 samples:
  14. #0 : [time: 5.70s, size: 2889 bytes, offset: 396943 bytes]
  15. #1 : [time: 5.74s, size: 2913 bytes, offset: 399832 bytes]
  16. #2 : [time: 5.78s, size: 1939 bytes, offset: 402745 bytes]
  17. #3 : [time: 5.82s, size: 2232 bytes, offset: 404684 bytes]
  18. #4 : [time: 5.87s, size: 2316 bytes, offset: 406916 bytes]
  19. ...
  20. #9 : [time: 6.07s, size: 1094 bytes, offset: 439393 bytes]
  21. #10 : [time: 6.12s, size: 1255 bytes, offset: 440487 bytes]
  22. #11 : [time: 6.16s, size: 1264 bytes, offset: 441742 bytes]
  23. #12 : [time: 6.20s, size: 1308 bytes, offset: 447492 bytes]
  24. #13 : [time: 6.24s, size: 1361 bytes, offset: 448800 bytes]

What else?

  1. Entire container can be dumped by the following few lines of code:

    1. cat ../../mpeg-profiler/demo/dump.cc
    1. auto container_ptr = profiler.detach_container();
    2. const auto &container = *container_ptr;
    3. bitstream::output::print::to_stdout << container;
  2. Build and run it:

    1. g++ \
    2. -o dump \
    3. -std=c++17 -Wno-multichar \
    4. -I install/include \
    5. -Wl,-rpath,$(pwd)/install/lib64 install/lib64/*.so \
    6. ../../mpeg-profiler/demo/dump.cc
    7. time ./dump sample.mp4
  3. Check out the output

    1. | Container: [major_brand: mp42, minor_version: 1, compatible_brands: [mp42, avc1]]
    2. | Data: [size: 5229792 bytes in 2 'mdat' boxes]
    3. +- Movie [duration: 36048/600=60.08s, created: Wed Mar 16 10:41:51 2011, modified: Wed Mar 16 10:42:48 2011]
    4. | +- Track(soun) [duration: 36048/600=60.08s, created: Wed Mar 16 10:41:53 2011, modified: Wed Mar 16 10:42:48 2011]
    5. | | +- Edit List: [duration: 36048/600=60.08s, time: 0/44100=0.00s, rate: 1.00]
    6. | | +- Media [duration: 2652160/44100=60.14s, language: English, created: Wed Mar 16 10:41:53 2011, modified: Wed Mar 16 10:42:48 2011]
    7. | | | +- Samples [
    8. | | | | Decoding times: [duration: 2652160/44100=60.14s, 2590 samples (in 1 entry)],
    9. | | | | Descriptions: [1 entry, mp4a, reference: [#0: <same file>], channels: 2, sample size: 16, sample rate: 44100.00],
    10. | | | | Sizes: [2590 samples, total size: 470957 bytes (9.01%)],
    11. | | | | Samples to chunks: [2590 samples (in 236 runs)],
    12. | | | | Chunks (offsets): [236 chunks],
    13. | | | | ]
    14. | | | | #0:
    15. | | | | size: 4 bytes
    16. | | | | decoding: [#0: time: 0/44100=0.00s]
    17. | | | | composition: [offset: 0/44100=0.00s, time: 0/44100=0.00s]
    18. | | | | chunk: [#0: first_index: 0, index: 0, offset: 44558 bytes]
    19. | | | | offset: [44558 bytes, #0 samples in #0 chunck of 14 sampleses in run of 1 chunk]
    20. | | | | description: [#0: mp4a, reference: [#0: <same file>], channels: 2, sample size: 16, sample rate: 44100.00]
    21. | | | | #1:
    22. | | | | size: 56 bytes
    23. | | | | decoding: [#0: time: 1024/44100=0.02s]
    24. | | | | composition: [offset: 0/44100=0.00s, time: 1024/44100=0.02s]
    25. | | | | chunk: [#0: first_index: 0, index: 0, offset: 44558 bytes]
    26. | | | | offset: [44562 bytes, #1 samples in #0 chunck of 14 sampleses in run of 1 chunk]
    27. | | | | description: [#0: mp4a, reference: [#0: <same file>], channels: 2, sample size: 16, sample rate: 44100.00]
    28. | | | | #2:
    29. | | | | size: 200 bytes
    30. | | | | decoding: [#0: time: 2048/44100=0.05s]
    31. | | | | composition: [offset: 0/44100=0.00s, time: 2048/44100=0.05s]
    32. | | | | chunk: [#0: first_index: 0, index: 0, offset: 44558 bytes]
    33. | | | | offset: [44618 bytes, #2 samples in #0 chunck of 14 sampleses in run of 1 chunk]
    34. | | | | description: [#0: mp4a, reference: [#0: <same file>], channels: 2, sample size: 16, sample rate: 44100.00]
    35. | | | | #3:
    36. | | | | size: 264 bytes
    37. | | | | decoding: [#0: time: 3072/44100=0.07s]
    38. | | | | composition: [offset: 0/44100=0.00s, time: 3072/44100=0.07s]
    39. | | | | chunk: [#0: first_index: 0, index: 0, offset: 44558 bytes]
    40. | | | | offset: [44818 bytes, #3 samples in #0 chunck of 14 sampleses in run of 1 chunk]
    41. | | | | description: [#0: mp4a, reference: [#0: <same file>], channels: 2, sample size: 16, sample rate: 44100.00]
    42. | | | | #4:
    43. | | | | size: 221 bytes
    44. | | | | decoding: [#0: time: 4096/44100=0.09s]
    45. | | | | composition: [offset: 0/44100=0.00s, time: 4096/44100=0.09s]
    46. | | | | chunk: [#0: first_index: 0, index: 0, offset: 44558 bytes]
    47. | | | | offset: [45082 bytes, #4 samples in #0 chunck of 14 sampleses in run of 1 chunk]
    48. | | | | description: [#0: mp4a, reference: [#0: <same file>], channels: 2, sample size: 16, sample rate: 44100.00]
    49. | | | |
    50. | | | | ...
    51. | | | |
    52. | | | | #2585:
    53. | | | | size: 143 bytes
    54. | | | | decoding: [#0: time: 2647040/44100=60.02s]
    55. | | | | composition: [offset: 0/44100=0.00s, time: 2647040/44100=60.02s]
    56. | | | | chunk: [#234: first_index: 234, index: 234, offset: 5170386 bytes]
    57. | | | | offset: [5172369 bytes, #11 samples in #0 chunck of 13 sampleses in run of 1 chunk]
    58. | | | | description: [#0: mp4a, reference: [#0: <same file>], channels: 2, sample size: 16, sample rate: 44100.00]
    59. | | | | #2586:
    60. | | | | size: 61 bytes
    61. | | | | decoding: [#0: time: 2648064/44100=60.05s]
    62. | | | | composition: [offset: 0/44100=0.00s, time: 2648064/44100=60.05s]
    63. | | | | chunk: [#234: first_index: 234, index: 234, offset: 5170386 bytes]
    64. | | | | offset: [5172512 bytes, #12 samples in #0 chunck of 13 sampleses in run of 1 chunk]
    65. | | | | description: [#0: mp4a, reference: [#0: <same file>], channels: 2, sample size: 16, sample rate: 44100.00]
    66. | | | | #2587:
    67. | | | | size: 4 bytes
    68. | | | | decoding: [#0: time: 2649088/44100=60.07s]
    69. | | | | composition: [offset: 0/44100=0.00s, time: 2649088/44100=60.07s]
    70. | | | | chunk: [#235: first_index: 235, index: 235, offset: 5172573 bytes]
    71. | | | | offset: [5172573 bytes, #0 samples in #0 chunck of 3 sampleses in run of 1 chunk]
    72. | | | | description: [#0: mp4a, reference: [#0: <same file>], channels: 2, sample size: 16, sample rate: 44100.00]
    73. | | | | #2588:
    74. | | | | size: 4 bytes
    75. | | | | decoding: [#0: time: 2650112/44100=60.09s]
    76. | | | | composition: [offset: 0/44100=0.00s, time: 2650112/44100=60.09s]
    77. | | | | chunk: [#235: first_index: 235, index: 235, offset: 5172573 bytes]
    78. | | | | offset: [5172577 bytes, #1 samples in #0 chunck of 3 sampleses in run of 1 chunk]
    79. | | | | description: [#0: mp4a, reference: [#0: <same file>], channels: 2, sample size: 16, sample rate: 44100.00]
    80. | | | | #2589:
    81. | | | | size: 4 bytes
    82. | | | | decoding: [#0: time: 2651136/44100=60.12s]
    83. | | | | composition: [offset: 0/44100=0.00s, time: 2651136/44100=60.12s]
    84. | | | | chunk: [#235: first_index: 235, index: 235, offset: 5172573 bytes]
    85. | | | | offset: [5172581 bytes, #2 samples in #0 chunck of 3 sampleses in run of 1 chunk]
    86. | | | | description: [#0: mp4a, reference: [#0: <same file>], channels: 2, sample size: 16, sample rate: 44100.00]
    87. | +- Track(vide) [duration: 36048/600=60.08s, resolution: 640.00x360.00, created: Wed Mar 16 10:41:52 2011, modified: Wed Mar 16 10:42:48 2011]
    88. | | +- Edit List: [duration: 36048/600=60.08s, time: 0/2500=0.00s, rate: 1.00]
    89. | | +- Media [duration: 150280/2500=60.11s, language: English, created: Wed Mar 16 10:41:52 2011, modified: Wed Mar 16 10:42:48 2011]
    90. | | | +- Samples [
    91. | | | | Decoding times: [duration: 150280/2500=60.11s, 1445 samples (in 1 entry)],
    92. | | | | Descriptions: [1 entry, avc1, reference: [#0: <same file>], compressor: <undetermined>, 640 x 360, resolution: 72.00 x 72.00, frames per sample: 1],
    93. | | | | Sizes: [1445 samples, total size: 4758819 bytes (90.99%)],
    94. | | | | Samples to chunks: [1445 samples (in 11 runs)],
    95. | | | | Chunks (offsets): [119 chunks],
    96. | | | | Sync samples: [61 entries],
    97. | | | | ]
    98. | | | | #0:
    99. | | | | size: 28627 bytes
    100. | | | | decoding: [#0: time: 0/2500=0.00s]
    101. | | | | composition: [offset: 0/2500=0.00s, time: 0/2500=0.00s]
    102. | | | | chunk: [#0: first_index: 0, index: 0, offset: 40 bytes]
    103. | | | | offset: [40 bytes, #0 samples in #0 chunck of 5 sampleses in run of 1 chunk]
    104. | | | | description: [#0: avc1, reference: [#0: <same file>], compressor: <undetermined>, 640 x 360, resolution: 72.00 x 72.00, frames per sample: 1]
    105. | | | | #1:
    106. | | | | size: 12533 bytes
    107. | | | | decoding: [#0: time: 104/2500=0.04s]
    108. | | | | composition: [offset: 0/2500=0.00s, time: 104/2500=0.04s]
    109. | | | | chunk: [#0: first_index: 0, index: 0, offset: 40 bytes]
    110. | | | | offset: [28667 bytes, #1 samples in #0 chunck of 5 sampleses in run of 1 chunk]
    111. | | | | description: [#0: avc1, reference: [#0: <same file>], compressor: <undetermined>, 640 x 360, resolution: 72.00 x 72.00, frames per sample: 1]
    112. | | | | #2:
    113. | | | | size: 1239 bytes
    114. | | | | decoding: [#0: time: 208/2500=0.08s]
    115. | | | | composition: [offset: 0/2500=0.00s, time: 208/2500=0.08s]
    116. | | | | chunk: [#0: first_index: 0, index: 0, offset: 40 bytes]
    117. | | | | offset: [41200 bytes, #2 samples in #0 chunck of 5 sampleses in run of 1 chunk]
    118. | | | | description: [#0: avc1, reference: [#0: <same file>], compressor: <undetermined>, 640 x 360, resolution: 72.00 x 72.00, frames per sample: 1]
    119. | | | | #3:
    120. | | | | size: 1024 bytes
    121. | | | | decoding: [#0: time: 312/2500=0.12s]
    122. | | | | composition: [offset: 0/2500=0.00s, time: 312/2500=0.12s]
    123. | | | | chunk: [#0: first_index: 0, index: 0, offset: 40 bytes]
    124. | | | | offset: [42439 bytes, #3 samples in #0 chunck of 5 sampleses in run of 1 chunk]
    125. | | | | description: [#0: avc1, reference: [#0: <same file>], compressor: <undetermined>, 640 x 360, resolution: 72.00 x 72.00, frames per sample: 1]
    126. | | | | #4:
    127. | | | | size: 1095 bytes
    128. | | | | decoding: [#0: time: 416/2500=0.17s]
    129. | | | | composition: [offset: 0/2500=0.00s, time: 416/2500=0.17s]
    130. | | | | chunk: [#0: first_index: 0, index: 0, offset: 40 bytes]
    131. | | | | offset: [43463 bytes, #4 samples in #0 chunck of 5 sampleses in run of 1 chunk]
    132. | | | | description: [#0: avc1, reference: [#0: <same file>], compressor: <undetermined>, 640 x 360, resolution: 72.00 x 72.00, frames per sample: 1]
    133. | | | |
    134. | | | | ...
    135. | | | |
    136. | | | | #1440:
    137. | | | | size: 34173 bytes
    138. | | | | decoding: [#0: time: 149760/2500=59.90s]
    139. | | | | composition: [offset: 0/2500=0.00s, time: 149760/2500=59.90s]
    140. | | | | chunk: [#10: first_index: 118, index: 118, offset: 5172585 bytes]
    141. | | | | offset: [5188518 bytes, #5 samples in #0 chunck of 10 sampleses in run of 1 chunk]
    142. | | | | description: [#0: avc1, reference: [#0: <same file>], compressor: <undetermined>, 640 x 360, resolution: 72.00 x 72.00, frames per sample: 1]
    143. | | | | #1441:
    144. | | | | size: 1573 bytes
    145. | | | | decoding: [#0: time: 149864/2500=59.95s]
    146. | | | | composition: [offset: 0/2500=0.00s, time: 149864/2500=59.95s]
    147. | | | | chunk: [#10: first_index: 118, index: 118, offset: 5172585 bytes]
    148. | | | | offset: [5222691 bytes, #6 samples in #0 chunck of 10 sampleses in run of 1 chunk]
    149. | | | | description: [#0: avc1, reference: [#0: <same file>], compressor: <undetermined>, 640 x 360, resolution: 72.00 x 72.00, frames per sample: 1]
    150. | | | | #1442:
    151. | | | | size: 3000 bytes
    152. | | | | decoding: [#0: time: 149968/2500=59.99s]
    153. | | | | composition: [offset: 0/2500=0.00s, time: 149968/2500=59.99s]
    154. | | | | chunk: [#10: first_index: 118, index: 118, offset: 5172585 bytes]
    155. | | | | offset: [5224264 bytes, #7 samples in #0 chunck of 10 sampleses in run of 1 chunk]
    156. | | | | description: [#0: avc1, reference: [#0: <same file>], compressor: <undetermined>, 640 x 360, resolution: 72.00 x 72.00, frames per sample: 1]
    157. | | | | #1443:
    158. | | | | size: 1588 bytes
    159. | | | | decoding: [#0: time: 150072/2500=60.03s]
    160. | | | | composition: [offset: 0/2500=0.00s, time: 150072/2500=60.03s]
    161. | | | | chunk: [#10: first_index: 118, index: 118, offset: 5172585 bytes]
    162. | | | | offset: [5227264 bytes, #8 samples in #0 chunck of 10 sampleses in run of 1 chunk]
    163. | | | | description: [#0: avc1, reference: [#0: <same file>], compressor: <undetermined>, 640 x 360, resolution: 72.00 x 72.00, frames per sample: 1]
    164. | | | | #1444:
    165. | | | | size: 964 bytes
    166. | | | | decoding: [#0: time: 150176/2500=60.07s]
    167. | | | | composition: [offset: 0/2500=0.00s, time: 150176/2500=60.07s]
    168. | | | | chunk: [#10: first_index: 118, index: 118, offset: 5172585 bytes]
    169. | | | | offset: [5228852 bytes, #9 samples in #0 chunck of 10 sampleses in run of 1 chunk]
    170. | | | | description: [#0: avc1, reference: [#0: <same file>], compressor: <undetermined>, 640 x 360, resolution: 72.00 x 72.00, frames per sample: 1]