xultz
Posts: 8
Joined: Thu Apr 26, 2018 5:24 pm

Showing YUV frames on the center of the screen

Thu May 10, 2018 5:40 pm

Hi!
I'm trying to show some YUV420 frames on the Rpi screen using dispmanx. I'm using the composite out, with display_rotate=1 on config.txt, so, my screen resolution is 480x720, which is fine. I have frames with 480x640, and after a HUGE help from 6by9, I'm able to show the frames on the screen, sitting them on the top of the screen. I made the following code that loads two frames to the memory, and show them, alternating them with 1 second delay for some times, and exiting gracefully. The code can be seen here: https://pastebin.com/yKTmwt9j , and the frames cand be downloaded here, if anyone is curious about them: https://filebin.net/ofw3pon7tqzqsch6/f1.yuv?t=1grlzmt7 and https://filebin.net/ofw3pon7tqzqsch6/f2.yuv?t=1grlzmt7 .
Since the frame is 80 pixels smaller than the screen on the vertical, the bottom 80 lines of the screen stays black. What I would like to do is show them on the center of screen, so I had to put 40 pixels of offset on the dst_rect. I saw some examples, and it looked like it was just that. But when I change my code to create the dst_rect with something like vc_dispmanx_rect_set( &dst_rect, 0, 40, width, height ); absolutelly nothing works. I tried changing some things randomly on the code, with no luck.
My question is: is it possible to change my code, so I can show the image on the center?
Are there any resource that makes it possible to resize the frame, in order to occupy the entire screen?

Thank you so much for any help!

With best regards
Christian Schultz

6by9
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 5663
Joined: Wed Dec 04, 2013 11:27 am
Location: ZZ9 Plural Z Alpha, aka just outside Cambridge.

Re: Showing YUV frames on the center of the screen

Fri May 11, 2018 10:43 am

You're using dst_rect for two purposes - vc_dispmanx_element_add and vc_dispmanx_resource_write_data.
The rectangle passed to vc_dispmanx_element_add will control where the image is on the screen (I've just checked that).
The rectangle passed to vc_dispmanx_resource_write_data tells it where to write this new block of image data within the image buffer, and that needs to remain as (0,0,width,height)

A very quick hacked version of your code to prove the point (I'm memsetting instead of loading your files). Update disp_rect to move the image around the screen.

Code: Select all

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
#include <unistd.h>
#include <sys/time.h>
 
#include "bcm_host.h"
 
#define WIDTH   480
#define HEIGHT  640
 
#ifndef ALIGN_UP
#define ALIGN_UP(x,y)  ((x + (y)-1) & ~((y)-1))
#endif
 
int main(void)
{    
    uint32_t screen = 0;
    int ret;
 
    DISPMANX_DISPLAY_HANDLE_T display;      // Esse display será aberto por vc_dispmanx_display_open()
    DISPMANX_MODEINFO_T info;               // Esta estrutura será preenchida pelo comando vc_dispmanx_display_get_info()
    DISPMANX_RESOURCE_HANDLE_T resource;    // Este handle é obtido pelo comando vc_dispmanx_resource_create()
    DISPMANX_UPDATE_HANDLE_T update;        // Este handle é obtido pelo comando vc_dispmanx_update_start()
    DISPMANX_ELEMENT_HANDLE_T element;      // Este handle é obtido pelo comando vc_dispmanx_element_add
    VC_RECT_T src_rect;
    VC_RECT_T dst_rect;
    VC_RECT_T disp_rect;
 
    FILE * fp;
   
    uint8_t * img1;
    uint8_t * img2;
           
    uint32_t vc_image_ptr;              // Este valor é preenchido (provavelmente) pela função vc_dispmanx_resource_create()
    int width = WIDTH;                  // Tamanho do retângulo, definido em #define acima
    int height = HEIGHT;                // Tamanho do retângulo, definido em #define acima
    int pitch = ALIGN_UP(width, 16);
 
    img1 = calloc((WIDTH*HEIGHT*3)>>1, 1);
    img2 = calloc((WIDTH*HEIGHT*3)>>1, 1);
 
    VC_DISPMANX_ALPHA_T alpha = { DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS, 255, 0 };
 
    bcm_host_init();
 
   
    // Carrega imagens para memória
    #if 0
    fp = fopen("f1.yuv", "rb");
    assert(fp);
 
    ret = fread(img1, 1, (WIDTH*HEIGHT*3)>>1, fp);
    assert(ret);
 
    fclose(fp);
   
    fp = fopen("f2.yuv", "rb");
    assert(fp);
 
    ret = fread(img2, 1, (WIDTH*HEIGHT*3)>>1, fp);
    assert(ret);
 
    fclose(fp);
    #endif
    memset(img1, 0x80, (WIDTH*HEIGHT*3)>>1);
    memset(img2, 0x00, (WIDTH*HEIGHT*3)>>1);
   
   
    // Mostra imagens na tela
    display = vc_dispmanx_display_open( screen );          
    ret = vc_dispmanx_display_get_info( display, &info);   
    assert(ret == 0);
 
    resource = vc_dispmanx_resource_create( VC_IMAGE_YUV420, width, height, &vc_image_ptr );
    assert( resource );
 
    update = vc_dispmanx_update_start( 10 );
    assert( update );
   
    vc_dispmanx_rect_set( &src_rect, 0, 0, width << 16, height << 16 );
    vc_dispmanx_rect_set( &dst_rect, 0, 0, width, height );
    vc_dispmanx_rect_set( &disp_rect, 100, 100, width*2, height*2 );
   
    element = vc_dispmanx_element_add( update, display, 2000, &disp_rect, resource, &src_rect, DISPMANX_PROTECTION_NONE, &alpha, NULL, VC_IMAGE_ROT0 );
 
    // Coloca primeiro frame na tela
    ret = vc_dispmanx_resource_write_data(resource, VC_IMAGE_YUV420, (pitch * 3)>>1, img1, &dst_rect );
    assert( ret == 0 );
   
    ret = vc_dispmanx_update_submit_sync(update);
    assert( ret == 0 );
   
    sleep(1);
   
    for(int n = 0; n < 5; n++)
    {  
        // Coloca segundo frame na tela
        update = vc_dispmanx_update_start( 10 );
        assert( update );
       
        ret = vc_dispmanx_resource_write_data(resource, VC_IMAGE_YUV420, (pitch * 3)>>1, img2, &dst_rect );
        assert( ret == 0 );
       
        ret = vc_dispmanx_update_submit_sync(update);
        assert( ret == 0 );
       
        sleep(1);
       
        update = vc_dispmanx_update_start( 10 );
        assert( update );
       
        ret = vc_dispmanx_resource_write_data(resource, VC_IMAGE_YUV420, (pitch * 3)>>1, img1, &dst_rect );
        assert( ret == 0 );
       
        ret = vc_dispmanx_update_submit_sync(update);
        assert( ret == 0 );
       
        sleep(1);
    }
   
    // Encerra display
    printf("Desligando\n");
   
    update = vc_dispmanx_update_start( 10 );
    assert(update);
 
    ret = vc_dispmanx_element_remove(update, element);
    assert( ret == 0 );
 
    ret = vc_dispmanx_update_submit_sync(update);
    assert( ret == 0 );
 
    ret = vc_dispmanx_resource_delete(resource);
    assert( ret == 0 );
 
    ret = vc_dispmanx_display_close(display);
    assert( ret == 0 );
 
    printf("Fim\n");
   
    return 0;
}
BTW from the previous conversation, https://github.com/6by9/mmal_render_example is a simple example of using MMAL to render images.
Software Engineer at Raspberry Pi Trading. Views expressed are still personal views.
Please don't send PMs asking for support - use the forum.
I'm not interested in doing contracts for bespoke functionality - please don't ask.

xultz
Posts: 8
Joined: Thu Apr 26, 2018 5:24 pm

Re: Showing YUV frames on the center of the screen

Fri May 11, 2018 4:53 pm

Dude, you're absolutely awesome, I simply don't know how to thank you!
The changes you made worked great. I than changed the line where the disp_rect is created with vc_dispmanx_rect_set( &disp_rect, 0, 0, 480, 720 ); and the image is automagically resized and appears fullscreen, exactly what I needed!

Thank you so much for your help!!!!!

BTW, as soon as I have some time, I will test the MMAL code you uploaded to github, I'm sure this one is also great!

Return to “Graphics programming”

Who is online

Users browsing this forum: No registered users and 2 guests