leandromoreira / ffmpeg-libav-tutorial

FFmpeg libav tutorial - learn how media works from basic to transmuxing, transcoding and more. Translations: πŸ‡ΊπŸ‡Έ πŸ‡¨πŸ‡³ πŸ‡°πŸ‡· πŸ‡ͺπŸ‡Έ πŸ‡»πŸ‡³ πŸ‡§πŸ‡·
https://github.com/leandromoreira/ffmpeg-libav-tutorial
BSD 3-Clause "New" or "Revised" License
9.82k stars 941 forks source link

Hey, can I get some help, have no clue how this works. #74

Closed bruhhhhhhhhhh7 closed 3 years ago

bruhhhhhhhhhh7 commented 3 years ago
static void save_gray_frame(unsigned char *buf, int wrap, int xsize, int ysize, char *filename)
{
    FILE *f;
    int i;
    f = fopen(filename,"w");
    // writing the minimal required header for a pgm file format
    // portable graymap format -> https://en.wikipedia.org/wiki/Netpbm_format#PGM_example
    fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255);

    // writing line by line
    for (i = 0; i < ysize; i++)
        fwrite(buf + i * xsize, 1, xsize, f);
    fclose(f);
}

fwrite(buf + i * xsize, 1, xsize, f); buf + i * xsize How do you get the data stream to do that? Like, what is it doing? Where do you get that expression from?

leandromoreira commented 3 years ago
// for each frame we take the Y plane (think of a huge "2d" array containing all the pixels)
// and the linesize (wrap - size in bytes of each picture line) if we use a byte per pixel then it's equals to width
// , width, height, and the file name
save_gray_frame(pFrame->data[0], pFrame->linesize[0], pFrame->width, pFrame->height, frame_filename);

// we must write the minimal header (providing resolution and magical string)
fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255);

// and finally we just need to write to the file
// since we write line by line then what we do is just to use the ysize iteration 
// (one increment for i, up to the frame height((yssize))

// FOR THAT matter, we use pointer arithmetics and
    for (i = 0; i < ysize; i++)
        // fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
        // a pointer (updated/calculated each line) of size 1 but
        // writes xsize items of data on file f
        fwrite(buf + i * wrap, 1, xsize, f);

Anyway, to sum up, buf + i * wrap it's just a way to move for the next line in number of bytes. Let's do a simple simulation here:

height=720
width=1280

for i = 0; i < height; i++ 
 // for 0 we just point to the start of the buffer
buf(0x00000) + 0 *  1280 = 0 
storing 1280 bytes
// for 1 we just move the pointer to the next line
buf(0x00000) + 1 *  1280 = 1280
.... 

links

leandromoreira commented 3 years ago

if you still have doubts, feel comfortable to ask.

bruhhhhhhhhhh7 commented 3 years ago

Does the data stream itself get multiplied? I know that it doesn't, but why does that work? Thanks btw, I appreciate this a lot. I'm new to C++, this is the first library that I'm learning haha.

leandromoreira commented 3 years ago

Does the data stream itself get multiplied?

No, think of buf as an address to the memory where the data stream starts, then if you do buf + 1 what is effectively happening is you're now pointing to the start address + 1 byte, then if you transpose that for any operation you are just moving where to start reading.


# an oversimplification of a memory

memory = []

memory[0x000] = 0xFF # random information on memory
memory[0x001] = 0x2B # random information on memory
# ....
memory[0xFC1] = 0x03 # the data stream starts here
memory[0xFC2] = 0x3A
memory[0xFC3] = 0x19
memory[0xFC4] = 0xFB

buff = 0xFC1
# when we do any arithmetic it changes the address 
bruhhhhhhhhhh7 commented 3 years ago

Thanks a ton, I get it now :)