0

Previously i successfully opened, decoded and saved frames from .mp4 file. Raw frames were in YUV420P format which i converted to RGB24 using sws_scale() function and saved them into a .ppm file. What i'm trying to do now is to keep raw decoded frames in YUV420P, or convert frames that i get to YUV420P just to make sure they are in YUV420P. But the problem is that i don't know which type of file should i use, i'm guessing .yuv? And another problem is that i also don't know how to save YUV420P data.

I used to save RGB24 in .ppmlike this:

for (y = 0; y < height; y++)
{
fwrite(frame->data[0] + y*frame->linesize[0], 1, width * 3, pf);
}

which worked fine since i was using only 1 plane. But YUV420P uses 3 planes (Y,Cb,Cr). What i tried to do is to save Y component first, and Cb/Cr after that.

for (y = 0; y < height; y++)
{
    fwrite(frame->data[0] + y*frame->linesize[0], 1, width, pf);
}

for (y = 0; y < height / 2; y++)
{
    fwrite(frame->data[1] + y*frame->linesize[1], 1, width, pf);
    fwrite(frame->data[2] + y*frame->linesize[2], 1, width, pf);
}

But as you can guess that is not working at all. Actually it does, but it saves only Y component. Could anyone guide me to right direction please?

EDIT I've changed mine saveFrame() function like you said, but instead of interleaved chroma writing i used planar. But, i'm still getting only Y component picture (black-white).

fprintf(pf, "P5\n%d %d\n255\n", width, height);

for (y = 0; y < height; y++)
{
    fwrite(frame->data[0] + y*frame->linesize[0], 1, width, pf);
}

for (y = 0; y < height / 2; y++)
{
    fwrite(frame->data[1] + y*frame->linesize[1], 1, width / 2, pf);
}

for (y = 0; y < height / 2; y++)
{
    fwrite(frame->data[2] + y*frame->linesize[2], 1, width / 2, pf);
}
Sir DrinksCoffeeALot
  • 593
  • 2
  • 11
  • 20

1 Answers1

1

Your chroma code is wrong:

for (y = 0; y < height / 2; y++)
{
    fwrite(frame->data[1] + y*frame->linesize[1], 1, width / 2, pf);
    fwrite(frame->data[2] + y*frame->linesize[2], 1, width / 2, pf);
}

I'd also claim that height / 2 or width / 2 is wrong, since you should round up, not down, but that's relatively minor.

Ronald S. Bultje
  • 10,828
  • 26
  • 47
  • in PPM, the "height" argument should be h*3/2 for yuv420p, so that the total size of the two numbers is the number of elements in the image, not just the Y plane. See https://www.ffmpeg.org/doxygen/trunk/pnmenc_8c_source.html – Ronald S. Bultje Mar 14 '16 at 12:36
  • Oh god, thank you very much, this is so useful, i finally realized how saving YUV420P is done. But something is tickling my mind, in that file, particularly `ptr1 += p->linesize[1]; ptr2 += p->linesize[2];`. If we save chroma data like that, won't that be saved as semi-planar and not fully-planar considering this picture: [YUV420 Planar/Interleaved/SemiPlanar](http://3.bp.blogspot.com/-wQp0uFzDOC4/T3Rp9PU04sI/AAAAAAAABOw/u24jEPKzLCY/s1600/YUV420P&YUV420SP.png) – Sir DrinksCoffeeALot Mar 15 '16 at 08:01
  • Yes, I'm not entirely sure why they decided to do it this way but it's how it works, right? – Ronald S. Bultje Mar 15 '16 at 10:54
  • Well even if i save it as semi-planar, i'm getting really weird images, code i used is pretty much the same as their for saving into buffer, instead of buffer i'm saving it into a .ppm file : [Code](http://pastebin.com/Z6QUuFmA) – Sir DrinksCoffeeALot Mar 15 '16 at 11:24
  • I also checked if maybe i'm getting frames with wrong pixel format, but i'm not, i'm getting frames with `codecContext->pix_fmt = 0` which is `PIX_FMT_YUV420P`. – Sir DrinksCoffeeALot Mar 15 '16 at 11:29
  • For testing: if you use ppmenc in ffmpeg, does it work correctly? – Ronald S. Bultje Mar 15 '16 at 19:41
  • I didn't work with static build of ffmpeg so im noob when it comes to ffmpeg commands, though ill try to find something on the Internet about that. I'll come back with results i hope. – Sir DrinksCoffeeALot Mar 16 '16 at 07:55
  • https://en.wikipedia.org/wiki/Netpbm_format says yuv420p in ppm is a ffmpeg-only extension (search for "pgmyuv"). Can you use raw YUV (without header) or something like that? What do you want to use the output image for? I.e. what application should read the resulting file? – Ronald S. Bultje Mar 16 '16 at 13:29
  • I did succeed to save YUV420P format into a file without writing the header using fwrite function and open it with InfraView. I tried that same thing with GIMP but i was unable to do it. I guess GIMP's missing support for that. After that i tried to save only Y data (`frame->data[0]`) and open it with InfraView. I did not get what i was hoping to (black-white picture), instead when i saved `data[0]` i got one of the color component, and frame that i was reading data from was saved in YUV420P pixel format. Anyways i'll post in day or two what i have found that works fine without too much hassle – Sir DrinksCoffeeALot Mar 17 '16 at 12:48