2015-11-26 11 views
1

Я пытаюсь преобразовать изображение YUV420P (AV_PIX_FMT_YUV420P) в JPEG, используя ffmpeg's libavformat и libavcodec. Это мой код до сих пор:Как преобразовать изображение YUV420P в JPEG с помощью библиотек ffmpeg?

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 из командной строки?

ответ

3

Следующий code Ваш вопрос:

.pix_fmts  = (const enum AVPixelFormat[]){ 
    AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_NONE 
}, 

Как вы можете видеть, он хочет AV_PIX_FMT_YUVJ420P, не YUV420P. Это старое оставшееся время и в значительной степени считается устаревшим, но оно еще не удалено или не отмечено для удаления и по-прежнему используется в некоторых местах. Литературным значением YUVJ420P является «YUV420P с цветовым диапазоном JPEG» (то есть пиксели используют диапазон 0-255 вместо диапазона 16-235, где 0 вместо 16 - черный, а 255 вместо 235 - белый). Вы также можете использовать это с помощью AV_PIX_FMT_YUV420P, а затем установить, например, avctx-> color_range - 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, см., Например, this example.