159 lines
6.4 KiB
C
159 lines
6.4 KiB
C
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:4;tab-width:4;coding:utf-8 -*-│
|
|
│vi: set et ft=c ts=4 sw=4 fenc=utf-8 :vi│
|
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
│ PL_MPEG - MPEG1 Video decoder, MP2 Audio decoder, MPEG-PS demuxer │
|
|
│ Dominic Szablewski - https://phoboslab.org │
|
|
│ │
|
|
│ The MIT License(MIT) │
|
|
│ Copyright(c) 2019 Dominic Szablewski │
|
|
│ │
|
|
│ 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 "dsp/mpeg/buffer.h"
|
|
#include "dsp/mpeg/mpeg.h"
|
|
#include "libc/calls/calls.h"
|
|
#include "libc/log/check.h"
|
|
#include "libc/mem/mem.h"
|
|
#include "libc/stdio/stdio.h"
|
|
#include "libc/str/str.h"
|
|
#include "libc/sysv/consts/madv.h"
|
|
|
|
asm(".ident\t\"\\n\\n\
|
|
PL_MPEG (MIT License)\\n\
|
|
Copyright(c) 2019 Dominic Szablewski\\n\
|
|
https://phoboslab.org\"");
|
|
asm(".include \"libc/disclaimer.inc\"");
|
|
|
|
/* clang-format off */
|
|
// -----------------------------------------------------------------------------
|
|
// plm_buffer implementation
|
|
|
|
plm_buffer_t *plm_buffer_create_with_filename(const char *filename) {
|
|
FILE *fh = fopen(filename, "rb");
|
|
if (!fh) {
|
|
return NULL;
|
|
}
|
|
fadvise(fileno(fh), 0, 0, MADV_SEQUENTIAL);
|
|
return plm_buffer_create_with_file(fh, true);
|
|
}
|
|
|
|
plm_buffer_t *plm_buffer_create_with_file(FILE *fh, int close_when_done) {
|
|
plm_buffer_t *b;
|
|
b = plm_buffer_create_with_capacity(PLM_BUFFER_DEFAULT_SIZE);
|
|
b->fh = fh;
|
|
b->close_when_done = close_when_done;
|
|
b->mode = PLM_BUFFER_MODE_FILE;
|
|
plm_buffer_set_load_callback(b, plm_buffer_load_file_callback, NULL);
|
|
return b;
|
|
}
|
|
|
|
plm_buffer_t *plm_buffer_create_with_memory(unsigned char *bytes, size_t length, int free_when_done) {
|
|
plm_buffer_t *b;
|
|
b = memalign(alignof(plm_buffer_t), sizeof(plm_buffer_t));
|
|
memset(b, 0, sizeof(plm_buffer_t));
|
|
b->capacity = length;
|
|
b->length = length;
|
|
b->free_when_done = free_when_done;
|
|
b->bytes = bytes;
|
|
b->mode = PLM_BUFFER_MODE_FIXED_MEM;
|
|
return b;
|
|
}
|
|
|
|
plm_buffer_t * plm_buffer_create_with_capacity(size_t capacity) {
|
|
plm_buffer_t *b;
|
|
b = memalign(alignof(plm_buffer_t), sizeof(plm_buffer_t));
|
|
memset(b, 0, sizeof(plm_buffer_t));
|
|
b->capacity = capacity;
|
|
b->free_when_done = true;
|
|
b->bytes = (unsigned char *)malloc(capacity);
|
|
b->mode = PLM_BUFFER_MODE_DYNAMIC_MEM;
|
|
return b;
|
|
}
|
|
|
|
void plm_buffer_destroy(plm_buffer_t *self) {
|
|
if (self->fh && self->close_when_done) {
|
|
fclose(self->fh);
|
|
}
|
|
if (self->free_when_done) {
|
|
free(self->bytes);
|
|
}
|
|
free(self);
|
|
}
|
|
|
|
size_t plm_buffer_write(plm_buffer_t *self, unsigned char *bytes, size_t length) {
|
|
if (self->mode == PLM_BUFFER_MODE_FIXED_MEM) {
|
|
return 0;
|
|
}
|
|
// This should be a ring buffer, but instead it just shifts all unread data
|
|
// to the beginning of the buffer and appends new data at the end. Seems
|
|
// to be good enough.
|
|
plm_buffer_discard_read_bytes(self);
|
|
// Do we have to resize to fit the new data?
|
|
size_t bytes_available = self->capacity - self->length;
|
|
if (bytes_available < length) {
|
|
size_t new_size = self->capacity;
|
|
do {
|
|
new_size *= 2;
|
|
} while (new_size - self->length < length);
|
|
self->bytes = (unsigned char *)realloc(self->bytes, new_size);
|
|
self->capacity = new_size;
|
|
}
|
|
memcpy(self->bytes + self->length, bytes, length);
|
|
self->length += length;
|
|
return length;
|
|
}
|
|
|
|
void plm_buffer_set_load_callback(plm_buffer_t *self, plm_buffer_load_callback fp, void *user) {
|
|
self->load_callback = fp;
|
|
self->load_callback_user_data = user;
|
|
}
|
|
|
|
void plm_buffer_rewind(plm_buffer_t *self) {
|
|
if (self->fh) {
|
|
fseek(self->fh, 0, SEEK_SET);
|
|
self->length = 0;
|
|
}
|
|
if (self->mode != PLM_BUFFER_MODE_FIXED_MEM) {
|
|
self->length = 0;
|
|
}
|
|
self->bit_index = 0;
|
|
}
|
|
|
|
void plm_buffer_discard_read_bytes(plm_buffer_t *self) {
|
|
size_t byte_pos = self->bit_index >> 3;
|
|
if (byte_pos == self->length) {
|
|
self->bit_index = 0;
|
|
self->length = 0;
|
|
}
|
|
else if (byte_pos > 0) {
|
|
memmove(self->bytes, self->bytes + byte_pos, self->length - byte_pos);
|
|
self->bit_index -= byte_pos << 3;
|
|
self->length -= byte_pos;
|
|
}
|
|
}
|
|
|
|
void plm_buffer_load_file_callback(plm_buffer_t *self, void *user) {
|
|
plm_buffer_discard_read_bytes(self);
|
|
unsigned bytes_available = self->capacity - self->length;
|
|
unsigned bytes_read = fread(self->bytes + self->length, 1, bytes_available, self->fh);
|
|
self->length += bytes_read;
|
|
}
|