资讯详情

最简单的基于FFMPEG 4.4 的图形编码器(参考雷神的文章)

最简单的基础FFMPEG图像编码器(YUV编码为JPEG)_雷霄华博客-CSDN博客_ffmpeg 编码图片

简介:参考雷神的文章。实现最简单的视频编码器。

ffmpeg 版本:Releases · ShiftMediaProject/FFmpeg · GitHub

4.4 最新版本。

一、加载yuv 到avframe:

注意这里写死的yuv420p 960* 400

#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <thread> #include <vector> #include <functional> #include <cassert> #include <chrono> #include <string> extern "C" { #include <libswresample/swresample.h> #include <libavformat/avformat.h> #include <libavutil/imgutils.h> #include <libswscale/swscale.h> #include <libavcodec/avcodec.h> #include <libavcodec/codec.h> #include <libswscale/swscale.h> #include <libavutil/opt.h> } #pragma comment(lib, "avutil.lib") #pragma comment(lib, "avcodec.lib") #pragma comment(lib, "avformat.lib") #pragma comment(lib, "swscale.lib")  std::string GetFFmpegErorString(int errnum) {  char g_av_error[AV_ERROR_MAX_STRING_SIZE] = { 0 };  return std::string(av_make_error_string(g_av_error, AV_ERROR_MAX_STRING_SIZE, errnum)); }  std::string strInputYUVFileName = "yuv420p_960_400_99_yuv420.yuv"; int width = 960; int height = 400; AVPixelFormat format = AVPixelFormat::AV_PIX_FMT_YUV420P;  AVFrame* load_yuv_file_to_avframe(std::string filePath) {  AVFrame* avFrameYUV = nullptr;  FILE* fReadYUV = nullptr;  do  {   FILE* fReadYUV = fopen(strInputYUVFileName.c_str(), "rb");    if (!fReadYUV) {    std::cout << "Failed to open file[" << strInputYUVFileName << "]" << std::endl;    break;   }    avFrameYUV = av_frame_alloc();// 需要使用av_frame_free 释放,要重复使用,需要使用av_frame_unref 将avFrame 设置为初始默认值   int bufferSize = av_image_alloc(avFrameYUV->data, avFrameYUV->linesize, width, height, format, 1);   if (bufferSize < 0) {    std::cout << GetFFmpegErorString(bufferSize) << std::endl;    av_frame_free(&avFrameYUV);    break;   }    avFrameYUV->format = format;   avFrameYUV->width = width;   avFrameYUV->height = height;    fread(avFrameYUV->data[0], 1, avFrameYUV->linesize[0] * avFrameYUV->height, fReadYUV);   fread(avFrameYUV->data[1], 1, avFrameYUV->linesize[1] * avFrameYUV->height, fReadYUV);   fread(avFrameYUV->data[2], 1, avFrameYUV->linesize[2] * avFrameYUV->height, fReadYUV);   } while (0);  if (fReadYUV) {   fclose(fReadYUV);   fReadYUV = nullptr;  }  return avFrameYUV; }

二、保存avFrame 为jpeg 文件

 int save_frame_as_mjpeg(AVFrame* pFrame) {  std::string strName = "output.jpeg";  if (!pFrame) {   return AVERROR(EINVAL);  }   const AVCodec* jpegCodec = avcodec_find_encoder(AV_CODEC_ID_MJPEG);  if (!jpegCodec) {   return AVERROR(EINVAL);  }  AVCodecContext* jpegContext = avcodec_alloc_context3(jpegCodec);  if (!jpegContext) {   return AVERROR(EINVAL);  }   jpegContext->pix_fmt = (AVPixelFormat)pFrame->format;  jpegContext->height = pFrame->height;  jpegContext->width = pFrame->width;  jpegContext->time_base.num = 1;  jpegContext->time_base.den = 30;  jpegContext->strict_std_compliance = FF_COMPLIANCE_UNOFFICIAL;  int ret = 0;  if ((ret = avcodec_open2(jpegContext, jpegCodec, NULL)) < 0) {   std::cout << GetFFmpegErorString(ret) << std::endl;   return -1;  }  FILE* JPEGFile;  char JPEGFName[256];   AVPacket* packet = av_packet_alloc();  int gotFrame;  ret = avcodec_send_frame(jpegContext, pFrame);  if (ret < 0) {   std::cout << GetFFmpegErorString(ret) << std::endl;   return -1;  }  ret = avcodec_receive_packet(jpegContext, packet);  if (ret < 0) {   std::cout << GetFFmpegErorString(ret) << std::endl;   return -1;  }  JPEGFile = fopen(strName.c_str(), "wb");  fwrite(packet->data, 1, packet->size, JPEGFile);  fclose(JPEGFile);   av_packet_free(&packet);  avcodec_close(jpegContext);  return 0;  }

报告以下错误:

搜索ffmpeg 代码发现:

因此,ffmpeg 的 mpjeg 编码器只支持特定类型的编码器pix_fmt。

事实上,所有的编码器都显示了他们需要的类型:

显示支持yuv420p,但需要特定的参数。试着修改:

 int save_frame_as_mjpeg(AVFrame* pFrame) {  std::string strName = "output.jpeg";  if (!pFrame) {   return AVERROR(EINVAL);  }   const AVCodec* jpegCodec = avcodec_find_encoder(AV_CODEC_ID_MJPEG);  if (!jpegCodec) {   return AVERROR(EINVAL);  }  AVCodecContext* jpegContext = avcodec_alloc_context3(jpegCodec);  if (!jpegContext) {   return AVERROR(EINVAL);  }   jpegContext->pix_fmt = (AVPixelFormat)pFrame->format;  jpegContext->height = pFrame->height;  jpegCotext->width = pFrame->width;
	jpegContext->time_base.num = 1;
	jpegContext->time_base.den = 30;
	jpegContext->strict_std_compliance = FF_COMPLIANCE_UNOFFICIAL;
	int ret = 0;
	if ((ret = avcodec_open2(jpegContext, jpegCodec, NULL)) < 0) {
		std::cout << GetFFmpegErorString(ret) << std::endl;
		return -1;
	}
	FILE* JPEGFile;
	char JPEGFName[256];

	AVPacket* packet = av_packet_alloc();
	int gotFrame;
	ret = avcodec_send_frame(jpegContext, pFrame);
	if (ret < 0) {
		std::cout << GetFFmpegErorString(ret) << std::endl;
		return -1;
	}
	ret = avcodec_receive_packet(jpegContext, packet);
	if (ret < 0) {
		std::cout << GetFFmpegErorString(ret) << std::endl;
		return -1;
	}
	JPEGFile = fopen(strName.c_str(), "wb");
	fwrite(packet->data, 1, packet->size, JPEGFile);
	fclose(JPEGFile);

	av_packet_unref(packet);
	avcodec_close(jpegContext);
	return 0;

}

成功了。

另外:ffplay -video_size 960x400 -pixel_format yuv420p -i D:\learn\FFmpegEncoder\x64\Release\yuv420p_960_400_99_yuv420.yuv 可以使用ffplay 来播放指定的文件。

ffmpegavframetojpeg-编解码文档类资源-CSDN下载

标签: 3x400高压电缆电容值

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

 锐单商城 - 一站式电子元器件采购平台  

 深圳锐单电子有限公司