Coverage Report

Created: 2025-08-29 07:30

/src/vlc/modules/demux/mp4/fragments.c
Line
Count
Source (jump to first uncovered line)
1
/*****************************************************************************
2
 * fragments.c : MP4 fragments
3
 *****************************************************************************
4
 * Copyright (C) 2001-2015 VLC authors and VideoLAN
5
 *
6
 * This program is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU Lesser General Public License as published by
8
 * the Free Software Foundation; either version 2.1 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
 * GNU Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public License
17
 * along with this program; if not, write to the Free Software Foundation,
18
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19
 *****************************************************************************/
20
#ifdef HAVE_CONFIG_H
21
# include "config.h"
22
#endif
23
24
#include "fragments.h"
25
#include <limits.h>
26
27
void MP4_Fragments_Index_Delete( mp4_fragments_index_t *p_index )
28
10.0k
{
29
10.0k
    if( p_index )
30
452
    {
31
452
        free( p_index->pi_pos );
32
452
        free( p_index->p_times );
33
452
        free( p_index );
34
452
    }
35
10.0k
}
36
37
mp4_fragments_index_t * MP4_Fragments_Index_New( unsigned i_tracks, unsigned i_num )
38
452
{
39
452
    if( !i_tracks || !i_num || SIZE_MAX / i_num < i_tracks )
40
0
        return NULL;
41
452
    mp4_fragments_index_t *p_index = malloc( sizeof(*p_index) );
42
452
    if( p_index )
43
452
    {
44
452
        p_index->p_times = calloc( (size_t)i_num * i_tracks, sizeof(*p_index->p_times) );
45
452
        p_index->pi_pos = calloc( i_num, sizeof(*p_index->pi_pos) );
46
452
        if( !p_index->p_times || !p_index->pi_pos )
47
0
        {
48
0
            MP4_Fragments_Index_Delete( p_index );
49
0
            return NULL;
50
0
        }
51
452
        p_index->i_entries = i_num;
52
452
        p_index->i_last_time = 0;
53
452
        p_index->i_tracks = i_tracks;
54
452
    }
55
452
    return p_index;
56
452
}
57
58
stime_t MP4_Fragment_Index_GetTrackStartTime( mp4_fragments_index_t *p_index,
59
                                              unsigned i_track_index, uint64_t i_moof_pos )
60
106
{
61
157
    for( size_t i=0; i<p_index->i_entries; i++ )
62
156
    {
63
156
        if( p_index->pi_pos[i] >= i_moof_pos )
64
105
            return p_index->p_times[i * p_index->i_tracks + i_track_index];
65
156
    }
66
1
    return 0;
67
106
}
68
69
stime_t MP4_Fragment_Index_GetTracksDuration( const mp4_fragments_index_t *p_index )
70
245
{
71
245
    return p_index->i_last_time;
72
245
}
73
74
bool MP4_Fragments_Index_Lookup( mp4_fragments_index_t *p_index, stime_t *pi_time,
75
                                 uint64_t *pi_pos, unsigned i_track_index )
76
0
{
77
0
    if( *pi_time >= p_index->i_last_time || p_index->i_entries < 1 ||
78
0
        i_track_index >= p_index->i_tracks )
79
0
        return false;
80
81
0
    for( size_t i=1; i<p_index->i_entries; i++ )
82
0
    {
83
0
        if( p_index->p_times[i * p_index->i_tracks + i_track_index] > *pi_time )
84
0
        {
85
0
            *pi_time = p_index->p_times[(i - 1) * p_index->i_tracks + i_track_index];
86
0
            *pi_pos = p_index->pi_pos[i - 1];
87
0
            return true;
88
0
        }
89
0
    }
90
91
0
    *pi_time = p_index->p_times[(size_t)(p_index->i_entries - 1) * p_index->i_tracks];
92
0
    *pi_pos = p_index->pi_pos[p_index->i_entries - 1];
93
0
    return true;
94
0
}
95
96
#ifdef MP4_VERBOSE
97
static inline int64_t movietime_to_ms(stime_t time, uint32_t i_movie_timescale)
98
3.32k
{
99
3.32k
    if( i_movie_timescale == INT64_C( 1000 ) )
100
0
        return time;
101
102
3.32k
    if( time <= INT64_MAX / INT64_C( 1000 ) )
103
3.31k
        return time * INT64_C( 1000 ) / i_movie_timescale;
104
105
    /* overflow */
106
5
    int64_t q = time / i_movie_timescale;
107
5
    int64_t r = time % i_movie_timescale;
108
5
    return q * INT64_C( 1000 ) + r * INT64_C( 1000 ) / i_movie_timescale;
109
0
    return INT64_C( 1000 ) * time / i_movie_timescale;
110
3.32k
}
111
112
void MP4_Fragments_Index_Dump( vlc_object_t *p_obj, const mp4_fragments_index_t *p_index,
113
                               uint32_t i_movie_timescale )
114
452
{
115
1.73k
    for( size_t i=0; i<p_index->i_entries; i++ )
116
1.28k
    {
117
1.28k
        char *psz_starts = NULL;
118
119
1.28k
        stime_t i_end;
120
1.28k
        if( i + 1 == p_index->i_entries )
121
452
            i_end = p_index->i_last_time;
122
830
        else
123
830
            i_end = p_index->p_times[(i + 1) * p_index->i_tracks];
124
125
3.32k
        for( unsigned j=0; j<p_index->i_tracks; j++ )
126
2.04k
        {
127
2.04k
            char *psz_start = NULL;
128
2.04k
            if( 0 < asprintf( &psz_start, "%s [%u]%"PRId64"ms ",
129
2.04k
                      (psz_starts) ? psz_starts : "", j,
130
2.04k
                  movietime_to_ms(p_index->p_times[i * p_index->i_tracks + j], i_movie_timescale) ) )
131
2.04k
            {
132
2.04k
                free( psz_starts );
133
2.04k
                psz_starts = psz_start;
134
2.04k
            }
135
2.04k
        }
136
137
1.28k
        msg_Dbg( p_obj, "fragment offset @%"PRId64" %"PRId64"ms, start %s",
138
1.28k
                 p_index->pi_pos[i],
139
1.28k
                 movietime_to_ms( i_end, i_movie_timescale ), psz_starts );
140
141
1.28k
        free( psz_starts );
142
1.28k
    }
143
452
}
144
#endif