version
#define LIBAVUTIL_VERSION_MAJOR 58
#define LIBAVUTIL_VERSION_MINOR 12
#define LIBAVUTIL_VERSION_MICRO 100
note
1.
通过*.jpg推测时,out_fmt为image2,打开*.jpg文件时,in_fmt为image2
但是out_fmt为image2时,av_write_frame调用失败
2.
指定short_name为mjpeg,out_fmt为mjpeg
av_write_frame调用成功
code
void CFfmpegOps::EncodeYUVJ420pToMJPEG(const char *infile, const char *width_str, const char *height_str)
{if (!infile){return;}int32_t width = 0;int32_t height = 0;try{width = std::stoi(width_str);height = std::stoi(height_str);}catch (std::exception& e){return;}#if 0size_t data_bytes = width * height * 3 / 2;std::shared_ptr<uint8_t> data(new uint8_t[data_bytes]);
#endifFILE *in_fp = nullptr;size_t n = 0;AVCodecContext *encoder_ctx = nullptr;const AVCodec *encoder = nullptr;const char *outfile = nullptr;int ret = -1;AVFormatContext *out_fmt_ctx = nullptr;AVStream *mjpeg_stream = nullptr;const AVOutputFormat *out_fmt = nullptr;AVFrame *avframe = nullptr;AVPacket *avpacket = nullptr;int frame_bytes = 0;in_fp = fopen(infile, "rb");if (!in_fp){printf("fopen error\n");goto end;}avframe = av_frame_alloc();if (!avframe){printf("av_frame_alloc error\n");goto end;}avframe->width = width;avframe->height = height;avframe->format = AV_PIX_FMT_YUVJ420P;avframe->pts = 0;// 获取单帧yuvj420p的字节数frame_bytes = av_image_get_buffer_size((AVPixelFormat)(avframe->format), avframe->width, avframe->height, 1);
#if 0if ((int)data_bytes != frame_bytes){printf("data_bytes != frame_bytes\n");goto end;}
#endifret = av_frame_get_buffer(avframe, 0);if (ret < 0){printf("av_frame_get_buffer error:%s\n", GetFfmpegERR(ret));goto end;}// 读取y分量n = fread(avframe->data[0], sizeof(uint8_t), avframe->width * avframe->height, in_fp);if ((int)n != (avframe->width * avframe->height)){printf("n != (avframe->width * avframe->height)\n");goto end;}// 读取u分量n = fread(avframe->data[1], sizeof(uint8_t), avframe->width * avframe->height / 4, in_fp);if ((int)n != (avframe->width * avframe->height / 4)){printf("n != (avframe->width * avframe->height / 4)\n");goto end;}// 读取v分量n = fread(avframe->data[2], sizeof(uint8_t), avframe->width * avframe->height / 4, in_fp);if ((int)n != (avframe->width * avframe->height / 4)){printf("n != (avframe->width * avframe->height / 4)\n");goto end;}#if 0n = fread(data.get(), sizeof(uint8_t), data_bytes, in_fp);if (n != data_bytes){printf("n != data_bytes\n");goto end;}ret = av_image_fill_arrays(avframe->data, avframe->linesize,data.get(),encoder_ctx->pix_fmt, encoder_ctx->width, encoder_ctx->height, 1);if (ret < 0){printf("av_image_fill_arrays error:%s\n", GetFfmpegERR(ret));goto end;}else{printf("ret:%d, frame_bytes:%d\n", ret, frame_bytes);}
#endifavpacket = av_packet_alloc();if (!avpacket){printf("av_packet_alloc error\n");goto end;}encoder = avcodec_find_encoder(AV_CODEC_ID_MJPEG);if (!encoder){printf("avcodec_find_encoder error\n");goto end;}encoder_ctx = avcodec_alloc_context3(encoder);if (!encoder_ctx){printf("avcodec_alloc_context3 error\n");goto end;}// encoder_ctx->colorspace = ;// encoder_ctx->color_range = ;encoder_ctx->pix_fmt = AV_PIX_FMT_YUVJ420P;encoder_ctx->width = width;encoder_ctx->height = height;encoder_ctx->framerate.num = 25;encoder_ctx->framerate.den = 1;encoder_ctx->time_base.num = 1;encoder_ctx->time_base.den = 25;encoder_ctx->bit_rate = frame_bytes * encoder_ctx->framerate.num * 8;ret = avcodec_open2(encoder_ctx, encoder, nullptr);if (ret < 0){printf("avcodec_open2 error:%s\n", GetFfmpegERR(ret));goto end;}out_fmt_ctx = avformat_alloc_context();if (!out_fmt_ctx){printf("avformat_alloc_context error\n");goto end;}outfile = "image_%03d.jpg";
#if 0/*通过*.jpg推测时,out_fmt为image2,打开*.jpg文件时,in_fmt为image2但是out_fmt为image2时,av_write_frame调用失败*/out_fmt = av_guess_format(nullptr, outfile, nullptr);if (!out_fmt){printf("av_guess_format error\n");goto end;}
#else/*指定short_name为mjpeg,out_fmt为mjpegav_write_frame调用成功*/out_fmt = av_guess_format("mjpeg", nullptr, nullptr);if (!out_fmt){printf("av_guess_format error\n");goto end;}
#endifout_fmt_ctx->oformat = out_fmt;mjpeg_stream = avformat_new_stream(out_fmt_ctx, encoder);if (!mjpeg_stream){printf("avformat_new_stream error\n");goto end;}ret = avcodec_parameters_from_context(mjpeg_stream->codecpar, encoder_ctx);if (ret < 0){printf("avcodec_parameters_from_context error:%s\n", GetFfmpegERR(ret));goto end;}#if 0ret = avio_open(&(out_fmt_ctx->pb), outfile, AVIO_FLAG_WRITE);if (ret < 0){printf("avio_open error:%s\n", GetFfmpegERR(ret));goto end;}
#elseret = avio_open2(&(out_fmt_ctx->pb), outfile, AVIO_FLAG_READ_WRITE, nullptr, nullptr);if (ret < 0){printf("avio_open2 error:%s\n", GetFfmpegERR(ret));goto end;}
#endifret = avformat_write_header(out_fmt_ctx, nullptr);if (ret < 0){printf("avformat_write_header error:%s\n", GetFfmpegERR(ret));goto end;}ret = avcodec_send_frame(encoder_ctx, avframe);if (ret < 0){printf("avcodec_send_frame error:%s\n", GetFfmpegERR(ret));goto end;}while (1){ret = avcodec_receive_packet(encoder_ctx, avpacket);if (ret < 0){printf("avcodec_receive_packet error:%s\n", GetFfmpegERR(ret));break;}avpacket->time_base.num = encoder_ctx->time_base.num;avpacket->time_base.den = encoder_ctx->time_base.den;#if 0ret = av_interleaved_write_frame(out_fmt_ctx, avpacket);if (ret < 0){printf("av_interleaved_write_frame error:%s\n", GetFfmpegERR(ret));break;}
#elseret = av_write_frame(out_fmt_ctx, avpacket);if (ret < 0){printf("av_write_frame error:%s\n", GetFfmpegERR(ret));break;}
#endif}// 写元数据ret = av_write_trailer(out_fmt_ctx);if (ret < 0){printf("av_write_trailer error:%s\n", GetFfmpegERR(ret));goto end;}end:if (avpacket){av_packet_free(&avpacket);avpacket = nullptr;}if (avframe){av_frame_free(&avframe);avframe = nullptr;}if (out_fmt_ctx->pb){avio_close(out_fmt_ctx->pb);out_fmt_ctx->pb = nullptr;}if (out_fmt_ctx){avformat_free_context(out_fmt_ctx);out_fmt_ctx = nullptr;}if (encoder_ctx){avcodec_free_context(&encoder_ctx);encoder_ctx = nullptr;}if (in_fp){fclose(in_fp);in_fp = nullptr;}
}