ffmpeg 将yuv转换成H264

#include "stdafx.h"
#ifdef _WIN32
//Windows
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/opt.h"
#include "libavutil/parseutils.h"
#include "libavutil/avutil.h"
};
#else
//Linux...
#ifdef __cplusplus
extern "C"
{
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <libavutil/parseutils.h>
#include <libavutil/avutil.h>
#ifdef __cplusplus
};
#endif
#endif


void encoder()
{
	const char *pOutFile = "ds.h264";
	FILE*pFile = fopen("ds_480x272.yuv", "rb");
	if (!pFile){
		return;
	}
	// 注册 ffmpeg 中的所有的封装、解封装 和 协议等
	av_register_all();

	//  用作之后写入视频帧并编码成 h264,贯穿整个工程当中
	AVFormatContext *pFormatContext = avformat_alloc_context();

	// 通过这个函数可以获取输出文件的编码格式, 那么这里我们的 fmt 为 h264 格式(AVOutputFormat *)
	AVOutputFormat *pOutputFormat = av_guess_format(NULL, pOutFile, NULL);
	pFormatContext->oformat = pOutputFormat;

	//将输出文件中的数据读入到程序的 buffer 当中,方便之后的数据写入,也可以说缓存数据写入
	avio_open(&pFormatContext->pb, pOutFile, AVIO_FLAG_READ_WRITE);

	// 通过媒体文件控制者获取输出文件的流媒体数据,这里 AVCodec * 写 0 , 默认会为我们计算出合适的编码格式
	AVStream *pStream = avformat_new_stream(pFormatContext, 0);
	if (!pStream){
		return;
	}
	// 设置 25 帧每秒 ,也就是 fps 为 25。(其实不设置也可以)
	pStream->time_base.num = 1;
	pStream->time_base.den = 25;


	// 用户存储编码所需的参数格式等等
	AVCodecContext*pCodecContext = NULL;

	// 从媒体流中获取到编码结构体,他们是一一对应的关系,一个 AVStream 对应一个  AVCodecContext
	pCodecContext = pStream->codec;

	// 设置编码器的 id,每一个编码器都对应着自己的 id,例如 h264 的编码 id 就是 AV_CODEC_ID_H264
	pCodecContext->codec_id = pOutputFormat->video_codec;

	// 设置编码类型为 视频编码
	pCodecContext->codec_type = AVMEDIA_TYPE_VIDEO;

	// 设置像素格式为 yuv 格式
	pCodecContext->pix_fmt = PIX_FMT_YUVJ420P;

	// 设置视频的宽高
	pCodecContext->width = 480;
	pCodecContext->height = 272;

	// 设置 25 帧每秒 ,也就是 fps 为 25
	pCodecContext->time_base.num = 1;
	pCodecContext->time_base.den = 25;

	// 设置比特率,每秒传输多少比特数 bit,比特率越高,传送速度越快,也可以称作码率,
	// 视频中的比特是指由模拟信号转换为数字信号后,单位时间内的二进制数据量。
	pCodecContext->bit_rate = 400000;

	// 设置图像组层的大小。
	// 图像组层是在 MPEG 编码器中存在的概念,图像组包 若干幅图像, 组头包 起始码、GOP 标志等,如视频磁带记录器时间、控制码、B 帧处理码等;
	pCodecContext->gop_size = 250;

	pCodecContext->qmin = 10;
	pCodecContext->qmax = 51;
	pCodecContext->qcompress = 1;

	// 设置 B 帧最大的数量,B帧为视频图片空间的前后预测帧, B 帧相对于 I、P 帧来说,压缩率比较大,也就是说相同码率的情况下,
	// 越多 B 帧的视频,越清晰,现在很多打视频网站的高清视频,就是采用多编码 B 帧去提高清晰度,
	// 但同时对于编解码的复杂度比较高,比较消耗性能与时间
	pCodecContext->max_b_frames = 3;

	AVDictionary *param = 0;
	if(pCodecContext->codec_id == AV_CODEC_ID_H264) {// 可选设置
		// 通过--preset的参数调节编码速度和质量的平衡。
		av_dict_set(¶m, "preset", "slow", 0);

		// 通过--tune的参数值指定片子的类型,是和视觉优化的参数,或有特别的情况。
		// zerolatency: 零延迟,用在需要非常低的延迟的情况下,比如电视电话会议的编码
		av_dict_set(¶m, "tune", "zerolatency", 0);
	}

	// 通过 codec_id 找到对应的编码器
	AVCodec *pCodec = avcodec_find_encoder(pCodecContext->codec_id);
	if (!pCodec){
		return;
	}
	
	// 打开编码器,并设置参数 param
	avcodec_open2(pCodecContext, pCodec, ¶m);

	AVFrame *pFrame = av_frame_alloc();

	// 通过像素格式(这里为 YUV)获取图片的真实大小,例如将 480 * 720 转换成 int 类型
	int nPicSize = avpicture_get_size(pCodecContext->pix_fmt, pCodecContext->width, pCodecContext->height);

	// 将 picture_size 转换成字节数据,byte
	uint8_t *buf = (uint8_t*)av_malloc(nPicSize);

	// 设置原始数据 AVFrame 的每一个frame 的图片大小,AVFrame 这里存储着 YUV 非压缩数据
	avpicture_fill((AVPicture*)pFrame, buf, pCodecContext->pix_fmt, pCodecContext->width, pCodecContext->height);

	// 编写 h264 封装格式的文件头部,基本上每种编码都有着自己的格式的头部,想看具体实现的同学可以看看 h264 的具体实现
	avformat_write_header(pFormatContext, NULL);

	//创建编码后的数据 AVPacket 结构体来存储 AVFrame 编码后生成的数据
	AVPacket pkt;
	av_new_packet(&pkt, nPicSize);

	int i = 0;
	int y_size = pCodecContext->width * pCodecContext->height;
	while (true){
		if (fread(buf, 1, y_size*3/2, pFile) <= 0){
			printf("Could not read input file.");
			break;
		}
		else if(feof(pFile)){
			break;
		}
		pFrame->data[0] = buf;  // 亮度Y
		pFrame->data[1] = buf+ y_size;  // U 
		pFrame->data[2] = buf+ y_size*5/4; // V

		pFrame->pts = i++;
		//Encode
		int got_picture = 0;
		int ret = avcodec_encode_video2(pCodecContext, &pkt, pFrame, &got_picture);
		if(ret < 0){
			printf("Encode Error.\n");
			break;
		}
		if (got_picture == 1){// 编码成功后写入 AVPacket 到 输入输出数据操作着 pFormatCtx 中,当然,记得释放内存
			pkt.stream_index = pStream->index;
			ret = av_write_frame(pFormatContext, &pkt);
			av_free_packet(&pkt);
		}
	}

	av_free_packet(&pkt);
	// 写入数据流尾部到输出文件当中,并释放文件的私有数据
	av_write_trailer(pFormatContext);

	if (pStream){
		avcodec_close(pStream->codec);// 关闭编码器
	}
	av_free(pFrame);
	av_free(buf);
	avio_close(pFormatContext->pb);
	avformat_free_context(pFormatContext);// 关闭输入数据的缓存

	fclose(pFile);
	return ;
}

int _tmain(int argc, _TCHAR* argv[])
{
	encoder();
	return 0;
}
http://download.csdn.net/detail/sz76211822/9698824
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值