[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