2015-11-26 63 views
1

我試圖用ffmpeg的libavformatlibavcodec將YUV420P圖像(AV_PIX_FMT_YUV420P)轉換爲JPEG格式。這是到目前爲止我的代碼:如何使用ffmpeg的庫將YUV420P圖像轉換爲JPEG格式?

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的字面含義是「帶有JPEG色彩範圍的YUV420P」(即像素使用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在具有MPEG範圍的AV_PIX_FMT_YUV420P和AV_PIX_FMT_YUVJ420P之間進行轉換,參見例如。 this example

相關問題