Search code examples
c++ffmpegmultimedia

YUV to JPG encoding using ffmpeg


I am trying to encode a YVU file and save it as jpg file. but i didn't understand the following

1.why the packet size is size*3.

av_new_packet(&pkt,size*3);`

2.In fread why we using size*3/2.

if(fread(buffer , 1, size*3/2, ptrInputFile)<=0)`

3.how they are filling data here

frame->data[0] = buffer;

frame->data[1] = buffer + siz;

frame->data[2] = buffer + siz*5/4;

code:

AVFormatContext *avFrameContext;
AVOutputFormat *avOutputFormat;
AVStream *avStream;
AVCodecContext *avCodecContext;
AVCodec *avCodec;
AVFrame *frame;
AVPacket pkt;

const char *output = "temp.jpg";
FILE *ptrInputFile;
const char *input = "cuc_view_480x272.yuv";

ptrInputFile = fopen(input ,"rb");
if(!ptrInputFile)
    return -1;

avFrameContext = avformat_alloc_context();
avOutputFormat = av_guess_format("mjpeg", NULL, NULL);
if(!avOutputFormat)
    return -1;
avFrameContext->oformat = avOutputFormat;

if(avio_open(&avFrameContext->pb ,output ,AVIO_FLAG_READ_WRITE)<0)
    return -1;


avStream = avformat_new_stream(avFrameContext,NULL);
if(!avStream)
    return -1;

avCodecContext = avStream->codec;
avCodecContext->codec_id = avOutputFormat->video_codec;
avCodecContext->codec_type = AVMEDIA_TYPE_VIDEO;
avCodecContext->pix_fmt = PIX_FMT_YUVJ420P;

avCodecContext->width = 480;
avCodecContext->height = 272;
avCodecContext->time_base.num = 1;
avCodecContext->time_base.den = 25;

avCodec = avcodec_find_encoder(avCodecContext->codec_id);

if(!avCodec)
    return -1;


if(avcodec_open2(avCodecContext ,avCodec,NULL)<0)
    return -1;

frame = av_frame_alloc();
int size = avpicture_get_size(PIX_FMT_YUVJ420P ,avCodecContext->width, avCodecContext->height);
uint8_t *buffer = (uint8_t*)av_malloc(size*sizeof(uint8_t));

avpicture_fill((AVPicture*)frame, buffer, avCodecContext->pix_fmt ,avCodecContext->width, avCodecContext->height);


//write header
avformat_write_header(avFrameContext, NULL);

int siz = avCodecContext->width*avCodecContext->height;

av_new_packet(&pkt,siz*3);

if(fread(buffer , 1, siz*3/2, ptrInputFile)<=0)
    return -1;

frame->data[0] = buffer;
frame->data[1] = buffer + siz;
frame->data[2] = buffer + siz*5/4;

Solution

  • If you look at the format of the yuv420p (wiki) the data is formatted in the file as:

    As there are 'siz' length of pixels in the image:
    siz length of y value
    siz/4 length of u value
    siz/4 length of v value
    

    So for question 2: we have siz*3/2 length of data to read.

    For question 3: y starts at buffer+0, u starts at buffer+siz, and v starts at buffer+siz*5/4.

    As for question 1: I am not sure if the data is converted to RGB. If it is converted then it would require 3 byte for each pixel. Additional code is required to see that.