Work at SourceForge, help us to make it a better place! We have an immediate need for a Support Technician in our San Francisco or Denver office.

Close

#730 MediaInfo shows wrong Samples Count for M4A Files

Incorrect_result
open-accepted
3
2013-11-22
2013-01-17
robertcollier4
No

In the following M4A AAC file, WrongSamplescountExample.m4a, the correct number of samples is 4143104. However, MediaInfo shows in "Debug > Advanced Mode" the wrong information: "Samples count : 4143120"

The correct samples count value can be verified by running:
"mp4box.exe -diso -std WrongSamplescountExample.m4a > mp4box-analysis.txt"

The file mp4box-analysis.txt shows the correct value in the following XML node:
TrackHeaderBox Duration="4143104"

Discussion

1 2 > >> (Page 1 of 2)
  • robertcollier4
    robertcollier4
    2013-01-17

    Update: I think the problem is coming from rounding error that is introduced from calculating:
    "Samples Count" = Duration * Sample Rate.

    However, this is the wrong way of doing it, since Duration already has rounding in it.

    You should first calculate "Samples Count". Then calculate Duration in milliseconds from:
    1000 * Samples Count / Sample Rate

     
    • status: open --> open-accepted
    • assigned_to: Jerome Martinez
    • priority: 5 --> 3
     
  • It is due to rounding issues in MediaInfo, I must avoid them.

     
  • robertcollier4
    robertcollier4
    2013-02-23

    Samples Count should not be from any calculations. It is always an integer. You should be able to read Samples Count as an integer directly from the file. Duration is the value that has rounding and is calculated from SamplesCount / SampleRate - it is okay for this value to have rounding - but Samples Count should always be perfectly reported since it is an integer coming directly from the data. The current error is not about fixing rounding problems - it is about having MediaInfo read the Samples Count directly from the data. Thanks.

     
  • Yes, it is the theory.

    You should be able to read Samples Count as an integer directly from the file.

    Ok, let me know where this integer is in the header, for sure. Because as far as I know, I have a duration and a time scale, and time scale is not always the sampling rate, so duration is not always the sampling count. Currently, I did not care about such precision so I am saving only one floating number and after this, I compute sampling count from this rounded duration. It is definitely a wrong method for computing sampling count, but this method is generic to any stream kind (video, audio, text...) and any container (MXF, MPEG-TS...) and sampling count computing was a quick hack for my needs. the exact sample count is a matter of development time. Any patch for avoiding this rounding in the workflow (but the patch must take care of all cases else it will be rejected) is welcome, but in the meanwhile this bug is still present, and I have more urgent (for me, for my customers who pay the support) tickets to take care of.

    but Samples Count should always be perfectly reported since it is an integer coming directly from the data.

    No. Or show me where this number is when time scale is not the sample rate (time scale being sample rate is not mandatory), for MPEG-4. Show me the place of such integer in the several containers supported by MediaInfo (hint: some container are broadcasted, so there is no header with any duration or any sample count).


    The ticket is set as "accepted", because it is a bug for sure, this is not the problem, I perfectly understand that there is a problem in the way it is currently coded. But resolving this bug is not so easy with current code (quick and awful hack because it was enough for my needs) + it is in the low priority list, there is no ETA for free support.

     
    Last edit: Jerome Martinez 2013-02-23
  • robertcollier4
    robertcollier4
    2013-02-24

    okay thanks, I understand there may be many complexities especially when dealing with different file types, or adts aac streams.

    For mp4 aac quicktime containers perhaps this can be of reference - http://wiki.multimedia.cx/index.php?title=QuickTime_container#stsz
    "The stsz atom can operate in one of two modes. First, it is possible that all of the samples in a trak have the same size. In this case, the uniform size field is set to the constant size. The number of sample sizes field is set to the total number samples in the track, and there is no sample size table following. This mode is commonly used in the stsz atom of audio tracks.
    In the second mode, all of the samples are a different size (logically, this mode would have to be used even if all of the samples were the same size except for one). In this case, the uniform size field is set to 0. The number of sample sizes field contains the number of entries in the sample size table. Each entry in the sample size table contains the size of a sample in the trak."

     
    Last edit: robertcollier4 2013-02-24
  • robertcollier4
    robertcollier4
    2013-02-24

    http://getid3.sourceforge.net/source2/module.audio-video.quicktime.phps
    $frames_count = 0;
    for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
    $atom_structure['time_to_sample_table'][$i]['sample_count'] = getid3_lib::BigEndian2Int(substr($atom_data, $stts_entries_data_offset, 4));
    $frames_count += $atom_structure['time_to_sample_table'][$i]['sample_count'];
    }
    $info['quicktime']['stts_framecount'][] = $frames_count;

    http://getid3.sourceforge.net/source2/module.audio-video.quicktime.phps
    case 'stsz': // Sample Table SiZe atom
    /
    $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
    $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
    $atom_structure['sample_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
    $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
    $stsz_entries_data_offset = 12;
    if ($atom_structure['sample_size'] == 0) {
    for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
    $atom_structure['sample_size_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stsz_entries_data_offset, 4));
    $stsz_entries_data_offset += 4;
    }
    }

    /
    break;

     
    Last edit: robertcollier4 2013-02-24
  • robertcollier4
    robertcollier4
    2013-02-24

    http://svn.gnumonks.org/trunk/21c3-video/ffmpeg/ffmpeg-0.4.9-pre1/libavformat/movenc.c
    / Sample size atom /
    static int mov_write_stsz_tag(ByteIOContext pb, MOVTrack track)
    {
    int equalChunks = 1;
    int i, j, entries = 0, tst = -1, oldtst = -1;

    int pos = url_ftell(pb);
    put_be32(pb, 0); / size /
    put_tag(pb, "stsz");
    put_be32(pb, 0); / version & flags /

    for (i=0; i<track->entry; i++) {
    int cl = i / MOV_INDEX_CLUSTER_SIZE;
    int id = i % MOV_INDEX_CLUSTER_SIZE;
    tst = track->cluster[cl][id].size/track->cluster[cl][id].entries;
    if(oldtst != -1 && tst != oldtst) {
    equalChunks = 0;
    }
    oldtst = tst;
    entries += track->cluster[cl][id].entries;
    }
    if (equalChunks) {
    int sSize = track->cluster[0][0].size/track->cluster[0][0].entries;
    put_be32(pb, sSize); // sample size
    put_be32(pb, entries); // sample count
    }
    else {
    put_be32(pb, 0); // sample size
    put_be32(pb, entries); // sample count
    for (i=0; i<track->entry; i++) {
    int cl = i / MOV_INDEX_CLUSTER_SIZE;
    int id = i % MOV_INDEX_CLUSTER_SIZE;
    for ( j=0; j<track->cluster[cl][id].entries; j++) {
    put_be32(pb, track->cluster[cl][id].size /
    track->cluster[cl][id].entries);
    }
    }
    }
    return updateSize (pb, pos);
    }

     
  • robertcollier4
    robertcollier4
    2013-02-24

    http://ffmpeg.org/doxygen/trunk/movenc_8c-source.html

    00130 / Sample size atom /
    00131 static int mov_write_stsz_tag(AVIOContext pb, MOVTrack track)
    00132 {
    00133 int equalChunks = 1;
    00134 int i, j, entries = 0, tst = -1, oldtst = -1;
    00135
    00136 int64_t pos = avio_tell(pb);
    00137 avio_wb32(pb, 0); / size /
    00138 ffio_wfourcc(pb, "stsz");
    00139 avio_wb32(pb, 0); / version & flags /
    00140
    00141 for (i=0; i<track->entry; i++) {
    00142 tst = track->cluster[i].size/track->cluster[i].entries;
    00143 if(oldtst != -1 && tst != oldtst) {
    00144 equalChunks = 0;
    00145 }
    00146 oldtst = tst;
    00147 entries += track->cluster[i].entries;
    00148 }
    00149 if (equalChunks && track->entry) {
    00150 int sSize = track->entry ? track->cluster[0].size/track->cluster[0].entries : 0;
    00151 sSize = FFMAX(1, sSize); // adpcm mono case could make sSize == 0
    00152 avio_wb32(pb, sSize); // sample size
    00153 avio_wb32(pb, entries); // sample count
    00154 }
    00155 else {
    00156 avio_wb32(pb, 0); // sample size
    00157 avio_wb32(pb, entries); // sample count
    00158 for (i=0; i<track->entry; i++) {
    00159 for (j=0; j<track->cluster[i].entries; j++) {
    00160 avio_wb32(pb, track->cluster[i].size /
    00161 track->cluster[i].entries);
    00162 }
    00163 }
    00164 }
    00165 return update_size(pb, pos);
    00166 }

     
  • FYI, stsz is "sample size" atom, with:
    sample = a block (for AAC, an AAC frame)
    size = size in bytes of the block.

    Nothing related to what we are discussing.

     
    Last edit: Jerome Martinez 2013-02-25
1 2 > >> (Page 1 of 2)