[FFmpeg-user] Levels and Primaries

Andy Furniss adf.lists at gmail.com
Tue Feb 4 21:15:45 CET 2014


Rio Kierkels wrote:
> Thanks Andy,
>
> If this is true it's good news for ffmpeg, bad news for the other
> apps and our current delivery pipeline. My next step would be to
> create a very basic mxf parser to determine the Y' values but as
> I've said my C skills are sub par to my python skills. Does anybody
> have some other nice tool to determine levels to cross check this.
> Or maybe someone who can verify that the ffmpeg mxf parser and
> mpeg2video decoder doesn't do anything to the levels when converting
> it to a waveform?

My C skills aren't up to much either so maybe you should have more
confidence in something you write in python.

Attached is what I used to look (cue someone spots blindingly obvious
bug) of course looking means decoding with
ffmpeg to rawvideo either to a file or a named pipe.

So if you compile the file - gcc -Wall yuvp-counter.c -o count-yuv

My sanity test file is 100% bars (+ subsampling artifacts) from

ftp://ftp.tek.com/tv/test/streams/Element/MPEG-Video/625/100b_400.m2v

for 422 or for 420

ftp://ftp.tek.com/tv/test/streams/Element/MPEG-Video/625/100b_060.m2v

Save & make a named pipe somewhere -

mkfifo myfifo

In one terminal/konsole/whatever run

ffmpeg -i  100b_400.m2v -f rawvideo -y myfifo

Look at the output to get width, height and format (must be planar)

and from another term set wide so you have a couple of hundred chars run eg.

./count-yuv 704 576 422 myfifo

To me the output from that looks sane so I assume my counter works
sometimes at least :-)

-------------- next part --------------
#define _FILE_OFFSET_BITS 64
#define _LARGEFILE_SOURCE 1
#define _LARGEFILE64_SOURCE 1

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>

unsigned long ytot_tab[256];
unsigned long utot_tab[256];
unsigned long vtot_tab[256];

int main(int argc, char **argv)
{
    int fd, i, plane, format, ret, width, height, ybytes, uvbytes, ycount, ucount, vcount;
    unsigned char val[4096];
    unsigned long long total = 0, ytotal = 0, vtotal = 0, utotal = 0;
    unsigned long yover = 0, yunder = 0, vover = 0, vunder = 0, uover = 0, uunder = 0;
    float over_pc, under_pc;

    if (argc !=5){
        fprintf(stderr,"usage: count-yuv <width> <height> <format> [420|422|444] <filename>\n");
        exit(1);
    }
    
    fd = open(argv[4], O_RDONLY);

    if (fd < 0){
        perror("open");
        exit(1);
    }
    
    width = atoi(argv[1]);
    height = atoi(argv[2]);

    if ((width < 1) || (width > 4096) || (height < 1) || (height > 4096)){
        fprintf(stderr,"width or height out of range\n\nusage: count-yuv <width> <height> <format> [420|422|444] <filename>\n");
        exit(1);
    }

    ybytes = width * height;
    format = atoi(argv[3]);

    if (!((format == 420) || (format == 422) || (format == 444))){
        fprintf(stderr,"Invalid format\n\nusage: count-yuv <width> <height> <format> [420|422|444] <filename>\n");
        exit(1);
        }

    if (format == 420)
        uvbytes = ybytes / 4;

    if (format == 422)
        uvbytes = ybytes / 2;

    if (format == 444)
        uvbytes = ybytes;

    ycount = ybytes;
    ucount = 0;
    vcount = 0;
    plane = 1;

    while (1){
        ret = read(fd, val, 4096);

        if (ret < 0){
            perror("read");
            break;
        }

        if (ret == 0 )
            break;
        
        for (i = 0; i < ret; i++){
            total++;

            switch(plane){      
            case 1: //y
                ytot_tab[val[i]]++;
                ytotal++;
                if (val[i] < 16)
                    yunder++;
                if (val[i] > 235)
                    yover++;
                ycount--;
                if (!ycount){
                    ucount = uvbytes;
                    plane = 2;
                }
                break;
    
            case 2: //u
                utot_tab[val[i]]++;
                utotal++;
                    if (val[i] < 16)
                        uunder++;
                    if (val[i] > 240)
                        uover++;
                ucount--;
                if (!ucount){
                    vcount = uvbytes;
                    plane = 3;
                }
                break;

            case 3: //v
                vtot_tab[val[i]]++;
                vtotal++;
                if (val[i] < 16)
                    vunder++;
                if (val[i] > 240)
                    vover++;
                vcount--;
                if (!vcount){
                    ycount = ybytes;
                    plane = 1;
                }
                break;
            }
        }
    }
                        
    printf("\n");

    for (i = 0; i < 256; i+=8)
        printf("%3d = %10lu | %3d =%10lu | %3d =%10lu | %3d =%10lu | %3d =%10lu | %3d =%10lu | %3d =%10lu | %3d =%10lu\n"
            , i, ytot_tab[i],
            i+1, ytot_tab[i+1],
            i+2, ytot_tab[i+2],
            i+3, ytot_tab[i+3],
            i+4, ytot_tab[i+4],
            i+5, ytot_tab[i+5],
            i+6, ytot_tab[i+6],
            i+7, ytot_tab[i+7]);

    printf("\nY Total read = %llu\n", ytotal);

    over_pc = (float)yover / (float)ytotal * 100.0;
    under_pc = (float)yunder / (float)ytotal * 100.0;

    printf("Over = %lu = %3.4f%%\nUnder = %lu = %3.4f%%\n\n", yover, over_pc, yunder, under_pc);
    
    for (i = 0; i < 256; i+=8)
        printf("%3d = %10lu | %3d =%10lu | %3d =%10lu | %3d =%10lu | %3d =%10lu | %3d =%10lu | %3d =%10lu | %3d =%10lu\n"
            , i, utot_tab[i],
            i+1, utot_tab[i+1],
            i+2, utot_tab[i+2],
            i+3, utot_tab[i+3],
            i+4, utot_tab[i+4],
            i+5, utot_tab[i+5],
            i+6, utot_tab[i+6],
            i+7, utot_tab[i+7]);

    printf("\nU Total read = %llu\n", utotal);

    over_pc = (float)uover / (float)utotal * 100.0;
    under_pc = (float)uunder / (float)utotal * 100.0;

    printf("Over = %lu = %3.4f%%\nUnder = %lu = %3.4f%%\n\n", uover, over_pc, uunder, under_pc);

    for (i = 0; i < 256; i+=8)
        printf("%3d = %10lu | %3d =%10lu | %3d =%10lu | %3d =%10lu | %3d =%10lu | %3d =%10lu | %3d =%10lu | %3d =%10lu\n"
            , i, vtot_tab[i],
            i+1, vtot_tab[i+1],
            i+2, vtot_tab[i+2],
            i+3, vtot_tab[i+3],
            i+4, vtot_tab[i+4],
            i+5, vtot_tab[i+5],
            i+6, vtot_tab[i+6],
            i+7, vtot_tab[i+7]);

    printf("\nV Total read = %llu\n", vtotal);

    over_pc = (float)vover / (float)vtotal * 100.0;
    under_pc = (float)vunder / (float)vtotal * 100.0;

    printf("Over = %lu = %3.4f%%\nUnder = %lu = %3.4f%%\n\n", vover, over_pc, vunder, under_pc);

    printf("\nTotal Bytes read = %llu\n\n", total);

    printf("Width = %d\nHeight= %d\nformat = %d\nybytes = %d\nuvbytes = %d\n\n", width, height, format, ybytes, uvbytes);

    if (ybytes != ycount)
         printf("\n****** MISMATCH BETWEEN SIZE/FORMAT AND INPUT SIZE DETECTED ******\n\n");

    close (fd);
    exit(0);
}



More information about the ffmpeg-user mailing list