如何使用ffmpeg的库将YUV420P图像转换为JPEG? [英] How to convert YUV420P image to JPEG using ffmpeg's libraries?

查看:1370
本文介绍了如何使用ffmpeg的库将YUV420P图像转换为JPEG?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用ffmpeg的libavformatlibavcodec将YUV420P图像(AV_PIX_FMT_YUV420P)转换为JPEG.到目前为止,这是我的代码:

I'm trying to convert a YUV420P image (AV_PIX_FMT_YUV420P) to a JPEG using ffmpeg's libavformat and libavcodec. This is my code so far:

AVFormatContext* pFormatCtx;
AVOutputFormat* fmt;
AVStream* video_st;
AVCodecContext* pCodecCtx;
AVCodec* pCodec;

uint8_t* picture_buf;
AVFrame* picture;
AVPacket pkt;
int y_size;
int got_picture=0;
int size;

int ret=0;

FILE *in_file = NULL;                            //YUV source
int in_w = 720, in_h = 576;                      //YUV's width and height
const char* out_file = "encoded_pic.jpg";    //Output file

in_file = fopen(argv[1], "rb");
av_register_all();

pFormatCtx = avformat_alloc_context();

fmt = NULL;
fmt = av_guess_format("mjpeg", NULL, NULL);
pFormatCtx->oformat = fmt;

//Output URL
if (avio_open(&pFormatCtx->pb,out_file, AVIO_FLAG_READ_WRITE) < 0)
{
    printf("Couldn't open output file.");
    return -1;
}

video_st = avformat_new_stream(pFormatCtx, 0);

if (video_st==NULL)
    return -1;

pCodecCtx = video_st->codec;
pCodecCtx->codec_id = fmt->video_codec;
pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;

pCodecCtx->width = in_w;
pCodecCtx->height = in_h;

pCodecCtx->time_base.num = 1;
pCodecCtx->time_base.den = 25;

//Output some information
av_dump_format(pFormatCtx, 0, out_file, 1);

pCodec = avcodec_find_encoder(pCodecCtx->codec_id);

if (!pCodec)
{
    printf("Codec not found.");
    return -1;
}

if (avcodec_open2(pCodecCtx, pCodec,NULL) < 0){
    printf("Could not open codec.\n");
    return -1;
}

picture = avcodec_alloc_frame();
size = avpicture_get_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);

picture_buf = (uint8_t *)av_malloc(size);

if (!picture_buf)
    return -1;

avpicture_fill((AVPicture *)picture, picture_buf, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);

//Write Header
avformat_write_header(pFormatCtx,NULL);

y_size = pCodecCtx->width * pCodecCtx->height;
av_new_packet(&pkt,y_size*3);

//Read YUV
if (fread(picture_buf, 1, y_size*3/2, in_file) <=0)
{
    printf("Could not read input file.");
    return -1;
}

picture->data[0] = picture_buf;  // Y
picture->data[1] = picture_buf+ y_size;  // U
picture->data[2] = picture_buf+ y_size*5/4; // V

//Encode
ret = avcodec_encode_video2(pCodecCtx, &pkt,picture, &got_picture);
if(ret < 0)
{
    printf("Encode Error.\n");
    return -1;
}

if (got_picture==1)
{
    pkt.stream_index = video_st->index;
    ret = av_write_frame(pFormatCtx, &pkt);
}

av_free_packet(&pkt);
//Write Trailer
av_write_trailer(pFormatCtx);

printf("Encode Successful.\n");

if (video_st)
{
    avcodec_close(video_st->codec);
    av_free(picture);
    av_free(picture_buf);
}

avio_close(pFormatCtx->pb);
avformat_free_context(pFormatCtx);

fclose(in_file);

我收到此错误:

Output #0, mjpeg, to 'encoded_pic.jpg':
Stream #0.0: Video: mjpeg, yuv420p, 720x576, q=2-31, 200 kb/s, 90k tbn, 25 tbc
[mjpeg @ 0x78c3a0] Specified pix_fmt is not supported
Could not open codec.

如果ffmpeg的文档中没有提及此转换的内容?如果有的话,我们该如何规避呢?当我们使用ffmpeg的命令行版本时,ffmpeg如何在内部进行转换?

If there any mention of this conversion not being allowed in ffmpeg's documentation? If there is, how can we circumvent it? How does ffmpeg internally convert it when we use the command-line version of ffmpeg?

推荐答案

以下如您所见,它需要AV_PIX_FMT_YUVJ420P,而不是YUV420P.这是旧的剩菜,在很大程度上被认为已弃用,但尚未删除或标记为要删除,并且仍在某些地方使用. YUVJ420P的字面意思是具有JPEG颜色范围的YUV420P"(即,像素使用0-255范围而不是16-235范围,其中0而不是16是黑色,而255而不是235是白色).您也可以使用AV_PIX_FMT_YUV420P然后设置例如avctx-> color_range到 AVCOL_RANGE_JPEG .

As you can see, it wants AV_PIX_FMT_YUVJ420P, not YUV420P. This is an old leftover and is largely considered deprecated, but it has not yet been removed or marked for removal, and is still used in some places. The literal meaning of YUVJ420P is "YUV420P with JPEG color-range" (i.e. pixels use 0-255 range instead of 16-235 range, where 0 instead of 16 is black, and 255 instead of 235 is white). You can alternatively also do that using AV_PIX_FMT_YUV420P and then setting e.g. avctx->color_range to AVCOL_RANGE_JPEG.

您可能想知道,您可能对此并不在意,如何将AV_PIX_FMT_YUV420P转换为AV_PIX_FMT_YUVJ420P ?好吧,在这种情况下,您的输入是JPEG,因此它可能使用JPEG范围数据(通过检查avctx-> color_range或avframe-> color_range进行检查).然后,您可以简单地将avframe-> pix_fmt从AV_PIX_FMT_YUV420P更改为AV_PIX_FMT_YUVJ420P.如果出于某种原因color_range是AVCOL_RANGE_MPEG,则可以使用 libswscale 在AV_PIX_FMT_YUV420P与MPEG范围和AV_PIX_FMT_YUVJ420P,请参见例如此示例.

You probably don't care about that, you want to know, how can I convert AV_PIX_FMT_YUV420P to AV_PIX_FMT_YUVJ420P? Well, in this case, your input is JPEG so it probably uses JPEG range data (check that by checking avctx->color_range or avframe->color_range). Then you can simply change avframe->pix_fmt from AV_PIX_FMT_YUV420P to AV_PIX_FMT_YUVJ420P. If for whatever reason color_range is AVCOL_RANGE_MPEG, you can probably use libswscale to convert between the AV_PIX_FMT_YUV420P with MPEG-range and AV_PIX_FMT_YUVJ420P, see e.g. this example.

这篇关于如何使用ffmpeg的库将YUV420P图像转换为JPEG?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆