pl_mpegDC ported running but community help needed

If you have any questions on programming, this is the place to ask them, whether you're a newbie or an experienced programmer. Discussion on programming in general is also welcome. We will help you with programming homework, but we will not do your work for you! Any porting requests must be made in Developmental Ideas.
|darc|
DCEmu Webmaster
DCEmu Webmaster
Posts: 16375
https://www.artistsworkshop.eu/meble-kuchenne-na-wymiar-warszawa-gdzie-zamowic/
Joined: Wed Mar 14, 2001 6:00 pm
Location: New Orleans, LA
Has thanked: 104 times
Been thanked: 91 times
Contact:

Re: pl_mpegDC ported running but community help needed

Post by |darc| »

Twada wrote: Tue Sep 19, 2023 10:56 pm We would be honored if you could add us to Kos-Ports! Please feel free to use it!
Thank you so much for this! It will be fantastic to have this immediately available to all KOS users. :grin: :grin:
These users thanked the author |darc| for the post (total 2):
Ian RobinsonTwada
It's thinking...
Twada
DC Developer
DC Developer
Posts: 42
Joined: Wed Jan 20, 2016 4:55 am
Has thanked: 18 times
Been thanked: 53 times

Re: pl_mpegDC ported running but community help needed

Post by Twada »

Ian Robinson wrote: Wed Sep 20, 2023 8:46 am Do you think with this it would be possible to add function for pause/resume a movie ? ..
I think it's possible.
mpeg1.c is a short code just for playback, but pl_mpeg.h is optimized, so it should be possible if you create a suitable wrapper.

Until recently, I hadn't put pvr_wait_ready in the right place, which seems to have added more load than it should have. It probably has enough power to display the UI of the video player as well.

However, I haven't touched plm_seek at all, so I won't know about seek processing until I try it. In that case, you still need to rewrite the sound callback.
GyroVorbis wrote: Wed Sep 20, 2023 2:57 pm Oh yeah, this is totally expected. After all, you just barely got the thing up and working! I figured there would be some polishing that would need to be done. I've added a task to the KOS backlog for helping to get this ready to be added as a KOS-Port! :mrgreen:
That's great news!
These users thanked the author Twada for the post:
Ian Robinson
User avatar
Ian Robinson
DC Developer
DC Developer
Posts: 116
Joined: Mon Mar 11, 2019 7:12 am
Has thanked: 209 times
Been thanked: 41 times

Re: pl_mpegDC ported running but community help needed

Post by Ian Robinson »

Ok i worked on tighter frame control and resetting the sound call back and adding a buffer to keep it more in sync on longer videos

Here are the changes look it over for me ..

Code: Select all

#include <kos.h>
#define PL_MPEG_IMPLEMENTATION
#include "pl_mpeg.h"
#include "mpeg1.h"

static plm_t *plm;

/* textures */
static pvr_ptr_t texture;
static int width, height;
// Output texture width and height initial values
// You can choose from 32, 64, 128, 256, 512, 1024
#define MPEG1_TEXTURE_WIDTH 512
#define MPEG1_TEXTURE_HEIGHT 256

snd_stream_hnd_t snd_hnd;
__attribute__((aligned(32))) unsigned int snd_buf[0x10000 / 4];

void display_draw(void)
{
    pvr_poly_cxt_t cxt;
    pvr_poly_hdr_t hdr;
    pvr_vertex_t vert;
    float u = (float)width / (float)MPEG1_TEXTURE_WIDTH;
    float v = (float)height / (float)MPEG1_TEXTURE_HEIGHT;

    pvr_poly_cxt_txr(&cxt, PVR_LIST_OP_POLY, PVR_TXRFMT_YUV422 | PVR_TXRFMT_NONTWIDDLED, MPEG1_TEXTURE_WIDTH, MPEG1_TEXTURE_HEIGHT, texture, PVR_FILTER_BILINEAR);
    pvr_poly_compile(&hdr, &cxt);

    // hdr.mode3 |= 0x02000000; /* stride */
    pvr_prim(&hdr, sizeof(hdr));

    vert.argb = PVR_PACK_COLOR(1.0f, 1.0f, 1.0f, 1.0f);
    vert.oargb = 0;
    vert.flags = PVR_CMD_VERTEX;

    vert.x = 1;
    vert.y = 1;
    vert.z = 1;
    vert.u = 0.0f;
    vert.v = 0.0f;
    pvr_prim(&vert, sizeof(vert));

    vert.x = 640;
    vert.y = 1;
    vert.z = 1;
    vert.u = u;
    vert.v = 0.0;
    pvr_prim(&vert, sizeof(vert));

    vert.x = 1;
    vert.y = 480;
    vert.z = 1;
    vert.u = 0.0f;
    vert.v = v;
    pvr_prim(&vert, sizeof(vert));

    vert.x = 640;
    vert.y = 480;
    vert.z = 1;
    vert.u = u;
    vert.v = v;
    vert.flags = PVR_CMD_VERTEX_EOL;
    pvr_prim(&vert, sizeof(vert));
}

void app_on_video(plm_t *mpeg, plm_frame_t *frame, void *user)
{
    unsigned int *dest = (unsigned int *)texture;
    unsigned int *src = (unsigned int *)frame->display;

    volatile unsigned int *d = (volatile unsigned int *)0xa05f8148;
    volatile unsigned int *cfg = (volatile unsigned int *)0xa05f814c;

    volatile unsigned int *stride_reg = (volatile unsigned int *)0xa05f80e4;
    int stride_value;
    int stride = 0;

    int x, y, w, h, i;

    if (!frame)
        return;

    /* set frame size. */
    w = frame->width >> 4;
    h = frame->height >> 4;
    stride_value = (w >> 1); /* 16 pixel / 2 */

    /* Set Stride value. */
    *stride_reg &= 0xffffffe0;
    *stride_reg |= stride_value & 0x01f;

    /* Set SQ to YUV converter. */
    *d = ((unsigned int)dest) & 0xffffff;
    *cfg = 0x00000f1f;
    x = *cfg; /* read on once */

    for (y = 0; y < h; y++)
    {
        for (x = 0; x < w; x++, src += 96)
        {
            sq_cpy((void *)0x10800000, (void *)src, 384);
        }
        if (!stride)
        {
            /* Send dummy mb */
            for (i = 0; i < 32 - w; i++)
            {
                sq_set((void *)0x10800000, 0, 384);
            }
        }
    }
    for (i = 0; i < 16 - h; i++)
    {
        if (!stride)
            sq_set((void *)0x10800000, 0, 384 * 32);
        else
            sq_set((void *)0x10800000, 0, 384 * w);
    }
}

// Define a buffer for audio samples
#define AUDIO_SAMPLE_BUFFER_SIZE (1152 * 2 * 10) // Adjust the size as needed

// Static variables for sound callback
static int mod_start = 0;
static int mod_size = 0;
static unsigned int audio_sample_buffer[AUDIO_SAMPLE_BUFFER_SIZE];

// Function to reset sound callback's static variables
void reset_sound_callback()
{
    mod_start = 0;
    mod_size = 0;
}

// Sound callback function
void *sound_callback(snd_stream_hnd_t hnd, int size, int *size_out)
{
    unsigned int *dest = audio_sample_buffer;
    unsigned int *src;
    int out = 0;

    src = audio_sample_buffer + mod_start / 4;
    for (int i = 0; i < mod_size / 4; i++)
        *dest++ = *src++;
    out += mod_size;

    while (size > out)
    {
        plm_samples_t *sample = plm_decode_audio(plm);

        if (sample == NULL)
        {
            reset_sound_callback(); // Reset static variables when audio ends
            break;
        }

        src = (unsigned int *)sample->pcm;
        for (int i = 0; i < 1152 / 2; i++)
            *dest++ = *src++;
        out += 1152 * 2;
    }

    mod_start = size;
    mod_size = out - size;
    *size_out = size;

    return (void *)audio_sample_buffer;
}


int Mpeg1Play(const char *filename, unsigned int buttons)
{
    int cancel = 0;

    plm = plm_create_with_filename(filename);
    if (!plm)
        return -1;
    texture = pvr_mem_malloc(512 * 256 * 2);
    width = plm_get_width(plm);
    height = plm_get_height(plm);

    /* Set SQ to YUV converter. */
    PVR_SET(PVR_YUV_ADDR, (((unsigned int)texture) & 0xffffff));
    // Divide texture width and texture height by 16 and subtract 1.
    // The actual values to set are 1, 3, 7, 15, 31, 63.
    PVR_SET(PVR_YUV_CFG_1, (((MPEG1_TEXTURE_HEIGHT / 16) - 1) << 8) | ((MPEG1_TEXTURE_WIDTH / 16) - 1));
    PVR_GET(PVR_YUV_CFG_1);

    /* First frame */
    plm_frame_t *frame = plm_decode_video(plm);
    float start_time = (float)timer_ms_gettime64() / 1000.0;
    float playing_time = 0.0f;
    float frame_time = 1.0f / (float)plm_get_framerate(plm);
    int decoded = 1;

    /* Init sound stream. */
    int samplerate = plm_get_samplerate(plm);
    snd_hnd = snd_stream_alloc(sound_callback, 0x10000);
    snd_stream_volume(snd_hnd, 0xff);
    snd_stream_queue_enable(snd_hnd);
    snd_stream_start(snd_hnd, samplerate, 0);
    snd_stream_queue_go(snd_hnd);

    while (!cancel)
    {
        /* Check cancel buttons. */
        if (buttons)
        {
            MAPLE_FOREACH_BEGIN(MAPLE_FUNC_CONTROLLER, cont_state_t, st)
            if ((st->buttons & buttons) == buttons)
                cancel = 1;
            MAPLE_FOREACH_END()
        }

        /* Decode */
        playing_time = ((float)timer_ms_gettime64() / 1000.0) - start_time;
        if ((frame->time - playing_time) < frame_time)
        {
            frame = plm_decode_video(plm);
            if (!frame)
                break;
            decoded = 1;
        }
        snd_stream_poll(snd_hnd);

        /* Render */
        pvr_wait_ready();
        pvr_scene_begin();
        if (decoded)
        {
            app_on_video(plm, frame, 0);
            decoded = 0;
        }
        pvr_list_begin(PVR_LIST_OP_POLY);
        display_draw();
        pvr_list_finish();
        pvr_scene_finish();
    }

    plm_destroy(plm);
    pvr_mem_free(texture);
    snd_stream_destroy(snd_hnd);

    return 0;
}
seems to be working correct. always good to have other eyes. I notice running from a cdr not /rd/ the audio getting out of sync and out of no where it gets super slow. So far this fixes this problem.
also for a cdr

Code: Select all

ffmpeg -i input.mp4 -vf "scale=320:240" -b:v 800k -ac 1 -ar 44100 -b:a 80k -f mpeg output.mpeg
These users thanked the author Ian Robinson for the post:
|darc|
Twada
DC Developer
DC Developer
Posts: 42
Joined: Wed Jan 20, 2016 4:55 am
Has thanked: 18 times
Been thanked: 53 times

Re: pl_mpegDC ported running but community help needed

Post by Twada »

Ian Robinson wrote: Thu Sep 21, 2023 9:37 am Ok i worked on tighter frame control and resetting the sound call back and adding a buffer to keep it more in sync on longer videos

Here are the changes look it over for me ..

Code: Select all

#include <kos.h>
#define PL_MPEG_IMPLEMENTATION
#include "pl_mpeg.h"
#include "mpeg1.h"

static plm_t *plm;

/* textures */
static pvr_ptr_t texture;
static int width, height;
// Output texture width and height initial values
// You can choose from 32, 64, 128, 256, 512, 1024
#define MPEG1_TEXTURE_WIDTH 512
#define MPEG1_TEXTURE_HEIGHT 256

snd_stream_hnd_t snd_hnd;
__attribute__((aligned(32))) unsigned int snd_buf[0x10000 / 4];

void display_draw(void)
{
    pvr_poly_cxt_t cxt;
    pvr_poly_hdr_t hdr;
    pvr_vertex_t vert;
    float u = (float)width / (float)MPEG1_TEXTURE_WIDTH;
    float v = (float)height / (float)MPEG1_TEXTURE_HEIGHT;

    pvr_poly_cxt_txr(&cxt, PVR_LIST_OP_POLY, PVR_TXRFMT_YUV422 | PVR_TXRFMT_NONTWIDDLED, MPEG1_TEXTURE_WIDTH, MPEG1_TEXTURE_HEIGHT, texture, PVR_FILTER_BILINEAR);
    pvr_poly_compile(&hdr, &cxt);

    // hdr.mode3 |= 0x02000000; /* stride */
    pvr_prim(&hdr, sizeof(hdr));

    vert.argb = PVR_PACK_COLOR(1.0f, 1.0f, 1.0f, 1.0f);
    vert.oargb = 0;
    vert.flags = PVR_CMD_VERTEX;

    vert.x = 1;
    vert.y = 1;
    vert.z = 1;
    vert.u = 0.0f;
    vert.v = 0.0f;
    pvr_prim(&vert, sizeof(vert));

    vert.x = 640;
    vert.y = 1;
    vert.z = 1;
    vert.u = u;
    vert.v = 0.0;
    pvr_prim(&vert, sizeof(vert));

    vert.x = 1;
    vert.y = 480;
    vert.z = 1;
    vert.u = 0.0f;
    vert.v = v;
    pvr_prim(&vert, sizeof(vert));

    vert.x = 640;
    vert.y = 480;
    vert.z = 1;
    vert.u = u;
    vert.v = v;
    vert.flags = PVR_CMD_VERTEX_EOL;
    pvr_prim(&vert, sizeof(vert));
}

void app_on_video(plm_t *mpeg, plm_frame_t *frame, void *user)
{
    unsigned int *dest = (unsigned int *)texture;
    unsigned int *src = (unsigned int *)frame->display;

    volatile unsigned int *d = (volatile unsigned int *)0xa05f8148;
    volatile unsigned int *cfg = (volatile unsigned int *)0xa05f814c;

    volatile unsigned int *stride_reg = (volatile unsigned int *)0xa05f80e4;
    int stride_value;
    int stride = 0;

    int x, y, w, h, i;

    if (!frame)
        return;

    /* set frame size. */
    w = frame->width >> 4;
    h = frame->height >> 4;
    stride_value = (w >> 1); /* 16 pixel / 2 */

    /* Set Stride value. */
    *stride_reg &= 0xffffffe0;
    *stride_reg |= stride_value & 0x01f;

    /* Set SQ to YUV converter. */
    *d = ((unsigned int)dest) & 0xffffff;
    *cfg = 0x00000f1f;
    x = *cfg; /* read on once */

    for (y = 0; y < h; y++)
    {
        for (x = 0; x < w; x++, src += 96)
        {
            sq_cpy((void *)0x10800000, (void *)src, 384);
        }
        if (!stride)
        {
            /* Send dummy mb */
            for (i = 0; i < 32 - w; i++)
            {
                sq_set((void *)0x10800000, 0, 384);
            }
        }
    }
    for (i = 0; i < 16 - h; i++)
    {
        if (!stride)
            sq_set((void *)0x10800000, 0, 384 * 32);
        else
            sq_set((void *)0x10800000, 0, 384 * w);
    }
}

// Define a buffer for audio samples
#define AUDIO_SAMPLE_BUFFER_SIZE (1152 * 2 * 10) // Adjust the size as needed

// Static variables for sound callback
static int mod_start = 0;
static int mod_size = 0;
static unsigned int audio_sample_buffer[AUDIO_SAMPLE_BUFFER_SIZE];

// Function to reset sound callback's static variables
void reset_sound_callback()
{
    mod_start = 0;
    mod_size = 0;
}

// Sound callback function
void *sound_callback(snd_stream_hnd_t hnd, int size, int *size_out)
{
    unsigned int *dest = audio_sample_buffer;
    unsigned int *src;
    int out = 0;

    src = audio_sample_buffer + mod_start / 4;
    for (int i = 0; i < mod_size / 4; i++)
        *dest++ = *src++;
    out += mod_size;

    while (size > out)
    {
        plm_samples_t *sample = plm_decode_audio(plm);

        if (sample == NULL)
        {
            reset_sound_callback(); // Reset static variables when audio ends
            break;
        }

        src = (unsigned int *)sample->pcm;
        for (int i = 0; i < 1152 / 2; i++)
            *dest++ = *src++;
        out += 1152 * 2;
    }

    mod_start = size;
    mod_size = out - size;
    *size_out = size;

    return (void *)audio_sample_buffer;
}


int Mpeg1Play(const char *filename, unsigned int buttons)
{
    int cancel = 0;

    plm = plm_create_with_filename(filename);
    if (!plm)
        return -1;
    texture = pvr_mem_malloc(512 * 256 * 2);
    width = plm_get_width(plm);
    height = plm_get_height(plm);

    /* Set SQ to YUV converter. */
    PVR_SET(PVR_YUV_ADDR, (((unsigned int)texture) & 0xffffff));
    // Divide texture width and texture height by 16 and subtract 1.
    // The actual values to set are 1, 3, 7, 15, 31, 63.
    PVR_SET(PVR_YUV_CFG_1, (((MPEG1_TEXTURE_HEIGHT / 16) - 1) << 8) | ((MPEG1_TEXTURE_WIDTH / 16) - 1));
    PVR_GET(PVR_YUV_CFG_1);

    /* First frame */
    plm_frame_t *frame = plm_decode_video(plm);
    float start_time = (float)timer_ms_gettime64() / 1000.0;
    float playing_time = 0.0f;
    float frame_time = 1.0f / (float)plm_get_framerate(plm);
    int decoded = 1;

    /* Init sound stream. */
    int samplerate = plm_get_samplerate(plm);
    snd_hnd = snd_stream_alloc(sound_callback, 0x10000);
    snd_stream_volume(snd_hnd, 0xff);
    snd_stream_queue_enable(snd_hnd);
    snd_stream_start(snd_hnd, samplerate, 0);
    snd_stream_queue_go(snd_hnd);

    while (!cancel)
    {
        /* Check cancel buttons. */
        if (buttons)
        {
            MAPLE_FOREACH_BEGIN(MAPLE_FUNC_CONTROLLER, cont_state_t, st)
            if ((st->buttons & buttons) == buttons)
                cancel = 1;
            MAPLE_FOREACH_END()
        }

        /* Decode */
        playing_time = ((float)timer_ms_gettime64() / 1000.0) - start_time;
        if ((frame->time - playing_time) < frame_time)
        {
            frame = plm_decode_video(plm);
            if (!frame)
                break;
            decoded = 1;
        }
        snd_stream_poll(snd_hnd);

        /* Render */
        pvr_wait_ready();
        pvr_scene_begin();
        if (decoded)
        {
            app_on_video(plm, frame, 0);
            decoded = 0;
        }
        pvr_list_begin(PVR_LIST_OP_POLY);
        display_draw();
        pvr_list_finish();
        pvr_scene_finish();
    }

    plm_destroy(plm);
    pvr_mem_free(texture);
    snd_stream_destroy(snd_hnd);

    return 0;
}
seems to be working correct. always good to have other eyes. I notice running from a cdr not /rd/ the audio getting out of sync and out of no where it gets super slow. So far this fixes this problem.
also for a cdr

Code: Select all

ffmpeg -i input.mp4 -vf "scale=320:240" -b:v 800k -ac 1 -ar 44100 -b:a 80k -f mpeg output.mpeg
Thank you for the necessary correction.
I was concerned that if I stop the video in the middle without playing it to the end, the previous mod_start and mod_size may remain.
How about making sure to call reset_sound_callback() before initializing the sound stream?
(Actually, I wanted to implement a cool ring buffer instead of copying data. Hahaha)

And thank you for verifying the bitrate.
If the video and audio reading positions are too far apart due to processing delays, the loading becomes very complicated and seems to hang.
It certainly seems like 800kbps is a reasonable size. It was helpful.
These users thanked the author Twada for the post:
Ian Robinson
User avatar
Ian Robinson
DC Developer
DC Developer
Posts: 116
Joined: Mon Mar 11, 2019 7:12 am
Has thanked: 209 times
Been thanked: 41 times

Re: pl_mpegDC ported running but community help needed

Post by Ian Robinson »

Ok this played my test video and stayed on sync

correct me where i went wrong right now it's the first time it played
the matrix trailer and did not slow down

Code: Select all

#include <kos.h>
#define PL_MPEG_IMPLEMENTATION
#include "pl_mpeg.h"
#include "mpeg1.h"

static plm_t *plm;

/* textures */
static pvr_ptr_t texture;
static int width, height;
// Output texture width and height initial values
// You can choose from 32, 64, 128, 256, 512, 1024
#define MPEG1_TEXTURE_WIDTH 512
#define MPEG1_TEXTURE_HEIGHT 256

snd_stream_hnd_t snd_hnd;
__attribute__((aligned(32))) unsigned int snd_buf[0x10000 / 4];

void display_draw(void)
{
    pvr_poly_cxt_t cxt;
    pvr_poly_hdr_t hdr;
    pvr_vertex_t vert;
    float u = (float)width / (float)MPEG1_TEXTURE_WIDTH;
    float v = (float)height / (float)MPEG1_TEXTURE_HEIGHT;

    pvr_poly_cxt_txr(&cxt, PVR_LIST_OP_POLY, PVR_TXRFMT_YUV422 | PVR_TXRFMT_NONTWIDDLED, MPEG1_TEXTURE_WIDTH, MPEG1_TEXTURE_HEIGHT, texture, PVR_FILTER_BILINEAR);
    pvr_poly_compile(&hdr, &cxt);

    // hdr.mode3 |= 0x02000000; /* stride */
    pvr_prim(&hdr, sizeof(hdr));

    vert.argb = PVR_PACK_COLOR(1.0f, 1.0f, 1.0f, 1.0f);
    vert.oargb = 0;
    vert.flags = PVR_CMD_VERTEX;

    vert.x = 1;
    vert.y = 1;
    vert.z = 1;
    vert.u = 0.0f;
    vert.v = 0.0f;
    pvr_prim(&vert, sizeof(vert));

    vert.x = 640;
    vert.y = 1;
    vert.z = 1;
    vert.u = u;
    vert.v = 0.0;
    pvr_prim(&vert, sizeof(vert));

    vert.x = 1;
    vert.y = 480;
    vert.z = 1;
    vert.u = 0.0f;
    vert.v = v;
    pvr_prim(&vert, sizeof(vert));

    vert.x = 640;
    vert.y = 480;
    vert.z = 1;
    vert.u = u;
    vert.v = v;
    vert.flags = PVR_CMD_VERTEX_EOL;
    pvr_prim(&vert, sizeof(vert));
}

void app_on_video(plm_t *mpeg, plm_frame_t *frame, void *user)
{
    unsigned int *dest = (unsigned int *)texture;
    unsigned int *src = (unsigned int *)frame->display;

    volatile unsigned int *d = (volatile unsigned int *)0xa05f8148;
    volatile unsigned int *cfg = (volatile unsigned int *)0xa05f814c;

    volatile unsigned int *stride_reg = (volatile unsigned int *)0xa05f80e4;
    int stride_value;
    int stride = 0;

    int x, y, w, h, i;

    if (!frame)
        return;

    /* set frame size. */
    w = frame->width >> 4;
    h = frame->height >> 4;
    stride_value = (w >> 1); /* 16 pixel / 2 */

    /* Set Stride value. */
    *stride_reg &= 0xffffffe0;
    *stride_reg |= stride_value & 0x01f;

    /* Set SQ to YUV converter. */
    *d = ((unsigned int)dest) & 0xffffff;
    *cfg = 0x00000f1f;
    x = *cfg; /* read on once */

    for (y = 0; y < h; y++)
    {
        for (x = 0; x < w; x++, src += 96)
        {
            sq_cpy((void *)0x10800000, (void *)src, 384);
        }
        if (!stride)
        {
            /* Send dummy mb */
            for (i = 0; i < 32 - w; i++)
            {
                sq_set((void *)0x10800000, 0, 384);
            }
        }
    }
    for (i = 0; i < 16 - h; i++)
    {
        if (!stride)
            sq_set((void *)0x10800000, 0, 384 * 32);
        else
            sq_set((void *)0x10800000, 0, 384 * w);
    }
}

// Define a buffer for audio samples
#define AUDIO_SAMPLE_BUFFER_SIZE (1152 * 2 * 10) // Adjust the size as needed

// Static variables for sound callback
static int mod_start = 0;
static int mod_size = 0;
static unsigned int audio_sample_buffer[AUDIO_SAMPLE_BUFFER_SIZE];

// Function to reset sound callback's static variables
void reset_sound_callback()
{
    mod_start = 0;
    mod_size = 0;
}

// Sound callback function
void *sound_callback(snd_stream_hnd_t hnd, int size, int *size_out)
{
    unsigned int *dest = audio_sample_buffer;
    unsigned int *src;
    int out = 0;

    src = audio_sample_buffer + mod_start / 4;
    for (int i = 0; i < mod_size / 4; i++)
        *dest++ = *src++;
    out += mod_size;

    while (size > out)
    {
        plm_samples_t *sample = plm_decode_audio(plm);

        if (sample == NULL)
        {
            reset_sound_callback(); // Reset static variables when audio ends
            break;
        }

        src = (unsigned int *)sample->pcm;
        for (int i = 0; i < 1152 / 2; i++)
            *dest++ = *src++;
        out += 1152 * 2;
    }

    mod_start = size;
    mod_size = out - size;
    *size_out = size;

    return (void *)audio_sample_buffer;
}


int Mpeg1Play(const char *filename, unsigned int buttons)
{
    int cancel = 0;

    plm = plm_create_with_filename(filename);
    if (!plm)
        return -1;
    texture = pvr_mem_malloc(512 * 256 * 2);
    width = plm_get_width(plm);
    height = plm_get_height(plm);

    /* Set SQ to YUV converter. */
    PVR_SET(PVR_YUV_ADDR, (((unsigned int)texture) & 0xffffff));
    // Divide texture width and texture height by 16 and subtract 1.
    // The actual values to set are 1, 3, 7, 15, 31, 63.
    PVR_SET(PVR_YUV_CFG_1, (((MPEG1_TEXTURE_HEIGHT / 16) - 1) << 8) | ((MPEG1_TEXTURE_WIDTH / 16) - 1));
    PVR_GET(PVR_YUV_CFG_1);

    /* First frame */
    plm_frame_t *frame = plm_decode_video(plm);
    float start_time = (float)timer_ms_gettime64() / 1000.0;
    float playing_time = 0.0f;
    float frame_time = 1.0f / (float)plm_get_framerate(plm);
    int decoded = 1;
    reset_sound_callback();
    /* Init sound stream. */
    int samplerate = plm_get_samplerate(plm);
    snd_hnd = snd_stream_alloc(sound_callback, 0x10000);
    snd_stream_volume(snd_hnd, 0xff);
    snd_stream_queue_enable(snd_hnd);
    snd_stream_start(snd_hnd, samplerate, 0);
    snd_stream_queue_go(snd_hnd);

    while (!cancel)
    {
        /* Check cancel buttons. */
        if (buttons)
        {
            MAPLE_FOREACH_BEGIN(MAPLE_FUNC_CONTROLLER, cont_state_t, st)
            if ((st->buttons & buttons) == buttons)
                cancel = 1;
            MAPLE_FOREACH_END()
        }

        /* Decode */
        playing_time = ((float)timer_ms_gettime64() / 1000.0) - start_time;
        if ((frame->time - playing_time) < frame_time)
        {
            frame = plm_decode_video(plm);
            if (!frame)
                break;
            decoded = 1;
        }
        snd_stream_poll(snd_hnd);

        /* Render */
        pvr_wait_ready();
        pvr_scene_begin();
        if (decoded)
        {
            app_on_video(plm, frame, 0);
            decoded = 0;
        }
        pvr_list_begin(PVR_LIST_OP_POLY);
        display_draw();
        pvr_list_finish();
        pvr_scene_finish();
    }
    reset_sound_callback();
    plm_destroy(plm);
    pvr_mem_free(texture);
    snd_stream_destroy(snd_hnd);

    return 0;
}
example.c

Code: Select all

#include <kos.h>
#include <string.h>
#include <stdio.h>
#include <arch/arch.h>
#include "mpeg1.h"

/* romdisk */
extern uint8 romdisk_boot[];
KOS_INIT_ROMDISK(romdisk_boot);



int main(void)
{

    pvr_init_defaults();
    snd_stream_init();

    Mpeg1Play("/cd/zample.mpg", CONT_START);
    //Ian micheal now exits at the end of video
    snd_stream_shutdown();
    spu_disable(); // Disable the Sound Processing Unit (SPU).
    arch_exit(); // Perform system-specific exit operations.
    return 0;
}
Names starting with Z are the fastest when dummied.
Before these changes the music would always complete first. Ok still a few places it goes out of sync but much better https://streamable.com/qtn6s4 .. I have done the ring buffer thing before i will see what i can do with that.. Threading did not make it better i tried and it made it crash all the time.. 5 hours wasted!
I will leave your version and not update it till you say so i made a folder with the work today now exits to dcload serial when the video ends it did not before.
https://github.com/ianmicheal/MPEG1-Dec ... updates%5D marked where the changes are in this folder.
Developing a cdrom/gdrom benchmark tool which will show you all speeds of all files on the disc almost done..It benchmarks the disc captures the log to the vmu and can read back with the pvr log viewer with scrolling..
Toolmenu https://streamable.com/5ub9iz
Pvr vmu log viewer https://streamable.com/eb2sp9
Benchmark menu https://streamable.com/lrn7av
It will load the texture of the game benchmark then save to the vmu..
I did this to see speed on a cdr where the best place and names are for media files..There is a very big change depending on how you create and order the files.
Twada
DC Developer
DC Developer
Posts: 42
Joined: Wed Jan 20, 2016 4:55 am
Has thanked: 18 times
Been thanked: 53 times

Re: pl_mpegDC ported running but community help needed

Post by Twada »

Ian Robinson wrote: Thu Sep 21, 2023 8:47 pm Ok this played my test video and stayed on sync

correct me where i went wrong right now it's the first time it played
the matrix trailer and did not slow down

Code: Select all

#include <kos.h>
#define PL_MPEG_IMPLEMENTATION
#include "pl_mpeg.h"
#include "mpeg1.h"

static plm_t *plm;

/* textures */
static pvr_ptr_t texture;
static int width, height;
// Output texture width and height initial values
// You can choose from 32, 64, 128, 256, 512, 1024
#define MPEG1_TEXTURE_WIDTH 512
#define MPEG1_TEXTURE_HEIGHT 256

snd_stream_hnd_t snd_hnd;
__attribute__((aligned(32))) unsigned int snd_buf[0x10000 / 4];

void display_draw(void)
{
    pvr_poly_cxt_t cxt;
    pvr_poly_hdr_t hdr;
    pvr_vertex_t vert;
    float u = (float)width / (float)MPEG1_TEXTURE_WIDTH;
    float v = (float)height / (float)MPEG1_TEXTURE_HEIGHT;

    pvr_poly_cxt_txr(&cxt, PVR_LIST_OP_POLY, PVR_TXRFMT_YUV422 | PVR_TXRFMT_NONTWIDDLED, MPEG1_TEXTURE_WIDTH, MPEG1_TEXTURE_HEIGHT, texture, PVR_FILTER_BILINEAR);
    pvr_poly_compile(&hdr, &cxt);

    // hdr.mode3 |= 0x02000000; /* stride */
    pvr_prim(&hdr, sizeof(hdr));

    vert.argb = PVR_PACK_COLOR(1.0f, 1.0f, 1.0f, 1.0f);
    vert.oargb = 0;
    vert.flags = PVR_CMD_VERTEX;

    vert.x = 1;
    vert.y = 1;
    vert.z = 1;
    vert.u = 0.0f;
    vert.v = 0.0f;
    pvr_prim(&vert, sizeof(vert));

    vert.x = 640;
    vert.y = 1;
    vert.z = 1;
    vert.u = u;
    vert.v = 0.0;
    pvr_prim(&vert, sizeof(vert));

    vert.x = 1;
    vert.y = 480;
    vert.z = 1;
    vert.u = 0.0f;
    vert.v = v;
    pvr_prim(&vert, sizeof(vert));

    vert.x = 640;
    vert.y = 480;
    vert.z = 1;
    vert.u = u;
    vert.v = v;
    vert.flags = PVR_CMD_VERTEX_EOL;
    pvr_prim(&vert, sizeof(vert));
}

void app_on_video(plm_t *mpeg, plm_frame_t *frame, void *user)
{
    unsigned int *dest = (unsigned int *)texture;
    unsigned int *src = (unsigned int *)frame->display;

    volatile unsigned int *d = (volatile unsigned int *)0xa05f8148;
    volatile unsigned int *cfg = (volatile unsigned int *)0xa05f814c;

    volatile unsigned int *stride_reg = (volatile unsigned int *)0xa05f80e4;
    int stride_value;
    int stride = 0;

    int x, y, w, h, i;

    if (!frame)
        return;

    /* set frame size. */
    w = frame->width >> 4;
    h = frame->height >> 4;
    stride_value = (w >> 1); /* 16 pixel / 2 */

    /* Set Stride value. */
    *stride_reg &= 0xffffffe0;
    *stride_reg |= stride_value & 0x01f;

    /* Set SQ to YUV converter. */
    *d = ((unsigned int)dest) & 0xffffff;
    *cfg = 0x00000f1f;
    x = *cfg; /* read on once */

    for (y = 0; y < h; y++)
    {
        for (x = 0; x < w; x++, src += 96)
        {
            sq_cpy((void *)0x10800000, (void *)src, 384);
        }
        if (!stride)
        {
            /* Send dummy mb */
            for (i = 0; i < 32 - w; i++)
            {
                sq_set((void *)0x10800000, 0, 384);
            }
        }
    }
    for (i = 0; i < 16 - h; i++)
    {
        if (!stride)
            sq_set((void *)0x10800000, 0, 384 * 32);
        else
            sq_set((void *)0x10800000, 0, 384 * w);
    }
}

// Define a buffer for audio samples
#define AUDIO_SAMPLE_BUFFER_SIZE (1152 * 2 * 10) // Adjust the size as needed

// Static variables for sound callback
static int mod_start = 0;
static int mod_size = 0;
static unsigned int audio_sample_buffer[AUDIO_SAMPLE_BUFFER_SIZE];

// Function to reset sound callback's static variables
void reset_sound_callback()
{
    mod_start = 0;
    mod_size = 0;
}

// Sound callback function
void *sound_callback(snd_stream_hnd_t hnd, int size, int *size_out)
{
    unsigned int *dest = audio_sample_buffer;
    unsigned int *src;
    int out = 0;

    src = audio_sample_buffer + mod_start / 4;
    for (int i = 0; i < mod_size / 4; i++)
        *dest++ = *src++;
    out += mod_size;

    while (size > out)
    {
        plm_samples_t *sample = plm_decode_audio(plm);

        if (sample == NULL)
        {
            reset_sound_callback(); // Reset static variables when audio ends
            break;
        }

        src = (unsigned int *)sample->pcm;
        for (int i = 0; i < 1152 / 2; i++)
            *dest++ = *src++;
        out += 1152 * 2;
    }

    mod_start = size;
    mod_size = out - size;
    *size_out = size;

    return (void *)audio_sample_buffer;
}


int Mpeg1Play(const char *filename, unsigned int buttons)
{
    int cancel = 0;

    plm = plm_create_with_filename(filename);
    if (!plm)
        return -1;
    texture = pvr_mem_malloc(512 * 256 * 2);
    width = plm_get_width(plm);
    height = plm_get_height(plm);

    /* Set SQ to YUV converter. */
    PVR_SET(PVR_YUV_ADDR, (((unsigned int)texture) & 0xffffff));
    // Divide texture width and texture height by 16 and subtract 1.
    // The actual values to set are 1, 3, 7, 15, 31, 63.
    PVR_SET(PVR_YUV_CFG_1, (((MPEG1_TEXTURE_HEIGHT / 16) - 1) << 8) | ((MPEG1_TEXTURE_WIDTH / 16) - 1));
    PVR_GET(PVR_YUV_CFG_1);

    /* First frame */
    plm_frame_t *frame = plm_decode_video(plm);
    float start_time = (float)timer_ms_gettime64() / 1000.0;
    float playing_time = 0.0f;
    float frame_time = 1.0f / (float)plm_get_framerate(plm);
    int decoded = 1;
    reset_sound_callback();
    /* Init sound stream. */
    int samplerate = plm_get_samplerate(plm);
    snd_hnd = snd_stream_alloc(sound_callback, 0x10000);
    snd_stream_volume(snd_hnd, 0xff);
    snd_stream_queue_enable(snd_hnd);
    snd_stream_start(snd_hnd, samplerate, 0);
    snd_stream_queue_go(snd_hnd);

    while (!cancel)
    {
        /* Check cancel buttons. */
        if (buttons)
        {
            MAPLE_FOREACH_BEGIN(MAPLE_FUNC_CONTROLLER, cont_state_t, st)
            if ((st->buttons & buttons) == buttons)
                cancel = 1;
            MAPLE_FOREACH_END()
        }

        /* Decode */
        playing_time = ((float)timer_ms_gettime64() / 1000.0) - start_time;
        if ((frame->time - playing_time) < frame_time)
        {
            frame = plm_decode_video(plm);
            if (!frame)
                break;
            decoded = 1;
        }
        snd_stream_poll(snd_hnd);

        /* Render */
        pvr_wait_ready();
        pvr_scene_begin();
        if (decoded)
        {
            app_on_video(plm, frame, 0);
            decoded = 0;
        }
        pvr_list_begin(PVR_LIST_OP_POLY);
        display_draw();
        pvr_list_finish();
        pvr_scene_finish();
    }
    reset_sound_callback();
    plm_destroy(plm);
    pvr_mem_free(texture);
    snd_stream_destroy(snd_hnd);

    return 0;
}
example.c

Code: Select all

#include <kos.h>
#include <string.h>
#include <stdio.h>
#include <arch/arch.h>
#include "mpeg1.h"

/* romdisk */
extern uint8 romdisk_boot[];
KOS_INIT_ROMDISK(romdisk_boot);



int main(void)
{

    pvr_init_defaults();
    snd_stream_init();

    Mpeg1Play("/cd/zample.mpg", CONT_START);
    //Ian micheal now exits at the end of video
    snd_stream_shutdown();
    spu_disable(); // Disable the Sound Processing Unit (SPU).
    arch_exit(); // Perform system-specific exit operations.
    return 0;
}
Names starting with Z are the fastest when dummied.
Before these changes the music would always complete first. Ok still a few places it goes out of sync but much better https://streamable.com/qtn6s4 .. I have done the ring buffer thing before i will see what i can do with that.. Threading did not make it better i tried and it made it crash all the time.. 5 hours wasted!
I will leave your version and not update it till you say so i made a folder with the work today now exits to dcload serial when the video ends it did not before.
https://github.com/ianmicheal/MPEG1-Dec ... updates%5D marked where the changes are in this folder.
Developing a cdrom/gdrom benchmark tool which will show you all speeds of all files on the disc almost done..It benchmarks the disc captures the log to the vmu and can read back with the pvr log viewer with scrolling..
Toolmenu https://streamable.com/5ub9iz
Pvr vmu log viewer https://streamable.com/eb2sp9
Benchmark menu https://streamable.com/lrn7av
It will load the texture of the game benchmark then save to the vmu..
I did this to see speed on a cdr where the best place and names are for media files..There is a very big change depending on how you create and order the files.

I think it's very good! Are you not using the snd_buf array anymore?
I also saw the Matrix trailer. Ah, so nostalgic. It's definitely slowing down. From what I've seen, it looks like the processing can't keep up where scenes are rapidly changing.
Should I skip frames when a delay occurs? I think it is the file reading that is slow, so perhaps there is room to improve the file reading functions (plm_buffer etc.) in the future. It would be great if I could use something like GDDMA...
Your 5 hours were for us. thank you!

If it is updated, could I also ask for changes to the cancel button processing in mpeg.c?

Code: Select all

/* Check cancel buttons. */
MAPLE_FOREACH_BEGIN(MAPLE_FUNC_CONTROLLER, cont_state_t, st)
if (buttons && ((st->buttons & buttons) == buttons))
   cancel = 1; /* Push cancel buttons */
if (st->buttons == 0x60e)
   cancel = 2; /* ABXY + START (Software reset) */
MAPLE_FOREACH_END()
...
...
return cancel;
If you return cancel as a return, you will be able to know the reason when Mpeg1Play ends.

However, it is surprising that there is such a difference in disk reading speed. Your tools are very interesting.
These users thanked the author Twada for the post (total 2):
Ian RobinsonGyroVorbis
User avatar
Ian Robinson
DC Developer
DC Developer
Posts: 116
Joined: Mon Mar 11, 2019 7:12 am
Has thanked: 209 times
Been thanked: 41 times

Re: pl_mpegDC ported running but community help needed

Post by Ian Robinson »

Implemented a ringbuffer version

Code: Select all

#include <kos.h>
#define PL_MPEG_IMPLEMENTATION
#include "pl_mpeg.h"
#include "mpeg1.h"

static plm_t *plm;

/* textures */
static pvr_ptr_t texture;
static int width, height;
// Output texture width and height initial values
// You can choose from 32, 64, 128, 256, 512, 1024
#define MPEG1_TEXTURE_WIDTH 512
#define MPEG1_TEXTURE_HEIGHT 256

snd_stream_hnd_t snd_hnd;
__attribute__((aligned(32))) unsigned int snd_buf[0x10000 / 4];

// Structure to represent a video frame
typedef struct {
    plm_frame_t *frame;
} VideoFrame;
//Ian micheal Implemented a ringbuffer version
// Ring buffer to hold video frames
#define RING_BUFFER_SIZE 10
static VideoFrame ringBuffer[RING_BUFFER_SIZE];
static int ringBufferHead = 0;
static int ringBufferTail = 0;

// Function to initialize the ring buffer
void initRingBuffer() {
    ringBufferHead = 0;
    ringBufferTail = 0;
    memset(ringBuffer, 0, sizeof(ringBuffer));
}

// Function to enqueue a video frame into the ring buffer
void enqueueFrame(plm_frame_t *frame) {
    if ((ringBufferHead + 1) % RING_BUFFER_SIZE != ringBufferTail) {
        ringBuffer[ringBufferHead].frame = frame;
        ringBufferHead = (ringBufferHead + 1) % RING_BUFFER_SIZE;
    }
}

// Function to dequeue a video frame from the ring buffer
plm_frame_t *dequeueFrame() {
    plm_frame_t *frame = NULL;
    if (ringBufferHead != ringBufferTail) {
        frame = ringBuffer[ringBufferTail].frame;
        ringBufferTail = (ringBufferTail + 1) % RING_BUFFER_SIZE;
    }
    return frame;
}

void display_draw(void)
{
    pvr_poly_cxt_t cxt;
    pvr_poly_hdr_t hdr;
    pvr_vertex_t vert;
    float u = (float)width / (float)MPEG1_TEXTURE_WIDTH;
    float v = (float)height / (float)MPEG1_TEXTURE_HEIGHT;

    pvr_poly_cxt_txr(&cxt, PVR_LIST_OP_POLY, PVR_TXRFMT_YUV422 | PVR_TXRFMT_NONTWIDDLED, MPEG1_TEXTURE_WIDTH, MPEG1_TEXTURE_HEIGHT, texture, PVR_FILTER_BILINEAR);
    pvr_poly_compile(&hdr, &cxt);

    // hdr.mode3 |= 0x02000000; /* stride */
    pvr_prim(&hdr, sizeof(hdr));

    vert.argb = PVR_PACK_COLOR(1.0f, 1.0f, 1.0f, 1.0f);
    vert.oargb = 0;
    vert.flags = PVR_CMD_VERTEX;

    vert.x = 1;
    vert.y = 1;
    vert.z = 1;
    vert.u = 0.0f;
    vert.v = 0.0f;
    pvr_prim(&vert, sizeof(vert));

    vert.x = 640;
    vert.y = 1;
    vert.z = 1;
    vert.u = u;
    vert.v = 0.0;
    pvr_prim(&vert, sizeof(vert));

    vert.x = 1;
    vert.y = 480;
    vert.z = 1;
    vert.u = 0.0f;
    vert.v = v;
    pvr_prim(&vert, sizeof(vert));

    vert.x = 640;
    vert.y = 480;
    vert.z = 1;
    vert.u = u;
    vert.v = v;
    vert.flags = PVR_CMD_VERTEX_EOL;
    pvr_prim(&vert, sizeof(vert));
}

void app_on_video(plm_t *mpeg, plm_frame_t *frame, void *user)
{
    unsigned int *dest = (unsigned int *)texture;
    unsigned int *src = (unsigned int *)frame->display;

    volatile unsigned int *d = (volatile unsigned int *)0xa05f8148;
    volatile unsigned int *cfg = (volatile unsigned int *)0xa05f814c;

    volatile unsigned int *stride_reg = (volatile unsigned int *)0xa05f80e4;
    int stride_value;
    int stride = 0;

    int x, y, w, h, i;

    if (!frame)
        return;

    /* set frame size. */
    w = frame->width >> 4;
    h = frame->height >> 4;
    stride_value = (w >> 1); /* 16 pixel / 2 */

    /* Set Stride value. */
    *stride_reg &= 0xffffffe0;
    *stride_reg |= stride_value & 0x01f;

    /* Set SQ to YUV converter. */
    *d = ((unsigned int)dest) & 0xffffff;
    *cfg = 0x00000f1f;
    x = *cfg; /* read on once */

    for (y = 0; y < h; y++)
    {
        for (x = 0; x < w; x++, src += 96)
        {
            sq_cpy((void *)0x10800000, (void *)src, 384);
        }
        if (!stride)
        {
            /* Send dummy mb */
            for (i = 0; i < 32 - w; i++)
            {
                sq_set((void *)0x10800000, 0, 384);
            }
        }
    }
    for (i = 0; i < 16 - h; i++)
    {
        if (!stride)
            sq_set((void *)0x10800000, 0, 384 * 32);
        else
            sq_set((void *)0x10800000, 0, 384 * w);
    }
}

// Define a buffer for audio samples
#define AUDIO_SAMPLE_BUFFER_SIZE (1152 * 2 * 10) // Adjust the size as needed

// Static variables for sound callback
static int mod_start = 0;
static int mod_size = 0;
static unsigned int audio_sample_buffer[AUDIO_SAMPLE_BUFFER_SIZE];
 //Ian micheal added call back sound reset and buffer
// Function to reset sound callback's static variables
void reset_sound_callback()
{
    mod_start = 0;
    mod_size = 0;
}

// Sound callback function
void *sound_callback(snd_stream_hnd_t hnd, int size, int *size_out)
{
    unsigned int *dest = audio_sample_buffer;
    unsigned int *src;
    int out = 0;

    src = audio_sample_buffer + mod_start / 4;
    for (int i = 0; i < mod_size / 4; i++)
        *dest++ = *src++;
    out += mod_size;

    while (size > out)
    {
        plm_samples_t *sample = plm_decode_audio(plm);

        if (sample == NULL)
        {
            reset_sound_callback(); // Reset static variables when audio ends
            break;
        }

        src = (unsigned int *)sample->pcm;
        for (int i = 0; i < 1152 / 2; i++)
            *dest++ = *src++;
        out += 1152 * 2;
    }

    mod_start = size;
    mod_size = out - size;
    *size_out = size;

    return (void *)audio_sample_buffer;
}

int Mpeg1Play(const char *filename, unsigned int buttons)
{
    int cancel = 0;

    plm = plm_create_with_filename(filename);
    if (!plm)
        return -1;
    texture = pvr_mem_malloc(512 * 256 * 2);
    width = plm_get_width(plm);
    height = plm_get_height(plm);

    // Initialize the ring buffer
    initRingBuffer();

    /* Set SQ to YUV converter. */
    PVR_SET(PVR_YUV_ADDR, (((unsigned int)texture) & 0xffffff));
    // Divide texture width and texture height by 16 and subtract 1.
    // The actual values to set are 1, 3, 7, 15, 31, 63.
    PVR_SET(PVR_YUV_CFG_1, (((MPEG1_TEXTURE_HEIGHT / 16) - 1) << 8) | ((MPEG1_TEXTURE_WIDTH / 16) - 1));
    PVR_GET(PVR_YUV_CFG_1);

    /* First frame */
    plm_frame_t *frame = plm_decode_video(plm);
    float start_time = (float)timer_ms_gettime64() / 1000.0;
    float playing_time = 0.0f;
    float frame_time = 1.0f / (float)plm_get_framerate(plm);
    int decoded = 1;
    //Ian micheal added call back sound reset and buffer
    reset_sound_callback();
    /* Init sound stream. */
    int samplerate = plm_get_samplerate(plm);
    snd_hnd = snd_stream_alloc(sound_callback, 0x10000);
    snd_stream_volume(snd_hnd, 0xff);
    snd_stream_queue_enable(snd_hnd);
    snd_stream_start(snd_hnd, samplerate, 0);
    snd_stream_queue_go(snd_hnd);

    while (!cancel)
    {
        /* Check cancel buttons. */
        if (buttons)
        {
            MAPLE_FOREACH_BEGIN(MAPLE_FUNC_CONTROLLER, cont_state_t, st)
            if ((st->buttons & buttons) == buttons)
                cancel = 1;
            MAPLE_FOREACH_END()
        }

        /* Decode */
        playing_time = ((float)timer_ms_gettime64() / 1000.0) - start_time;
        if ((frame->time - playing_time) < frame_time)
        {
            frame = plm_decode_video(plm);
            if (!frame)
                break;
            decoded = 1;
            // Enqueue the frame into the ring buffer
            enqueueFrame(frame);
        }
        snd_stream_poll(snd_hnd);

        /* Render */
        pvr_wait_ready();
        pvr_scene_begin();
        if (decoded)
        {
            frame = dequeueFrame();
            if (frame) {
                app_on_video(plm, frame, 0);
            }
            decoded = 0;
        }
        pvr_list_begin(PVR_LIST_OP_POLY);
        display_draw();
        pvr_list_finish();
        pvr_scene_finish();
    }
     //Ian micheal added call back sound reset and buffer
    reset_sound_callback();
    plm_destroy(plm);
    pvr_mem_free(texture);
    snd_stream_destroy(snd_hnd);

    return 0;
}
working about the same but slightly better :)
https://github.com/ianmicheal/MPEG1-Dec ... ngbuffer.c
Twada
DC Developer
DC Developer
Posts: 42
Joined: Wed Jan 20, 2016 4:55 am
Has thanked: 18 times
Been thanked: 53 times

Re: pl_mpegDC ported running but community help needed

Post by Twada »

Ian Robinson wrote: Fri Sep 22, 2023 5:10 pm Implemented a ringbuffer version

Code: Select all

#include <kos.h>
#define PL_MPEG_IMPLEMENTATION
#include "pl_mpeg.h"
#include "mpeg1.h"

static plm_t *plm;

/* textures */
static pvr_ptr_t texture;
static int width, height;
// Output texture width and height initial values
// You can choose from 32, 64, 128, 256, 512, 1024
#define MPEG1_TEXTURE_WIDTH 512
#define MPEG1_TEXTURE_HEIGHT 256

snd_stream_hnd_t snd_hnd;
__attribute__((aligned(32))) unsigned int snd_buf[0x10000 / 4];

// Structure to represent a video frame
typedef struct {
    plm_frame_t *frame;
} VideoFrame;
//Ian micheal Implemented a ringbuffer version
// Ring buffer to hold video frames
#define RING_BUFFER_SIZE 10
static VideoFrame ringBuffer[RING_BUFFER_SIZE];
static int ringBufferHead = 0;
static int ringBufferTail = 0;

// Function to initialize the ring buffer
void initRingBuffer() {
    ringBufferHead = 0;
    ringBufferTail = 0;
    memset(ringBuffer, 0, sizeof(ringBuffer));
}

// Function to enqueue a video frame into the ring buffer
void enqueueFrame(plm_frame_t *frame) {
    if ((ringBufferHead + 1) % RING_BUFFER_SIZE != ringBufferTail) {
        ringBuffer[ringBufferHead].frame = frame;
        ringBufferHead = (ringBufferHead + 1) % RING_BUFFER_SIZE;
    }
}

// Function to dequeue a video frame from the ring buffer
plm_frame_t *dequeueFrame() {
    plm_frame_t *frame = NULL;
    if (ringBufferHead != ringBufferTail) {
        frame = ringBuffer[ringBufferTail].frame;
        ringBufferTail = (ringBufferTail + 1) % RING_BUFFER_SIZE;
    }
    return frame;
}

void display_draw(void)
{
    pvr_poly_cxt_t cxt;
    pvr_poly_hdr_t hdr;
    pvr_vertex_t vert;
    float u = (float)width / (float)MPEG1_TEXTURE_WIDTH;
    float v = (float)height / (float)MPEG1_TEXTURE_HEIGHT;

    pvr_poly_cxt_txr(&cxt, PVR_LIST_OP_POLY, PVR_TXRFMT_YUV422 | PVR_TXRFMT_NONTWIDDLED, MPEG1_TEXTURE_WIDTH, MPEG1_TEXTURE_HEIGHT, texture, PVR_FILTER_BILINEAR);
    pvr_poly_compile(&hdr, &cxt);

    // hdr.mode3 |= 0x02000000; /* stride */
    pvr_prim(&hdr, sizeof(hdr));

    vert.argb = PVR_PACK_COLOR(1.0f, 1.0f, 1.0f, 1.0f);
    vert.oargb = 0;
    vert.flags = PVR_CMD_VERTEX;

    vert.x = 1;
    vert.y = 1;
    vert.z = 1;
    vert.u = 0.0f;
    vert.v = 0.0f;
    pvr_prim(&vert, sizeof(vert));

    vert.x = 640;
    vert.y = 1;
    vert.z = 1;
    vert.u = u;
    vert.v = 0.0;
    pvr_prim(&vert, sizeof(vert));

    vert.x = 1;
    vert.y = 480;
    vert.z = 1;
    vert.u = 0.0f;
    vert.v = v;
    pvr_prim(&vert, sizeof(vert));

    vert.x = 640;
    vert.y = 480;
    vert.z = 1;
    vert.u = u;
    vert.v = v;
    vert.flags = PVR_CMD_VERTEX_EOL;
    pvr_prim(&vert, sizeof(vert));
}

void app_on_video(plm_t *mpeg, plm_frame_t *frame, void *user)
{
    unsigned int *dest = (unsigned int *)texture;
    unsigned int *src = (unsigned int *)frame->display;

    volatile unsigned int *d = (volatile unsigned int *)0xa05f8148;
    volatile unsigned int *cfg = (volatile unsigned int *)0xa05f814c;

    volatile unsigned int *stride_reg = (volatile unsigned int *)0xa05f80e4;
    int stride_value;
    int stride = 0;

    int x, y, w, h, i;

    if (!frame)
        return;

    /* set frame size. */
    w = frame->width >> 4;
    h = frame->height >> 4;
    stride_value = (w >> 1); /* 16 pixel / 2 */

    /* Set Stride value. */
    *stride_reg &= 0xffffffe0;
    *stride_reg |= stride_value & 0x01f;

    /* Set SQ to YUV converter. */
    *d = ((unsigned int)dest) & 0xffffff;
    *cfg = 0x00000f1f;
    x = *cfg; /* read on once */

    for (y = 0; y < h; y++)
    {
        for (x = 0; x < w; x++, src += 96)
        {
            sq_cpy((void *)0x10800000, (void *)src, 384);
        }
        if (!stride)
        {
            /* Send dummy mb */
            for (i = 0; i < 32 - w; i++)
            {
                sq_set((void *)0x10800000, 0, 384);
            }
        }
    }
    for (i = 0; i < 16 - h; i++)
    {
        if (!stride)
            sq_set((void *)0x10800000, 0, 384 * 32);
        else
            sq_set((void *)0x10800000, 0, 384 * w);
    }
}

// Define a buffer for audio samples
#define AUDIO_SAMPLE_BUFFER_SIZE (1152 * 2 * 10) // Adjust the size as needed

// Static variables for sound callback
static int mod_start = 0;
static int mod_size = 0;
static unsigned int audio_sample_buffer[AUDIO_SAMPLE_BUFFER_SIZE];
 //Ian micheal added call back sound reset and buffer
// Function to reset sound callback's static variables
void reset_sound_callback()
{
    mod_start = 0;
    mod_size = 0;
}

// Sound callback function
void *sound_callback(snd_stream_hnd_t hnd, int size, int *size_out)
{
    unsigned int *dest = audio_sample_buffer;
    unsigned int *src;
    int out = 0;

    src = audio_sample_buffer + mod_start / 4;
    for (int i = 0; i < mod_size / 4; i++)
        *dest++ = *src++;
    out += mod_size;

    while (size > out)
    {
        plm_samples_t *sample = plm_decode_audio(plm);

        if (sample == NULL)
        {
            reset_sound_callback(); // Reset static variables when audio ends
            break;
        }

        src = (unsigned int *)sample->pcm;
        for (int i = 0; i < 1152 / 2; i++)
            *dest++ = *src++;
        out += 1152 * 2;
    }

    mod_start = size;
    mod_size = out - size;
    *size_out = size;

    return (void *)audio_sample_buffer;
}

int Mpeg1Play(const char *filename, unsigned int buttons)
{
    int cancel = 0;

    plm = plm_create_with_filename(filename);
    if (!plm)
        return -1;
    texture = pvr_mem_malloc(512 * 256 * 2);
    width = plm_get_width(plm);
    height = plm_get_height(plm);

    // Initialize the ring buffer
    initRingBuffer();

    /* Set SQ to YUV converter. */
    PVR_SET(PVR_YUV_ADDR, (((unsigned int)texture) & 0xffffff));
    // Divide texture width and texture height by 16 and subtract 1.
    // The actual values to set are 1, 3, 7, 15, 31, 63.
    PVR_SET(PVR_YUV_CFG_1, (((MPEG1_TEXTURE_HEIGHT / 16) - 1) << 8) | ((MPEG1_TEXTURE_WIDTH / 16) - 1));
    PVR_GET(PVR_YUV_CFG_1);

    /* First frame */
    plm_frame_t *frame = plm_decode_video(plm);
    float start_time = (float)timer_ms_gettime64() / 1000.0;
    float playing_time = 0.0f;
    float frame_time = 1.0f / (float)plm_get_framerate(plm);
    int decoded = 1;
    //Ian micheal added call back sound reset and buffer
    reset_sound_callback();
    /* Init sound stream. */
    int samplerate = plm_get_samplerate(plm);
    snd_hnd = snd_stream_alloc(sound_callback, 0x10000);
    snd_stream_volume(snd_hnd, 0xff);
    snd_stream_queue_enable(snd_hnd);
    snd_stream_start(snd_hnd, samplerate, 0);
    snd_stream_queue_go(snd_hnd);

    while (!cancel)
    {
        /* Check cancel buttons. */
        if (buttons)
        {
            MAPLE_FOREACH_BEGIN(MAPLE_FUNC_CONTROLLER, cont_state_t, st)
            if ((st->buttons & buttons) == buttons)
                cancel = 1;
            MAPLE_FOREACH_END()
        }

        /* Decode */
        playing_time = ((float)timer_ms_gettime64() / 1000.0) - start_time;
        if ((frame->time - playing_time) < frame_time)
        {
            frame = plm_decode_video(plm);
            if (!frame)
                break;
            decoded = 1;
            // Enqueue the frame into the ring buffer
            enqueueFrame(frame);
        }
        snd_stream_poll(snd_hnd);

        /* Render */
        pvr_wait_ready();
        pvr_scene_begin();
        if (decoded)
        {
            frame = dequeueFrame();
            if (frame) {
                app_on_video(plm, frame, 0);
            }
            decoded = 0;
        }
        pvr_list_begin(PVR_LIST_OP_POLY);
        display_draw();
        pvr_list_finish();
        pvr_scene_finish();
    }
     //Ian micheal added call back sound reset and buffer
    reset_sound_callback();
    plm_destroy(plm);
    pvr_mem_free(texture);
    snd_stream_destroy(snd_hnd);

    return 0;
}
working about the same but slightly better :)
https://github.com/ianmicheal/MPEG1-Dec ... ngbuffer.c
Oh, cool ring buffer!
However, pl_mpeg only has a three frame buffer internally.
forward, backward, and current. pl_mpeg uses these three buffers interchangeably.
This order is the reference order, not the playback order. B frames are not referenced, so they never go forward and backward.
Therefore, if you hold a pointer in a ring buffer, the contents will be overwritten.
When implementing a ring buffer, I think you have to create a new buffer and copy its contents.
These users thanked the author Twada for the post:
Ian Robinson
User avatar
Ian Robinson
DC Developer
DC Developer
Posts: 116
Joined: Mon Mar 11, 2019 7:12 am
Has thanked: 209 times
Been thanked: 41 times

Re: pl_mpegDC ported running but community help needed

Post by Ian Robinson »

Twada wrote: Fri Sep 22, 2023 6:04 pm
Ian Robinson wrote: Fri Sep 22, 2023 5:10 pm Implemented a ringbuffer version

Code: Select all

#include <kos.h>
#define PL_MPEG_IMPLEMENTATION
#include "pl_mpeg.h"
#include "mpeg1.h"

static plm_t *plm;

/* textures */
static pvr_ptr_t texture;
static int width, height;
// Output texture width and height initial values
// You can choose from 32, 64, 128, 256, 512, 1024
#define MPEG1_TEXTURE_WIDTH 512
#define MPEG1_TEXTURE_HEIGHT 256

snd_stream_hnd_t snd_hnd;
__attribute__((aligned(32))) unsigned int snd_buf[0x10000 / 4];

// Structure to represent a video frame
typedef struct {
    plm_frame_t *frame;
} VideoFrame;
//Ian micheal Implemented a ringbuffer version
// Ring buffer to hold video frames
#define RING_BUFFER_SIZE 10
static VideoFrame ringBuffer[RING_BUFFER_SIZE];
static int ringBufferHead = 0;
static int ringBufferTail = 0;

// Function to initialize the ring buffer
void initRingBuffer() {
    ringBufferHead = 0;
    ringBufferTail = 0;
    memset(ringBuffer, 0, sizeof(ringBuffer));
}

// Function to enqueue a video frame into the ring buffer
void enqueueFrame(plm_frame_t *frame) {
    if ((ringBufferHead + 1) % RING_BUFFER_SIZE != ringBufferTail) {
        ringBuffer[ringBufferHead].frame = frame;
        ringBufferHead = (ringBufferHead + 1) % RING_BUFFER_SIZE;
    }
}

// Function to dequeue a video frame from the ring buffer
plm_frame_t *dequeueFrame() {
    plm_frame_t *frame = NULL;
    if (ringBufferHead != ringBufferTail) {
        frame = ringBuffer[ringBufferTail].frame;
        ringBufferTail = (ringBufferTail + 1) % RING_BUFFER_SIZE;
    }
    return frame;
}

void display_draw(void)
{
    pvr_poly_cxt_t cxt;
    pvr_poly_hdr_t hdr;
    pvr_vertex_t vert;
    float u = (float)width / (float)MPEG1_TEXTURE_WIDTH;
    float v = (float)height / (float)MPEG1_TEXTURE_HEIGHT;

    pvr_poly_cxt_txr(&cxt, PVR_LIST_OP_POLY, PVR_TXRFMT_YUV422 | PVR_TXRFMT_NONTWIDDLED, MPEG1_TEXTURE_WIDTH, MPEG1_TEXTURE_HEIGHT, texture, PVR_FILTER_BILINEAR);
    pvr_poly_compile(&hdr, &cxt);

    // hdr.mode3 |= 0x02000000; /* stride */
    pvr_prim(&hdr, sizeof(hdr));

    vert.argb = PVR_PACK_COLOR(1.0f, 1.0f, 1.0f, 1.0f);
    vert.oargb = 0;
    vert.flags = PVR_CMD_VERTEX;

    vert.x = 1;
    vert.y = 1;
    vert.z = 1;
    vert.u = 0.0f;
    vert.v = 0.0f;
    pvr_prim(&vert, sizeof(vert));

    vert.x = 640;
    vert.y = 1;
    vert.z = 1;
    vert.u = u;
    vert.v = 0.0;
    pvr_prim(&vert, sizeof(vert));

    vert.x = 1;
    vert.y = 480;
    vert.z = 1;
    vert.u = 0.0f;
    vert.v = v;
    pvr_prim(&vert, sizeof(vert));

    vert.x = 640;
    vert.y = 480;
    vert.z = 1;
    vert.u = u;
    vert.v = v;
    vert.flags = PVR_CMD_VERTEX_EOL;
    pvr_prim(&vert, sizeof(vert));
}

void app_on_video(plm_t *mpeg, plm_frame_t *frame, void *user)
{
    unsigned int *dest = (unsigned int *)texture;
    unsigned int *src = (unsigned int *)frame->display;

    volatile unsigned int *d = (volatile unsigned int *)0xa05f8148;
    volatile unsigned int *cfg = (volatile unsigned int *)0xa05f814c;

    volatile unsigned int *stride_reg = (volatile unsigned int *)0xa05f80e4;
    int stride_value;
    int stride = 0;

    int x, y, w, h, i;

    if (!frame)
        return;

    /* set frame size. */
    w = frame->width >> 4;
    h = frame->height >> 4;
    stride_value = (w >> 1); /* 16 pixel / 2 */

    /* Set Stride value. */
    *stride_reg &= 0xffffffe0;
    *stride_reg |= stride_value & 0x01f;

    /* Set SQ to YUV converter. */
    *d = ((unsigned int)dest) & 0xffffff;
    *cfg = 0x00000f1f;
    x = *cfg; /* read on once */

    for (y = 0; y < h; y++)
    {
        for (x = 0; x < w; x++, src += 96)
        {
            sq_cpy((void *)0x10800000, (void *)src, 384);
        }
        if (!stride)
        {
            /* Send dummy mb */
            for (i = 0; i < 32 - w; i++)
            {
                sq_set((void *)0x10800000, 0, 384);
            }
        }
    }
    for (i = 0; i < 16 - h; i++)
    {
        if (!stride)
            sq_set((void *)0x10800000, 0, 384 * 32);
        else
            sq_set((void *)0x10800000, 0, 384 * w);
    }
}

// Define a buffer for audio samples
#define AUDIO_SAMPLE_BUFFER_SIZE (1152 * 2 * 10) // Adjust the size as needed

// Static variables for sound callback
static int mod_start = 0;
static int mod_size = 0;
static unsigned int audio_sample_buffer[AUDIO_SAMPLE_BUFFER_SIZE];
 //Ian micheal added call back sound reset and buffer
// Function to reset sound callback's static variables
void reset_sound_callback()
{
    mod_start = 0;
    mod_size = 0;
}

// Sound callback function
void *sound_callback(snd_stream_hnd_t hnd, int size, int *size_out)
{
    unsigned int *dest = audio_sample_buffer;
    unsigned int *src;
    int out = 0;

    src = audio_sample_buffer + mod_start / 4;
    for (int i = 0; i < mod_size / 4; i++)
        *dest++ = *src++;
    out += mod_size;

    while (size > out)
    {
        plm_samples_t *sample = plm_decode_audio(plm);

        if (sample == NULL)
        {
            reset_sound_callback(); // Reset static variables when audio ends
            break;
        }

        src = (unsigned int *)sample->pcm;
        for (int i = 0; i < 1152 / 2; i++)
            *dest++ = *src++;
        out += 1152 * 2;
    }

    mod_start = size;
    mod_size = out - size;
    *size_out = size;

    return (void *)audio_sample_buffer;
}

int Mpeg1Play(const char *filename, unsigned int buttons)
{
    int cancel = 0;

    plm = plm_create_with_filename(filename);
    if (!plm)
        return -1;
    texture = pvr_mem_malloc(512 * 256 * 2);
    width = plm_get_width(plm);
    height = plm_get_height(plm);

    // Initialize the ring buffer
    initRingBuffer();

    /* Set SQ to YUV converter. */
    PVR_SET(PVR_YUV_ADDR, (((unsigned int)texture) & 0xffffff));
    // Divide texture width and texture height by 16 and subtract 1.
    // The actual values to set are 1, 3, 7, 15, 31, 63.
    PVR_SET(PVR_YUV_CFG_1, (((MPEG1_TEXTURE_HEIGHT / 16) - 1) << 8) | ((MPEG1_TEXTURE_WIDTH / 16) - 1));
    PVR_GET(PVR_YUV_CFG_1);

    /* First frame */
    plm_frame_t *frame = plm_decode_video(plm);
    float start_time = (float)timer_ms_gettime64() / 1000.0;
    float playing_time = 0.0f;
    float frame_time = 1.0f / (float)plm_get_framerate(plm);
    int decoded = 1;
    //Ian micheal added call back sound reset and buffer
    reset_sound_callback();
    /* Init sound stream. */
    int samplerate = plm_get_samplerate(plm);
    snd_hnd = snd_stream_alloc(sound_callback, 0x10000);
    snd_stream_volume(snd_hnd, 0xff);
    snd_stream_queue_enable(snd_hnd);
    snd_stream_start(snd_hnd, samplerate, 0);
    snd_stream_queue_go(snd_hnd);

    while (!cancel)
    {
        /* Check cancel buttons. */
        if (buttons)
        {
            MAPLE_FOREACH_BEGIN(MAPLE_FUNC_CONTROLLER, cont_state_t, st)
            if ((st->buttons & buttons) == buttons)
                cancel = 1;
            MAPLE_FOREACH_END()
        }

        /* Decode */
        playing_time = ((float)timer_ms_gettime64() / 1000.0) - start_time;
        if ((frame->time - playing_time) < frame_time)
        {
            frame = plm_decode_video(plm);
            if (!frame)
                break;
            decoded = 1;
            // Enqueue the frame into the ring buffer
            enqueueFrame(frame);
        }
        snd_stream_poll(snd_hnd);

        /* Render */
        pvr_wait_ready();
        pvr_scene_begin();
        if (decoded)
        {
            frame = dequeueFrame();
            if (frame) {
                app_on_video(plm, frame, 0);
            }
            decoded = 0;
        }
        pvr_list_begin(PVR_LIST_OP_POLY);
        display_draw();
        pvr_list_finish();
        pvr_scene_finish();
    }
     //Ian micheal added call back sound reset and buffer
    reset_sound_callback();
    plm_destroy(plm);
    pvr_mem_free(texture);
    snd_stream_destroy(snd_hnd);

    return 0;
}
working about the same but slightly better :)
https://github.com/ianmicheal/MPEG1-Dec ... ngbuffer.c
Oh, cool ring buffer!
However, pl_mpeg only has a three frame buffer internally.
forward, backward, and current. pl_mpeg uses these three buffers interchangeably.
This order is the reference order, not the playback order. B frames are not referenced, so they never go forward and backward.
Therefore, if you hold a pointer in a ring buffer, the contents will be overwritten.
When implementing a ring buffer, I think you have to create a new buffer and copy its contents.
Right i was just trying it out :) crazy it seem to help..
These users thanked the author Ian Robinson for the post:
GyroVorbis
User avatar
Ian Robinson
DC Developer
DC Developer
Posts: 116
Joined: Mon Mar 11, 2019 7:12 am
Has thanked: 209 times
Been thanked: 41 times

Re: pl_mpegDC ported running but community help needed

Post by Ian Robinson »

Implemented correct texture scaling

Code: Select all

#define UV_EPSILON 0.100f
#define screenWidth 640
#define screenHeight 480
void display_draw(void)
{
    pvr_poly_cxt_t cxt;
    pvr_poly_hdr_t hdr;
    pvr_vertex_t vert;
    float u = (float)width / (float)MPEG1_TEXTURE_WIDTH;
    float v = (float)height / (float)MPEG1_TEXTURE_HEIGHT;

    pvr_poly_cxt_txr(&cxt, PVR_LIST_OP_POLY, PVR_TXRFMT_YUV422 | PVR_TXRFMT_NONTWIDDLED, MPEG1_TEXTURE_WIDTH, MPEG1_TEXTURE_HEIGHT, texture, PVR_FILTER_BILINEAR);
    pvr_poly_compile(&hdr, &cxt);

    // hdr.mode3 |= 0x02000000; /* stride */
    pvr_prim(&hdr, sizeof(hdr));

    vert.argb = PVR_PACK_COLOR(1.0f, 1.0f, 1.0f, 1.0f);
    vert.oargb = 0;
    vert.flags = PVR_CMD_VERTEX;

    vert.x = 1;
    vert.y = 1;
    vert.z = 1;
    vert.u = UV_EPSILON;
    vert.v = UV_EPSILON;
    pvr_prim(&vert, sizeof(vert));

    vert.x = screenWidth;
    vert.y = 1;
    vert.z = 1;
    vert.u = u - UV_EPSILON;
    vert.v = UV_EPSILON;
    pvr_prim(&vert, sizeof(vert));

    vert.x = 1;
    vert.y = screenHeight;
    vert.z = 1;
    vert.u = UV_EPSILON;
    vert.v = v - UV_EPSILON;
    pvr_prim(&vert, sizeof(vert));

    vert.x = screenWidth;
    vert.y = screenHeight;
    vert.z = 1;
    vert.u = u - UV_EPSILON;
    vert.v = v - UV_EPSILON;
    vert.flags = PVR_CMD_VERTEX_EOL;
    pvr_prim(&vert, sizeof(vert));
}
example fixed
demul1 2023-09-24 14-27-42-574.jpg
demul1 2023-09-24 14-27-46-172.jpg
Before squashed
bandicam 2023-09-24 14-30-45-344.jpg
These users thanked the author Ian Robinson for the post (total 2):
TwadaGyroVorbis
User avatar
Ian Robinson
DC Developer
DC Developer
Posts: 116
Joined: Mon Mar 11, 2019 7:12 am
Has thanked: 209 times
Been thanked: 41 times

Re: pl_mpegDC ported running but community help needed

Post by Ian Robinson »

Well i did more profiling and testing found it stays perfect on sync with these settings
bandicam 2023-09-27 17-15-15-785.jpg
Example video 1
https://streamable.com/wo7d47
bandicam 2023-09-27 17-29-17-266.jpg
Example video 2
https://streamable.com/dd5v3s
bandicam 2023-09-27 17-32-49-266.jpg
Example 3 HQ
https://streamable.com/ygtjjh
bandicam 2023-09-27 18-03-02-051.jpg
Updated texture scale now shows the whole screen both sizes in frame..
Other things in this update just throwing things at the wall..
Using 64bit SQ code i have does not make any change i dont think
does not break anything ether.

Code: Select all

#include <kos.h>
#define PL_MPEG_IMPLEMENTATION
#include "pl_mpeg.h"
#include "mpeg1.h"

static plm_t *plm;

/* textures */
static pvr_ptr_t texture;
static int width, height;
// Output texture width and height initial values
// You can choose from 32, 64, 128, 256, 512, 1024
#define MPEG1_TEXTURE_WIDTH 512
#define MPEG1_TEXTURE_HEIGHT 256

snd_stream_hnd_t snd_hnd;
__attribute__((aligned(32))) unsigned int snd_buf[0x10000 / 4];

// Structure to represent a video frame
typedef struct {
    plm_frame_t *frame;
} VideoFrame;
//Ian micheal Implemented a ringbuffer version
// Ring buffer to hold video frames
#define RING_BUFFER_SIZE 20
static VideoFrame ringBuffer[RING_BUFFER_SIZE];
static int ringBufferHead = 0;
static int ringBufferTail = 0;

// Function to initialize the ring buffer
void initRingBuffer() {
    ringBufferHead = 0;
    ringBufferTail = 0;
    memset(ringBuffer, 0, sizeof(ringBuffer));
}

// Function to enqueue a video frame into the ring buffer
void enqueueFrame(plm_frame_t *frame) {
    if ((ringBufferHead + 1) % RING_BUFFER_SIZE != ringBufferTail) {
        ringBuffer[ringBufferHead].frame = frame;
        ringBufferHead = (ringBufferHead + 1) % RING_BUFFER_SIZE;
    }
}

// Function to dequeue a video frame from the ring buffer
plm_frame_t *dequeueFrame() {
    plm_frame_t *frame = NULL;
    if (ringBufferHead != ringBufferTail) {
        frame = ringBuffer[ringBufferTail].frame;
        ringBufferTail = (ringBufferTail + 1) % RING_BUFFER_SIZE;
    }
    return frame;
}
#define UV_EPSILON 0.045f  // Adjust the value as needed
#define screenWidth 640
#define screenHeight 480
void display_draw(void)
{
    pvr_poly_cxt_t cxt;
    pvr_poly_hdr_t hdr;
    pvr_vertex_t vert;
    float u = (float)width / (float)MPEG1_TEXTURE_WIDTH;
    float v = (float)height / (float)MPEG1_TEXTURE_HEIGHT;

    pvr_poly_cxt_txr(&cxt, PVR_LIST_OP_POLY, PVR_TXRFMT_YUV422 | PVR_TXRFMT_NONTWIDDLED, MPEG1_TEXTURE_WIDTH, MPEG1_TEXTURE_HEIGHT, texture, PVR_FILTER_TRILINEAR2);
    pvr_poly_compile(&hdr, &cxt);

    // hdr.mode3 |= 0x02000000; /* stride */
    pvr_prim(&hdr, sizeof(hdr));

    vert.argb = PVR_PACK_COLOR(1.0f, 1.0f, 1.0f, 1.0f);
    vert.oargb = 0;
    vert.flags = PVR_CMD_VERTEX;

    vert.x = 1;
    vert.y = 1;
    vert.z = 1;
    vert.u = UV_EPSILON;
    vert.v = UV_EPSILON;
    pvr_prim(&vert, sizeof(vert));

    vert.x = screenWidth;
    vert.y = 1;
    vert.z = 1;
    vert.u = u - UV_EPSILON;
    vert.v = UV_EPSILON;
    pvr_prim(&vert, sizeof(vert));

    vert.x = 1;
    vert.y = screenHeight;
    vert.z = 1;
    vert.u = UV_EPSILON;
    vert.v = v - UV_EPSILON;
    pvr_prim(&vert, sizeof(vert));

    vert.x = screenWidth;
    vert.y = screenHeight;
    vert.z = 1;
    vert.u = u - UV_EPSILON;
    vert.v = v - UV_EPSILON;
    vert.flags = PVR_CMD_VERTEX_EOL;
    pvr_prim(&vert, sizeof(vert));
}



/* n must be multiple of 64 */
void dc_sq_cpy(void *dest, void *src, int n)
{

  uint32 *sq;
  uint32 *d, *s;
  
  d = (uint32 *)(0xe0000000 | (((uint32)dest) & 0x03ffffe0));
  s = (uint32 *)(src);
  
  
  *((volatile unsigned int*)0xFF000038) = ((((uint32)dest)>>26)<<2)&0x1c;
  *((volatile unsigned int*)0xFF00003C) = ((((uint32)dest)>>26)<<2)&0x1c;
  
  n >>= 6;
  while (n--) 
  {
    // sq0 
    sq = d;
    *sq++ = *s++; *sq++ = *s++;
    *sq++ = *s++; *sq++ = *s++;
    *sq++ = *s++; *sq++ = *s++;
    *sq++ = *s++; *sq++ = *s++;
 	
    __asm__("pref @%0" : : "r" (d));	
    __asm__("ocbi @%0" : : "r" (d));
    d += 8;
    
    // sq1 
    sq = d;
    *sq++ = *s++; *sq++ = *s++;
    *sq++ = *s++; *sq++ = *s++;
    *sq++ = *s++; *sq++ = *s++;
    *sq++ = *s++; *sq++ = *s++;
	
    __asm__("pref @%0" : : "r" (d));	
   __asm__("ocbi @%0" : : "r" (d));
    d += 8;
  }

  *((uint32 *)(0xe0000000)) = 0;
  *((uint32 *)(0xe0000020)) = 0;

}
void app_on_video(plm_t *mpeg, plm_frame_t *frame, void *user)
{
    unsigned int *dest = (unsigned int *)texture;
    unsigned int *src = (unsigned int *)frame->display;

    volatile unsigned int *d = (volatile unsigned int *)0xa05f8148;
    volatile unsigned int *cfg = (volatile unsigned int *)0xa05f814c;

    volatile unsigned int *stride_reg = (volatile unsigned int *)0xa05f80e4;
    int stride_value;
    int stride = 0;

    int x, y, w, h, i;

    if (!frame)
        return;

    /* set frame size. */
    w = frame->width >> 4;
    h = frame->height >> 4;
    stride_value = (w >> 1); /* 16 pixel / 2 */

    /* Set Stride value. */
    *stride_reg &= 0xffffffe0;
    *stride_reg |= stride_value & 0x01f;

    /* Set SQ to YUV converter. */
    *d = ((unsigned int)dest) & 0xffffff;
    *cfg = 0x00000f1f;
    x = *cfg; /* read on once */

    for (y = 0; y < h; y++)
    {
        for (x = 0; x < w; x++, src += 96)
        {
            dc_sq_cpy((void *)0x10800000, (void *)src, 384);
        }
        if (!stride)
        {
            /* Send dummy mb */
            for (i = 0; i < 32 - w; i++)
            {
                sq_set((void *)0x10800000, 0, 384);
            }
        }
    }
    for (i = 0; i < 16 - h; i++)
    {
        if (!stride)
            sq_set((void *)0x10800000, 0, 384 * 32);
        else
            sq_set((void *)0x10800000, 0, 384 * w);
    }
}

// Define a buffer for audio samples
#define AUDIO_SAMPLE_BUFFER_SIZE (1152 * 2 * 10) // Adjust the size as needed

// Static variables for sound callback
static int mod_start = 0;
static int mod_size = 0;
static unsigned int audio_sample_buffer[AUDIO_SAMPLE_BUFFER_SIZE];
 //Ian micheal added call back sound reset and buffer
// Function to reset sound callback's static variables
void reset_sound_callback()
{
    mod_start = 0;
    mod_size = 0;
}

// Sound callback function
// Sound callback function
void *sound_callback(snd_stream_hnd_t hnd, int size, int *size_out)
{
    unsigned int *dest = audio_sample_buffer;
   unsigned int *src = NULL; // Initialize src pointer
    int out = 0;

    // Prefetch the initial 'src' address
    __asm__("pref @%0" : : "r" (src));

    src = audio_sample_buffer + mod_start / 4;
    for (int i = 0; i < mod_size / 4; i++) {
        *dest++ = *src++;
        // Prefetch the next memory location (adjust the distance as needed)
        __asm__("pref @%0" : : "r" (src));
    }
    out += mod_size;

    while (size > out)
    {
        plm_samples_t *sample = plm_decode_audio(plm);

        if (sample == NULL)
        {
            reset_sound_callback(); // Reset static variables when audio ends
            break;
        }

        // Prefetch the initial 'src' address for the audio samples
        __asm__("pref @%0" : : "r" (src));

        src = (unsigned int *)sample->pcm;
        for (int i = 0; i < 1152 / 2; i++) {
            *dest++ = *src++;
            // Prefetch the next memory location (adjust the distance as needed)
            __asm__("pref @%0" : : "r" (src));
        }
        out += 1152 * 2;
    }

    mod_start = size;
    mod_size = out - size;
    *size_out = size;

    return (void *)audio_sample_buffer;
}


int Mpeg1Play(const char *filename, unsigned int buttons)
{
    int cancel = 0;

    plm = plm_create_with_filename(filename);
    if (!plm)
        return -1;
    texture = pvr_mem_malloc(512 * 256 * 2);
    width = plm_get_width(plm);
    height = plm_get_height(plm);

    // Initialize the ring buffer
    initRingBuffer();

    /* Set SQ to YUV converter. */
    PVR_SET(PVR_YUV_ADDR, (((unsigned int)texture) & 0xffffff));
    // Divide texture width and texture height by 16 and subtract 1.
    // The actual values to set are 1, 3, 7, 15, 31, 63.
    PVR_SET(PVR_YUV_CFG_1, (((MPEG1_TEXTURE_HEIGHT / 16) - 1) << 8) | ((MPEG1_TEXTURE_WIDTH / 16) - 1));
    PVR_GET(PVR_YUV_CFG_1);

    /* First frame */
    plm_frame_t *frame = plm_decode_video(plm);
    float start_time = (float)timer_ms_gettime64() / 1000.0;
    float playing_time = 0.0f;
    float frame_time = 1.0f / (float)plm_get_framerate(plm);
    int decoded = 1;
    //Ian micheal added call back sound reset and buffer
    reset_sound_callback();
    /* Init sound stream. */
    int samplerate = plm_get_samplerate(plm);
    snd_hnd = snd_stream_alloc(sound_callback, 0x10000);
    snd_stream_volume(snd_hnd, 0xff);
    snd_stream_queue_enable(snd_hnd);
    snd_stream_start(snd_hnd, samplerate, 0);
    snd_stream_queue_go(snd_hnd);

    while (!cancel)
    {
        /* Check cancel buttons. */
        if (buttons)
        {
    /* Check cancel buttons. */
MAPLE_FOREACH_BEGIN(MAPLE_FUNC_CONTROLLER, cont_state_t, st)
if (buttons && ((st->buttons & buttons) == buttons))
   cancel = 1; /* Push cancel buttons */
if (st->buttons == 0x60e)
   cancel = 2; /* ABXY + START (Software reset) */
MAPLE_FOREACH_END()


        }

        /* Decode */
        playing_time = ((float)timer_ms_gettime64() / 1000.0) - start_time;
        if ((frame->time - playing_time) < frame_time)
        {
            frame = plm_decode_video(plm);
            if (!frame)
                break;
            decoded = 1;
            // Enqueue the frame into the ring buffer
            enqueueFrame(frame);
        }
        snd_stream_poll(snd_hnd);

        /* Render */
        pvr_wait_ready();
        pvr_scene_begin();
        if (decoded)
        {
            frame = dequeueFrame();
            if (frame) {
                app_on_video(plm, frame, 0);
            }
            decoded = 0;
        }
        pvr_list_begin(PVR_LIST_OP_POLY);
        display_draw();
        pvr_list_finish();
        pvr_scene_finish();
    }
     //Ian micheal added call back sound reset and buffer
    reset_sound_callback();
    plm_destroy(plm);
    pvr_mem_free(texture);
    snd_stream_destroy(snd_hnd);
    return cancel;
}
For movies on sync on ffmpeg i used

Code: Select all

ffmpeg -i input.mp4 -vf "scale=320:240" -b:v 642k -ac 1 -ar 44100 -c:a mp2 -b:a 64k -f mpg output.mpeg
I found xilisoft to make better looking at the same bitrate but it was set for cbr so more like this

Code: Select all

ffmpeg -i input.mp4 -vf "scale=320:240" -b:v 642k -minrate 642k -maxrate 642k -bufsize 642k -ac 1 -ar 44100 -c:a mp2 -b:a 64k -f mpeg output.mpg

Ok after many cdrs burned today i found best
video sample
https://streamable.com/leic1n
[code]ffmpeg -i input.mp4 -vf "scale=320:240" -b:v 742k -minrate 742k -maxrate 742k -bufsize 742k -ac 1 -ar 32000 -c:a mp2 -b:a 64k -f mpeg output.mpg
this above is for 24fps best quality so far and on sync

Example video of HQ again OLE tv demo lol
https://streamable.com/35gj9y
These users thanked the author Ian Robinson for the post (total 2):
|darc|Twada
Twada
DC Developer
DC Developer
Posts: 42
Joined: Wed Jan 20, 2016 4:55 am
Has thanked: 18 times
Been thanked: 53 times

Re: pl_mpegDC ported running but community help needed

Post by Twada »

Thank you for your detailed verification.
The 64-byte original store queue is also cool. Please merge anytime.

I realized something important thanks to your sample video.
There seems to be a bug in video decoding. U and V are flickering in YUV. This is especially evident in the Universal logo on the Jurassic Park trailer.
Please wait while we identify the issue...
These users thanked the author Twada for the post:
Ian Robinson
User avatar
Ian Robinson
DC Developer
DC Developer
Posts: 116
Joined: Mon Mar 11, 2019 7:12 am
Has thanked: 209 times
Been thanked: 41 times

Re: pl_mpegDC ported running but community help needed

Post by Ian Robinson »

Twada wrote: Wed Sep 27, 2023 6:36 pm Thank you for your detailed verification.
The 64-byte original store queue is also cool. Please merge anytime.

I realized something important thanks to your sample video.
There seems to be a bug in video decoding. U and V are flickering in YUV. This is especially evident in the Universal logo on the Jurassic Park trailer.
Please wait while we identify the issue...
I did notice that can see it even on the sample video you did but very much not notice-able..
I'm going to profile the code find out more with https://gitlab.com/simulant/dcprof/tree/master

Code: Select all

sh-elf-gprof.exe YOUR.elf gmon.out > gprof.out

Code: Select all

cat gprof.out | gprof2dot | dot -Tpng -o output.png
Just -g and follow the other parts on the repo..
User avatar
Ian Robinson
DC Developer
DC Developer
Posts: 116
Joined: Mon Mar 11, 2019 7:12 am
Has thanked: 209 times
Been thanked: 41 times

Re: pl_mpegDC ported running but community help needed

Post by Ian Robinson »

Ok i did the profiling to see the bottlenecks whats taking the most time..
when it first starts
output.png
When it plays longer
output.png
As it plays longer you can see it gets more heavy
seems strange but i do see it we have to look at this.
These users thanked the author Ian Robinson for the post:
Twada
Twada
DC Developer
DC Developer
Posts: 42
Joined: Wed Jan 20, 2016 4:55 am
Has thanked: 18 times
Been thanked: 53 times

Re: pl_mpegDC ported running but community help needed

Post by Twada »

Ian Robinson wrote: Wed Sep 27, 2023 8:50 pm Ok i did the profiling to see the bottlenecks whats taking the most time..
when it first starts
output.png
When it plays longer
output.png

As it plays longer you can see it gets more heavy
seems strange but i do see it we have to look at this.
I see, this is how profiling can be used! It is very easy to see where the bottleneck is.
We need to fix the problem that slows down when playing videos for a long time. Is there a memory leak occurring somewhere?
Your profiling can help. Please give me some time.


Fixed UV flickering. It was my mistake.
Please replace pl_mpeg.h.
pl_mpeg.h
(144.51 KiB) Downloaded 60 times
These users thanked the author Twada for the post:
Ian Robinson
User avatar
Ian Robinson
DC Developer
DC Developer
Posts: 116
Joined: Mon Mar 11, 2019 7:12 am
Has thanked: 209 times
Been thanked: 41 times

Re: pl_mpegDC ported running but community help needed

Post by Ian Robinson »

Twada wrote: Fri Sep 29, 2023 2:48 am
Ian Robinson wrote: Wed Sep 27, 2023 8:50 pm Ok i did the profiling to see the bottlenecks whats taking the most time..
when it first starts
output.png
When it plays longer
output.png

As it plays longer you can see it gets more heavy
seems strange but i do see it we have to look at this.
I see, this is how profiling can be used! It is very easy to see where the bottleneck is.
We need to fix the problem that slows down when playing videos for a long time. Is there a memory leak occurring somewhere?
Your profiling can help. Please give me some time.


Fixed UV flickering. It was my mistake.
Please replace pl_mpeg.h.
pl_mpeg.h
That fixed it :)

Demo video
https://streamable.com/etk2bo
User avatar
Ian Robinson
DC Developer
DC Developer
Posts: 116
Joined: Mon Mar 11, 2019 7:12 am
Has thanked: 209 times
Been thanked: 41 times

Re: pl_mpegDC ported running but community help needed

Post by Ian Robinson »

I will show known problem with the sh4 target and loop unrolling i can get up to 12% more time just doing loop unrolling by hand.

Dont know if seen this https://github.com/DragonMinded/libdrag ... 34a8ae9c7c

Loop unroll test https://gist.github.com/pcercuei/051c97 ... a2936d600e
bandicam 2023-09-29 19-05-12-098.jpg

I will profile and show it started on it you can see it lower time.

Not sure of a memory leak i have had it run over 30 mins watching a show and it never crashed.
User avatar
Ian Robinson
DC Developer
DC Developer
Posts: 116
Joined: Mon Mar 11, 2019 7:12 am
Has thanked: 209 times
Been thanked: 41 times

Re: pl_mpegDC ported running but community help needed

Post by Ian Robinson »

Ok been optimizing
before
outputbefore.png
after
OptimizedSQoutput.png
I have to do a number of tests and i update the SQCOPY and SQSET

Seeing nice improvement.
These users thanked the author Ian Robinson for the post:
Twada
Twada
DC Developer
DC Developer
Posts: 42
Joined: Wed Jan 20, 2016 4:55 am
Has thanked: 18 times
Been thanked: 53 times

Re: pl_mpegDC ported running but community help needed

Post by Twada »

Fixed to synchronize with audio time.
Once the video lags, it should catch up with the audio.
However, videos without audio are not eligible.
mpeg1dc09.rar
(3.38 MiB) Downloaded 56 times
I decided to unify my handle name to Twada. Because it's complicated...
These users thanked the author Twada for the post:
Ian Robinson
User avatar
Ian Robinson
DC Developer
DC Developer
Posts: 116
Joined: Mon Mar 11, 2019 7:12 am
Has thanked: 209 times
Been thanked: 41 times

Re: pl_mpegDC ported running but community help needed

Post by Ian Robinson »

With my update before been able to watch 1 hour with no sync problems audio with the right encoding.
These users thanked the author Ian Robinson for the post:
|darc|
Post Reply