~martijnbraam/pyatem

6eea83648dc53c3f3fe1fde8be64181a7d2a1d4d — Martijn Braam 1 year, 11 months ago 131b9f1 feature/mediaconvert-encode
Use an uint64_t based RLE encoder
1 files changed, 39 insertions(+), 61 deletions(-)

M pyatem/mediaconvertmodule.c
M pyatem/mediaconvertmodule.c => pyatem/mediaconvertmodule.c +39 -61
@@ 1,4 1,5 @@
#define PY_SSIZE_T_CLEAN
#define RLE_HEADER 0xFEFEFEFEFEFEFEFE

#include <Python.h>



@@ 19,6 20,12 @@ const int cr_middle = 224 / 2;
const double bt709_ri_range = bt709_coeff_ri / cr_middle;
const double bt709_bi_range = bt709_coeff_bi / cr_middle;

void
beputu64(uint64_t *dest, uint64_t v)
{
    uint8_t *buf = (uint8_t *)dest;
    for (int i = 0; i < 8; i++) buf[i] = (v >> ((7 - i) * 8)) & 0xff;
}

static PyObject *
method_atem_to_rgb(PyObject *self, PyObject *args)


@@ 118,10 125,10 @@ method_rgb_to_atem(PyObject *self, PyObject *args)
        float cr16 = 0;
        float cb16 = 0;

        unsigned short y10a = (int)y16a >> 6;
        unsigned short y10b = (int)y16b >> 6;
        unsigned short cr10 = (int)cr16 >> 6;
        unsigned short cb10 = (int)cb16 >> 6;
        unsigned short y10a = ((int) y16a) >> 6;
        unsigned short y10b = ((int) y16b) >> 6;
        unsigned short cr10 = ((int) cr16) >> 6;
        unsigned short cb10 = ((int) cb16) >> 6;
        unsigned short a10a = ((buffer[3] << 2) * 219 / 255) + (16 << 2);
        unsigned short a10b = ((buffer[7] << 2) * 219 / 255) + (16 << 2);



@@ 153,69 160,40 @@ method_rle_encode(PyObject *self, PyObject *args)
        return NULL;
    }

    char *data;
    data = input_buffer.buf;

    unsigned char *buffer = (unsigned char *) malloc(input_buffer.len);

    if (buffer == NULL) {
        return PyErr_NoMemory();
    }

    unsigned long long block_counter = 0;
    ssize_t lastblock = 0;
    ssize_t wp = 0;
    for (int i = 0; i < input_buffer.len; i += 8) {
        if (memcmp(&data[i], &data[lastblock], 8) == 0) {
            // Block is same as previous, increment counter only
            block_counter++;
            continue;
    Py_ssize_t c = 0, i, w;
    uint64_t *data = input_buffer.buf;
    uint64_t *buf = malloc(input_buffer.len);
    for (i = 0, w = 0, c = 0; i < input_buffer.len / 8; ++i) {
        assert(data[i] != RLE_HEADER);
        if (i != 0 && data[i - 1] == data[i]) {
            ++c;
            if (i + 1 < input_buffer.len) {
                continue;
            }
        }
        if (block_counter > 2) {
            // RLE header
            memset(&buffer[wp], 0xfe, 8);
            wp += 8;

            // Block repeat count
            for (int h = 0; h < 8; h++) buffer[wp + h] = (block_counter >> ((7 - h) * 8)) & 0xff;
            wp += 8;

            // Block value
            memcpy(&buffer[wp], &data[lastblock], 8);
            wp += 8;
        } else if (block_counter > 0) {
            // Only two repeats, the RLE header would make the compressed chunk longer
            // write the 2 blocks without compression instead
            for (unsigned long long j = 0; j < block_counter; j++) {
                memcpy(&buffer[wp], &data[lastblock], 8);
                wp += 8;
        if (c > 2) {
            buf[w++] = RLE_HEADER;
            beputu64(&buf[w++], c);
            buf[w++] = data[i - 1];
        } else if (c > 0) {
            for (Py_ssize_t j = 0; j < c; ++j) {
                buf[w++] = data[i - 1];
            }
        } else {
            buf[w++] = data[i];
        }

        // Write the current block to the result
        memcpy(&buffer[wp], &data[i], 8);
        wp += 8;

        // Reset for next iteration
        lastblock = i;
        block_counter = 0;
        c = 0;
    }
    if (block_counter > 0) {
        // RLE header
        memset(&buffer[wp], 0xfe, 8);
        wp += 8;

        // Block repeat count
        for (int h = 0; h < 8; h++) buffer[wp + h] = (block_counter >> ((7 - h) * 8)) & 0xff;
        wp += 8;

        // Block value
        memcpy(&buffer[wp], &data[lastblock], 8);
        wp += 8;
    if (c > 0 && input_buffer.len > 1) {
        buf[w++] = RLE_HEADER;
        beputu64(&buf[w++], c);
        buf[w++] = data[i - 1];
    } else if (input_buffer.len == 1) {
        buf[0] = data[0];
    }

    res = Py_BuildValue("y#", buffer, wp);
    free(buffer);
    res = Py_BuildValue("y#", buf, w * 8);
    free(buf);
    return res;
}