mirror of
https://github.com/libretro/libretro-common.git
synced 2026-11-07 11:06:12 -10:00
Resync
This commit is contained in:
1 parent
a0403d4273
commit
4c1ae8b2f1
24 files changed
+5543
-610
No files matched your search
+797
-260
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+8
-3
@@ -356,6 +356,7 @@ struct rchd
|
||||
* audio/video pays nothing for them. */
|
||||
uint16_t *av_lookup;
|
||||
int16_t *av_samples;
|
||||
uint32_t av_samples_capacity;
|
||||
struct rchd_av_scratch *av_scratch;
|
||||
|
||||
/* One decoded hunk, kept so a range spanning several hunks, or two
|
||||
@@ -1550,11 +1551,15 @@ static int rchd_decode_avhuff(rchd_t *chd, const uint8_t *src,
|
||||
|
||||
if (mode == 0xffff)
|
||||
{
|
||||
if (!chd->av_samples)
|
||||
if (samples > chd->av_samples_capacity)
|
||||
{
|
||||
chd->av_samples = (int16_t*)malloc((size_t)samples * sizeof(int16_t));
|
||||
if (!chd->av_samples)
|
||||
int16_t *grown = (int16_t*)realloc(chd->av_samples,
|
||||
(size_t)samples * sizeof(int16_t));
|
||||
|
||||
if (!grown)
|
||||
return RCHD_ERROR_MEM;
|
||||
chd->av_samples = grown;
|
||||
chd->av_samples_capacity = samples;
|
||||
}
|
||||
|
||||
fmt.sample_rate = 44100;
|
||||
|
||||
+555
-252
File diff suppressed because it is too large.
Load diff
@@ -152,3 +152,18 @@ void image_yuv_i420_to_rgb32(uint32_t *dst, unsigned dst_stride,
|
||||
image_yuv_frame(dst, dst_stride, y, y_stride,
|
||||
u, u_stride, 1, v, v_stride, 1, w, h, flags);
|
||||
}
|
||||
|
||||
void image_yuv_coefficients(unsigned flags, float c[6])
|
||||
{
|
||||
const image_yuv_coef_t *k =
|
||||
&image_yuv_coefs[((flags & IMAGE_YUV_FLAG_BT709) ? 2 : 0)
|
||||
| ((flags & IMAGE_YUV_FLAG_FULL_RANGE) ? 1 : 0)];
|
||||
const float one = (float)(1 << IMAGE_YUV_SHIFT);
|
||||
c[0] = (float)k->ym / one;
|
||||
/* the bias less its rounding half, in 0..1 */
|
||||
c[1] = (float)(k->yb - (1 << (IMAGE_YUV_SHIFT - 1))) / one / 255.0f;
|
||||
c[2] = (float)k->rv / one;
|
||||
c[3] = (float)k->gu / one;
|
||||
c[4] = (float)k->gv / one;
|
||||
c[5] = (float)k->bu / one;
|
||||
}
|
||||
@@ -388,6 +388,7 @@ bool image_loader_finish(image_loader_t *l, struct texture_image *img)
|
||||
return false;
|
||||
img->pixels = l->pixels;
|
||||
img->compressed = l->compressed;
|
||||
img->planar = NULL;
|
||||
img->width = l->width;
|
||||
img->height = l->height;
|
||||
img->supports_rgba = l->req.rgba;
|
||||
@@ -445,6 +446,7 @@ static void image_texture_clear(struct texture_image *img)
|
||||
img->width = 0;
|
||||
img->height = 0;
|
||||
img->compressed = NULL;
|
||||
img->planar = NULL;
|
||||
img->pix10 = false;
|
||||
img->fp16 = false;
|
||||
}
|
||||
@@ -460,6 +462,7 @@ static bool image_texture_load_buffer_probe(struct texture_image *out_img,
|
||||
if (!out_img)
|
||||
return false;
|
||||
out_img->compressed = NULL;
|
||||
out_img->planar = NULL;
|
||||
if (!ptr || !len || !(l = image_loader_new(type, req)))
|
||||
{
|
||||
image_texture_clear(out_img);
|
||||
|
||||
@@ -1899,6 +1899,13 @@ static uint8_t* hunk_read_compressed(chd_file *chd, uint64_t offset, size_t size
|
||||
{
|
||||
size_t bytes;
|
||||
|
||||
/* The staging buffer is one uncompressed hunk large. A malformed map
|
||||
* can advertise a larger 24-bit compressed length; reading that much
|
||||
* into chd->compressed would overflow it. CHD writers store a hunk
|
||||
* uncompressed when compression does not make it smaller. */
|
||||
if (size > chd->header.hunkbytes)
|
||||
return NULL;
|
||||
|
||||
if (chd->file_cache != NULL)
|
||||
{
|
||||
return chd->file_cache + offset;
|
||||
|
||||
@@ -509,7 +509,13 @@ enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decode
|
||||
{
|
||||
struct node_t* node = &decoder->huffnode[curcode];
|
||||
if (node->numbits > 0)
|
||||
{
|
||||
/* An oversubscribed tree assigns codes outside the space for
|
||||
* this length, which would index past the lookup table. */
|
||||
if (bithisto[node->numbits] >= (1U << node->numbits))
|
||||
return HUFFERR_INVALID_DATA;
|
||||
node->bits = bithisto[node->numbits]++;
|
||||
}
|
||||
}
|
||||
return HUFFERR_NONE;
|
||||
}
|
||||
|
||||
+179
-45
@@ -89,6 +89,12 @@ struct rmpeg1_ps
|
||||
uint32_t mux_rate;
|
||||
uint32_t resyncs;
|
||||
|
||||
/* Data borrowed from the caller (rmpeg1_ps_borrow), parsed in place:
|
||||
* NULL when there is none */
|
||||
const uint8_t *ext;
|
||||
size_t ext_len;
|
||||
size_t ext_rd;
|
||||
|
||||
bool ended;
|
||||
bool synced; /* a start code has been located at least once */
|
||||
};
|
||||
@@ -156,6 +162,7 @@ void rmpeg1_ps_reset(rmpeg1_ps_t *ps)
|
||||
ps->mux_rate = 0;
|
||||
ps->ended = false;
|
||||
ps->synced = false;
|
||||
ps->ext = NULL;
|
||||
/* resyncs is a cumulative health counter and deliberately survives. */
|
||||
}
|
||||
|
||||
@@ -171,7 +178,8 @@ size_t rmpeg1_ps_write(rmpeg1_ps_t *ps, const uint8_t *data, size_t len)
|
||||
{
|
||||
size_t room;
|
||||
|
||||
if (!ps || !data || len == 0)
|
||||
/* Not behind data still borrowed, which comes first */
|
||||
if (!ps || !data || len == 0 || ps->ext)
|
||||
return 0;
|
||||
|
||||
if (ps->capacity - ps->wr < len)
|
||||
@@ -214,28 +222,29 @@ static uint64_t rmpeg1_ps_read_ts(const uint8_t *p)
|
||||
*
|
||||
* Leaves the trailing two bytes unconsumed on failure: a prefix may straddle
|
||||
* the end of what we have been given so far. */
|
||||
static size_t rmpeg1_ps_find_start(rmpeg1_ps_t *ps)
|
||||
static size_t rmpeg1_ps_find_start(const uint8_t *buf, size_t *rdp,
|
||||
size_t wr)
|
||||
{
|
||||
size_t i;
|
||||
size_t end;
|
||||
|
||||
if (ps->wr < ps->rd + 3)
|
||||
if (wr < *rdp + 3)
|
||||
return (size_t)-1;
|
||||
|
||||
end = ps->wr - 2;
|
||||
end = wr - 2;
|
||||
|
||||
for (i = ps->rd; i < end; i++)
|
||||
for (i = *rdp; i < end; i++)
|
||||
{
|
||||
if ( ps->buf[i ] == 0x00
|
||||
&& ps->buf[i + 1] == 0x00
|
||||
&& ps->buf[i + 2] == 0x01)
|
||||
if ( buf[i ] == 0x00
|
||||
&& buf[i + 1] == 0x00
|
||||
&& buf[i + 2] == 0x01)
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Nothing found. Everything before the last two bytes is garbage and can
|
||||
* be dropped so the buffer does not grow without bound on a broken
|
||||
* stream. */
|
||||
ps->rd = end;
|
||||
*rdp = end;
|
||||
return (size_t)-1;
|
||||
}
|
||||
|
||||
@@ -273,10 +282,11 @@ static uint8_t rmpeg1_ps_classify(uint8_t stream_id, uint8_t *index)
|
||||
/* Parser */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
int rmpeg1_ps_next(rmpeg1_ps_t *ps, rmpeg1_ps_packet_t *out)
|
||||
/* One packet out of buf[*rdp..wr): 1, or 0 with *rdp at the start of
|
||||
* what is not yet a whole unit */
|
||||
static int rmpeg1_ps_parse(rmpeg1_ps_t *ps, const uint8_t *buf,
|
||||
size_t *rdp, size_t wr, rmpeg1_ps_packet_t *out)
|
||||
{
|
||||
if (!ps || !out)
|
||||
return 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
@@ -295,7 +305,7 @@ int rmpeg1_ps_next(rmpeg1_ps_t *ps, rmpeg1_ps_packet_t *out)
|
||||
if (ps->ended)
|
||||
return 0;
|
||||
|
||||
sc = rmpeg1_ps_find_start(ps);
|
||||
sc = rmpeg1_ps_find_start(buf, rdp, wr);
|
||||
if (sc == (size_t)-1)
|
||||
return 0;
|
||||
|
||||
@@ -305,14 +315,14 @@ int rmpeg1_ps_next(rmpeg1_ps_t *ps, rmpeg1_ps_packet_t *out)
|
||||
* legal and expected. Only count a resync when the skipped bytes are
|
||||
* something other than zero fill, so the counter stays meaningful as a
|
||||
* stream-health signal rather than firing once per sector. */
|
||||
if (sc != ps->rd)
|
||||
if (sc != *rdp)
|
||||
{
|
||||
size_t g;
|
||||
bool fill = true;
|
||||
|
||||
for (g = ps->rd; g < sc; g++)
|
||||
for (g = *rdp; g < sc; g++)
|
||||
{
|
||||
if (ps->buf[g] != 0x00)
|
||||
if (buf[g] != 0x00)
|
||||
{
|
||||
fill = false;
|
||||
break;
|
||||
@@ -322,21 +332,21 @@ int rmpeg1_ps_next(rmpeg1_ps_t *ps, rmpeg1_ps_packet_t *out)
|
||||
if (!fill || !ps->synced)
|
||||
ps->resyncs++;
|
||||
|
||||
ps->rd = sc;
|
||||
*rdp = sc;
|
||||
}
|
||||
|
||||
ps->synced = true;
|
||||
|
||||
avail = ps->wr - ps->rd;
|
||||
avail = wr - *rdp;
|
||||
if (avail < 4)
|
||||
return 0;
|
||||
|
||||
stream_id = ps->buf[ps->rd + 3];
|
||||
stream_id = buf[*rdp + 3];
|
||||
|
||||
/* --- end code ------------------------------------------------- */
|
||||
if (stream_id == RMPEG1_PS_END_CODE)
|
||||
{
|
||||
ps->rd += 4;
|
||||
*rdp += 4;
|
||||
ps->ended = true;
|
||||
return 0;
|
||||
}
|
||||
@@ -349,14 +359,38 @@ int rmpeg1_ps_next(rmpeg1_ps_t *ps, rmpeg1_ps_packet_t *out)
|
||||
if (avail < 12)
|
||||
return 0;
|
||||
|
||||
p = ps->buf + ps->rd + 4;
|
||||
p = buf + *rdp + 4;
|
||||
|
||||
/* MPEG-1 packs carry '0010' here. MPEG-2 uses '01', and its pack
|
||||
* header is 14 bytes with a different SCR layout; we do not claim
|
||||
* to parse those, so resync past it rather than misread it. */
|
||||
/* MPEG-2 (ISO/IEC 13818-1) packs carry '01' here: 14 bytes, the
|
||||
* SCR in another layout, a 22-bit mux rate and up to 7 bytes of
|
||||
* stuffing after. */
|
||||
if ((p[0] & 0xC0) == 0x40)
|
||||
{
|
||||
size_t len;
|
||||
if (avail < 14)
|
||||
return 0;
|
||||
len = 14 + (size_t)(p[9] & 0x07);
|
||||
if (avail < len)
|
||||
return 0;
|
||||
ps->scr = ((uint64_t)((p[0] >> 3) & 0x07) << 30)
|
||||
| ((uint64_t)( p[0] & 0x03) << 28)
|
||||
| ((uint64_t) p[1] << 20)
|
||||
| ((uint64_t)((p[2] >> 3) & 0x1F) << 15)
|
||||
| ((uint64_t)( p[2] & 0x03) << 13)
|
||||
| ((uint64_t) p[3] << 5)
|
||||
| (uint64_t)((p[4] >> 3) & 0x1F);
|
||||
ps->mux_rate = ((uint32_t)p[6] << 14)
|
||||
| ((uint32_t)p[7] << 6)
|
||||
| ((uint32_t)p[8] >> 2);
|
||||
*rdp += len;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* MPEG-1 packs carry '0010' here: anything else is not a pack
|
||||
* header we know, so resync past it rather than misread it. */
|
||||
if ((p[0] & 0xF0) != 0x20)
|
||||
{
|
||||
ps->rd += 4;
|
||||
*rdp += 4;
|
||||
ps->resyncs++;
|
||||
continue;
|
||||
}
|
||||
@@ -367,7 +401,7 @@ int rmpeg1_ps_next(rmpeg1_ps_t *ps, rmpeg1_ps_packet_t *out)
|
||||
| ((uint32_t)p[6] << 7)
|
||||
| ((uint32_t)p[7] >> 1);
|
||||
|
||||
ps->rd += 12;
|
||||
*rdp += 12;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -375,7 +409,7 @@ int rmpeg1_ps_next(rmpeg1_ps_t *ps, rmpeg1_ps_packet_t *out)
|
||||
if (avail < 6)
|
||||
return 0;
|
||||
|
||||
packet_len = ((size_t)ps->buf[ps->rd + 4] << 8) | ps->buf[ps->rd + 5];
|
||||
packet_len = ((size_t)buf[*rdp + 4] << 8) | buf[*rdp + 5];
|
||||
|
||||
if (avail < 6 + packet_len)
|
||||
{
|
||||
@@ -383,21 +417,22 @@ int rmpeg1_ps_next(rmpeg1_ps_t *ps, rmpeg1_ps_packet_t *out)
|
||||
* this start code and resync rather than stalling forever. */
|
||||
if (6 + packet_len > ps->capacity)
|
||||
{
|
||||
ps->rd += 4;
|
||||
*rdp += 4;
|
||||
ps->resyncs++;
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
pos = ps->rd + 6;
|
||||
pos = *rdp + 6;
|
||||
payload_end = pos + packet_len;
|
||||
|
||||
|
||||
/* System headers describe the stream set; they carry no elementary
|
||||
* data, so record nothing and move on. */
|
||||
if (stream_id == RMPEG1_PS_SYSTEM_HEADER)
|
||||
{
|
||||
ps->rd = payload_end;
|
||||
*rdp = payload_end;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -405,7 +440,7 @@ int rmpeg1_ps_next(rmpeg1_ps_t *ps, rmpeg1_ps_packet_t *out)
|
||||
|
||||
if (type == RMPEG1_PS_PADDING)
|
||||
{
|
||||
ps->rd = payload_end;
|
||||
*rdp = payload_end;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -413,76 +448,99 @@ int rmpeg1_ps_next(rmpeg1_ps_t *ps, rmpeg1_ps_packet_t *out)
|
||||
* recognise) are skipped whole. */
|
||||
if (type == RMPEG1_PS_NONE)
|
||||
{
|
||||
ps->rd = payload_end;
|
||||
*rdp = payload_end;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* private_stream_2 has no header extension at all: payload starts
|
||||
* immediately. Everything else gets the stuffing/STD/timestamp
|
||||
* preamble. */
|
||||
if (type != RMPEG1_PS_PRIVATE_2)
|
||||
/* MPEG-2: '10', two flag bytes and the length of the optional
|
||||
* fields, the timestamps first among them */
|
||||
if ( type != RMPEG1_PS_PRIVATE_2 && pos + 3 <= payload_end
|
||||
&& (buf[pos] & 0xC0) == 0x80)
|
||||
{
|
||||
unsigned flags = buf[pos + 1] >> 6;
|
||||
size_t hdr = pos + 3;
|
||||
size_t hlen = buf[pos + 2];
|
||||
if ( hdr + hlen > payload_end
|
||||
|| flags == 1
|
||||
|| (flags == 2 && hlen < 5)
|
||||
|| (flags == 3 && hlen < 10))
|
||||
{
|
||||
*rdp = payload_end;
|
||||
ps->resyncs++;
|
||||
continue;
|
||||
}
|
||||
if (flags & 2)
|
||||
pts = rmpeg1_ps_read_ts(buf + hdr);
|
||||
if (flags == 3)
|
||||
dts = rmpeg1_ps_read_ts(buf + hdr + 5);
|
||||
pos = hdr + hlen;
|
||||
}
|
||||
else if (type != RMPEG1_PS_PRIVATE_2)
|
||||
{
|
||||
/* Up to 16 stuffing bytes. The spec caps it; enforcing the cap
|
||||
* stops a run of FFh in corrupt data from eating the packet. */
|
||||
stuffing = 0;
|
||||
while (pos < payload_end && ps->buf[pos] == 0xFF && stuffing < 16)
|
||||
while (pos < payload_end && buf[pos] == 0xFF && stuffing < 16)
|
||||
{
|
||||
pos++;
|
||||
stuffing++;
|
||||
}
|
||||
|
||||
if (pos + 1 < payload_end && (ps->buf[pos] & 0xC0) == 0x40)
|
||||
if (pos + 1 < payload_end && (buf[pos] & 0xC0) == 0x40)
|
||||
pos += 2; /* STD buffer scale and size */
|
||||
|
||||
if (pos < payload_end)
|
||||
{
|
||||
uint8_t flag = (uint8_t)(ps->buf[pos] & 0xF0);
|
||||
uint8_t flag = (uint8_t)(buf[pos] & 0xF0);
|
||||
|
||||
if (flag == 0x20)
|
||||
{
|
||||
if (pos + 5 > payload_end)
|
||||
{
|
||||
ps->rd = payload_end;
|
||||
*rdp = payload_end;
|
||||
ps->resyncs++;
|
||||
continue;
|
||||
}
|
||||
pts = rmpeg1_ps_read_ts(ps->buf + pos);
|
||||
pts = rmpeg1_ps_read_ts(buf + pos);
|
||||
pos += 5;
|
||||
}
|
||||
else if (flag == 0x30)
|
||||
{
|
||||
if (pos + 10 > payload_end)
|
||||
{
|
||||
ps->rd = payload_end;
|
||||
*rdp = payload_end;
|
||||
ps->resyncs++;
|
||||
continue;
|
||||
}
|
||||
pts = rmpeg1_ps_read_ts(ps->buf + pos);
|
||||
dts = rmpeg1_ps_read_ts(ps->buf + pos + 5);
|
||||
pts = rmpeg1_ps_read_ts(buf + pos);
|
||||
dts = rmpeg1_ps_read_ts(buf + pos + 5);
|
||||
pos += 10;
|
||||
}
|
||||
else if (ps->buf[pos] == 0x0F)
|
||||
else if (buf[pos] == 0x0F)
|
||||
pos += 1;
|
||||
else
|
||||
{
|
||||
/* None of the three legal encodings. The header is malformed;
|
||||
* drop the packet rather than emit whatever follows as if it
|
||||
* were elementary data. */
|
||||
ps->rd = payload_end;
|
||||
*rdp = payload_end;
|
||||
ps->resyncs++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ps->rd = payload_end;
|
||||
*rdp = payload_end;
|
||||
|
||||
/* A packet whose header consumed everything is legal and carries no
|
||||
* data. Nothing downstream wants a zero-length buffer, so skip it. */
|
||||
if (pos >= payload_end)
|
||||
continue;
|
||||
|
||||
out->data = ps->buf + pos;
|
||||
out->data = buf + pos;
|
||||
out->size = payload_end - pos;
|
||||
out->pts = pts;
|
||||
out->dts = dts;
|
||||
@@ -494,6 +552,82 @@ int rmpeg1_ps_next(rmpeg1_ps_t *ps, rmpeg1_ps_packet_t *out)
|
||||
}
|
||||
}
|
||||
|
||||
/* Bytes the unit at the start of the buffered data needs before it can
|
||||
* be parsed whole; at least one */
|
||||
static size_t rmpeg1_ps_unit_need(const rmpeg1_ps_t *ps)
|
||||
{
|
||||
const uint8_t *b = ps->buf + ps->rd;
|
||||
size_t avail = ps->wr - ps->rd;
|
||||
size_t need;
|
||||
if (avail < 6 || b[0] || b[1] || b[2] != 1)
|
||||
need = 6;
|
||||
else if (b[3] == RMPEG1_PS_PACK_START)
|
||||
need = (b[4] & 0xC0) == 0x40
|
||||
? (avail >= 14 ? 14 + (size_t)(b[13] & 0x07) : 14) : 12;
|
||||
else if (b[3] == RMPEG1_PS_END_CODE)
|
||||
need = 4;
|
||||
else
|
||||
need = 6 + (((size_t)b[4] << 8) | b[5]);
|
||||
return need > avail ? need - avail : 1;
|
||||
}
|
||||
|
||||
/* @n borrowed bytes into the buffer, made room for */
|
||||
static void rmpeg1_ps_take(rmpeg1_ps_t *ps, size_t n)
|
||||
{
|
||||
if (ps->capacity - ps->wr < n)
|
||||
rmpeg1_ps_compact(ps);
|
||||
memcpy(ps->buf + ps->wr, ps->ext + ps->ext_rd, n);
|
||||
ps->wr += n;
|
||||
ps->ext_rd += n;
|
||||
if (ps->ext_rd == ps->ext_len)
|
||||
ps->ext = NULL;
|
||||
}
|
||||
|
||||
int rmpeg1_ps_next(rmpeg1_ps_t *ps, rmpeg1_ps_packet_t *out)
|
||||
{
|
||||
if (!ps || !out)
|
||||
return 0;
|
||||
for (;;)
|
||||
{
|
||||
/* What was written, or a unit borrowed data ended part way into */
|
||||
if (ps->rd < ps->wr)
|
||||
{
|
||||
size_t n;
|
||||
if (rmpeg1_ps_parse(ps, ps->buf, &ps->rd, ps->wr, out))
|
||||
return 1;
|
||||
if (!ps->ext || ps->ended)
|
||||
return 0;
|
||||
/* Completed from the borrowed data, as much of it as it takes */
|
||||
n = rmpeg1_ps_unit_need(ps);
|
||||
if (n > ps->ext_len - ps->ext_rd)
|
||||
n = ps->ext_len - ps->ext_rd;
|
||||
rmpeg1_ps_take(ps, n);
|
||||
continue;
|
||||
}
|
||||
if (!ps->ext)
|
||||
return 0;
|
||||
ps->rd = ps->wr = 0;
|
||||
/* Borrowed data is parsed where it lies */
|
||||
if (rmpeg1_ps_parse(ps, ps->ext, &ps->ext_rd, ps->ext_len, out))
|
||||
return 1;
|
||||
/* A unit it ends part way into is kept for the next */
|
||||
if (ps->ext && ps->ext_rd < ps->ext_len && !ps->ended)
|
||||
rmpeg1_ps_take(ps, ps->ext_len - ps->ext_rd);
|
||||
ps->ext = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t rmpeg1_ps_borrow(rmpeg1_ps_t *ps, const uint8_t *data, size_t len)
|
||||
{
|
||||
if (!ps || !data || !len || ps->ext)
|
||||
return 0;
|
||||
ps->ext = data;
|
||||
ps->ext_len = len;
|
||||
ps->ext_rd = 0;
|
||||
return len;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Accessors */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
+14
-8
@@ -3167,6 +3167,20 @@ bool rpng_iterate_image(rpng_t *rpng)
|
||||
if (!rpng_process_ihdr(&rpng->ihdr))
|
||||
return false;
|
||||
|
||||
/* PNG only defines compression and filter method 0, and
|
||||
* interlace methods 0 (none) and 1 (Adam7). In particular,
|
||||
* the decode path treats every non-zero interlace value as
|
||||
* Adam7 while the buffer setup only treats 1 as Adam7. */
|
||||
if ( rpng->ihdr.compression != 0
|
||||
|| rpng->ihdr.filter != 0
|
||||
|| rpng->ihdr.interlace > 1)
|
||||
{
|
||||
#if defined(DEBUG) || defined(RPNG_TEST)
|
||||
fprintf(stderr, "[RPNG] Error in line %d.\n", __LINE__);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rpng->ihdr.width == 0 || rpng->ihdr.height == 0)
|
||||
return false;
|
||||
|
||||
@@ -3212,14 +3226,6 @@ bool rpng_iterate_image(rpng_t *rpng)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rpng->ihdr.compression != 0)
|
||||
{
|
||||
#if defined(DEBUG) || defined(RPNG_TEST)
|
||||
fprintf(stderr, "[RPNG] Error in line %d.\n", __LINE__);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
rpng->flags |= RPNG_FLAG_HAS_IHDR;
|
||||
break;
|
||||
|
||||
|
||||
@@ -0,0 +1,312 @@
|
||||
/* Copyright (C) 2010-2026 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (rpsmf.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <formats/rpsmf.h>
|
||||
#include <formats/rmpeg1_ps.h>
|
||||
|
||||
#define RPSMF_SUBSTREAMS 16
|
||||
/* A frame header and the largest frame after it */
|
||||
#define RPSMF_FRAME_MAX (8 + RPSMF_ATRAC3P_FRAME_BYTES(3, 255))
|
||||
/* Where in a substream's first packet the first frame may start */
|
||||
#define RPSMF_SKIP_MAX 16
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t frame[RPSMF_FRAME_MAX];
|
||||
size_t have; /* bytes of the frame held, its header among them */
|
||||
size_t need; /* the whole frame, once its header is in; else 0 */
|
||||
uint64_t pts;
|
||||
int skip; /* the packets' own header bytes; -1 until learnt */
|
||||
} rpsmf_sub_t;
|
||||
|
||||
struct rpsmf
|
||||
{
|
||||
rmpeg1_ps_t *ps;
|
||||
/* The audio packet being cut into frames, where the demuxer has it:
|
||||
* nothing is written or borrowed until it is used up */
|
||||
const uint8_t *pkt;
|
||||
size_t pkt_len;
|
||||
size_t pkt_pos;
|
||||
uint64_t pkt_pts; /* for the first frame to start in it */
|
||||
int pkt_sub;
|
||||
uint32_t resyncs;
|
||||
rpsmf_sub_t sub[RPSMF_SUBSTREAMS];
|
||||
};
|
||||
|
||||
static uint32_t rpsmf_be32(const uint8_t *p)
|
||||
{
|
||||
return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16)
|
||||
| ((uint32_t)p[2] << 8) | (uint32_t)p[3];
|
||||
}
|
||||
|
||||
bool rpsmf_parse_header(const uint8_t *buf, size_t len, rpsmf_info_t *out)
|
||||
{
|
||||
unsigned i;
|
||||
if ( !buf || !out || len < RPSMF_HEADER_SIZE
|
||||
|| memcmp(buf, "PSMF", 4))
|
||||
return false;
|
||||
out->version = 0;
|
||||
for (i = 4; i < 8; i++)
|
||||
{
|
||||
if (buf[i] < '0' || buf[i] > '9')
|
||||
return false;
|
||||
out->version = out->version * 10 + (uint32_t)(buf[i] - '0');
|
||||
}
|
||||
out->data_offset = rpsmf_be32(buf + 0x08);
|
||||
out->data_size = rpsmf_be32(buf + 0x0C);
|
||||
out->tick_freq = rpsmf_be32(buf + 0x56);
|
||||
out->duration = rpsmf_be32(buf + 0x5C);
|
||||
out->mux_rate = rpsmf_be32(buf + 0x60);
|
||||
return out->data_offset >= RPSMF_HEADER_SIZE;
|
||||
}
|
||||
|
||||
static bool rpsmf_frame_header(const uint8_t *p)
|
||||
{
|
||||
return p[0] == 0x0F && p[1] == 0xD0
|
||||
&& !p[4] && !p[5] && !p[6] && !p[7];
|
||||
}
|
||||
|
||||
static void rpsmf_sub_clear(rpsmf_sub_t *s)
|
||||
{
|
||||
s->have = 0;
|
||||
s->need = 0;
|
||||
s->pts = RPSMF_NO_PTS;
|
||||
s->skip = -1;
|
||||
}
|
||||
|
||||
rpsmf_t *rpsmf_init(void)
|
||||
{
|
||||
rpsmf_t *d = (rpsmf_t*)calloc(1, sizeof(*d));
|
||||
if (!d)
|
||||
return NULL;
|
||||
if (!(d->ps = rmpeg1_ps_init(0)))
|
||||
{
|
||||
free(d);
|
||||
return NULL;
|
||||
}
|
||||
rpsmf_reset(d);
|
||||
return d;
|
||||
}
|
||||
|
||||
void rpsmf_free(rpsmf_t *d)
|
||||
{
|
||||
if (!d)
|
||||
return;
|
||||
rmpeg1_ps_free(d->ps);
|
||||
free(d);
|
||||
}
|
||||
|
||||
void rpsmf_reset(rpsmf_t *d)
|
||||
{
|
||||
unsigned i;
|
||||
if (!d)
|
||||
return;
|
||||
rmpeg1_ps_reset(d->ps);
|
||||
d->pkt_len = 0;
|
||||
d->pkt_pos = 0;
|
||||
for (i = 0; i < RPSMF_SUBSTREAMS; i++)
|
||||
rpsmf_sub_clear(&d->sub[i]);
|
||||
}
|
||||
|
||||
size_t rpsmf_write(rpsmf_t *d, const uint8_t *data, size_t len)
|
||||
{
|
||||
return (d && d->pkt_pos >= d->pkt_len)
|
||||
? rmpeg1_ps_write(d->ps, data, len) : 0;
|
||||
}
|
||||
|
||||
size_t rpsmf_borrow(rpsmf_t *d, const uint8_t *data, size_t len)
|
||||
{
|
||||
return (d && d->pkt_pos >= d->pkt_len)
|
||||
? rmpeg1_ps_borrow(d->ps, data, len) : 0;
|
||||
}
|
||||
|
||||
uint32_t rpsmf_resyncs(const rpsmf_t *d)
|
||||
{
|
||||
return d ? d->resyncs : 0;
|
||||
}
|
||||
|
||||
/* The next frame header in the packet from its cursor on: the cursor
|
||||
* there and true, or past the end and false */
|
||||
static bool rpsmf_seek_header(rpsmf_t *d)
|
||||
{
|
||||
while (d->pkt_pos + 8 <= d->pkt_len)
|
||||
{
|
||||
if (rpsmf_frame_header(d->pkt + d->pkt_pos))
|
||||
return true;
|
||||
d->pkt_pos++;
|
||||
}
|
||||
d->pkt_pos = d->pkt_len;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* More of the current audio packet into its substream's frame: 1 and
|
||||
* *out when a frame is whole, 0 when the packet is used up */
|
||||
static int rpsmf_cut(rpsmf_t *d, rpsmf_packet_t *out)
|
||||
{
|
||||
rpsmf_sub_t *s = &d->sub[d->pkt_sub];
|
||||
while (d->pkt_pos < d->pkt_len)
|
||||
{
|
||||
size_t take;
|
||||
/* A frame whole within the packet goes out from where it lies */
|
||||
if (!s->have && d->pkt_len - d->pkt_pos >= 8
|
||||
&& rpsmf_frame_header(d->pkt + d->pkt_pos))
|
||||
{
|
||||
const uint8_t *f = d->pkt + d->pkt_pos;
|
||||
size_t n = RPSMF_ATRAC3P_FRAME_BYTES(f[2], f[3]);
|
||||
if (8 + n <= d->pkt_len - d->pkt_pos)
|
||||
{
|
||||
out->data = f + 8;
|
||||
out->size = n;
|
||||
out->pts = d->pkt_pts;
|
||||
out->dts = RPSMF_NO_PTS;
|
||||
out->kind = RPSMF_ATRAC3P;
|
||||
out->stream = (uint8_t)d->pkt_sub;
|
||||
out->params[0] = f[2];
|
||||
out->params[1] = f[3];
|
||||
d->pkt_pts = RPSMF_NO_PTS;
|
||||
d->pkt_pos += 8 + n;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (!s->need)
|
||||
{
|
||||
/* A frame starts here: the packet's timestamp is the first
|
||||
* such frame's */
|
||||
if (!s->have)
|
||||
{
|
||||
s->pts = d->pkt_pts;
|
||||
d->pkt_pts = RPSMF_NO_PTS;
|
||||
}
|
||||
take = 8 - s->have;
|
||||
if (take > d->pkt_len - d->pkt_pos)
|
||||
take = d->pkt_len - d->pkt_pos;
|
||||
memcpy(s->frame + s->have, d->pkt + d->pkt_pos, take);
|
||||
s->have += take;
|
||||
d->pkt_pos += take;
|
||||
if (s->have < 8)
|
||||
return 0;
|
||||
if (!rpsmf_frame_header(s->frame))
|
||||
{
|
||||
/* Not where a frame should be: the next header there is */
|
||||
d->resyncs++;
|
||||
s->have = 0;
|
||||
if (!rpsmf_seek_header(d))
|
||||
return 0;
|
||||
continue;
|
||||
}
|
||||
s->need = 8 + RPSMF_ATRAC3P_FRAME_BYTES(s->frame[2], s->frame[3]);
|
||||
}
|
||||
take = s->need - s->have;
|
||||
if (take > d->pkt_len - d->pkt_pos)
|
||||
take = d->pkt_len - d->pkt_pos;
|
||||
memcpy(s->frame + s->have, d->pkt + d->pkt_pos, take);
|
||||
s->have += take;
|
||||
d->pkt_pos += take;
|
||||
if (s->have == s->need)
|
||||
{
|
||||
out->data = s->frame + 8;
|
||||
out->size = s->need - 8;
|
||||
out->pts = s->pts;
|
||||
out->dts = RPSMF_NO_PTS;
|
||||
out->kind = RPSMF_ATRAC3P;
|
||||
out->stream = (uint8_t)d->pkt_sub;
|
||||
out->params[0] = s->frame[2];
|
||||
out->params[1] = s->frame[3];
|
||||
s->have = 0;
|
||||
s->need = 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rpsmf_next(rpsmf_t *d, rpsmf_packet_t *out)
|
||||
{
|
||||
rmpeg1_ps_packet_t pkt;
|
||||
if (!d || !out)
|
||||
return 0;
|
||||
for (;;)
|
||||
{
|
||||
if (d->pkt_pos < d->pkt_len && rpsmf_cut(d, out))
|
||||
return 1;
|
||||
if (!rmpeg1_ps_next(d->ps, &pkt))
|
||||
return 0;
|
||||
if (pkt.type == RMPEG1_PS_VIDEO)
|
||||
{
|
||||
out->data = pkt.data;
|
||||
out->size = pkt.size;
|
||||
out->pts = pkt.pts;
|
||||
out->dts = pkt.dts;
|
||||
out->kind = RPSMF_VIDEO;
|
||||
out->stream = pkt.index;
|
||||
out->params[0] = out->params[1] = 0;
|
||||
return 1;
|
||||
}
|
||||
if (pkt.type != RMPEG1_PS_PRIVATE_1 || pkt.size < 2)
|
||||
continue;
|
||||
if (pkt.data[0] >= RPSMF_SUBSTREAMS)
|
||||
{
|
||||
out->data = pkt.data + 1;
|
||||
out->size = pkt.size - 1;
|
||||
out->pts = pkt.pts;
|
||||
out->dts = RPSMF_NO_PTS;
|
||||
out->kind = RPSMF_PRIVATE;
|
||||
out->stream = pkt.data[0];
|
||||
out->params[0] = out->params[1] = 0;
|
||||
return 1;
|
||||
}
|
||||
{
|
||||
rpsmf_sub_t *s = &d->sub[pkt.data[0]];
|
||||
d->pkt = pkt.data + 1;
|
||||
d->pkt_len = pkt.size - 1;
|
||||
d->pkt_pos = 0;
|
||||
d->pkt_pts = pkt.pts;
|
||||
d->pkt_sub = pkt.data[0];
|
||||
/* The substream's first packet starts a frame right after the
|
||||
* packet's own header: how long that is, for every packet */
|
||||
if (s->skip < 0)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i <= RPSMF_SKIP_MAX
|
||||
&& (size_t)i + 8 <= d->pkt_len; i++)
|
||||
if (rpsmf_frame_header(d->pkt + i))
|
||||
break;
|
||||
if (i > RPSMF_SKIP_MAX || (size_t)i + 8 > d->pkt_len)
|
||||
{
|
||||
d->resyncs++;
|
||||
d->pkt_len = 0;
|
||||
continue;
|
||||
}
|
||||
s->skip = i;
|
||||
}
|
||||
if ((size_t)s->skip >= d->pkt_len)
|
||||
{
|
||||
d->pkt_len = 0;
|
||||
continue;
|
||||
}
|
||||
d->pkt_pos = (size_t)s->skip;
|
||||
}
|
||||
}
|
||||
}
|
||||
+71
-1
@@ -48,6 +48,19 @@ enum image_process_code
|
||||
|
||||
struct texture_compressed; /* defined below, after enum image_type_enum */
|
||||
|
||||
/* An 8-bit YCbCr 4:2:0 frame where it lies. Plane 0 is luma; planes
|
||||
* 1 and 2 are Cb and Cr, @chroma_step bytes between neighbours (1 for
|
||||
* I420; 2 for NV12, whose one interleaved plane is planes 1 and 2 at
|
||||
* offsets 0 and 1). Strides in bytes; @yuv is IMAGE_YUV_FLAG_*
|
||||
* (formats/image_yuv_blit.h). */
|
||||
struct texture_planar
|
||||
{
|
||||
const uint8_t *planes[3];
|
||||
unsigned strides[3];
|
||||
unsigned chroma_step;
|
||||
unsigned yuv;
|
||||
};
|
||||
|
||||
struct texture_image
|
||||
{
|
||||
uint32_t *pixels;
|
||||
@@ -69,6 +82,9 @@ struct texture_image
|
||||
* image_texture_realize_rgba() decodes to ->pixels on demand for
|
||||
* drivers that cannot sample the format. */
|
||||
struct texture_compressed *compressed;
|
||||
/* When non-NULL the frame is this, ->pixels is NULL, and only a
|
||||
* driver answering TEXTURE_GPU_FORMAT_YUV420 is given it. */
|
||||
const struct texture_planar *planar;
|
||||
};
|
||||
|
||||
enum image_type_enum
|
||||
@@ -124,7 +140,10 @@ enum texture_gpu_format
|
||||
* texture drawn in the menu or over content is shown as linear
|
||||
* scRGB - 1.0 at 80 nits, the 709 primaries - rather than as an
|
||||
* SDR-encoded one: true only while the output is HDR. */
|
||||
TEXTURE_GPU_FORMAT_SCRGB
|
||||
TEXTURE_GPU_FORMAT_SCRGB,
|
||||
/* 8-bit YCbCr 4:2:0 on ->planar (I420 or NV12), converted to RGB
|
||||
* on the GPU: whether load_texture and update_texture take one. */
|
||||
TEXTURE_GPU_FORMAT_YUV420
|
||||
};
|
||||
|
||||
/* Numeric mip layout reported by a loader without decoding. Offsets are
|
||||
@@ -170,6 +189,57 @@ enum image_type_enum image_texture_get_type(const char *path);
|
||||
* hook, or at the byte frontier. image_texture_load() is this loader
|
||||
* run to completion in one call. */
|
||||
|
||||
/* Pixel layouts, a bit each, so a consumer can accept several and a
|
||||
* producer pick the best it can emit. A name is a promise about the
|
||||
* layout, not about any consumer taking it. The frontend's surfaces
|
||||
* and a core's own renderer name formats the same way. */
|
||||
enum image_pixfmt
|
||||
{
|
||||
/* 8 bits a channel in a 32-bit word, ARGB or memory-order RGBA */
|
||||
IMAGE_PIXFMT_8888 = (1 << 0),
|
||||
/* XRGB2101010: bits [29:20]=R [19:10]=G [9:0]=B */
|
||||
IMAGE_PIXFMT_2101010 = (1 << 1),
|
||||
/* Half float a channel, linear scRGB (1.0 = 80 nits) */
|
||||
IMAGE_PIXFMT_FP16 = (1 << 2),
|
||||
IMAGE_PIXFMT_FP32 = (1 << 3),
|
||||
IMAGE_PIXFMT_565 = (1 << 4),
|
||||
IMAGE_PIXFMT_4444 = (1 << 5),
|
||||
/* GX RGBA8, the GameCube/Wii layout: 4x4 tiles of 64 bytes, the AR
|
||||
* halves of a tile's 16 texels then their GB halves, both axes
|
||||
* multiples of 4 (image_texture_tile_gx) */
|
||||
IMAGE_PIXFMT_GX_RGBA8 = (1 << 6),
|
||||
/* YCbCr 4:2:0, as video decoders and cameras produce it: a luma
|
||||
* plane, then chroma at half resolution on both axes. I420 has the
|
||||
* two chroma planes apart, NV12 interleaves them Cb,Cr in one, P010
|
||||
* is NV12 with 16-bit samples holding 10 bits in the high bits. */
|
||||
IMAGE_PIXFMT_I420 = (1 << 7),
|
||||
IMAGE_PIXFMT_NV12 = (1 << 8),
|
||||
IMAGE_PIXFMT_P010 = (1 << 9)
|
||||
};
|
||||
|
||||
#define IMAGE_PIXFMT_PLANAR \
|
||||
(IMAGE_PIXFMT_I420 | IMAGE_PIXFMT_NV12 | IMAGE_PIXFMT_P010)
|
||||
|
||||
/* Planes of one image_pixfmt bit */
|
||||
#define IMAGE_PIXFMT_PLANES(f) \
|
||||
(((f) & IMAGE_PIXFMT_I420) ? 3u \
|
||||
: ((f) & (IMAGE_PIXFMT_NV12 | IMAGE_PIXFMT_P010)) ? 2u : 1u)
|
||||
|
||||
/* Bytes a texel of a packed format takes, or a luma sample of a planar
|
||||
* one */
|
||||
#define IMAGE_PIXFMT_BPP(f) \
|
||||
(((f) & IMAGE_PIXFMT_FP32) ? 16u \
|
||||
: ((f) & IMAGE_PIXFMT_FP16) ? 8u \
|
||||
: ((f) & (IMAGE_PIXFMT_565 | IMAGE_PIXFMT_4444 | IMAGE_PIXFMT_P010)) ? 2u \
|
||||
: ((f) & (IMAGE_PIXFMT_I420 | IMAGE_PIXFMT_NV12)) ? 1u : 4u)
|
||||
|
||||
/* Bytes of a whole tightly packed @w x @h frame, every plane of it */
|
||||
#define IMAGE_PIXFMT_FRAME_SIZE(f, w, h) \
|
||||
((size_t)(w) * (size_t)(h) * IMAGE_PIXFMT_BPP(f) \
|
||||
+ (((f) & IMAGE_PIXFMT_PLANAR) \
|
||||
? 2u * (((size_t)(w) + 1) >> 1) * (((size_t)(h) + 1) >> 1) \
|
||||
* IMAGE_PIXFMT_BPP(f) : 0u))
|
||||
|
||||
/* What the caller takes of a still, asked of it once by whoever knows
|
||||
* (the video driver, a core's own renderer) and handed down. Zero is
|
||||
* the ordinary 8-bit image, ARGB words. */
|
||||
|
||||
@@ -66,6 +66,14 @@ void image_yuv_i420_to_rgb32(uint32_t *dst, unsigned dst_stride,
|
||||
const uint8_t *v, unsigned v_stride,
|
||||
unsigned w, unsigned h, unsigned flags);
|
||||
|
||||
/* The matrix @flags names (BT709, FULL_RANGE), for a GPU to apply to
|
||||
* samples normalised to 0..1: with chroma less 128/255,
|
||||
* R = c[0] * Y + c[1] + c[2] * Cr
|
||||
* G = c[0] * Y + c[1] + c[3] * Cb + c[4] * Cr
|
||||
* B = c[0] * Y + c[1] + c[5] * Cb
|
||||
* the same matrix the conversions above use. */
|
||||
void image_yuv_coefficients(unsigned flags, float c[6]);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,95 @@
|
||||
/* Copyright (C) 2010-2026 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (ratrac3.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_FORMAT_RATRAC3_H
|
||||
#define __LIBRETRO_SDK_FORMAT_RATRAC3_H
|
||||
|
||||
/* ATRAC3 audio decoder (Sony's LP2/LP4 codec, as in PSP .at3 files,
|
||||
* WAVE format tag 270h, and OpenMG).
|
||||
*
|
||||
* Written clean-room: the bit-stream syntax from public format notes,
|
||||
* the signal path measured against an existing decoder's output, never
|
||||
* its source. Every frame decodes to 1024 samples a channel.
|
||||
*
|
||||
* A frame is block_align bytes: one sound unit a channel, block_align /
|
||||
* channels bytes each, or, in joint stereo (the 66 kb/s LP4 mode), a
|
||||
* mid unit read forwards from the start and a side unit read backwards
|
||||
* from the end, with the stereo parameters at the very end.
|
||||
*
|
||||
* ratrac3_info_t info;
|
||||
* ratrac3_parse_wave_fmt(fmt_chunk, fmt_len, &info);
|
||||
* ratrac3_t *d = ratrac3_new(info.channels, info.block_align,
|
||||
* info.joint_stereo);
|
||||
* while (have a frame)
|
||||
* ratrac3_decode_s16(d, frame, info.block_align, pcm);
|
||||
*
|
||||
* C89. A decoder holds no pointer into the input between calls. */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <retro_common_api.h>
|
||||
#include <boolean.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
#define RATRAC3_SAMPLES 1024 /* a channel, every frame */
|
||||
#define RATRAC3_FORMAT_TAG 0x0270
|
||||
|
||||
typedef struct ratrac3 ratrac3_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned channels; /* 1 or 2 */
|
||||
unsigned sample_rate; /* 44100 as a rule */
|
||||
unsigned block_align; /* bytes a frame */
|
||||
unsigned bitrate; /* bits a second */
|
||||
bool joint_stereo;
|
||||
} ratrac3_info_t;
|
||||
|
||||
/* Reads a WAVE 'fmt ' chunk's body (format tag 270h and its 14 bytes
|
||||
* of extra data). Returns false when it is not ATRAC3 or not a layout
|
||||
* this decoder takes. */
|
||||
bool ratrac3_parse_wave_fmt(const uint8_t *fmt, size_t len,
|
||||
ratrac3_info_t *info);
|
||||
|
||||
/* channels 1 or 2; block_align as the container gives it; joint stereo
|
||||
* only with two channels. NULL on a layout the decoder does not take. */
|
||||
ratrac3_t *ratrac3_new(unsigned channels, unsigned block_align,
|
||||
bool joint_stereo);
|
||||
void ratrac3_free(ratrac3_t *d);
|
||||
|
||||
/* Forgets the signal history, as at a seek. */
|
||||
void ratrac3_reset(ratrac3_t *d);
|
||||
|
||||
/* Decodes one frame of len (at least block_align) bytes into
|
||||
* RATRAC3_SAMPLES samples a channel, interleaved. Returns
|
||||
* RATRAC3_SAMPLES, or -1 on a frame that does not parse: the output
|
||||
* is then silence and the history is kept as it was. */
|
||||
int ratrac3_decode_s16(ratrac3_t *d, const uint8_t *frame, size_t len,
|
||||
int16_t *out);
|
||||
int ratrac3_decode_float(ratrac3_t *d, const uint8_t *frame, size_t len,
|
||||
float *out);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -3,7 +3,9 @@
|
||||
|
||||
/* MPEG-1 Systems (Program Stream) demultiplexer.
|
||||
*
|
||||
* Written from ISO/IEC 11172-1. Splits an MPEG-1 Program Stream into its
|
||||
* Written from ISO/IEC 11172-1, and takes the MPEG-2 program stream of
|
||||
* ISO/IEC 13818-1 as well - its pack and PES headers, packet by packet -
|
||||
* which is what a PSP movie (rpsmf.h) and a DVD's VOBs are. Splits an MPEG-1 Program Stream into its
|
||||
* constituent elementary streams (MPEG-1 video, MPEG-1 audio layer I/II/III,
|
||||
* private and padding streams) and recovers the timestamps attached to them.
|
||||
*
|
||||
@@ -82,6 +84,14 @@ size_t rmpeg1_ps_space(const rmpeg1_ps_t *ps);
|
||||
* when the buffer is full; drain with rmpeg1_ps_next() and retry the rest. */
|
||||
size_t rmpeg1_ps_write(rmpeg1_ps_t *ps, const uint8_t *data, size_t len);
|
||||
|
||||
/* Hand over input to be parsed where it lies, rather than copied in: the
|
||||
* packets that lie whole within it point into it, and a unit it ends part
|
||||
* way into is copied, to be completed by what comes next. @data must stay
|
||||
* valid and unchanged until rmpeg1_ps_next() returns 0. Returns @len, or 0
|
||||
* while data borrowed before is still being parsed; rmpeg1_ps_write()
|
||||
* likewise takes nothing until it has been. */
|
||||
size_t rmpeg1_ps_borrow(rmpeg1_ps_t *ps, const uint8_t *data, size_t len);
|
||||
|
||||
/* Pull one packet. Returns 1 and fills *out on success, 0 when more input is
|
||||
* needed. Padding packets are consumed silently and never returned. */
|
||||
int rmpeg1_ps_next(rmpeg1_ps_t *ps, rmpeg1_ps_packet_t *out);
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/* Copyright (C) 2010-2026 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (rpsmf.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_FORMAT_RPSMF_H
|
||||
#define __LIBRETRO_SDK_FORMAT_RPSMF_H
|
||||
|
||||
/* PSP movie (PSMF, .pmf) demultiplexer.
|
||||
*
|
||||
* A PSMF file is a 2048-byte header and an MPEG-2 program stream: H.264
|
||||
* video in stream E0h, ATRAC3plus audio in private stream 1, substream
|
||||
* by substream. The stream goes through rmpeg1_ps; this layer reads the
|
||||
* header, passes video on as it comes, and cuts the audio into whole
|
||||
* ATRAC3plus frames.
|
||||
*
|
||||
* An ATRAC3plus frame in a PSMF is an 8-byte header - 0Fh D0h, two bytes
|
||||
* of parameters, four of zero - and (((p0 & 3) << 8) | p1) * 8 + 8 bytes
|
||||
* of frame. Each private stream 1 packet starts with the substream byte
|
||||
* and a few header bytes of its own before the frame data, which runs on
|
||||
* across packets; the number of those bytes is learnt from the first
|
||||
* packet of a substream, where a frame starts right after them, and
|
||||
* checked against every frame header after. A frame that does not chain
|
||||
* resynchronises on the next frame header.
|
||||
*
|
||||
* Usage is push/pull, as rmpeg1_ps's:
|
||||
*
|
||||
* rpsmf_info_t info;
|
||||
* rpsmf_parse_header(file, file_len, &info);
|
||||
* rpsmf_t *d = rpsmf_init();
|
||||
* rpsmf_write(d, file + info.data_offset, n);
|
||||
* while (rpsmf_next(d, &pkt))
|
||||
* ...
|
||||
*
|
||||
* Packet data points into the demuxer, or into borrowed input, and stays
|
||||
* valid until the next rpsmf_next(). C89. */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <retro_common_api.h>
|
||||
#include <boolean.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
#define RPSMF_HEADER_SIZE 0x64
|
||||
#define RPSMF_NO_PTS ((uint64_t)UINT64_C(0xFFFFFFFFFFFFFFFF))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t version; /* "0012" .. "0015" as 12 .. 15 */
|
||||
uint32_t data_offset; /* where the program stream starts, 2048 */
|
||||
uint32_t data_size; /* its length from there */
|
||||
uint32_t tick_freq; /* ticks a second of @duration */
|
||||
uint32_t duration;
|
||||
uint32_t mux_rate; /* 50 bytes/s, as the pack headers say */
|
||||
} rpsmf_info_t;
|
||||
|
||||
enum rpsmf_kind
|
||||
{
|
||||
RPSMF_NONE = 0,
|
||||
RPSMF_VIDEO, /* H.264 byte stream, as the PES carried it */
|
||||
RPSMF_ATRAC3P, /* one whole ATRAC3plus frame */
|
||||
RPSMF_PRIVATE /* another private stream 1 substream, raw */
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const uint8_t *data;
|
||||
size_t size;
|
||||
uint64_t pts; /* 90 kHz, or RPSMF_NO_PTS */
|
||||
uint64_t dts; /* video only; 90 kHz, or RPSMF_NO_PTS */
|
||||
uint8_t kind; /* enum rpsmf_kind */
|
||||
uint8_t stream; /* E0h's low nibble, or the substream */
|
||||
/* An ATRAC3plus frame's two parameter bytes, as its header has them:
|
||||
* the frame size, and the channel layout and rate of the stream */
|
||||
uint8_t params[2];
|
||||
} rpsmf_packet_t;
|
||||
|
||||
/* The header's fields from the first RPSMF_HEADER_SIZE bytes of a file.
|
||||
* False when it is not a PSMF or @len is short. */
|
||||
bool rpsmf_parse_header(const uint8_t *buf, size_t len, rpsmf_info_t *out);
|
||||
|
||||
/* Bytes of an ATRAC3plus frame after its header, from the two parameter
|
||||
* bytes */
|
||||
#define RPSMF_ATRAC3P_FRAME_BYTES(p0, p1) \
|
||||
((((size_t)((p0) & 3) << 8) | (size_t)(p1)) * 8 + 8)
|
||||
|
||||
typedef struct rpsmf rpsmf_t;
|
||||
|
||||
rpsmf_t *rpsmf_init(void);
|
||||
void rpsmf_free(rpsmf_t *d);
|
||||
/* After a seek: everything buffered and every partial frame goes */
|
||||
void rpsmf_reset(rpsmf_t *d);
|
||||
/* Program stream bytes, from the header's data_offset on, copied in.
|
||||
* Returns what was taken: less than @len only when full, or nothing while
|
||||
* the last packet is not yet drained by rpsmf_next(). */
|
||||
size_t rpsmf_write(rpsmf_t *d, const uint8_t *data, size_t len);
|
||||
/* The same parsed where it lies (rmpeg1_ps_borrow): video packets and
|
||||
* the audio frames whole within one packet point into @data, which stays
|
||||
* valid and unchanged until rpsmf_next() returns 0. No copy but the
|
||||
* frames that run across packets, and what @data ends part way into. */
|
||||
size_t rpsmf_borrow(rpsmf_t *d, const uint8_t *data, size_t len);
|
||||
/* One packet: 1 and *out filled, 0 when more input is needed */
|
||||
int rpsmf_next(rpsmf_t *d, rpsmf_packet_t *out);
|
||||
/* Frames dropped because they did not chain */
|
||||
uint32_t rpsmf_resyncs(const rpsmf_t *d);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
+31
-6
@@ -130,8 +130,8 @@ RETRO_BEGIN_DECLS
|
||||
* subtraction would produce a giant array; guard with a max() so
|
||||
* the pad is always at least 1 byte and never underflows. */
|
||||
#define RETRO_SPSC_PAD0_BYTES \
|
||||
((RETRO_SPSC_CACHE_LINE > (sizeof(uint8_t*) + sizeof(size_t))) \
|
||||
? (RETRO_SPSC_CACHE_LINE - (sizeof(uint8_t*) + sizeof(size_t))) \
|
||||
((RETRO_SPSC_CACHE_LINE > (sizeof(uint8_t*) + 3 * sizeof(size_t))) \
|
||||
? (RETRO_SPSC_CACHE_LINE - (sizeof(uint8_t*) + 3 * sizeof(size_t))) \
|
||||
: 1)
|
||||
/* Each cursor shares its line with that side's private copy of the
|
||||
* other cursor (see cached_tail / cached_head below), so the pad is
|
||||
@@ -144,7 +144,14 @@ RETRO_BEGIN_DECLS
|
||||
typedef struct retro_spsc
|
||||
{
|
||||
uint8_t *buffer;
|
||||
size_t capacity; /* power of 2; mask = capacity - 1 */
|
||||
size_t capacity; /* power of 2: the most the ring holds */
|
||||
/* The buffer's size less one, also a power of 2: positions wrap
|
||||
* here. Equal to capacity - 1 unless the buffer is mirrored. */
|
||||
size_t mask;
|
||||
/* The buffer's size when its pages are mapped a second time right
|
||||
* behind it, else 0: a span then runs past the end into the
|
||||
* mirror, and no reservation is cut short at the wrap. */
|
||||
size_t mirror;
|
||||
/* Pad so head sits on a fresh cache line, isolating it from
|
||||
* the buffer/capacity fields that init may touch. */
|
||||
uint8_t _pad0[RETRO_SPSC_PAD0_BYTES];
|
||||
@@ -185,6 +192,22 @@ typedef struct retro_spsc
|
||||
*/
|
||||
bool retro_spsc_init(retro_spsc_t *q, size_t min_capacity);
|
||||
|
||||
/**
|
||||
* retro_spsc_init_mirrored:
|
||||
* @q : The queue.
|
||||
* @min_capacity : As retro_spsc_init; capacity is the same.
|
||||
*
|
||||
* As retro_spsc_init, but the buffer's pages are mapped twice, back
|
||||
* to back, where the platform allows it, so write_begin and read_begin
|
||||
* return every free or filled byte contiguously, across the wrap. The
|
||||
* buffer is at least a page (an allocation granule on Windows); a ring
|
||||
* smaller than that still holds only @min_capacity rounded up, so
|
||||
* capacity, room and fill read exactly as they would from
|
||||
* retro_spsc_init. Where mirroring is unavailable the queue is a plain
|
||||
* one and q->mirror is 0.
|
||||
*/
|
||||
bool retro_spsc_init_mirrored(retro_spsc_t *q, size_t min_capacity);
|
||||
|
||||
/**
|
||||
* retro_spsc_free:
|
||||
* @q : The queue.
|
||||
@@ -304,7 +327,8 @@ size_t retro_spsc_peek(const retro_spsc_t *q, void *data, size_t bytes);
|
||||
*
|
||||
* Producer-side zero-copy reservation. Returns the number of bytes
|
||||
* that can be written CONTIGUOUSLY at *@ptr - this is min(total free
|
||||
* space, distance to the physical end of the ring), so it can be
|
||||
* space, distance to the physical end of the ring; on a mirrored ring
|
||||
* the total free space alone), so it can be
|
||||
* smaller than retro_spsc_write_avail() when the head is near the
|
||||
* wrap point. No cursor moves; call retro_spsc_write_end() with the
|
||||
* number of bytes actually written (which may be 0, and must not
|
||||
@@ -345,8 +369,9 @@ void retro_spsc_write_end(retro_spsc_t *q, size_t bytes);
|
||||
*
|
||||
* Consumer-side zero-copy drain. Returns the number of bytes
|
||||
* readable CONTIGUOUSLY at *@ptr - min(total buffered, distance to
|
||||
* the physical end of the ring). Wrapped data needs a second
|
||||
* begin/end round after consuming the first span. No cursor moves;
|
||||
* the physical end of the ring; on a mirrored ring all of it).
|
||||
* Otherwise wrapped data needs a second begin/end round after
|
||||
* consuming the first span. No cursor moves;
|
||||
* call retro_spsc_read_end() with the bytes actually consumed.
|
||||
*
|
||||
* The region stays stable until read_end: the producer cannot write
|
||||
|
||||
+247
-31
@@ -20,10 +20,192 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* memfd_create goes through syscall(), and ftruncate and shm_open
|
||||
* are POSIX: strict C89 builds hide all three without these. */
|
||||
#if defined(__linux__) && !defined(_GNU_SOURCE)
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
/* Tiger must keep the legacy symbols rather than UNIX2003 variants. */
|
||||
#if defined(__APPLE__) && !defined(_DARWIN_C_SOURCE) \
|
||||
&& !(defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) \
|
||||
&& (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1050))
|
||||
#define _DARWIN_C_SOURCE
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <retro_inline.h>
|
||||
#include <retro_spsc.h>
|
||||
|
||||
/* Where a buffer can be mapped twice, back to back. RETRO_SPSC_MIRROR_SHM
|
||||
* selects the POSIX shm path on any POSIX host, for its tests. */
|
||||
#if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)
|
||||
#define SPSC_MIRROR_WIN32
|
||||
#elif defined(RETRO_SPSC_MIRROR_SHM)
|
||||
#define SPSC_MIRROR_SHM
|
||||
#elif defined(__linux__) && !defined(__EMSCRIPTEN__)
|
||||
#include <sys/syscall.h>
|
||||
#ifdef __NR_memfd_create
|
||||
#define SPSC_MIRROR_MEMFD
|
||||
#endif
|
||||
#elif defined(__APPLE__)
|
||||
#include <TargetConditionals.h>
|
||||
#if !TARGET_OS_IPHONE
|
||||
#define SPSC_MIRROR_SHM
|
||||
#endif
|
||||
#elif (defined(__FreeBSD__) && !defined(__ORBIS__)) || defined(__NetBSD__) \
|
||||
|| defined(__OpenBSD__)
|
||||
#define SPSC_MIRROR_SHM
|
||||
#endif
|
||||
|
||||
#if defined(SPSC_MIRROR_WIN32)
|
||||
#include <windows.h>
|
||||
#elif defined(SPSC_MIRROR_MEMFD) || defined(SPSC_MIRROR_SHM)
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#if defined(SPSC_MIRROR_WIN32) || defined(SPSC_MIRROR_MEMFD) \
|
||||
|| defined(SPSC_MIRROR_SHM)
|
||||
#define SPSC_MIRROR
|
||||
#endif
|
||||
|
||||
#ifdef SPSC_MIRROR_SHM
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
/* Bytes contiguous at @idx: to the buffer's end, or past it into the
|
||||
* mirror. */
|
||||
static INLINE size_t spsc_contig(const retro_spsc_t *q, size_t idx)
|
||||
{
|
||||
return q->mirror ? (size_t)-1 : q->mask + 1 - idx;
|
||||
}
|
||||
|
||||
#ifdef SPSC_MIRROR
|
||||
#if !defined(SPSC_MIRROR_WIN32) && !defined(MAP_ANONYMOUS)
|
||||
#define MAP_ANONYMOUS MAP_ANON
|
||||
#endif
|
||||
|
||||
/* What a mapping is made of: a page, or Windows' allocation granule. */
|
||||
static size_t spsc_mirror_granule(void)
|
||||
{
|
||||
#ifdef SPSC_MIRROR_WIN32
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
return (size_t)si.dwAllocationGranularity;
|
||||
#else
|
||||
long page = sysconf(_SC_PAGESIZE);
|
||||
return page > 0 ? (size_t)page : 4096;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void spsc_mirror_free(uint8_t *base, size_t size)
|
||||
{
|
||||
#ifdef SPSC_MIRROR_WIN32
|
||||
UnmapViewOfFile(base);
|
||||
UnmapViewOfFile(base + size);
|
||||
#else
|
||||
munmap(base, size * 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef SPSC_MIRROR_WIN32
|
||||
/* Both views of a descriptor's pages, inside one reservation so nothing
|
||||
* can land between them. Takes the descriptor. */
|
||||
static uint8_t *spsc_mirror_map(int fd, size_t size)
|
||||
{
|
||||
uint8_t *base = NULL;
|
||||
void *res;
|
||||
if (ftruncate(fd, (off_t)size) == 0)
|
||||
{
|
||||
res = mmap(NULL, size * 2, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
if (res != MAP_FAILED)
|
||||
{
|
||||
base = (uint8_t*)res;
|
||||
if ( mmap(base, size, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | MAP_FIXED, fd, 0) == MAP_FAILED
|
||||
|| mmap(base + size, size, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | MAP_FIXED, fd, 0) == MAP_FAILED)
|
||||
{
|
||||
munmap(base, size * 2);
|
||||
base = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
return base;
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint8_t *spsc_mirror_alloc(size_t size)
|
||||
{
|
||||
uint8_t *base = NULL;
|
||||
#if defined(SPSC_MIRROR_WIN32)
|
||||
unsigned tries;
|
||||
HANDLE h = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL,
|
||||
PAGE_READWRITE, (DWORD)((uint64_t)size >> 32), (DWORD)size, NULL);
|
||||
if (!h)
|
||||
return NULL;
|
||||
/* The reservation is released before the views are placed in it,
|
||||
* so another thread can take the address meanwhile: try again. */
|
||||
for (tries = 0; tries < 16 && !base; tries++)
|
||||
{
|
||||
uint8_t *at = (uint8_t*)VirtualAlloc(NULL, size * 2, MEM_RESERVE,
|
||||
PAGE_NOACCESS);
|
||||
void *lo, *hi;
|
||||
if (!at)
|
||||
break;
|
||||
VirtualFree(at, 0, MEM_RELEASE);
|
||||
if (!(lo = MapViewOfFileEx(h, FILE_MAP_ALL_ACCESS, 0, 0, size, at)))
|
||||
continue;
|
||||
hi = MapViewOfFileEx(h, FILE_MAP_ALL_ACCESS, 0, 0, size, at + size);
|
||||
if (hi == (void*)(at + size))
|
||||
base = at;
|
||||
else
|
||||
{
|
||||
if (hi)
|
||||
UnmapViewOfFile(hi);
|
||||
UnmapViewOfFile(lo);
|
||||
}
|
||||
}
|
||||
CloseHandle(h);
|
||||
#elif defined(SPSC_MIRROR_MEMFD)
|
||||
int fd = (int)syscall(__NR_memfd_create, "retro_spsc", 1u /* MFD_CLOEXEC */);
|
||||
if (fd >= 0)
|
||||
base = spsc_mirror_map(fd, size);
|
||||
#else
|
||||
static unsigned serial;
|
||||
unsigned tries;
|
||||
for (tries = 0; tries < 8 && !base; tries++)
|
||||
{
|
||||
char name[48];
|
||||
int fd;
|
||||
sprintf(name, "/retro_spsc.%lu.%u", (unsigned long)getpid(),
|
||||
serial++);
|
||||
if ((fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0)
|
||||
continue;
|
||||
shm_unlink(name);
|
||||
base = spsc_mirror_map(fd, size);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
/* A write through one view must read back through the other. */
|
||||
if (base)
|
||||
{
|
||||
base[0] = 0x5a;
|
||||
if (base[size] != 0x5a)
|
||||
{
|
||||
spsc_mirror_free(base, size);
|
||||
return NULL;
|
||||
}
|
||||
base[0] = 0;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Round @v up to the next power of 2. Returns 0 if @v == 0 or if
|
||||
* the next power of 2 would overflow (caller checks @v <= SIZE_MAX/2). */
|
||||
static size_t spsc_round_up_pow2(size_t v)
|
||||
@@ -58,6 +240,8 @@ bool retro_spsc_init(retro_spsc_t *q, size_t min_capacity)
|
||||
return false;
|
||||
|
||||
q->capacity = cap;
|
||||
q->mask = cap - 1;
|
||||
q->mirror = 0;
|
||||
q->cached_tail = 0;
|
||||
q->cached_head = 0;
|
||||
retro_atomic_size_init(&q->head, 0);
|
||||
@@ -65,16 +249,53 @@ bool retro_spsc_init(retro_spsc_t *q, size_t min_capacity)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool retro_spsc_init_mirrored(retro_spsc_t *q, size_t min_capacity)
|
||||
{
|
||||
#ifdef SPSC_MIRROR
|
||||
size_t cap, size, granule;
|
||||
uint8_t *buf;
|
||||
|
||||
if (!q || min_capacity == 0 || min_capacity > (SIZE_MAX / 2))
|
||||
return false;
|
||||
cap = spsc_round_up_pow2(min_capacity);
|
||||
granule = spsc_mirror_granule();
|
||||
/* Positions wrap at the buffer's size, so it has to be a power of
|
||||
* 2 as well: the capacity, or the granule where that is larger. */
|
||||
size = cap > granule ? cap : granule;
|
||||
if ( cap && !(granule & (granule - 1))
|
||||
&& size <= (SIZE_MAX / 4)
|
||||
&& (buf = spsc_mirror_alloc(size)))
|
||||
{
|
||||
q->buffer = buf;
|
||||
q->capacity = cap;
|
||||
q->mask = size - 1;
|
||||
q->mirror = size;
|
||||
q->cached_tail = 0;
|
||||
q->cached_head = 0;
|
||||
retro_atomic_size_init(&q->head, 0);
|
||||
retro_atomic_size_init(&q->tail, 0);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return retro_spsc_init(q, min_capacity);
|
||||
}
|
||||
|
||||
void retro_spsc_free(retro_spsc_t *q)
|
||||
{
|
||||
if (!q)
|
||||
return;
|
||||
if (q->buffer)
|
||||
{
|
||||
free(q->buffer);
|
||||
#ifdef SPSC_MIRROR
|
||||
if (q->mirror)
|
||||
spsc_mirror_free(q->buffer, q->mirror);
|
||||
else
|
||||
#endif
|
||||
free(q->buffer);
|
||||
q->buffer = NULL;
|
||||
}
|
||||
q->capacity = 0;
|
||||
q->mirror = 0;
|
||||
}
|
||||
|
||||
void retro_spsc_clear(retro_spsc_t *q)
|
||||
@@ -130,7 +351,7 @@ size_t retro_spsc_read_avail(const retro_spsc_t *q)
|
||||
|
||||
size_t retro_spsc_write(retro_spsc_t *q, const void *data, size_t bytes)
|
||||
{
|
||||
size_t mask, head_idx, first;
|
||||
size_t head_idx, first;
|
||||
const uint8_t *src = (const uint8_t*)data;
|
||||
/* head is ours (relaxed). Room is first computed from our private
|
||||
* copy of tail, which is never ahead of the real one; only when it
|
||||
@@ -149,11 +370,10 @@ size_t retro_spsc_write(retro_spsc_t *q, const void *data, size_t bytes)
|
||||
if (bytes == 0)
|
||||
return 0;
|
||||
|
||||
mask = q->capacity - 1;
|
||||
head_idx = head & mask;
|
||||
head_idx = head & q->mask;
|
||||
|
||||
/* first = bytes from head_idx to end-of-buffer */
|
||||
first = q->capacity - head_idx;
|
||||
first = spsc_contig(q, head_idx);
|
||||
if (first > bytes)
|
||||
first = bytes;
|
||||
|
||||
@@ -183,8 +403,8 @@ size_t retro_spsc_write_frames(retro_spsc_t *q, const void *data,
|
||||
if (!frames) return 0;
|
||||
/* Multiplication is bounded by capacity, even for an oversized request. */
|
||||
bytes = frames * frame_bytes;
|
||||
index = head & (q->capacity - 1);
|
||||
first = q->capacity - index;
|
||||
index = head & q->mask;
|
||||
first = spsc_contig(q, index);
|
||||
if (first > bytes) first = bytes;
|
||||
memcpy(q->buffer + index, src, first);
|
||||
memcpy(q->buffer, src + first, bytes - first);
|
||||
@@ -194,7 +414,7 @@ size_t retro_spsc_write_frames(retro_spsc_t *q, const void *data,
|
||||
|
||||
size_t retro_spsc_read(retro_spsc_t *q, void *data, size_t bytes)
|
||||
{
|
||||
size_t mask, tail_idx, first;
|
||||
size_t tail_idx, first;
|
||||
uint8_t *dst = (uint8_t*)data;
|
||||
/* acquire on head pairs with producer's release-store; this is
|
||||
* what makes the subsequent memcpys safe to read. */
|
||||
@@ -214,10 +434,9 @@ size_t retro_spsc_read(retro_spsc_t *q, void *data, size_t bytes)
|
||||
if (bytes == 0)
|
||||
return 0;
|
||||
|
||||
mask = q->capacity - 1;
|
||||
tail_idx = tail & mask;
|
||||
tail_idx = tail & q->mask;
|
||||
|
||||
first = q->capacity - tail_idx;
|
||||
first = spsc_contig(q, tail_idx);
|
||||
if (first > bytes)
|
||||
first = bytes;
|
||||
|
||||
@@ -231,7 +450,7 @@ size_t retro_spsc_read(retro_spsc_t *q, void *data, size_t bytes)
|
||||
|
||||
size_t retro_spsc_peek(const retro_spsc_t *q, void *data, size_t bytes)
|
||||
{
|
||||
size_t mask, tail_idx, first;
|
||||
size_t tail_idx, first;
|
||||
uint8_t *dst = (uint8_t*)data;
|
||||
/* Consumer side, same scheme as retro_spsc_read; the cast is only
|
||||
* because peek takes a const queue and the cached copy is state. */
|
||||
@@ -248,10 +467,9 @@ size_t retro_spsc_peek(const retro_spsc_t *q, void *data, size_t bytes)
|
||||
if (bytes == 0)
|
||||
return 0;
|
||||
|
||||
mask = q->capacity - 1;
|
||||
tail_idx = tail & mask;
|
||||
tail_idx = tail & q->mask;
|
||||
|
||||
first = q->capacity - tail_idx;
|
||||
first = spsc_contig(q, tail_idx);
|
||||
if (first > bytes)
|
||||
first = bytes;
|
||||
|
||||
@@ -263,21 +481,20 @@ size_t retro_spsc_peek(const retro_spsc_t *q, void *data, size_t bytes)
|
||||
|
||||
size_t retro_spsc_write_begin(retro_spsc_t *q, void **ptr)
|
||||
{
|
||||
size_t mask, head_idx, span;
|
||||
size_t head_idx, span;
|
||||
/* head is ours (relaxed). Room from the private copy of tail
|
||||
* first; re-read the consumer's tail only when that says none.
|
||||
* See retro_spsc_write. */
|
||||
* first; re-read the consumer's tail only when that copy, rather
|
||||
* than the wrap, is what limits the span - a stale copy would hand
|
||||
* back less than is free. See retro_spsc_write. */
|
||||
size_t head = retro_atomic_load_relaxed_size(&q->head);
|
||||
size_t avail = q->capacity - (head - q->cached_tail);
|
||||
if (avail == 0)
|
||||
head_idx = head & q->mask;
|
||||
span = spsc_contig(q, head_idx);
|
||||
if (avail < span && avail < q->capacity)
|
||||
{
|
||||
q->cached_tail = retro_atomic_load_acquire_size(&q->tail);
|
||||
avail = q->capacity - (head - q->cached_tail);
|
||||
}
|
||||
|
||||
mask = q->capacity - 1;
|
||||
head_idx = head & mask;
|
||||
span = q->capacity - head_idx;
|
||||
if (span > avail)
|
||||
span = avail;
|
||||
*ptr = q->buffer + head_idx;
|
||||
@@ -301,21 +518,20 @@ void retro_spsc_write_end(retro_spsc_t *q, size_t bytes)
|
||||
|
||||
size_t retro_spsc_read_begin(retro_spsc_t *q, const void **ptr)
|
||||
{
|
||||
size_t mask, tail_idx, span;
|
||||
size_t tail_idx, span;
|
||||
/* tail is ours (relaxed). Available from the private copy of
|
||||
* head first; re-read the producer's head only when that says
|
||||
* none. See retro_spsc_read. */
|
||||
* head first; re-read the producer's head only when that copy,
|
||||
* rather than the wrap, is what limits the span. See
|
||||
* retro_spsc_read. */
|
||||
size_t tail = retro_atomic_load_relaxed_size(&q->tail);
|
||||
size_t avail = q->cached_head - tail;
|
||||
if (avail == 0)
|
||||
tail_idx = tail & q->mask;
|
||||
span = spsc_contig(q, tail_idx);
|
||||
if (avail < span && avail < q->capacity)
|
||||
{
|
||||
q->cached_head = retro_atomic_load_acquire_size(&q->head);
|
||||
avail = q->cached_head - tail;
|
||||
}
|
||||
|
||||
mask = q->capacity - 1;
|
||||
tail_idx = tail & mask;
|
||||
span = q->capacity - tail_idx;
|
||||
if (span > avail)
|
||||
span = avail;
|
||||
*ptr = q->buffer + tail_idx;
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
include ../../sample_objdir.mk
|
||||
|
||||
TARGET := ratrac3_test
|
||||
|
||||
LIBRETRO_COMM_DIR := ../../..
|
||||
|
||||
SOURCES := \
|
||||
ratrac3_test.c \
|
||||
$(LIBRETRO_COMM_DIR)/formats/atrac3/ratrac3.c
|
||||
|
||||
OBJS := $(call sample_objs,$(SOURCES:.c=.o))
|
||||
|
||||
CFLAGS += -Wall -pedantic -std=c89 -g -O1 -I$(LIBRETRO_COMM_DIR)/include
|
||||
|
||||
ifneq ($(SANITIZER),)
|
||||
CFLAGS := -fsanitize=$(SANITIZER) -fno-omit-frame-pointer $(CFLAGS)
|
||||
LDFLAGS := -fsanitize=$(SANITIZER) $(LDFLAGS)
|
||||
endif
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c -o $@ $< $(CFLAGS)
|
||||
|
||||
$(SAMPLE_OBJDIR)/%.o: $$(call sample_src,$$*).c
|
||||
@mkdir -p $(@D)
|
||||
$(CC) -c -o $@ $< $(CFLAGS)
|
||||
|
||||
$(TARGET): $(OBJS)
|
||||
$(CC) -o $@ $^ $(LDFLAGS) -lm
|
||||
|
||||
clean:
|
||||
rm -rf $(SAMPLE_OBJDIR)
|
||||
rm -f $(TARGET) $(OBJS)
|
||||
|
||||
.PHONY: clean
|
||||
@@ -0,0 +1,341 @@
|
||||
/* Copyright (C) 2010-2026 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (ratrac3_test.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* ratrac3 against a reference decoder's output for two crafted streams:
|
||||
* a stereo one (gain control, tonal components in all their codings,
|
||||
* the band limits, fewer coded bands, an empty unit) and a joint stereo
|
||||
* one (every matrix and weight change, padding, side units of one to
|
||||
* four bands). Then the s16 output, the fmt chunk, bad frames, reset,
|
||||
* and garbage. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <formats/ratrac3.h>
|
||||
|
||||
#include "ratrac3_test_data.h"
|
||||
|
||||
static int failures = 0;
|
||||
|
||||
static void CHECK(int cond, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
if (cond)
|
||||
return;
|
||||
va_start(ap, fmt);
|
||||
printf("FAIL: ");
|
||||
vprintf(fmt, ap);
|
||||
printf("\n");
|
||||
va_end(ap);
|
||||
failures++;
|
||||
}
|
||||
|
||||
#define FRAMES 12
|
||||
|
||||
static double compare(const uint8_t *stream, unsigned block_align,
|
||||
bool joint, const float (*ref)[2], unsigned nref, const char *name)
|
||||
{
|
||||
static float pcm[FRAMES * RATRAC3_SAMPLES * 2];
|
||||
ratrac3_t *d = ratrac3_new(2, block_align, joint);
|
||||
unsigned f, i;
|
||||
double err = 0.0, sig = 0.0, worst = 0.0;
|
||||
|
||||
CHECK(d != NULL, "%s: new", name);
|
||||
if (!d)
|
||||
return 0.0;
|
||||
for (f = 0; f < FRAMES; f++)
|
||||
{
|
||||
int r = ratrac3_decode_float(d, stream + f * block_align, block_align,
|
||||
pcm + f * RATRAC3_SAMPLES * 2);
|
||||
CHECK(r == RATRAC3_SAMPLES, "%s: frame %u returned %d", name, f, r);
|
||||
}
|
||||
for (i = 0; i < nref; i++)
|
||||
{
|
||||
unsigned c;
|
||||
for (c = 0; c < 2; c++)
|
||||
{
|
||||
double a = pcm[i * STREAM_STEP * 2 + c], b = ref[i][c];
|
||||
double e = fabs(a - b);
|
||||
err += (a - b) * (a - b);
|
||||
sig += b * b;
|
||||
if (e > worst)
|
||||
worst = e;
|
||||
}
|
||||
}
|
||||
ratrac3_free(d);
|
||||
CHECK(worst < 2e-5, "%s: worst sample error %g", name, worst);
|
||||
return 10.0 * log10(sig / (err > 0.0 ? err : 1e-30));
|
||||
}
|
||||
|
||||
static void lane_reference(void)
|
||||
{
|
||||
double a = compare(stream_a, 384, false, ref_a,
|
||||
sizeof(ref_a) / sizeof(ref_a[0]), "stereo");
|
||||
double b = compare(stream_b, 192, true, ref_b,
|
||||
sizeof(ref_b) / sizeof(ref_b[0]), "joint stereo");
|
||||
printf("stereo %.1f dB, joint stereo %.1f dB against the reference\n",
|
||||
a, b);
|
||||
CHECK(a > 100.0 && b > 100.0, "reference match");
|
||||
}
|
||||
|
||||
/* s16 is the float output times 32768, rounded and clamped */
|
||||
static void lane_s16(void)
|
||||
{
|
||||
static float pf[RATRAC3_SAMPLES * 2];
|
||||
static int16_t ps[RATRAC3_SAMPLES * 2];
|
||||
ratrac3_t *df = ratrac3_new(2, 384, false);
|
||||
ratrac3_t *ds = ratrac3_new(2, 384, false);
|
||||
unsigned f, i, clipped = 0, bad = 0;
|
||||
for (f = 0; f < FRAMES; f++)
|
||||
{
|
||||
ratrac3_decode_float(df, stream_a + f * 384, 384, pf);
|
||||
ratrac3_decode_s16(ds, stream_a + f * 384, 384, ps);
|
||||
for (i = 0; i < RATRAC3_SAMPLES * 2; i++)
|
||||
{
|
||||
double v = pf[i] * 32768.0;
|
||||
long e;
|
||||
if (v >= 32767.0)
|
||||
{
|
||||
e = 32767;
|
||||
clipped++;
|
||||
}
|
||||
else if (v <= -32768.0)
|
||||
{
|
||||
e = -32768;
|
||||
clipped++;
|
||||
}
|
||||
else
|
||||
e = (long)(v < 0 ? v - 0.5 : v + 0.5);
|
||||
if (labs(e - ps[i]) > 1)
|
||||
bad++;
|
||||
}
|
||||
}
|
||||
CHECK(bad == 0, "s16: %u samples off", bad);
|
||||
CHECK(clipped > 0, "s16: the stereo stream should clip somewhere");
|
||||
ratrac3_free(df);
|
||||
ratrac3_free(ds);
|
||||
}
|
||||
|
||||
static void put16(uint8_t *p, unsigned v)
|
||||
{
|
||||
p[0] = (uint8_t)v;
|
||||
p[1] = (uint8_t)(v >> 8);
|
||||
}
|
||||
|
||||
static void put32(uint8_t *p, unsigned long v)
|
||||
{
|
||||
put16(p, (unsigned)(v & 0xFFFF));
|
||||
put16(p + 2, (unsigned)(v >> 16));
|
||||
}
|
||||
|
||||
static void make_fmt(uint8_t *fmt, unsigned tag, unsigned ch,
|
||||
unsigned ba, unsigned mode)
|
||||
{
|
||||
memset(fmt, 0, 32);
|
||||
put16(fmt, tag);
|
||||
put16(fmt + 2, ch);
|
||||
put32(fmt + 4, 44100);
|
||||
put32(fmt + 8, (unsigned long)ba * 44100 / 1024);
|
||||
put16(fmt + 12, ba);
|
||||
put16(fmt + 16, 14);
|
||||
put16(fmt + 18, 1);
|
||||
put32(fmt + 20, 0x1000);
|
||||
put16(fmt + 24, mode);
|
||||
put16(fmt + 26, mode);
|
||||
put16(fmt + 28, 1);
|
||||
}
|
||||
|
||||
static void lane_fmt(void)
|
||||
{
|
||||
uint8_t fmt[32];
|
||||
ratrac3_info_t info;
|
||||
|
||||
make_fmt(fmt, 0x270, 2, 192, 1);
|
||||
CHECK(ratrac3_parse_wave_fmt(fmt, 32, &info), "fmt: joint");
|
||||
CHECK(info.channels == 2 && info.block_align == 192 && info.joint_stereo
|
||||
&& info.sample_rate == 44100, "fmt: joint fields");
|
||||
CHECK(info.bitrate == 192u * 44100 / 1024 * 8, "fmt: bitrate %u",
|
||||
info.bitrate);
|
||||
|
||||
make_fmt(fmt, 0x270, 2, 384, 0);
|
||||
CHECK(ratrac3_parse_wave_fmt(fmt, 32, &info) && !info.joint_stereo
|
||||
&& info.block_align == 384, "fmt: stereo");
|
||||
|
||||
make_fmt(fmt, 0x270, 1, 192, 0);
|
||||
CHECK(ratrac3_parse_wave_fmt(fmt, 32, &info) && info.channels == 1,
|
||||
"fmt: mono");
|
||||
/* No extra data: not joint */
|
||||
CHECK(ratrac3_parse_wave_fmt(fmt, 16, &info) && !info.joint_stereo,
|
||||
"fmt: bare");
|
||||
|
||||
make_fmt(fmt, 0xFFFE, 2, 384, 0);
|
||||
CHECK(!ratrac3_parse_wave_fmt(fmt, 32, &info), "fmt: other tag");
|
||||
make_fmt(fmt, 0x270, 1, 192, 1);
|
||||
CHECK(!ratrac3_parse_wave_fmt(fmt, 32, &info), "fmt: mono joint");
|
||||
make_fmt(fmt, 0x270, 2, 191, 0);
|
||||
CHECK(!ratrac3_parse_wave_fmt(fmt, 32, &info), "fmt: odd block");
|
||||
make_fmt(fmt, 0x270, 3, 384, 0);
|
||||
CHECK(!ratrac3_parse_wave_fmt(fmt, 32, &info), "fmt: three channels");
|
||||
CHECK(!ratrac3_parse_wave_fmt(fmt, 15, &info), "fmt: short");
|
||||
CHECK(!ratrac3_parse_wave_fmt(NULL, 32, &info), "fmt: NULL");
|
||||
|
||||
CHECK(ratrac3_new(0, 384, false) == NULL, "new: no channels");
|
||||
CHECK(ratrac3_new(3, 384, false) == NULL, "new: three channels");
|
||||
CHECK(ratrac3_new(2, 0, false) == NULL, "new: no block");
|
||||
CHECK(ratrac3_new(2, 383, false) == NULL, "new: odd block");
|
||||
CHECK(ratrac3_new(1, 192, true) == NULL, "new: mono joint");
|
||||
}
|
||||
|
||||
/* A frame that does not parse gives silence and -1 and leaves the
|
||||
* history alone: what follows decodes as if it were not there */
|
||||
static void lane_bad_frame(void)
|
||||
{
|
||||
static float a[RATRAC3_SAMPLES * 2], b[RATRAC3_SAMPLES * 2];
|
||||
unsigned pass;
|
||||
for (pass = 0; pass < 2; pass++)
|
||||
{
|
||||
const uint8_t *s = pass ? stream_b : stream_a;
|
||||
unsigned ba = pass ? 192 : 384;
|
||||
unsigned at = pass ? 3 : 4;
|
||||
ratrac3_t *d1 = ratrac3_new(2, ba, pass != 0);
|
||||
ratrac3_t *d2 = ratrac3_new(2, ba, pass != 0);
|
||||
uint8_t bad[384];
|
||||
unsigned f, i;
|
||||
int r;
|
||||
|
||||
memcpy(bad, s + at * ba, ba);
|
||||
if (pass)
|
||||
bad[ba - 2] &= 0xF3; /* the side unit's id, after the weights */
|
||||
else
|
||||
bad[0] ^= 0x80; /* the unit id */
|
||||
|
||||
for (f = 0; f < FRAMES; f++)
|
||||
{
|
||||
if (f == at)
|
||||
{
|
||||
r = ratrac3_decode_float(d2, bad, ba, b);
|
||||
CHECK(r == -1, "bad frame: returned %d", r);
|
||||
for (i = 0; i < RATRAC3_SAMPLES * 2; i++)
|
||||
if (b[i] != 0.0f)
|
||||
break;
|
||||
CHECK(i == RATRAC3_SAMPLES * 2, "bad frame: not silent");
|
||||
continue;
|
||||
}
|
||||
ratrac3_decode_float(d1, s + f * ba, ba, a);
|
||||
ratrac3_decode_float(d2, s + f * ba, ba, b);
|
||||
CHECK(!memcmp(a, b, sizeof(a)), "bad frame: frame %u differs", f);
|
||||
}
|
||||
/* A short buffer is a bad frame */
|
||||
r = ratrac3_decode_float(d1, s, ba - 1, a);
|
||||
CHECK(r == -1, "short frame: returned %d", r);
|
||||
r = ratrac3_decode_float(d1, NULL, ba, a);
|
||||
CHECK(r == -1, "NULL frame: returned %d", r);
|
||||
ratrac3_free(d1);
|
||||
ratrac3_free(d2);
|
||||
}
|
||||
}
|
||||
|
||||
static void lane_reset(void)
|
||||
{
|
||||
static float a[RATRAC3_SAMPLES * 2], b[RATRAC3_SAMPLES * 2];
|
||||
ratrac3_t *d1 = ratrac3_new(2, 192, true);
|
||||
ratrac3_t *d2 = ratrac3_new(2, 192, true);
|
||||
unsigned f;
|
||||
for (f = 0; f < FRAMES; f++)
|
||||
ratrac3_decode_float(d1, stream_b + f * 192, 192, a);
|
||||
ratrac3_reset(d1);
|
||||
for (f = 0; f < FRAMES; f++)
|
||||
{
|
||||
ratrac3_decode_float(d1, stream_b + f * 192, 192, a);
|
||||
ratrac3_decode_float(d2, stream_b + f * 192, 192, b);
|
||||
CHECK(!memcmp(a, b, sizeof(a)), "reset: frame %u differs", f);
|
||||
}
|
||||
ratrac3_free(d1);
|
||||
ratrac3_free(d2);
|
||||
}
|
||||
|
||||
/* Garbage and mutations must not read or write out of bounds (run
|
||||
* under a sanitizer) and must keep the output finite */
|
||||
static unsigned long rng_state = 12345;
|
||||
static unsigned rng(void)
|
||||
{
|
||||
rng_state = rng_state * 1103515245UL + 12345UL;
|
||||
return (unsigned)(rng_state >> 16) & 0x7FFF;
|
||||
}
|
||||
|
||||
static void lane_garbage(void)
|
||||
{
|
||||
static float pcm[RATRAC3_SAMPLES * 2];
|
||||
unsigned mode;
|
||||
for (mode = 0; mode < 3; mode++)
|
||||
{
|
||||
unsigned ba = mode == 1 ? 192 : 384, ch = mode == 2 ? 1 : 2;
|
||||
ratrac3_t *d = ratrac3_new(ch, ba, mode == 1);
|
||||
unsigned n, ok = 0, nonfinite = 0;
|
||||
for (n = 0; n < 4000; n++)
|
||||
{
|
||||
uint8_t frame[384];
|
||||
unsigned i, k = rng() % 3;
|
||||
if (k == 0)
|
||||
for (i = 0; i < ba; i++)
|
||||
frame[i] = (uint8_t)rng();
|
||||
else
|
||||
{
|
||||
const uint8_t *src = mode == 1 ? stream_b + (n % FRAMES) * 192
|
||||
: stream_a + (n % FRAMES) * 384;
|
||||
memcpy(frame, src, ba);
|
||||
for (i = 0; i < 1 + rng() % 8; i++)
|
||||
frame[rng() % ba] ^= (uint8_t)(1u << (rng() % 8));
|
||||
if (k == 2)
|
||||
frame[0] = (uint8_t)(0xA0 | (frame[0] & 3));
|
||||
}
|
||||
if (ratrac3_decode_float(d, frame, ba, pcm) > 0)
|
||||
ok++;
|
||||
for (i = 0; i < RATRAC3_SAMPLES * ch; i++)
|
||||
if (!(pcm[i] == pcm[i]) || fabs(pcm[i]) > 1e30)
|
||||
nonfinite++;
|
||||
}
|
||||
CHECK(nonfinite == 0, "garbage: %u non-finite samples", nonfinite);
|
||||
printf("garbage mode %u: %u of 4000 frames decoded\n", mode, ok);
|
||||
ratrac3_free(d);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
lane_reference();
|
||||
lane_s16();
|
||||
lane_fmt();
|
||||
lane_bad_frame();
|
||||
lane_reset();
|
||||
lane_garbage();
|
||||
if (failures)
|
||||
{
|
||||
printf("%d failure(s)\n", failures);
|
||||
return 1;
|
||||
}
|
||||
printf("ratrac3: all tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,536 @@
|
||||
/* Generated: crafted ATRAC3 frames and a reference decoder's output
|
||||
* for them, sign flipped to this decoder's polarity. */
|
||||
|
||||
#define STREAM_STEP 97
|
||||
|
||||
static const uint8_t stream_a[4608] = {
|
||||
0xa3,0x00,0x00,0x2f,0xa4,0x9b,0xdb,0xf4,0xf0,0x29,0x3b,0x72,0xc3,0x34,0xec,0xb2,
|
||||
0xcc,0x40,0xce,0xa5,0x38,0x81,0x40,0x00,0x18,0x78,0x00,0x1e,0x40,0x06,0x40,0x21,
|
||||
0xc0,0x20,0x13,0x00,0x00,0x00,0x2c,0x0c,0xda,0x03,0x80,0x00,0x4c,0xf2,0x0a,0x9e,
|
||||
0x1e,0x01,0x34,0xa0,0x0a,0xe0,0x04,0x57,0x80,0x36,0x00,0x00,0x1f,0x60,0x00,0x44,
|
||||
0x00,0x09,0x02,0xc4,0x80,0x00,0x40,0xc8,0x3a,0x00,0x00,0x88,0x40,0x07,0xb8,0x1e,
|
||||
0x01,0xff,0xfc,0x04,0x2e,0x06,0x02,0x01,0x39,0x60,0x1c,0xa5,0x60,0x00,0xc8,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xa3,0x00,0x00,0x2f,0x23,0x7f,0xfc,0x56,0xcf,0x46,0xf2,0xab,0xb3,0x22,0xf2,0x34,
|
||||
0xb3,0x20,0x81,0xa0,0x9c,0x00,0x1a,0x01,0xbf,0xe3,0x2d,0xc7,0x00,0xa4,0x0a,0xc1,
|
||||
0xa6,0x00,0x00,0x4d,0x72,0xc0,0x00,0x60,0x0b,0x00,0xf3,0xa0,0x30,0x01,0x40,0x00,
|
||||
0x02,0x20,0xe8,0x22,0x40,0x0b,0xd8,0x06,0x3e,0x00,0x07,0x80,0x02,0x20,0x90,0x40,
|
||||
0x4f,0x38,0x00,0xd0,0x3b,0x00,0x58,0x00,0xf0,0x00,0x80,0x43,0x3c,0x0b,0x80,0x00,
|
||||
0x00,0x01,0xe0,0x77,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xa3,0x46,0x55,0xa0,0x84,0x00,0x38,0xd4,0xfc,0x01,0x32,0xbd,0x10,0x04,0x00,0x20,
|
||||
0x04,0x1d,0x3d,0x3b,0x6e,0xcf,0x3c,0x2f,0x2a,0xb1,0x96,0x9e,0xd7,0xe3,0x00,0x5e,
|
||||
0x00,0x1e,0x60,0x9c,0xfc,0x6a,0xe8,0xcd,0xd7,0xed,0x60,0x1b,0x14,0x0e,0x00,0xe7,
|
||||
0xf8,0x74,0x94,0xa7,0xe8,0x56,0x56,0x3c,0xc0,0x94,0x5d,0xea,0x06,0x40,0x30,0x00,
|
||||
0x80,0x04,0x99,0x50,0x00,0xd0,0x2b,0x0c,0x20,0x39,0x83,0xc9,0x86,0xec,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xa3,0x46,0x55,0xa0,0x84,0x00,0x38,0xd4,0xfc,0x01,0x37,0x67,0x40,0x07,0x00,0x50,
|
||||
0x07,0x15,0x40,0xcb,0x51,0x38,0xfa,0xcd,0xa8,0xa8,0x30,0x00,0xeb,0xf2,0x37,0x5a,
|
||||
0x01,0xc8,0xea,0xe3,0xf0,0x7e,0x80,0x00,0x3c,0x04,0xa1,0x80,0x3b,0xc8,0x0d,0x00,
|
||||
0x01,0xe8,0x10,0x00,0x68,0x58,0xac,0x79,0xf2,0xb0,0x34,0x79,0x0d,0x00,0x00,0x00,
|
||||
0xcc,0x0f,0x79,0x7f,0xfa,0x81,0x98,0x5c,0x00,0x24,0x30,0x02,0x8f,0xed,0x1a,0x00,
|
||||
0x00,0x19,0x00,0x05,0x07,0x80,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xa3,0x05,0xbe,0x00,0x8c,0x70,0x17,0x83,0xc5,0x80,0x00,0x5c,0xa2,0x40,0x41,0x60,
|
||||
0x02,0xcf,0xfd,0xb2,0x2a,0xc0,0x60,0x00,0x00,0x00,0x00,0xdf,0x89,0xa9,0x1c,0x47,
|
||||
0x03,0x43,0x66,0x81,0xa2,0x67,0x7f,0x34,0x68,0xa5,0xcc,0x8d,0x78,0x6b,0xcb,0x3d,
|
||||
0x9e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xa3,0x05,0xbe,0x00,0x8c,0x70,0x17,0x83,0xc5,0x80,0x00,0x5c,0xa2,0x40,0x41,0x60,
|
||||
0x02,0xcf,0xfd,0xb2,0x14,0xc0,0xe0,0x00,0x00,0x00,0x00,0x5c,0x79,0x57,0x65,0xaf,
|
||||
0x3f,0x5a,0x46,0x96,0x66,0xeb,0x1f,0x6c,0xdb,0x40,0x0f,0x7b,0x1b,0x3b,0xb6,0xcc,
|
||||
0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xa3,0x00,0x01,0x70,0xec,0x00,0x61,0xf5,0x64,0xc4,0xd6,0x15,0x05,0xe2,0x50,0x00,
|
||||
0x00,0x2d,0x64,0x41,0xef,0x24,0x90,0x00,0x00,0x80,0x00,0x00,0x80,0x02,0x8d,0x95,
|
||||
0xd4,0x69,0xe8,0x4f,0xc3,0x1c,0x00,0x01,0xf0,0x11,0x0c,0x30,0x00,0x03,0x00,0x03,
|
||||
0xc7,0x40,0x01,0x40,0x00,0x44,0x5c,0x3f,0x00,0x00,0x00,0x00,0x0d,0xc6,0xf8,0x00,
|
||||
0x00,0xe1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xa3,0x00,0x01,0x70,0xec,0x00,0x61,0xf5,0x64,0xc4,0xd6,0x15,0x05,0xe2,0x50,0x00,
|
||||
0x00,0x2d,0x64,0x41,0xef,0x24,0x90,0x00,0x00,0x80,0x00,0x00,0x80,0x05,0x69,0x55,
|
||||
0x23,0x52,0x35,0x50,0x00,0x40,0x03,0x03,0x03,0xc4,0x40,0x30,0x0c,0x77,0x4c,0xc7,
|
||||
0x03,0x54,0xfc,0x31,0x00,0x07,0x40,0x02,0x40,0x11,0x02,0x70,0x00,0x0f,0xc0,0x24,
|
||||
0x81,0x40,0x03,0xc8,0x00,0x43,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xa3,0x00,0x00,0x69,0xe7,0xc0,0x00,0x08,0x00,0x00,0x08,0x00,0x01,0x44,0x76,0x49,
|
||||
0xe7,0x75,0xd5,0x21,0x1e,0xc3,0x78,0x00,0x3b,0x87,0xfa,0xf0,0x00,0x00,0x39,0x0d,
|
||||
0xe6,0x80,0x01,0x1f,0xb7,0x06,0x90,0xd3,0x4d,0x68,0x02,0x01,0x00,0x00,0xe4,0x00,
|
||||
0x00,0x34,0x0d,0x3b,0xe0,0x02,0x00,0x0f,0xa0,0xf1,0xc3,0xdb,0xe3,0xc4,0x7c,0x17,
|
||||
0xac,0x8f,0xff,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xa3,0x00,0x00,0x69,0xd6,0x60,0x00,0x10,0x00,0x00,0x10,0x00,0x00,0xc5,0x55,0x69,
|
||||
0x5b,0x95,0x47,0x5c,0x00,0x5e,0x3e,0xc0,0x61,0x5f,0xf0,0x0a,0x29,0x20,0x8c,0x34,
|
||||
0xa0,0x00,0x91,0xc0,0x75,0xd4,0x37,0x03,0x00,0x00,0x34,0x0a,0x3c,0x00,0x00,0x0c,
|
||||
0x0f,0x8c,0x00,0xfc,0x08,0x3d,0x03,0x48,0x37,0x97,0xd0,0xab,0x00,0xfc,0x36,0xc9,
|
||||
0x00,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xa1,0x28,0x35,0x2a,0x25,0x83,0xd9,0x40,0x02,0x80,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x08,0x00,0xab,0x23,0x71,0xb2,0x1e,0x00,0x18,0x00,0x00,0x00,0x61,0x80,0x00,0x00,
|
||||
0x00,0x80,0x00,0x00,0x00,0x60,0x80,0x00,0x01,0x80,0x00,0x00,0x08,0x00,0x00,0x06,
|
||||
0x00,0x0a,0x00,0x00,0x00,0x00,0x80,0x7e,0x00,0x08,0x80,0x00,0x06,0x0a,0x18,0x08,
|
||||
0x00,0x20,0x00,0x00,0x00,0x22,0x88,0x00,0x61,0x80,0x00,0x18,0x06,0x00,0x38,0x60,
|
||||
0x00,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xa1,0x28,0x35,0x2a,0x25,0x83,0xd3,0x40,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x38,0x03,0xb1,0x2c,0xca,0x28,0x20,0x00,0x1e,0x01,0xa0,0x01,0x40,0x01,0x20,0x00,
|
||||
0x00,0x00,0x08,0x80,0x00,0x1e,0x6a,0x01,0xc0,0x30,0x00,0x00,0x00,0x03,0x00,0x00,
|
||||
0x06,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x50,0x00,0x00,0x38,0x00,0x18,0x00,0x00,
|
||||
0x1f,0x00,0x00,0x0c,0x38,0x00,0x16,0x9c,0x00,0x00,0x00,0x32,0x60,0x01,0x30,0x00,
|
||||
0x68,0x00,0xe0,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x01,0xd0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe3,0x00,0x00,0x04,
|
||||
0x60,0x00,0x00,0x19,0xee,0x68,0x09,0x4e,0x00,0x00,0x00,0xa9,0x80,0x11,0xb8,0x00,
|
||||
0x19,0xa8,0x11,0x80,0x00,0x60,0x01,0x60,0x00,0x00,0x04,0x21,0x01,0x80,0x00,0x55,
|
||||
0xf0,0x00,0x00,0x00,0x00,0x78,0xeb,0x00,0x00,0x00,0x00,0x00,0x71,0x17,0x00,0x00,
|
||||
0x00,0x7a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6e,0x00,0x00,0x00,0x00,0x1a,
|
||||
0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xa0,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xa0,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xa3,0x5e,0x10,0x10,0x08,0x01,0xff,0x07,0xda,0xaa,0x00,0x00,0x00,0x00,0x00,0x38,
|
||||
0x00,0x00,0x10,0x00,0xee,0xb1,0x13,0x31,0xb1,0x2c,0xe0,0x00,0x00,0x42,0x4a,0x30,
|
||||
0x01,0x4f,0x34,0x24,0x00,0x78,0x7e,0x9c,0x00,0x1e,0x30,0x8b,0xe0,0x64,0x0a,0x43,
|
||||
0xa7,0x81,0x80,0x94,0x8a,0x2b,0x86,0x50,0x1b,0xa0,0x09,0x80,0xfd,0x80,0xbc,0x0e,
|
||||
0x60,0x00,0x00,0x00,0x0f,0x8d,0xc0,0x0c,0x40,0x03,0xd8,0x00,0x00,0x9c,0x77,0x80,
|
||||
0x07,0x50,0x08,0x00,0x00,0x00,0x00,0x29,0x00,0x00,0x8a,0x43,0x27,0x00,0x00,0x24,
|
||||
0x80,0x13,0x00,0x3d,0xc7,0xcf,0xef,0xf0,0x00,0x00,0x00,0x03,0x70,0xdb,0xfe,0x00,
|
||||
0x00,0x0c,0xac,0xf6,0xee,0x00,0x0a,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xa3,0x5e,0x10,0x10,0x08,0x01,0xff,0x07,0xde,0x54,0x00,0x00,0x00,0x00,0x00,0x72,
|
||||
0x00,0x00,0x30,0x00,0x91,0xc7,0x2a,0xce,0x3f,0x04,0xc0,0x0a,0x00,0x02,0x3c,0x70,
|
||||
0x08,0x00,0x00,0x00,0x01,0x80,0x00,0x40,0x5a,0x07,0xe7,0xa8,0x0b,0x48,0x00,0x00,
|
||||
0x00,0x1c,0x40,0x00,0xa0,0xe0,0x00,0x05,0xe2,0x80,0x00,0x07,0x00,0x00,0x76,0x00,
|
||||
0xf8,0x02,0x05,0xe5,0x00,0x0f,0xb3,0xf4,0x90,0x51,0xfc,0x70,0x06,0x81,0xf3,0xc0,
|
||||
0x04,0x34,0x08,0xd2,0x78,0x02,0xe0,0x11,0x9a,0x66,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xa3,0x46,0x55,0xa0,0x84,0x00,0x38,0xd4,0xfc,0x01,0x32,0xbd,0x10,0x04,0x00,0x20,
|
||||
0x04,0x1d,0x3d,0x3b,0x6e,0xcf,0x3c,0x2f,0x2a,0xb1,0x96,0x9e,0xd7,0xe3,0x00,0x5e,
|
||||
0x00,0x1e,0x60,0x9c,0xfc,0x6a,0xe8,0xcd,0xd7,0xed,0x60,0x1b,0x14,0x0e,0x00,0xe7,
|
||||
0xf8,0x74,0x94,0xa7,0xe8,0x56,0x56,0x3c,0xc0,0x94,0x5d,0xea,0x06,0x40,0x30,0x00,
|
||||
0x80,0x04,0x99,0x50,0x00,0xd0,0x2b,0x0c,0x20,0x39,0x83,0xc9,0x86,0xec,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xa3,0x46,0x55,0xa0,0x84,0x00,0x38,0xd4,0xfc,0x01,0x37,0x67,0x40,0x07,0x00,0x50,
|
||||
0x07,0x15,0x40,0xcb,0x51,0x38,0xfa,0xcd,0xa8,0xa8,0x30,0x00,0xeb,0xf2,0x37,0x5a,
|
||||
0x01,0xc8,0xea,0xe3,0xf0,0x7e,0x80,0x00,0x3c,0x04,0xa1,0x80,0x3b,0xc8,0x0d,0x00,
|
||||
0x01,0xe8,0x10,0x00,0x68,0x58,0xac,0x79,0xf2,0xb0,0x34,0x79,0x0d,0x00,0x00,0x00,
|
||||
0xcc,0x0f,0x79,0x7f,0xfa,0x81,0x98,0x5c,0x00,0x24,0x30,0x02,0x8f,0xed,0x1a,0x00,
|
||||
0x00,0x19,0x00,0x05,0x07,0x80,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xa3,0x00,0x01,0x70,0xec,0x00,0x61,0xf5,0x64,0xc4,0xd6,0x15,0x05,0xe2,0x50,0x00,
|
||||
0x00,0x2d,0x64,0x41,0xef,0x24,0x90,0x00,0x00,0x80,0x00,0x00,0x80,0x02,0x8d,0x95,
|
||||
0xd4,0x69,0xe8,0x4f,0xc3,0x1c,0x00,0x01,0xf0,0x11,0x0c,0x30,0x00,0x03,0x00,0x03,
|
||||
0xc7,0x40,0x01,0x40,0x00,0x44,0x5c,0x3f,0x00,0x00,0x00,0x00,0x0d,0xc6,0xf8,0x00,
|
||||
0x00,0xe1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xa3,0x00,0x01,0x70,0xec,0x00,0x61,0xf5,0x64,0xc4,0xd6,0x15,0x05,0xe2,0x50,0x00,
|
||||
0x00,0x2d,0x64,0x41,0xef,0x24,0x90,0x00,0x00,0x80,0x00,0x00,0x80,0x05,0x69,0x55,
|
||||
0x23,0x52,0x35,0x50,0x00,0x40,0x03,0x03,0x03,0xc4,0x40,0x30,0x0c,0x77,0x4c,0xc7,
|
||||
0x03,0x54,0xfc,0x31,0x00,0x07,0x40,0x02,0x40,0x11,0x02,0x70,0x00,0x0f,0xc0,0x24,
|
||||
0x81,0x40,0x03,0xc8,0x00,0x43,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xa3,0x00,0x00,0x2f,0xa4,0x9b,0xdb,0xf4,0xf0,0x29,0x3b,0x72,0xc3,0x34,0xec,0xb2,
|
||||
0xcc,0x40,0xce,0xa5,0x38,0x81,0x40,0x00,0x18,0x78,0x00,0x1e,0x40,0x06,0x40,0x21,
|
||||
0xc0,0x20,0x13,0x00,0x00,0x00,0x2c,0x0c,0xda,0x03,0x80,0x00,0x4c,0xf2,0x0a,0x9e,
|
||||
0x1e,0x01,0x34,0xa0,0x0a,0xe0,0x04,0x57,0x80,0x36,0x00,0x00,0x1f,0x60,0x00,0x44,
|
||||
0x00,0x09,0x02,0xc4,0x80,0x00,0x40,0xc8,0x3a,0x00,0x00,0x88,0x40,0x07,0xb8,0x1e,
|
||||
0x01,0xff,0xfc,0x04,0x2e,0x06,0x02,0x01,0x39,0x60,0x1c,0xa5,0x60,0x00,0xc8,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xa3,0x00,0x00,0x2f,0x23,0x7f,0xfc,0x56,0xcf,0x46,0xf2,0xab,0xb3,0x22,0xf2,0x34,
|
||||
0xb3,0x20,0x81,0xa0,0x9c,0x00,0x1a,0x01,0xbf,0xe3,0x2d,0xc7,0x00,0xa4,0x0a,0xc1,
|
||||
0xa6,0x00,0x00,0x4d,0x72,0xc0,0x00,0x60,0x0b,0x00,0xf3,0xa0,0x30,0x01,0x40,0x00,
|
||||
0x02,0x20,0xe8,0x22,0x40,0x0b,0xd8,0x06,0x3e,0x00,0x07,0x80,0x02,0x20,0x90,0x40,
|
||||
0x4f,0x38,0x00,0xd0,0x3b,0x00,0x58,0x00,0xf0,0x00,0x80,0x43,0x3c,0x0b,0x80,0x00,
|
||||
0x00,0x01,0xe0,0x77,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xa3,0x5e,0x10,0x10,0x08,0x01,0xff,0x07,0xda,0xaa,0x00,0x00,0x00,0x00,0x00,0x38,
|
||||
0x00,0x00,0x10,0x00,0xee,0xb1,0x13,0x31,0xb1,0x2c,0xe0,0x00,0x00,0x42,0x4a,0x30,
|
||||
0x01,0x4f,0x34,0x24,0x00,0x78,0x7e,0x9c,0x00,0x1e,0x30,0x8b,0xe0,0x64,0x0a,0x43,
|
||||
0xa7,0x81,0x80,0x94,0x8a,0x2b,0x86,0x50,0x1b,0xa0,0x09,0x80,0xfd,0x80,0xbc,0x0e,
|
||||
0x60,0x00,0x00,0x00,0x0f,0x8d,0xc0,0x0c,0x40,0x03,0xd8,0x00,0x00,0x9c,0x77,0x80,
|
||||
0x07,0x50,0x08,0x00,0x00,0x00,0x00,0x29,0x00,0x00,0x8a,0x43,0x27,0x00,0x00,0x24,
|
||||
0x80,0x13,0x00,0x3d,0xc7,0xcf,0xef,0xf0,0x00,0x00,0x00,0x03,0x70,0xdb,0xfe,0x00,
|
||||
0x00,0x0c,0xac,0xf6,0xee,0x00,0x0a,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xa3,0x5e,0x10,0x10,0x08,0x01,0xff,0x07,0xde,0x54,0x00,0x00,0x00,0x00,0x00,0x72,
|
||||
0x00,0x00,0x30,0x00,0x91,0xc7,0x2a,0xce,0x3f,0x04,0xc0,0x0a,0x00,0x02,0x3c,0x70,
|
||||
0x08,0x00,0x00,0x00,0x01,0x80,0x00,0x40,0x5a,0x07,0xe7,0xa8,0x0b,0x48,0x00,0x00,
|
||||
0x00,0x1c,0x40,0x00,0xa0,0xe0,0x00,0x05,0xe2,0x80,0x00,0x07,0x00,0x00,0x76,0x00,
|
||||
0xf8,0x02,0x05,0xe5,0x00,0x0f,0xb3,0xf4,0x90,0x51,0xfc,0x70,0x06,0x81,0xf3,0xc0,
|
||||
0x04,0x34,0x08,0xd2,0x78,0x02,0xe0,0x11,0x9a,0x66,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
|
||||
};
|
||||
|
||||
/* every 97th sample, left then right */
|
||||
static const float ref_a[127][2] = {
|
||||
{ 1.126531982e-16f, 5.703195257e-17f }, { 6.125071650e-06f, 1.233613489e-06f }, { -6.888474454e-04f, -1.230235939e-04f },
|
||||
{ 5.519068800e-04f, -8.532244829e-04f }, { 1.288989442e-04f, 1.366461394e-03f }, { -2.320230938e-03f, -4.798891954e-03f },
|
||||
{ 1.825670945e-03f, 1.580715296e-03f }, { -1.879826188e-03f, 6.539559457e-03f }, { -1.153890509e-03f, -1.871578512e-03f },
|
||||
{ -3.846446285e-03f, 1.108263247e-02f }, { 1.676079631e-02f, -1.510275411e-03f }, { 1.152072800e-03f, 4.703115672e-03f },
|
||||
{ -1.258932240e-02f, 5.426196847e-03f }, { 1.211719215e-02f, -2.556819702e-03f }, { 2.875600569e-02f, -2.064039931e-03f },
|
||||
{ 2.302374877e-02f, 3.829095047e-03f }, { -4.200979602e-03f, -3.086568788e-03f }, { 3.564488888e-02f, -1.318836957e-02f },
|
||||
{ -1.136253029e-02f, 2.440769895e-04f }, { -2.095016278e-02f, 5.774464924e-03f }, { 1.388325356e-02f, -1.105636638e-02f },
|
||||
{ 1.803878322e-02f, -9.901482612e-03f }, { -3.065022640e-03f, 8.504002355e-03f }, { -3.011808731e-03f, -5.176807288e-03f },
|
||||
{ 6.512018153e-04f, 8.132720832e-04f }, { -5.101013463e-03f, -2.327305963e-03f }, { -4.732127301e-03f, -1.507790526e-03f },
|
||||
{ 1.980553614e-03f, 1.223168569e-03f }, { -4.459375050e-03f, -9.043966420e-04f }, { -1.054605562e-02f, -1.585059101e-03f },
|
||||
{ -9.816198610e-03f, 4.070995841e-03f }, { 1.447615679e-03f, 5.477414015e-05f }, { -6.903338246e-03f, 2.097342862e-03f },
|
||||
{ 8.691789117e-04f, -1.394752297e-03f }, { -1.128911041e-03f, -3.116167383e-03f }, { -4.925142974e-03f, -1.136097708e-03f },
|
||||
{ -2.611270174e-04f, -1.441219472e-03f }, { -2.003973117e-03f, 2.346458612e-03f }, { 9.383748285e-03f, 8.703176863e-03f },
|
||||
{ 5.156501662e-03f, -1.970787533e-03f }, { -2.604289446e-03f, -3.790183109e-04f }, { 7.721356815e-04f, 1.972476486e-03f },
|
||||
{ 3.145763883e-03f, -2.144733153e-04f }, { -4.673007876e-03f, 3.172734287e-03f }, { -3.764079185e-03f, -8.328152820e-03f },
|
||||
{ -4.485322628e-03f, 5.514724180e-03f }, { -2.461444587e-03f, -1.165697630e-02f }, { 8.184628561e-03f, 1.443392131e-03f },
|
||||
{ -4.455132410e-03f, 2.200886840e-03f }, { 2.179021714e-03f, -2.328114118e-03f }, { 7.237539161e-03f, -9.669236839e-03f },
|
||||
{ -8.640550077e-03f, -9.054285474e-03f }, { -1.206108485e-03f, -1.235498639e-04f }, { 1.546770241e-02f, 2.729752101e-03f },
|
||||
{ 1.731253974e-02f, 2.068402944e-03f }, { -2.271239832e-02f, -1.498918748e-03f }, { -1.283845399e-02f, 3.128156299e-03f },
|
||||
{ 8.735341020e-03f, 7.079254836e-03f }, { 9.860594757e-03f, 1.258777920e-02f }, { 2.355418546e-04f, -3.024128091e-04f },
|
||||
{ -8.113291115e-03f, -9.543613531e-03f }, { 2.948532579e-03f, 6.702618673e-03f }, { 7.945939898e-03f, -1.248920918e-03f },
|
||||
{ 2.162894234e-03f, -1.145169954e-03f }, { -6.329953671e-03f, -2.390238224e-03f }, { 5.018929020e-03f, 7.005940657e-03f },
|
||||
{ 5.766151589e-04f, -5.306253675e-03f }, { -2.266372554e-03f, -1.571175293e-03f }, { -3.949624021e-03f, 4.711580463e-03f },
|
||||
{ -2.273411723e-03f, -1.144108464e-04f }, { 1.253100461e-03f, -3.576075193e-03f }, { 4.559647641e-04f, 7.038487820e-04f },
|
||||
{ -5.256180884e-04f, 9.299787343e-04f }, { -2.848349395e-04f, -4.818271555e-04f }, { -3.020362237e-05f, 2.693361057e-05f },
|
||||
{ 3.569063265e-04f, -5.284890358e-05f }, { -7.915252820e-03f, 1.448417921e-02f }, { -6.198265776e-02f, 6.116967183e-03f },
|
||||
{ 1.139590219e-01f, -8.882056177e-02f }, { 1.860605031e-01f, -1.029657871e-01f }, { 8.342682570e-02f, -2.175923139e-01f },
|
||||
{ -1.267465651e-01f, -1.695801318e-01f }, { 1.777947247e-01f, -9.905706346e-02f }, { -4.146566093e-01f, 1.099241525e-01f },
|
||||
{ -6.887235045e-01f, -4.032902122e-01f }, { -1.824623048e-01f, 2.404407114e-01f }, { 2.246285090e-03f, -6.943063810e-03f },
|
||||
{ 3.249513451e-03f, 1.820311300e-03f }, { 2.485736646e-02f, 2.043555258e-03f }, { 1.782027073e-02f, 4.338612314e-03f },
|
||||
{ 1.211636467e-03f, 1.946543693e-03f }, { 4.025410116e-02f, 2.226956189e-03f }, { -6.107665226e-02f, 5.317269242e-04f },
|
||||
{ 2.078279667e-02f, -1.439446933e-03f }, { -9.420170449e-03f, -1.485835761e-02f }, { 5.996773485e-03f, 7.175534964e-03f },
|
||||
{ 1.865146309e-02f, -8.691115072e-04f }, { 7.165045245e-04f, -5.412854254e-03f }, { -1.429604273e-02f, 1.367502497e-03f },
|
||||
{ 1.265187562e-02f, -2.807899727e-04f }, { -1.218517311e-02f, -9.408306214e-04f }, { 1.495581027e-02f, -1.238323469e-02f },
|
||||
{ -2.702118829e-03f, 9.812001139e-03f }, { 5.178106483e-03f, -2.784847282e-03f }, { -6.819553673e-03f, -7.969203289e-04f },
|
||||
{ 3.727761097e-03f, 4.883892834e-03f }, { -3.865442704e-03f, 5.255972501e-04f }, { 1.125461538e-03f, 7.236050908e-03f },
|
||||
{ -7.945659570e-03f, 5.072486121e-03f }, { -1.109648217e-02f, 7.179707754e-03f }, { 1.727613504e-03f, 4.729861685e-04f },
|
||||
{ 9.447506629e-03f, 5.599674187e-04f }, { 2.738567814e-02f, 4.963728599e-03f }, { 2.249464020e-02f, -3.670364851e-03f },
|
||||
{ -3.687032033e-03f, 3.666515928e-03f }, { -4.840126261e-03f, -7.933497429e-03f }, { 8.647885174e-03f, 9.121629409e-03f },
|
||||
{ 3.246227279e-02f, -3.295462811e-03f }, { 2.384427376e-02f, 7.305985782e-03f }, { 3.664306924e-02f, -1.790498942e-02f },
|
||||
{ -4.988099262e-02f, 1.754104858e-03f }, { 6.852663308e-02f, 1.195446402e-01f }, { -8.833049238e-02f, 2.200989127e-01f },
|
||||
{ -3.651116192e-01f, 3.371975124e-01f }, { -2.209227383e-01f, 3.000091612e-01f }, { 4.843607843e-01f, -2.104127966e-02f },
|
||||
{ 1.098719388e-01f, -3.420371413e-01f }
|
||||
};
|
||||
|
||||
static const uint8_t stream_b[2304] = {
|
||||
0xa2,0x00,0x03,0x29,0x69,0x00,0x00,0x08,0x00,0x00,0x24,0x00,0x00,0x55,0x91,0xb8,
|
||||
0xe1,0x61,0xe8,0x94,0xef,0xc0,0x39,0x47,0x40,0x27,0xe3,0x80,0x1e,0x35,0xa7,0x47,
|
||||
0x4c,0x00,0x3a,0x06,0xf0,0x7d,0x40,0x07,0x8e,0x1c,0x10,0x04,0x67,0x40,0xa8,0x74,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x1e,0x2e,0x3d,0x14,0xd0,
|
||||
0x76,0x47,0x6e,0xef,0x6e,0x51,0x01,0x0c,0x28,0x62,0xe5,0xe7,0x18,0x00,0xfc,0xff,
|
||||
0xa2,0x00,0x03,0x3c,0xe4,0x00,0x00,0x18,0x00,0x00,0x09,0x00,0x01,0x9f,0x51,0xe9,
|
||||
0x5c,0x5d,0xc6,0x00,0x00,0x00,0x00,0x99,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0xc0,
|
||||
0x03,0xc8,0x00,0x00,0x04,0x0a,0x00,0x00,0x00,0xc0,0x01,0xc0,0x40,0x01,0x00,0x00,
|
||||
0x00,0x03,0x00,0x01,0xc0,0xf0,0x00,0x00,0x00,0xc1,0x26,0x14,0x09,0x06,0xd6,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0x10,0x70,0x0e,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0xd0,0x90,0xb8,0x88,0x21,0x01,0x2e,0x75,0x11,0xaf,0xf7,0x0e,0x00,
|
||||
0x0b,0xa6,0xa6,0x81,0x5a,0x00,0x00,0x00,0x00,0x00,0xa0,0x58,0x12,0x00,0x0d,0x13,
|
||||
0xa2,0x26,0xa0,0x01,0x95,0xdb,0x80,0x00,0x0c,0x00,0x00,0x12,0x00,0x00,0xae,0xac,
|
||||
0xbc,0x6f,0x43,0x13,0xa0,0x74,0x38,0x0d,0x87,0xa0,0x00,0xe8,0x00,0x00,0x1e,0x3f,
|
||||
0xc3,0x40,0x00,0x56,0xc8,0x3c,0xfa,0x3e,0x3a,0x67,0x08,0x73,0x80,0x1d,0x1a,0x0f,
|
||||
0x10,0x50,0x28,0xff,0x18,0xe2,0x9c,0x06,0xf8,0x00,0x01,0xe0,0x01,0xf8,0xc3,0xa3,
|
||||
0x80,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0xc0,0x00,0x28,0x5c,0x28,0x94,0x00,0x38,0xa8,0x01,0x31,0xd8,
|
||||
0xb1,0x00,0x00,0x00,0x40,0x87,0x79,0x5c,0x55,0x1f,0x00,0x6c,0x2f,0xf8,0xf8,0xf8,
|
||||
0xa2,0x00,0x03,0x33,0x3b,0x00,0x00,0x08,0x00,0x00,0x21,0x00,0x00,0xa4,0x92,0x39,
|
||||
0xe2,0x5e,0x16,0xf4,0x07,0x00,0x80,0x03,0x80,0x00,0x00,0x00,0x24,0x00,0x04,0x78,
|
||||
0x03,0x80,0x01,0x00,0x00,0xcc,0x00,0x38,0x00,0x03,0xd0,0x43,0x93,0x43,0x41,0x08,
|
||||
0x00,0x08,0x33,0xc0,0x00,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x0c,0x00,0x5c,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x40,0x00,0x04,0x40,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x07,0x43,0x30,0x1d,0x11,0x00,0xd0,0xc0,0xc0,0x13,0xd0,0x00,0x30,0x13,
|
||||
0x30,0x50,0xc0,0xc5,0x00,0x00,0x00,0x0c,0x13,0x04,0x00,0x0c,0x00,0x01,0x47,0x3c,
|
||||
0x0c,0x01,0xc0,0x30,0x55,0xcd,0xc1,0x00,0x0c,0x40,0xc0,0x30,0x40,0x10,0x00,0x03,
|
||||
0x70,0x04,0x33,0x03,0xd0,0x10,0xc7,0xc0,0xc0,0x04,0x00,0x40,0x00,0x30,0x84,0x0f,
|
||||
0xbd,0xe7,0x02,0x00,0x00,0x00,0x40,0x0c,0xb4,0x48,0x99,0xa5,0x05,0x8a,0x01,0x80,
|
||||
0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0xc0,0x3d,0x3f,0x00,0x40,0x2a,0x9f,0x8c,
|
||||
0xa2,0x00,0x03,0x23,0x0e,0x00,0x00,0x38,0x00,0x00,0x2b,0x00,0x01,0x15,0x65,0x79,
|
||||
0x65,0x55,0xe9,0xc1,0xc8,0x1b,0x20,0x07,0xbd,0xc0,0xdc,0x79,0x81,0xaa,0x97,0x00,
|
||||
0x00,0x03,0xdb,0x3e,0x7a,0x1d,0x40,0x48,0x20,0x80,0x00,0x03,0xf2,0x10,0x01,0xe7,
|
||||
0x9f,0x01,0xe1,0xf4,0x1a,0x0a,0x03,0xe5,0x20,0x00,0x47,0x40,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x40,0xa3,0xe5,0x7f,0xd7,0x7b,0x30,0x25,0xdf,0xc5,0x48,0xee,0x86,0x69,0x50,0xff,
|
||||
0x72,0xf0,0x83,0x1e,0x90,0xd5,0xd5,0xed,0x08,0xc2,0x41,0x33,0x2f,0xf3,0x34,0x72,
|
||||
0x0c,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x4f,0x43,0x03,0x00,0xfe,0x5d,0xf8,
|
||||
0xa2,0x00,0x03,0x39,0x33,0x00,0x00,0x28,0x00,0x00,0x0a,0x00,0x00,0x9c,0x51,0xe7,
|
||||
0xe7,0x62,0x06,0x00,0x00,0x00,0x00,0x00,0x03,0x80,0x00,0x00,0x31,0x80,0x1a,0x00,
|
||||
0x00,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0xc0,0x4c,0x00,0x00,0x00,
|
||||
0x01,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x38,0x40,0x90,0x08,
|
||||
0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x0e,0x60,0xd8,0x08,0x00,0xc8,
|
||||
0x83,0xc0,0xf6,0x00,0x03,0x14,0x7f,0x3c,0x98,0x69,0x57,0x5d,0x1b,0x00,0x3c,0xf0,
|
||||
0xa2,0x00,0x03,0x24,0xf2,0x00,0x00,0x28,0x00,0x00,0x19,0x00,0x01,0x65,0x5d,0xd9,
|
||||
0xa7,0x8a,0x28,0x80,0x1a,0x07,0x63,0xb0,0x06,0x80,0x00,0xf8,0x00,0x67,0xe7,0xa7,
|
||||
0x3d,0x06,0x32,0x38,0x0c,0x60,0xe0,0x4c,0x1f,0x73,0x71,0xe2,0x9a,0x4f,0xc3,0x9f,
|
||||
0x1b,0xce,0xd9,0xc0,0xe6,0x00,0x00,0x01,0xff,0xc7,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1d,0x41,0xc0,0x13,0x0c,0x0c,
|
||||
0x1c,0x10,0x1f,0x00,0x70,0x81,0x01,0x13,0x00,0x00,0x04,0x20,0xa5,0x3e,0x0d,0x00,
|
||||
0x40,0x56,0x67,0x8a,0x5c,0x00,0x00,0x00,0x00,0x00,0x70,0xca,0x12,0x00,0xcd,0x06,
|
||||
0xa2,0x26,0xa0,0x01,0x9a,0x71,0x00,0x00,0x10,0x00,0x00,0x18,0x80,0x00,0x2a,0x3f,
|
||||
0x0a,0x90,0xcc,0xf2,0xa0,0x00,0x00,0x00,0x84,0x02,0x60,0x9e,0x01,0xa0,0x01,0x02,
|
||||
0x00,0x00,0x01,0xc1,0xc8,0x1f,0xdc,0x00,0x20,0x00,0x03,0x41,0x1a,0x80,0x80,0x03,
|
||||
0x80,0x00,0x00,0x20,0x04,0x40,0x00,0x04,0x00,0x07,0xaa,0x00,0x00,0x00,0x61,0xe0,
|
||||
0x00,0x00,0x66,0x00,0x00,0x78,0x60,0x80,0x00,0x00,0x00,0x08,0x81,0x80,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf4,0x03,0x03,0x01,0x10,0x04,0x80,
|
||||
0x01,0x44,0x00,0x60,0x20,0xc2,0xa5,0x5d,0x1b,0x27,0x1d,0x00,0x5c,0xa9,0xf8,0xf8,
|
||||
0xa2,0x00,0x03,0x2d,0xeb,0x00,0x00,0x38,0x00,0x00,0x33,0x00,0x01,0x9f,0x61,0x49,
|
||||
0xa1,0x55,0x49,0x87,0x20,0x62,0xc0,0x0a,0xc0,0x00,0x44,0x93,0x00,0xf0,0xdc,0x61,
|
||||
0x38,0x00,0x00,0x05,0x80,0x7a,0x89,0xc0,0x00,0x10,0x03,0x7a,0x81,0xc0,0x1d,0x60,
|
||||
0x7f,0x17,0x41,0x8a,0x00,0x9e,0x3f,0x8f,0x2c,0x01,0x9a,0x6a,0x00,0x0e,0xba,0x7e,
|
||||
0x00,0x0f,0xa0,0xa8,0x00,0x90,0xf9,0x00,0x01,0xb1,0xd0,0x00,0x39,0x01,0x40,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xc6,0xdd,0x72,0xc9,0x8d,0x9c,0xad,0x6d,0x34,
|
||||
0x43,0x6a,0xca,0x0c,0x26,0x65,0x3b,0xe2,0xcd,0x85,0x37,0x6a,0x5a,0x3b,0x24,0x2e,
|
||||
0x73,0xb6,0x4d,0xaf,0x8d,0xe6,0xa2,0x61,0x85,0xca,0x24,0x00,0x20,0x1f,0xfc,0xac,
|
||||
0xb2,0x87,0x01,0xfa,0x00,0xd6,0x80,0xc7,0x6d,0x69,0x69,0xe2,0xc6,0x65,0x01,0x80,
|
||||
0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x70,0x9e,0x3e,0x00,0x40,0x2a,0xaf,0x3e,
|
||||
0xa2,0x00,0x03,0x36,0x97,0x00,0x00,0x10,0x00,0x00,0x0d,0x00,0x00,0xd5,0x85,0x86,
|
||||
0x19,0x9e,0x05,0x00,0xa8,0x0c,0xf6,0x00,0x00,0x00,0x00,0x00,0x00,0x3a,0xd0,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x11,0xc3,0x40,0x71,0x00,0x0c,0x10,0x00,
|
||||
0x10,0x03,0x40,0x00,0x03,0x80,0x00,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x00,0x00,
|
||||
0x18,0x00,0x00,0x00,0xbc,0x00,0xc0,0x4c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,
|
||||
0xf8,0xee,0xeb,0x03,0x34,0x6a,0x00,0x33,0x28,0x7a,0x58,0x99,0x1a,0x00,0xfc,0xff,
|
||||
0xa2,0x00,0x03,0x24,0xe2,0x00,0x00,0x28,0x00,0x00,0x22,0x00,0x01,0x1b,0x5d,0xe6,
|
||||
0x24,0x62,0x45,0x9d,0x0b,0xb8,0xe0,0xf9,0x4f,0xf4,0x3d,0x70,0xf7,0xe8,0x0f,0x4f,
|
||||
0x80,0x3e,0xe0,0x33,0x8f,0x87,0xfe,0xbc,0x6b,0xe6,0x1c,0xe0,0x00,0x02,0x06,0x06,
|
||||
0x7e,0x3c,0x90,0x40,0x47,0x87,0xbe,0x0e,0x8e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xcc,0x00,0x30,0x70,0xd0,0x70,0x10,
|
||||
0x00,0x06,0x00,0x80,0x0f,0x84,0x46,0x00,0x27,0x06,0x74,0x08,0xd8,0x00,0x00,0x42,
|
||||
0x00,0xda,0x78,0x81,0x62,0x00,0x00,0x00,0x00,0x00,0xb8,0xe4,0x12,0x00,0x1d,0x71,
|
||||
0xa2,0x00,0x03,0x3a,0x4f,0x00,0x00,0x18,0x00,0x00,0x1d,0x00,0x00,0x54,0x6a,0x36,
|
||||
0x59,0x7e,0x26,0x40,0x00,0x29,0xec,0x30,0x01,0x00,0x04,0x28,0x00,0x00,0x28,0x01,
|
||||
0x70,0x00,0x00,0x0e,0x00,0x00,0x72,0x00,0x00,0x00,0x5b,0x64,0x0a,0x18,0xa0,0x00,
|
||||
0xb3,0x74,0x00,0x2c,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x00,0x07,0xb4,0x02,0xc0,
|
||||
0x00,0x00,0x03,0x84,0x00,0x00,0x00,0x0c,0xc0,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x6c,0xfa,0x9b,0x19,0x8c,0x61,0x00,
|
||||
0x35,0x1e,0x00,0x00,0x00,0x00,0x70,0x66,0x89,0x66,0xe7,0x1c,0x00,0xec,0xc2,0xf8
|
||||
};
|
||||
|
||||
/* every 97th sample, left then right */
|
||||
static const float ref_b[127][2] = {
|
||||
{ 9.242755361e-17f, 1.773212686e-17f }, { -1.376676937e-05f, 5.907738796e-06f }, { -5.874811177e-05f, 1.788824011e-04f },
|
||||
{ -1.018570038e-03f, 2.464378485e-04f }, { -2.119569399e-04f, 7.377937436e-04f }, { 1.533148461e-03f, 9.435778484e-04f },
|
||||
{ 1.381888869e-03f, 1.630387618e-03f }, { -8.613474667e-03f, -6.845163181e-03f }, { -2.718295436e-03f, -8.763763122e-03f },
|
||||
{ 7.736574858e-03f, -2.141328296e-03f }, { 5.018206779e-03f, -2.315925667e-03f }, { 7.489276584e-03f, -1.907932223e-03f },
|
||||
{ 3.134268802e-03f, -1.610284904e-03f }, { -3.251069225e-03f, -9.966419078e-03f }, { 1.527063362e-02f, 2.392249880e-03f },
|
||||
{ 9.232130833e-03f, -4.118668585e-06f }, { 2.157462150e-04f, -4.446413834e-03f }, { 7.393121254e-03f, 3.141878173e-03f },
|
||||
{ -2.523394069e-03f, 2.551409125e-04f }, { -1.967095770e-03f, -7.605865598e-03f }, { 2.726608654e-03f, 4.839247558e-03f },
|
||||
{ 9.896017145e-04f, 3.117912682e-03f }, { -1.379047288e-03f, -8.059814572e-03f }, { -1.710425131e-03f, 6.043954752e-03f },
|
||||
{ -4.109190311e-03f, 1.150204800e-02f }, { 5.927567370e-03f, -1.051148307e-02f }, { -3.755969694e-03f, -1.236700173e-02f },
|
||||
{ 5.969046033e-04f, -1.793625206e-02f }, { -4.289786797e-03f, 7.779521868e-03f }, { 5.922518205e-03f, 1.685886644e-02f },
|
||||
{ -1.450977870e-03f, 1.807238720e-02f }, { 2.093485091e-03f, -3.580174409e-03f }, { -1.901602489e-03f, -5.925749429e-03f },
|
||||
{ -1.028684084e-03f, 1.101716235e-02f }, { 6.783198100e-03f, 5.522613879e-03f }, { 4.541845061e-03f, 7.188364863e-03f },
|
||||
{ -7.084840443e-03f, 8.068239549e-04f }, { 1.375457650e-04f, 1.930533722e-02f }, { 1.656097919e-02f, 1.760038361e-02f },
|
||||
{ -1.186118461e-03f, 3.760735318e-02f }, { -5.043789279e-03f, 1.314742863e-02f }, { -3.093298292e-04f, 3.411643847e-04f },
|
||||
{ 1.251654699e-02f, -1.258237846e-02f }, { 1.087525114e-02f, -2.453862503e-02f }, { 7.555384189e-02f, -2.235571155e-03f },
|
||||
{ 5.234836042e-02f, 4.892709665e-03f }, { 3.225525469e-02f, 5.978997797e-03f }, { 3.580965335e-03f, 9.903170168e-03f },
|
||||
{ 5.783449113e-02f, -9.272078983e-03f }, { -2.673234791e-02f, -3.140788060e-03f }, { 9.830247611e-03f, 1.172329299e-02f },
|
||||
{ 7.472440135e-03f, 9.373517707e-03f }, { -8.061029017e-03f, -4.368110094e-03f }, { -1.345834043e-02f, -1.348030660e-02f },
|
||||
{ 1.986056566e-02f, 7.570201997e-03f }, { 3.439211752e-03f, 4.588234238e-03f }, { -2.303057723e-02f, -8.068498224e-03f },
|
||||
{ 3.217371996e-04f, 1.693903119e-03f }, { 2.076347545e-02f, 6.854519714e-03f }, { 4.996277392e-03f, 1.656256150e-03f },
|
||||
{ -9.310330264e-03f, -1.143144537e-02f }, { -3.636383219e-03f, -1.356176334e-03f }, { 8.796998882e-04f, 3.965437878e-03f },
|
||||
{ 6.642710883e-03f, 5.764317233e-03f }, { 9.057056159e-04f, -1.389055629e-03f }, { -9.527881630e-04f, -1.039899536e-03f },
|
||||
{ -5.453730118e-04f, -7.614314673e-04f }, { -1.817151555e-03f, -7.841610350e-03f }, { 1.814443385e-03f, -2.783074416e-02f },
|
||||
{ -7.000409532e-03f, 8.080396801e-03f }, { 7.318077143e-03f, 1.025662571e-02f }, { -9.270641953e-03f, -5.419919267e-02f },
|
||||
{ -4.289797507e-03f, 4.784114659e-03f }, { -1.283136290e-02f, 2.585908212e-02f }, { -2.063469775e-02f, 2.611474693e-02f },
|
||||
{ -1.088263746e-02f, -2.781113377e-03f }, { -4.381132126e-02f, 2.648726571e-03f }, { -1.627543941e-02f, 1.495551667e-03f },
|
||||
{ -1.758247986e-02f, 3.056185134e-02f }, { -2.161317505e-02f, 3.084198339e-03f }, { -3.460384207e-03f, 5.233756732e-03f },
|
||||
{ -4.000281543e-02f, 3.118669428e-02f }, { -3.414784744e-02f, 1.190567622e-03f }, { -1.392255258e-02f, 5.745146424e-03f },
|
||||
{ 4.076865036e-03f, 8.290714584e-03f }, { 2.667550230e-03f, -2.540340833e-02f }, { 2.732063085e-02f, 1.718526590e-03f },
|
||||
{ -6.838950329e-03f, -9.659450734e-04f }, { -3.738116100e-02f, -1.083254628e-02f }, { 4.238779470e-02f, 1.795529155e-03f },
|
||||
{ 5.989202112e-02f, 2.687947825e-03f }, { 3.961244971e-02f, -1.531511266e-02f }, { 8.675146848e-02f, -1.046039443e-02f },
|
||||
{ 3.647199646e-02f, -7.589594927e-03f }, { 6.936357357e-03f, -2.834746847e-03f }, { 4.016721994e-02f, -4.069634713e-03f },
|
||||
{ 1.770015806e-03f, -3.062386252e-02f }, { 5.142065929e-04f, 3.951912280e-03f }, { 6.848720368e-03f, -1.778870448e-02f },
|
||||
{ 2.332988754e-02f, -2.948206849e-02f }, { -2.872671001e-03f, 4.000978172e-02f }, { -1.185696805e-03f, 4.486579075e-02f },
|
||||
{ 8.405883797e-03f, 6.196010858e-02f }, { 5.209826049e-04f, -1.904802211e-02f }, { 4.224623553e-03f, 1.020930591e-03f },
|
||||
{ -3.941879142e-03f, -8.879946545e-03f }, { -5.200563464e-03f, 1.905284473e-03f }, { 1.238461491e-02f, 1.621735469e-02f },
|
||||
{ 1.755487546e-02f, 1.866262965e-02f }, { 7.159634493e-03f, 7.472440600e-03f }, { -9.791470133e-03f, -9.339432232e-03f },
|
||||
{ -3.184349742e-03f, 4.346971764e-05f }, { 7.015237119e-03f, 1.872387156e-02f }, { -1.548395865e-02f, -1.042172778e-03f },
|
||||
{ 1.337395981e-02f, 1.080276817e-02f }, { 1.752130105e-03f, 3.874791786e-03f }, { -7.943656296e-03f, -9.540103376e-03f },
|
||||
{ 6.131154019e-03f, -5.150374956e-03f }, { -9.605278261e-03f, 2.796929143e-02f }, { 1.565933228e-02f, 5.550820846e-03f },
|
||||
{ -6.927136797e-03f, 3.162872745e-03f }, { 1.543233451e-02f, -2.282161964e-03f }, { 7.871425711e-03f, 1.122876909e-02f },
|
||||
{ 2.274056152e-02f, -5.603998434e-03f }, { -6.363321561e-03f, -1.313319081e-03f }, { 1.146048587e-02f, -2.974855248e-03f },
|
||||
{ 1.110625733e-02f, -8.095641620e-03f }
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
include ../../sample_objdir.mk
|
||||
|
||||
TARGET := rpsmf_test
|
||||
|
||||
LIBRETRO_COMM_DIR := ../../..
|
||||
|
||||
SOURCES := \
|
||||
rpsmf_test.c \
|
||||
$(LIBRETRO_COMM_DIR)/formats/psmf/rpsmf.c \
|
||||
$(LIBRETRO_COMM_DIR)/formats/mpeg1/rmpeg1_ps.c
|
||||
|
||||
OBJS := $(call sample_objs,$(SOURCES:.c=.o))
|
||||
|
||||
CFLAGS += -Wall -pedantic -std=c89 -g -O1 -I$(LIBRETRO_COMM_DIR)/include
|
||||
|
||||
ifneq ($(SANITIZER),)
|
||||
CFLAGS := -fsanitize=$(SANITIZER) -fno-omit-frame-pointer $(CFLAGS)
|
||||
LDFLAGS := -fsanitize=$(SANITIZER) $(LDFLAGS)
|
||||
endif
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c -o $@ $< $(CFLAGS)
|
||||
|
||||
$(SAMPLE_OBJDIR)/%.o: $$(call sample_src,$$*).c
|
||||
@mkdir -p $(@D)
|
||||
$(CC) -c -o $@ $< $(CFLAGS)
|
||||
|
||||
$(TARGET): $(OBJS)
|
||||
$(CC) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -rf $(SAMPLE_OBJDIR)
|
||||
rm -f $(TARGET) $(OBJS)
|
||||
|
||||
.PHONY: clean
|
||||
@@ -0,0 +1,285 @@
|
||||
/* rpsmf and the MPEG-2 side of rmpeg1_ps against program streams built
|
||||
* here: a PSMF header, MPEG-2 packs and PES headers, H.264 video with
|
||||
* PTS and DTS, and ATRAC3plus frames running across private stream 1
|
||||
* packets behind the packets' own header bytes - fed whole, a byte at a
|
||||
* time and in odd chunks, with a broken frame in between. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <formats/rpsmf.h>
|
||||
#include <formats/rmpeg1_ps.h>
|
||||
|
||||
static unsigned failures;
|
||||
|
||||
#define CHECK(c, msg) do { if (!(c)) { failures++; \
|
||||
printf("FAIL %s:%d: %s\n", __FILE__, __LINE__, msg); } } while (0)
|
||||
|
||||
static uint8_t ps[1 << 16];
|
||||
static size_t ps_len;
|
||||
|
||||
static void put(const void *p, size_t n)
|
||||
{
|
||||
if (n)
|
||||
memcpy(ps + ps_len, p, n);
|
||||
ps_len += n;
|
||||
}
|
||||
|
||||
static void put_ts(unsigned prefix, uint64_t ts)
|
||||
{
|
||||
uint8_t b[5];
|
||||
b[0] = (uint8_t)((prefix << 4) | (((ts >> 30) & 7) << 1) | 1);
|
||||
b[1] = (uint8_t)(ts >> 22);
|
||||
b[2] = (uint8_t)((((ts >> 15) & 0x7F) << 1) | 1);
|
||||
b[3] = (uint8_t)(ts >> 7);
|
||||
b[4] = (uint8_t)(((ts & 0x7F) << 1) | 1);
|
||||
put(b, 5);
|
||||
}
|
||||
|
||||
/* An MPEG-2 pack header, SCR @scr, two stuffing bytes */
|
||||
static void put_pack2(uint64_t scr)
|
||||
{
|
||||
uint8_t b[16];
|
||||
uint32_t mux = 0x1234;
|
||||
b[0] = 0; b[1] = 0; b[2] = 1; b[3] = 0xBA;
|
||||
b[4] = (uint8_t)(0x44 | (((scr >> 30) & 7) << 3) | ((scr >> 28) & 3));
|
||||
b[5] = (uint8_t)(scr >> 20);
|
||||
b[6] = (uint8_t)(((scr >> 15) & 0x1F) << 3 | 4 | ((scr >> 13) & 3));
|
||||
b[7] = (uint8_t)(scr >> 5);
|
||||
b[8] = (uint8_t)(((scr & 0x1F) << 3) | 4);
|
||||
b[9] = 1;
|
||||
b[10] = (uint8_t)(mux >> 14);
|
||||
b[11] = (uint8_t)(mux >> 6);
|
||||
b[12] = (uint8_t)(((mux & 0x3F) << 2) | 3);
|
||||
b[13] = 0xF8 | 2;
|
||||
b[14] = 0xFF;
|
||||
b[15] = 0xFF;
|
||||
put(b, 16);
|
||||
}
|
||||
|
||||
/* An MPEG-2 PES of @id: PTS (and DTS) when given, @lead bytes before
|
||||
* @payload (a private stream's substream byte and header) */
|
||||
static void put_pes2(uint8_t id, uint64_t pts, uint64_t dts,
|
||||
const uint8_t *lead, size_t lead_len,
|
||||
const uint8_t *payload, size_t len)
|
||||
{
|
||||
uint8_t b[9];
|
||||
size_t hlen = pts == RPSMF_NO_PTS ? 0 : dts == RPSMF_NO_PTS ? 5 : 10;
|
||||
size_t total = 3 + hlen + lead_len + len;
|
||||
b[0] = 0; b[1] = 0; b[2] = 1; b[3] = id;
|
||||
b[4] = (uint8_t)(total >> 8);
|
||||
b[5] = (uint8_t)total;
|
||||
b[6] = 0x81;
|
||||
b[7] = (uint8_t)(hlen == 10 ? 0xC0 : hlen ? 0x80 : 0);
|
||||
b[8] = (uint8_t)hlen;
|
||||
put(b, 9);
|
||||
if (hlen)
|
||||
put_ts(hlen == 10 ? 3 : 2, pts);
|
||||
if (hlen == 10)
|
||||
put_ts(1, dts);
|
||||
put(lead, lead_len);
|
||||
put(payload, len);
|
||||
}
|
||||
|
||||
/* Two ATRAC3plus frames back to back, headers and all, and a third */
|
||||
static uint8_t atrac[3][8 + 376];
|
||||
static uint8_t audio[3 * (8 + 376)];
|
||||
|
||||
static void make_frames(void)
|
||||
{
|
||||
unsigned f, i;
|
||||
for (f = 0; f < 3; f++)
|
||||
{
|
||||
atrac[f][0] = 0x0F; atrac[f][1] = 0xD0;
|
||||
atrac[f][2] = 0x28; atrac[f][3] = 0x2E;
|
||||
atrac[f][4] = atrac[f][5] = atrac[f][6] = atrac[f][7] = 0;
|
||||
for (i = 0; i < 376; i++)
|
||||
atrac[f][8 + i] = (uint8_t)(i * 7 + f * 31 + 1);
|
||||
memcpy(audio + f * (8 + 376), atrac[f], 8 + 376);
|
||||
}
|
||||
}
|
||||
|
||||
static const uint8_t video[] = {
|
||||
0, 0, 0, 1, 0x09, 0xF0, 0, 0, 0, 1, 0x67, 0x4D, 0x40, 0x1E };
|
||||
|
||||
/* A movie: header, then video, then the three frames across three
|
||||
* packets of substream 0 with @skip header bytes each, the second
|
||||
* frame split mid-way, and, when @broken, junk where the third frame's
|
||||
* header should be continued */
|
||||
static size_t build(uint8_t *file, unsigned skip, bool broken)
|
||||
{
|
||||
uint8_t lead[8];
|
||||
size_t a = 8 + 376;
|
||||
unsigned i;
|
||||
ps_len = 0;
|
||||
memset(lead, 0xAA, sizeof(lead));
|
||||
lead[0] = 0x00;
|
||||
put_pack2(1000);
|
||||
put_pes2(0xE0, 9000, 6000, NULL, 0, video, sizeof(video));
|
||||
/* frame 0 whole, frame 1's first 100 bytes */
|
||||
put_pes2(0xBD, 9100, RPSMF_NO_PTS, lead, 1 + skip, audio, a + 100);
|
||||
put_pack2(2000);
|
||||
/* the rest of frame 1, and frame 2's header and 50 bytes */
|
||||
put_pes2(0xBD, 9500, RPSMF_NO_PTS, lead, 1 + skip, audio + a + 100,
|
||||
a - 100 + 8 + 50);
|
||||
if (broken)
|
||||
ps[ps_len - 50 - 8] ^= 0xFF; /* frame 2's header broken... */
|
||||
/* ...and the rest of it */
|
||||
put_pes2(0xBD, RPSMF_NO_PTS, RPSMF_NO_PTS, lead, 1 + skip,
|
||||
audio + 2 * a + 8 + 50, a - 8 - 50);
|
||||
/* a fresh frame after, which a broken stream recovers on */
|
||||
put_pes2(0xBD, 9900, RPSMF_NO_PTS, lead, 1 + skip, atrac[0], a);
|
||||
ps[ps_len++] = 0; ps[ps_len++] = 0; ps[ps_len++] = 1; ps[ps_len++] = 0xB9;
|
||||
|
||||
memset(file, 0, 0x800);
|
||||
memcpy(file, "PSMF0015", 8);
|
||||
file[0x0A] = 0x08; /* data offset 0x800 */
|
||||
file[0x0C] = (uint8_t)(ps_len >> 24);
|
||||
file[0x0D] = (uint8_t)(ps_len >> 16);
|
||||
file[0x0E] = (uint8_t)(ps_len >> 8);
|
||||
file[0x0F] = (uint8_t)ps_len;
|
||||
file[0x57] = 0x01; file[0x58] = 0x5F; file[0x59] = 0x90; /* 90000 */
|
||||
file[0x5D] = 0x01; /* 65536 */
|
||||
file[0x62] = 0x12; file[0x63] = 0x34;
|
||||
for (i = 0; i < ps_len; i++)
|
||||
file[0x800 + i] = ps[i];
|
||||
return 0x800 + ps_len;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned video, frames, other, borrowed;
|
||||
uint64_t video_pts, video_dts;
|
||||
uint64_t pts[8];
|
||||
bool ok[8];
|
||||
} seen_t;
|
||||
|
||||
static const uint8_t *in_lo, *in_hi;
|
||||
|
||||
static void drain(rpsmf_t *d, seen_t *s)
|
||||
{
|
||||
rpsmf_packet_t p;
|
||||
while (rpsmf_next(d, &p))
|
||||
{
|
||||
if (p.kind == RPSMF_VIDEO)
|
||||
{
|
||||
CHECK(p.size == sizeof(video) && !memcmp(p.data, video, p.size),
|
||||
"video payload");
|
||||
s->video_pts = p.pts;
|
||||
s->video_dts = p.dts;
|
||||
s->video++;
|
||||
}
|
||||
else if (p.kind == RPSMF_ATRAC3P && s->frames < 8)
|
||||
{
|
||||
unsigned f = s->frames % 3;
|
||||
/* the last frame is atrac[0] again */
|
||||
if (s->frames >= 2)
|
||||
f = (p.pts == 9900) ? 0 : 2;
|
||||
s->ok[s->frames] = p.size == 376 && p.params[0] == 0x28
|
||||
&& p.params[1] == 0x2E && !memcmp(p.data, atrac[f] + 8, 376);
|
||||
s->pts[s->frames] = p.pts;
|
||||
if (p.data >= in_lo && p.data < in_hi)
|
||||
s->borrowed++;
|
||||
s->frames++;
|
||||
}
|
||||
else
|
||||
s->other++;
|
||||
}
|
||||
}
|
||||
|
||||
/* @borrow: the input parsed where it lies, rather than written in */
|
||||
static void run(const uint8_t *file, size_t len, size_t chunk,
|
||||
bool borrow, seen_t *s)
|
||||
{
|
||||
rpsmf_info_t info;
|
||||
rpsmf_t *d = rpsmf_init();
|
||||
size_t off;
|
||||
in_lo = file;
|
||||
in_hi = file + len;
|
||||
memset(s, 0, sizeof(*s));
|
||||
CHECK(rpsmf_parse_header(file, len, &info), "header");
|
||||
CHECK(info.version == 15 && info.data_offset == 0x800
|
||||
&& info.tick_freq == 90000 && info.duration == 65536
|
||||
&& info.mux_rate == 0x1234, "header fields");
|
||||
for (off = info.data_offset; off < len; )
|
||||
{
|
||||
size_t n = len - off < chunk ? len - off : chunk;
|
||||
size_t w = borrow ? rpsmf_borrow(d, file + off, n)
|
||||
: rpsmf_write(d, file + off, n);
|
||||
off += w;
|
||||
drain(d, s);
|
||||
}
|
||||
drain(d, s);
|
||||
rpsmf_free(d);
|
||||
}
|
||||
|
||||
static uint8_t file[0x800 + (1 << 16)];
|
||||
|
||||
int main(void)
|
||||
{
|
||||
static const size_t chunks[] = { (size_t)-1, 1, 7, 2048 };
|
||||
unsigned skip, c, b;
|
||||
make_frames();
|
||||
|
||||
for (b = 0; b < 2; b++)
|
||||
for (skip = 3; skip <= 5; skip += 2)
|
||||
for (c = 0; c < sizeof(chunks) / sizeof(chunks[0]); c++)
|
||||
{
|
||||
seen_t s;
|
||||
size_t len = build(file, skip, false);
|
||||
run(file, len, chunks[c], b != 0, &s);
|
||||
CHECK(s.video == 1 && s.video_pts == 9000 && s.video_dts == 6000,
|
||||
"video PTS and DTS");
|
||||
CHECK(s.frames == 4, "four ATRAC3plus frames");
|
||||
CHECK(s.ok[0] && s.ok[1] && s.ok[2] && s.ok[3], "frames whole");
|
||||
/* a packet's PTS is the first frame to start in it */
|
||||
CHECK(s.pts[0] == 9100 && s.pts[1] == RPSMF_NO_PTS
|
||||
&& s.pts[2] == 9500 && s.pts[3] == 9900, "frame PTS");
|
||||
CHECK(!s.other, "nothing else");
|
||||
/* fed in pieces as large as a packet, at least the first frame
|
||||
* lies whole where it was handed over */
|
||||
if (b && chunks[c] >= 2048)
|
||||
CHECK(s.borrowed >= 1, "frames whole in a packet not copied");
|
||||
|
||||
len = build(file, skip, true);
|
||||
run(file, len, chunks[c], b != 0, &s);
|
||||
/* the broken one goes; the stream comes back on the next */
|
||||
CHECK(s.frames == 3 && s.ok[0] && s.ok[1] && s.ok[2]
|
||||
&& s.pts[2] == 9900, "recovers after a broken frame");
|
||||
}
|
||||
|
||||
/* MPEG-1 still reads as it did */
|
||||
{
|
||||
static const uint8_t mpeg1[] = {
|
||||
0, 0, 1, 0xBA, 0x21, 0x00, 0x01, 0x00, 0x01, 0x80, 0x00, 0x01,
|
||||
0, 0, 1, 0xE0, 0, 9, 0x21, 0x00, 0x01, 0x00, 0x01, 0xAB, 0xCD,
|
||||
0xEF, 0x12,
|
||||
0, 0, 1, 0xB9 };
|
||||
rmpeg1_ps_packet_t p;
|
||||
rmpeg1_ps_t *m = rmpeg1_ps_init(0);
|
||||
rmpeg1_ps_write(m, mpeg1, sizeof(mpeg1));
|
||||
CHECK(rmpeg1_ps_next(m, &p) && p.type == RMPEG1_PS_VIDEO
|
||||
&& p.size == 4 && p.pts == 0 && p.data[0] == 0xAB,
|
||||
"MPEG-1 PES");
|
||||
rmpeg1_ps_free(m);
|
||||
}
|
||||
|
||||
/* Not a PSMF */
|
||||
{
|
||||
rpsmf_info_t info;
|
||||
memcpy(file, "PSMX0015", 8);
|
||||
CHECK(!rpsmf_parse_header(file, 0x800, &info), "bad magic");
|
||||
memcpy(file, "PSMF00x5", 8);
|
||||
CHECK(!rpsmf_parse_header(file, 0x800, &info), "bad version");
|
||||
CHECK(!rpsmf_parse_header(file, 10, &info), "short");
|
||||
}
|
||||
|
||||
if (failures)
|
||||
{
|
||||
printf("rpsmf_test: %u failure(s)\n", failures);
|
||||
return 1;
|
||||
}
|
||||
printf("rpsmf_test: all lanes pass\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -404,12 +404,13 @@ static int run_frame_span_checks(void)
|
||||
for (i = 0; i < sizeof(input); i++) input[i] = (uint8_t)(i * 13 + offset);
|
||||
memset(next, 0xa5, sizeof(next));
|
||||
if (retro_spsc_write_frames(&q, input, count, width) != count) goto fail;
|
||||
/* A nonempty cache can expose less than the published head. */
|
||||
/* A nonempty but stale cache: read_begin re-reads the
|
||||
* published head rather than expose less than it. */
|
||||
if (stale) q.cached_head = start + width;
|
||||
tail = retro_atomic_load_relaxed_size(&q.tail);
|
||||
available = retro_spsc_read_begin(&q, &span);
|
||||
physical = 128 - offset;
|
||||
cached = stale ? width : count * width;
|
||||
cached = count * width;
|
||||
if (available != (physical < cached ? physical : cached)) goto fail;
|
||||
if (memcmp(span, input, available)) goto fail;
|
||||
if (retro_spsc_write_frames(&q, next, 1, width)) goto fail;
|
||||
@@ -441,12 +442,224 @@ fail:
|
||||
retro_spsc_free(&q);
|
||||
return 1;
|
||||
}
|
||||
printf("[pass] %u frame span cases: ownership, fallback, stale cache and cursor wrap\n", cases);
|
||||
printf("[pass] %u frame span cases: ownership, fallback, stale cache refreshed and cursor wrap\n", cases);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---- mirrored rings ---------------------------------------------- */
|
||||
|
||||
/* Single-threaded: the mirrored ring reads like a plain one - capacity,
|
||||
* room and fill - and a reservation or a read that crosses the
|
||||
* buffer's end is one span, landing where the plain ring would have
|
||||
* split it. Run on a ring larger than a page and on one smaller, whose
|
||||
* buffer is a page but whose fill stops at the capacity asked for. */
|
||||
static int run_mirror_case(size_t min_capacity)
|
||||
{
|
||||
retro_spsc_t q;
|
||||
uint8_t *buf;
|
||||
void *wp;
|
||||
const void *rp;
|
||||
size_t cap, size, n, i;
|
||||
|
||||
if (!retro_spsc_init_mirrored(&q, min_capacity))
|
||||
{
|
||||
fprintf(stderr, "FAIL: mirror %u: init\n", (unsigned)min_capacity);
|
||||
return 1;
|
||||
}
|
||||
cap = q.capacity;
|
||||
size = q.mask + 1;
|
||||
if (!q.mirror)
|
||||
{
|
||||
printf("[skip] mirror %u: this platform maps no mirror, plain ring\n",
|
||||
(unsigned)min_capacity);
|
||||
retro_spsc_free(&q);
|
||||
return 0;
|
||||
}
|
||||
if ( cap != min_capacity || size < cap || (size & (size - 1))
|
||||
|| retro_spsc_write_avail(&q) != cap || retro_spsc_read_avail(&q))
|
||||
{
|
||||
fprintf(stderr, "FAIL: mirror %u: capacity %u in a %u-byte buffer\n",
|
||||
(unsigned)min_capacity, (unsigned)cap, (unsigned)size);
|
||||
return 1;
|
||||
}
|
||||
if (!(buf = (uint8_t*)malloc(cap + 512)))
|
||||
return 1;
|
||||
/* Fill stops at the capacity, not the buffer. */
|
||||
memset(buf, 0x11, cap + 512);
|
||||
if (retro_spsc_write(&q, buf, cap + 512) != cap
|
||||
|| retro_spsc_write_avail(&q) != 0
|
||||
|| retro_spsc_read(&q, buf, cap + 512) != cap)
|
||||
{
|
||||
fprintf(stderr, "FAIL: mirror %u: fill past the capacity\n",
|
||||
(unsigned)min_capacity);
|
||||
return 1;
|
||||
}
|
||||
/* Walk the cursors to 24 bytes short of the buffer's end. */
|
||||
n = (size - 24 + size - (cap & (size - 1))) & (size - 1);
|
||||
while (n)
|
||||
{
|
||||
size_t k = n > cap ? cap : n;
|
||||
retro_spsc_write(&q, buf, k);
|
||||
retro_spsc_read(&q, buf, k);
|
||||
n -= k;
|
||||
}
|
||||
/* One reservation of the whole capacity, across the end. */
|
||||
if (retro_spsc_write_begin(&q, &wp) != cap)
|
||||
{
|
||||
fprintf(stderr, "FAIL: mirror %u: reservation cut at the wrap\n",
|
||||
(unsigned)min_capacity);
|
||||
return 1;
|
||||
}
|
||||
for (i = 0; i < cap; i++)
|
||||
((uint8_t*)wp)[i] = (uint8_t)(i * 7 + 3);
|
||||
retro_spsc_write_end(&q, cap);
|
||||
/* What went past the end is at the buffer's start. */
|
||||
if (q.buffer[0] != (uint8_t)(24 * 7 + 3))
|
||||
{
|
||||
fprintf(stderr, "FAIL: mirror %u: the mirror is not the start\n",
|
||||
(unsigned)min_capacity);
|
||||
return 1;
|
||||
}
|
||||
if (retro_spsc_read_begin(&q, &rp) != cap)
|
||||
{
|
||||
fprintf(stderr, "FAIL: mirror %u: read cut at the wrap\n",
|
||||
(unsigned)min_capacity);
|
||||
return 1;
|
||||
}
|
||||
for (i = 0; i < cap; i++)
|
||||
if (((const uint8_t*)rp)[i] != (uint8_t)(i * 7 + 3))
|
||||
{
|
||||
fprintf(stderr, "FAIL: mirror %u: byte %u\n",
|
||||
(unsigned)min_capacity, (unsigned)i);
|
||||
return 1;
|
||||
}
|
||||
retro_spsc_read_end(&q, cap);
|
||||
/* The copying paths agree across the end. */
|
||||
memset(buf, 0x22, 64);
|
||||
n = retro_spsc_write(&q, buf, 64);
|
||||
memset(buf, 0, 64);
|
||||
if (n != 64 || retro_spsc_read(&q, buf, 64) != 64 || buf[0] != 0x22
|
||||
|| buf[63] != 0x22)
|
||||
{
|
||||
fprintf(stderr, "FAIL: mirror %u: copy across the end\n",
|
||||
(unsigned)min_capacity);
|
||||
return 1;
|
||||
}
|
||||
free(buf);
|
||||
retro_spsc_free(&q);
|
||||
if (q.buffer || q.mirror)
|
||||
{
|
||||
fprintf(stderr, "FAIL: mirror %u: free left state\n",
|
||||
(unsigned)min_capacity);
|
||||
return 1;
|
||||
}
|
||||
printf("[pass] mirror %u: capacity %u in a %u-byte buffer, spans cross the end whole\n",
|
||||
(unsigned)min_capacity, (unsigned)cap, (unsigned)size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Two threads, spans only: the producer reserves a varying amount and
|
||||
* fills it with a running byte count, the consumer drains spans and
|
||||
* checks the count. On a mirrored ring no span is shorter than the
|
||||
* free space or the fill it reports. */
|
||||
#define MIRROR_BYTES (64u << 20)
|
||||
typedef struct
|
||||
{
|
||||
retro_spsc_t q;
|
||||
unsigned long mismatches, short_writes, short_reads;
|
||||
} mirror_state_t;
|
||||
|
||||
static void mirror_producer(void *arg)
|
||||
{
|
||||
mirror_state_t *s = (mirror_state_t*)arg;
|
||||
size_t sent = 0, want = 1;
|
||||
uint8_t v = 0;
|
||||
while (sent < MIRROR_BYTES)
|
||||
{
|
||||
void *p;
|
||||
size_t free_now = retro_spsc_write_avail(&s->q);
|
||||
size_t span = retro_spsc_write_begin(&s->q, &p);
|
||||
size_t i, n;
|
||||
if (s->q.mirror && span < free_now)
|
||||
s->short_writes++;
|
||||
n = span < want ? span : want;
|
||||
if (n > MIRROR_BYTES - sent)
|
||||
n = MIRROR_BYTES - sent;
|
||||
if (!n)
|
||||
{
|
||||
retro_spsc_write_end(&s->q, 0);
|
||||
sthread_yield();
|
||||
continue;
|
||||
}
|
||||
for (i = 0; i < n; i++)
|
||||
((uint8_t*)p)[i] = v++;
|
||||
retro_spsc_write_end(&s->q, n);
|
||||
sent += n;
|
||||
want = want * 5 % 997 + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void mirror_consumer(void *arg)
|
||||
{
|
||||
mirror_state_t *s = (mirror_state_t*)arg;
|
||||
size_t got = 0;
|
||||
uint8_t v = 0;
|
||||
while (got < MIRROR_BYTES)
|
||||
{
|
||||
const void *p;
|
||||
size_t fill = retro_spsc_read_avail(&s->q);
|
||||
size_t span = retro_spsc_read_begin(&s->q, &p);
|
||||
size_t i;
|
||||
if (s->q.mirror && span < fill)
|
||||
s->short_reads++;
|
||||
if (!span)
|
||||
{
|
||||
sthread_yield();
|
||||
continue;
|
||||
}
|
||||
for (i = 0; i < span; i++)
|
||||
if (((const uint8_t*)p)[i] != v++)
|
||||
s->mismatches++;
|
||||
retro_spsc_read_end(&s->q, span);
|
||||
got += span;
|
||||
}
|
||||
}
|
||||
|
||||
static int run_mirror_stress(size_t min_capacity)
|
||||
{
|
||||
mirror_state_t s;
|
||||
sthread_t *prod, *cons;
|
||||
memset(&s, 0, sizeof(s));
|
||||
if (!retro_spsc_init_mirrored(&s.q, min_capacity))
|
||||
return 1;
|
||||
prod = sthread_create(mirror_producer, &s);
|
||||
cons = sthread_create(mirror_consumer, &s);
|
||||
if (!prod || !cons)
|
||||
{
|
||||
fprintf(stderr, "FAIL: mirror stress: threads\n");
|
||||
return 1;
|
||||
}
|
||||
sthread_join(prod);
|
||||
sthread_join(cons);
|
||||
if (s.mismatches || s.short_writes || s.short_reads)
|
||||
{
|
||||
fprintf(stderr, "FAIL: mirror stress %u: %lu mismatched, %lu short reservations, %lu short reads\n",
|
||||
(unsigned)min_capacity, s.mismatches, s.short_writes, s.short_reads);
|
||||
retro_spsc_free(&s.q);
|
||||
return 1;
|
||||
}
|
||||
printf("[pass] mirror stress: %u MiB through a %s %u-byte ring in spans, 0 mismatches%s\n",
|
||||
MIRROR_BYTES >> 20, s.q.mirror ? "mirrored" : "plain",
|
||||
(unsigned)s.q.capacity, s.q.mirror ? ", no span cut short" : "");
|
||||
retro_spsc_free(&s.q);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
if ( run_mirror_case(1024) != 0 || run_mirror_case(65536) != 0
|
||||
|| run_mirror_stress(1024) != 0 || run_mirror_stress(4096) != 0)
|
||||
return 1;
|
||||
if (run_frame_checks() != 0 || run_frame_span_checks() != 0
|
||||
|| run_frame_stress(0) != 0 || run_frame_stress(1) != 0) return 1;
|
||||
if (run_property_checks() != 0)
|
||||
|
||||
Reference in new issue
Block a user