I have a YUV frame that I need to convert to jpg. For the frames with resolution 1920x1080 or 2560x1080 or 2560x880 or 640x360, I'm easily able to encode and create a jpg using the following code. The frames with a resolution of 1512x982 with 12 bit per pixel I am getting a distorted image using the same code. Using the following ffmpeg command, I am able to get perfect looking jpg image from the same 1512x982 resolution YUV file:
fmpeg -y -s:v 1512x982 -pix_fmt yuv420p -i 0.yuv 0.jpg
Please help with the code part, as in what I may be missing here.
#include "ffmpeg-helper.h"
AVFrame * FFmpegHelper::allocPicture(enum AVPixelFormat pix_fmt, int width, int height)
{
// Allocate a frame
AVFrame * frame = av_frame_alloc();
if (frame == NULL) {
return NULL;
}
frame -> width = width;
frame -> height = height;
frame -> format = pix_fmt;
int ret = av_frame_get_buffer(frame, 0);
if (ret < 0) {
return NULL;
}
ret = av_frame_make_writable(frame);
if (ret < 0) {
return NULL;
}
return frame;
}
void FFmpegHelper::frameConversion(char * y, char * u, char * v,
int srcWidth, int srcHeight, string filePath)
{
avcodec_register_all();
AVFrame * src = allocPicture(AVPixelFormat::AV_PIX_FMT_YUV420P, srcWidth, srcHeight);
src -> data[0] = (uint8_t * ) y;
src -> data[1] = (uint8_t * ) u;
src -> data[2] = (uint8_t * ) v;
src -> pts = 1;
auto encoderContext = getEncoderContext(AV_CODEC_ID_MJPEG, srcWidth, srcHeight);
if (encoderContext == NULL) return;
FILE * frameFile = fopen(filePath.c_str(), "ab+");
auto pkt = av_packet_alloc();
encode(encoderContext, src, pkt, frameFile);
encode(encoderContext, NULL, pkt, frameFile);
// memory cleanup
avcodec_free_context( & encoderContext);
av_packet_unref(pkt);
av_frame_free( & src);
fclose(frameFile);
}
void FFmpegHelper::encode(AVCodecContext * enc_ctx, AVFrame * frame, AVPacket * pkt, FILE * outfile)
{
/* send the frame to the encoder */
if (frame == NULL) {
return;
}
int ret = avcodec_send_frame(enc_ctx, frame);
if (ret < 0) {
return;
}
ret = avcodec_receive_packet(enc_ctx, pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) return;
if (ret < 0) return;
fwrite(pkt -> data, pkt -> size, 1, outfile);
}
AVCodecContext * FFmpegHelper::getEncoderContext(AVCodecID extension, int width, int height)
{
auto codec = avcodec_find_encoder(extension);
if (!codec) {
return NULL;
}
auto encoderContext = avcodec_alloc_context3(codec);
encoderContext -> width = width;
encoderContext -> height = height;
encoderContext -> pix_fmt = AVPixelFormat::AV_PIX_FMT_YUVJ420P;
AVRational frameRate = {
1,
1
};
encoderContext -> time_base = frameRate;
if (avcodec_open2(encoderContext, codec, NULL) < 0) {
return;
}
return encoderContext;
}
The code starts from the function 'frameConversion' where I am providing data for Y, U, and V along with frame dimensions and file path to write.
Aucun commentaire:
Enregistrer un commentaire