Coverage Report

Created: 2024-11-21 06:52

/src/mpg123/src/libmpg123/gapless.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
  sampleadjust: gapless sample offset math
3
4
  copyright 1995-2023 by the mpg123 project - free software under the terms of the LGPL 2.1
5
  see COPYING and AUTHORS files in distribution or http://mpg123.org
6
7
  This is no stand-alone header, precisely to be able to fool it into using fake handle types for testing the math.
8
*/
9
10
#include "../common/debug.h"
11
12
#ifdef GAPLESS
13
/* From internal sample number to external. */
14
static int64_t sample_adjust(mpg123_handle *mh, int64_t x)
15
0
{
16
0
  int64_t s;
17
0
  if(mh->p.flags & MPG123_GAPLESS)
18
0
  {
19
    /* It's a bit tricky to do this computation for the padding samples.
20
       They are not there on the outside. */
21
0
    if(x > mh->end_os)
22
0
    {
23
0
      if(x < mh->fullend_os)
24
0
      s = mh->end_os - mh->begin_os;
25
0
      else
26
0
      s = x - (mh->fullend_os - mh->end_os + mh->begin_os);
27
0
    }
28
0
    else
29
0
    s = x - mh->begin_os;
30
0
  }
31
0
  else
32
0
  s = x;
33
34
0
  return s;
35
0
}
36
37
/* from external samples to internal */
38
static int64_t sample_unadjust(mpg123_handle *mh, int64_t x)
39
0
{
40
0
  int64_t s;
41
0
  if(mh->p.flags & MPG123_GAPLESS)
42
0
  {
43
0
    s = x + mh->begin_os;
44
    /* There is a hole; we don't create sample positions in there.
45
       Jump from the end of the gapless track directly to after the padding. */
46
0
    if(s >= mh->end_os)
47
0
    s += mh->fullend_os - mh->end_os;
48
0
  }
49
0
  else s = x;
50
51
0
  return s;
52
0
}
53
54
/*
55
  Take the buffer after a frame decode (strictly: it is the data from frame fr->num!) and cut samples out.
56
  fr->buffer.fill may then be smaller than before...
57
*/
58
static void frame_buffercheck(mpg123_handle *fr)
59
0
{
60
  /* When we have no accurate position, gapless code does not make sense. */
61
0
  if(!(fr->state_flags & FRAME_ACCURATE)) return;
62
63
  /* Get a grip on dirty streams that start with a gapless header.
64
     Simply accept all data from frames that are too much,
65
     they are supposedly attached to the stream after the fact. */
66
0
  if(fr->gapless_frames > 0 && fr->num >= fr->gapless_frames) return;
67
68
  /* Important: We first cut samples from the end, then cut from beginning (including left-shift of the buffer).
69
     This order works also for the case where firstframe == lastframe. */
70
71
  /* The last interesting (planned) frame: Only use some leading samples.
72
     Note a difference from the below: The last frame and offset are unchanges by seeks.
73
     The lastoff keeps being valid. */
74
0
  if(fr->lastframe > -1 && fr->num >= fr->lastframe)
75
0
  {
76
    /* There can be more than one frame of padding at the end, so we ignore the whole frame if we are beyond lastframe. */
77
0
    int64_t byteoff = (fr->num == fr->lastframe) ? INT123_samples_to_bytes(fr, fr->lastoff) : 0;
78
0
    if((int64_t)fr->buffer.fill > byteoff)
79
0
    {
80
0
      fr->buffer.fill = byteoff;
81
0
    }
82
0
    if(VERBOSE3)
83
0
      fprintf(stderr, "\nNote: Cut frame %" PRIi64 " buffer on end of stream to %"
84
0
         PRIi64 " samples, fill now %zu bytes.\n"
85
0
      , fr->num, (fr->num == fr->lastframe ? fr->lastoff : 0), fr->buffer.fill);
86
0
  }
87
88
  /* The first interesting frame: Skip some leading samples. */
89
0
  if(fr->firstoff && fr->num == fr->firstframe)
90
0
  {
91
0
    int64_t byteoff = INT123_samples_to_bytes(fr, fr->firstoff);
92
0
    if((int64_t)fr->buffer.fill > byteoff)
93
0
    {
94
0
      fr->buffer.fill -= byteoff;
95
      /* buffer.p != buffer.data only for own buffer */
96
0
      debug6("cutting %" PRIi64 " samples/%" PRIi64
97
0
        " bytes on begin, own_buffer=%i at %p=%p, buf[1]=%i"
98
0
      , fr->firstoff, byteoff, fr->own_buffer
99
0
      , (void*)fr->buffer.p, (void*)fr->buffer.data, ((short*)fr->buffer.p)[2]);
100
0
      if(fr->own_buffer) fr->buffer.p = fr->buffer.data + byteoff;
101
0
      else memmove(fr->buffer.data, fr->buffer.data + byteoff, fr->buffer.fill);
102
0
      debug3("done cutting, buffer at %p =? %p, buf[1]=%i",
103
0
              (void*)fr->buffer.p, (void*)fr->buffer.data, ((short*)fr->buffer.p)[2]);
104
0
    }
105
0
    else fr->buffer.fill = 0;
106
107
0
    if(VERBOSE3)
108
0
      fprintf(stderr, "\nNote: Cut frame %" PRIi64 
109
0
        " buffer on beginning of stream by %" PRIi64 " samples, fill now %zu bytes.\n"
110
0
      , fr->num, fr->firstoff, fr->buffer.fill);
111
    /* We can only reach this frame again by seeking. And on seeking, firstoff will be recomputed.
112
       So it is safe to null it here (and it makes the if() decision abort earlier). */
113
0
    fr->firstoff = 0;
114
0
  }
115
0
}
116
117
0
#define SAMPLE_ADJUST(mh,x)     sample_adjust(mh,x)
118
0
#define SAMPLE_UNADJUST(mh,x)   sample_unadjust(mh,x)
119
0
#define FRAME_BUFFERCHECK(mh) frame_buffercheck(mh)
120
121
#else /* no gapless code included */
122
123
#define SAMPLE_ADJUST(mh,x)   (x)
124
#define SAMPLE_UNADJUST(mh,x) (x)
125
#define FRAME_BUFFERCHECK(mh)
126
127
#endif