Skip to content

Commit

Permalink
mpeg: revisit API to make YUV blitting totally external
Browse files Browse the repository at this point in the history
  • Loading branch information
rasky committed Sep 7, 2024
1 parent ebf7401 commit ef14f4a
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 85 deletions.
35 changes: 22 additions & 13 deletions examples/videoplayer/videoplayer.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ int main(void) {
display_init(RESOLUTION_320x240, DEPTH_32_BPP, NUM_DISPLAY, GAMMA_NONE, FILTERS_DISABLED);
dfs_init(DFS_DEFAULT_LOCATION);
rdpq_init();
profile_init();
yuv_init();

audio_init(44100, 4);
mixer_init(8);
Expand All @@ -36,46 +38,47 @@ int main(void) {
assertf(f, "Movie not found!\nInstall wget and ffmpeg to download and encode the sample movie\n");
fclose(f);

mpeg2_t mp2;
mpeg2_open(&mp2, "rom:/movie.m1v", display_get_width(), display_get_height());
mpeg2_t *mp2 = mpeg2_open("rom:/movie.m1v");

// Create a YUV blitter to draw this movie
yuv_blitter_t yuv = yuv_blitter_new_fmv(
mpeg2_get_width(mp2), mpeg2_get_height(mp2), // Video size
display_get_width(), display_get_height(), // Output size
NULL // Colorspace (use default)
);

wav64_t music;
wav64_open(&music, "movie.wav64");

float fps = mpeg2_get_framerate(&mp2);
float fps = mpeg2_get_framerate(mp2);
throttle_init(fps, 0, 8);

mixer_ch_play(0, &music.wave);

debugf("start\n");
int nframes = 0;
display_context_t disp = 0;

while (1) {
mixer_throttle(44100.0f / fps);

if (!mpeg2_next_frame(&mp2))
if (!mpeg2_next_frame(mp2))
break;

disp = display_get();

// rdpq_attach(disp, NULL);
rdpq_attach_clear(disp, NULL);

mpeg2_draw_frame(&mp2, disp);
PROFILE_START(PS_YUV, 0);
yuv_frame_t frame = mpeg2_get_frame(mp2);
yuv_blitter_run(&yuv, &frame);
PROFILE_STOP(PS_YUV, 0);

rdpq_detach_show();

audio_poll();

nframes++;
// uint32_t t1 = TICKS_READ();
// if (TICKS_DISTANCE(t0, t1) > TICKS_PER_SECOND && nframes) {
// float fps = (float)nframes / (float)TICKS_DISTANCE(t0,t1) * TICKS_PER_SECOND;
// debugf("FPS: %.2f\n", fps);
// t0 = t1;
// nframes = 0;
// }

int ret = throttle_wait();
if (ret < 0) {
Expand All @@ -87,5 +90,11 @@ int main(void) {
PROFILE_START(PS_SYNC, 0);
rspq_wait();
PROFILE_STOP(PS_SYNC, 0);

profile_next_frame();
if (nframes % 128 == 0) {
profile_dump();
profile_init();
}
}
}
1 change: 1 addition & 0 deletions include/libdragon.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#include "timer.h"
#include "exception.h"
#include "dir.h"
#include "yuv.h"
#include "mpeg2.h"
#include "throttle.h"
#include "mixer.h"
Expand Down
17 changes: 5 additions & 12 deletions include/mpeg2.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,14 @@
extern "C" {
#endif

typedef struct plm_t plm_t;
typedef struct plm_buffer_t plm_buffer_t;
typedef struct plm_video_t plm_video_t;
typedef struct mpeg2_s mpeg2_t;

typedef struct {
plm_buffer_t *buf;
plm_video_t *v;
void *f;
yuv_blitter_t yuv_blitter;
} mpeg2_t;

void mpeg2_open(mpeg2_t *mp2, const char *fn, int output_width, int output_height);
mpeg2_t* mpeg2_open(const char *fn);
float mpeg2_get_framerate(mpeg2_t *mp2);
int mpeg2_get_width(mpeg2_t *mp2);
int mpeg2_get_height(mpeg2_t *mp2);
bool mpeg2_next_frame(mpeg2_t *mp2);
void mpeg2_draw_frame(mpeg2_t *mp2, display_context_t disp);
yuv_frame_t mpeg2_get_frame(mpeg2_t *mp2);
void mpeg2_rewind(mpeg2_t *mp2);
void mpeg2_close(mpeg2_t *mp2);

Expand Down
22 changes: 12 additions & 10 deletions include/yuv.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,12 @@ yuv_colorspace_t yuv_new_colorspace(float Kr, float Kb, int y0, int yrange, int
*/
color_t yuv_to_rgb(uint8_t y, uint8_t u, uint8_t v, const yuv_colorspace_t *cs);

/** @brief A YUV frame, made of three distinct planes */
typedef struct {
surface_t y; ///< Luminance plane (Y)
surface_t u; ///< Chrominance plane (U)
surface_t v; ///< Chrominance plane (V)
} yuv_frame_t;

/** @brief YUV blitter zoom configuration */
typedef enum {
Expand Down Expand Up @@ -338,14 +344,12 @@ yuv_blitter_t yuv_blitter_new_fmv(int video_width, int video_height,
* attached surface (see #rdpq_attach).
*
* The blitter is configured at creation time with parameters that describe
* where to draw ito the buffer, whether to perform a zoom, etc.
* where to draw into the buffer, whether to perform a zoom, etc.
*
* @param blitter Blitter created by #yuv_blitter_new_fmv or #yuv_blitter_new
* @param yp Y plane
* @param up U plane
* @param vp V plane
* @param frame YUV frame to blit
*/
void yuv_blitter_run(yuv_blitter_t *blitter, surface_t *yp, surface_t *up, surface_t *vp);
void yuv_blitter_run(yuv_blitter_t *blitter, yuv_frame_t *frame);

/**
* @brief Free the memory allocated by a blitter
Expand Down Expand Up @@ -373,9 +377,7 @@ void yuv_blitter_free(yuv_blitter_t *blitter);
*
* For more information on how to use this function, see #rdpq_tex_blit.
*
* @param yp Pointer to the Y plane (must be #FMT_I8)
* @param up Pointer to the U plane (must be #FMT_I8)
* @param vp Pointer to the V plane (must be #FMT_I8)
* @param frame YUV frame to blit
* @param x0 X coordinate where to blit the frame
* @param y0 Y coordinate where to blit the frame
* @param parms Optional blitting parameters (see #rdpq_blitparms_t)
Expand All @@ -387,8 +389,8 @@ void yuv_blitter_free(yuv_blitter_t *blitter);
* @see #yuv_blitter_new
* @see #yuv_blitter_new_fmv
*/
void yuv_tex_blit(surface_t *yp, surface_t *up, surface_t *vp,
float x0, float y0, const rdpq_blitparms_t *parms, const yuv_colorspace_t *cs);
void yuv_tex_blit(yuv_frame_t *frame, float x0, float y0,
const rdpq_blitparms_t *parms, const yuv_colorspace_t *cs);


#ifdef __cplusplus
Expand Down
67 changes: 24 additions & 43 deletions src/video/mpeg2.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@
#include <errno.h>
#include "mpeg1_internal.h"

#define YUV_MODE 1 // 0=CPU, 1=RSP+RDP
typedef struct mpeg2_s {
plm_buffer_t *buf;
plm_video_t *v;
void *f;
} mpeg2_t;

DEFINE_RSP_UCODE(rsp_mpeg1);

Expand Down Expand Up @@ -99,7 +103,8 @@ void rsp_mpeg1_set_quant_matrix(bool intra, const uint8_t quant_mtx[64]) {
#define PL_MPEG_IMPLEMENTATION
#include "pl_mpeg/pl_mpeg.h"

void mpeg2_open(mpeg2_t *mp2, const char *fn, int output_width, int output_height) {
mpeg2_t *mpeg2_open(const char *fn) {
mpeg2_t *mp2 = malloc(sizeof(mpeg2_t));
memset(mp2, 0, sizeof(mpeg2_t));

rsp_mpeg1_init();
Expand All @@ -118,25 +123,19 @@ void mpeg2_open(mpeg2_t *mp2, const char *fn, int output_width, int output_heigh

mp2->v = plm_video_create_with_buffer(mp2->buf, 1);
assert(mp2->v);
return mp2;
}

// Fetch resolution. These calls will automatically decode enough of the
// stream header to acquire these data.
int width = plm_video_get_width(mp2->v);
int height = plm_video_get_height(mp2->v);

debugf("Resolution: %dx%d\n", width, height);

if (YUV_MODE == 1) {
yuv_init();
int mpeg2_get_width(mpeg2_t *mp2) {
return plm_video_get_width(mp2->v);
}

// Create a YUV blitter for this resolution
mp2->yuv_blitter = yuv_blitter_new_fmv(
width, height,
output_width, output_height,
NULL);
}
int mpeg2_get_height(mpeg2_t *mp2) {
return plm_video_get_height(mp2->v);
}

profile_init();
float mpeg2_get_framerate(mpeg2_t *mp2) {
return plm_video_get_framerate(mp2->v);
}

bool mpeg2_next_frame(mpeg2_t *mp2) {
Expand All @@ -150,34 +149,16 @@ void mpeg2_rewind(mpeg2_t *mp2) {
plm_video_rewind(mp2->v);
}

void mpeg2_draw_frame(mpeg2_t *mp2, display_context_t disp) {
PROFILE_START(PS_YUV, 0);
if (YUV_MODE == 0) {
plm_frame_to_rgba(mp2->f, disp->buffer, disp->stride);
} else {
plm_frame_t *frame = mp2->f;
surface_t yp = surface_make_linear(frame->y.data, FMT_I8, frame->width, frame->height);
surface_t cbp = surface_make_linear(frame->cb.data, FMT_I8, frame->width/2, frame->height/2);
surface_t crp = surface_make_linear(frame->cr.data, FMT_I8, frame->width/2, frame->height/2);
yuv_blitter_run(&mp2->yuv_blitter, &yp, &cbp, &crp);
}
PROFILE_STOP(PS_YUV, 0);

static int nframes=0;
profile_next_frame();
if (++nframes % 128 == 0) {
profile_dump();
profile_init();
}
}

float mpeg2_get_framerate(mpeg2_t *mp2) {
return plm_video_get_framerate(mp2->v);
yuv_frame_t mpeg2_get_frame(mpeg2_t *mp2) {
plm_frame_t *frame = mp2->f;
surface_t yp = surface_make_linear(frame->y.data, FMT_I8, frame->width, frame->height);
surface_t cbp = surface_make_linear(frame->cb.data, FMT_I8, frame->width/2, frame->height/2);
surface_t crp = surface_make_linear(frame->cr.data, FMT_I8, frame->width/2, frame->height/2);
return (yuv_frame_t){ .y = yp, .u = cbp, .v = crp };
}

void mpeg2_close(mpeg2_t *mp2) {
plm_video_destroy(mp2->v);
plm_buffer_destroy(mp2->buf);
if (YUV_MODE == 1) yuv_blitter_free(&mp2->yuv_blitter);
memset(mp2, 0, sizeof(mpeg2_t));
free(mp2);
}
16 changes: 9 additions & 7 deletions src/video/yuv.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ void yuv_init(void)
rspq_init();
ovl_yuv = rspq_overlay_register(&rsp_yuv);
yuv_initialized = true;
debugf("YUV initialized %x\n", ovl_yuv);
}

void yuv_close(void)
Expand Down Expand Up @@ -355,16 +354,18 @@ static void yuv_tex_blit_run(int width, int height, float x0, float y0,
__rdpq_tex_blit(&dummy, x0, y0, parms, ltd_yuv2);
}

void yuv_tex_blit(surface_t *yp, surface_t *up, surface_t *vp,
float x0, float y0, const rdpq_blitparms_t *parms, const yuv_colorspace_t *cs)
void yuv_tex_blit(yuv_frame_t *frame, float x0, float y0,
const rdpq_blitparms_t *parms, const yuv_colorspace_t *cs)
{
yuv_tex_blit_setup(yp, up, vp);
yuv_tex_blit_run(yp->width, yp->height, x0, y0, parms, cs);
assertf(yuv_initialized, "yuv not initialized, call yuv_init() first");
yuv_tex_blit_setup(&frame->y, &frame->u, &frame->v);
yuv_tex_blit_run(frame->y.width, frame->y.height, x0, y0, parms, cs);
}

yuv_blitter_t yuv_blitter_new(int video_width, int video_height, float x0, float y0, const rdpq_blitparms_t *parms,
const yuv_colorspace_t *cs)
{
assertf(yuv_initialized, "yuv not initialized, call yuv_init() first");
// Compile the yuv_tex_blit_run into a block with the given parameters.
rspq_block_begin();
yuv_tex_blit_run(video_width, video_height, x0, y0, parms, cs);
Expand All @@ -377,6 +378,7 @@ yuv_blitter_t yuv_blitter_new(int video_width, int video_height, float x0, float
yuv_blitter_t yuv_blitter_new_fmv(int video_width, int video_height,
int screen_width, int screen_height, const yuv_fmv_parms_t *parms)
{
assertf(yuv_initialized, "yuv not initialized, call yuv_init() first");
static const yuv_fmv_parms_t default_parms = {0};
if (!parms) parms = &default_parms;

Expand Down Expand Up @@ -436,9 +438,9 @@ yuv_blitter_t yuv_blitter_new_fmv(int video_width, int video_height,
};
}

void yuv_blitter_run(yuv_blitter_t *blitter, surface_t *yp, surface_t *up, surface_t *vp)
void yuv_blitter_run(yuv_blitter_t *blitter, yuv_frame_t *frame)
{
yuv_tex_blit_setup(yp, up, vp);
yuv_tex_blit_setup(&frame->y, &frame->u, &frame->v);
rspq_block_run(blitter->block);
}

Expand Down

0 comments on commit ef14f4a

Please sign in to comment.