可以借鉴的:C++使用FFmpeg实现YUV数据编码转视频文件_C 语言_脚本之家
yuv文件下载地址:YUV Sequences
无压缩的方式推送本地yuv文件 代码:
#include <stdio.h>
#include <unistd.h>
#include <iostream>
extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
};
using namespace std;
const char* input_file = "/mnt/hgfs/shareVM/BigBuckBunny_CIF_24fps.yuv";
const char* output_rtmp_url = "rtmp://10.10.18.94:1935/live/test";
int main(int argc, char *argv[]) {
AVFormatContext *pFormatCtx = nullptr;
AVOutputFormat *fmt = nullptr;
AVStream *video_st = nullptr;
AVCodecContext *pCodecCtx = nullptr;
AVCodec *pCodec = nullptr;
uint8_t *picture_buf = nullptr;
int size;
//打开视频文件
FILE *in_file = fopen(input_file, "rb");
if (!in_file) {
cout << "can not open file!" << endl;
return -1;
}
//[1] --注册所有ffmpeg组件
avcodec_register_all();
av_register_all();
//[2] --初始化AVFormatContext结构体,根据文件名获取到合适的封装格式
avformat_alloc_output_context2(&pFormatCtx, NULL, "flv", output_rtmp_url);
fmt = pFormatCtx->oformat;
//[3] --打开文件
if (avio_open(&pFormatCtx->pb, output_rtmp_url, AVIO_FLAG_READ_WRITE)) {
cout << "output file open fail!";
return -1;
}
//[3]
//[4] --初始化视频码流
video_st = avformat_new_stream(pFormatCtx, 0);
if (video_st == NULL)
{
printf("failed allocating output stram\n");
return -1;
}
video_st->time_base.num = 1;
video_st->time_base.den = 25;
//[4]
//[5] --编码器Context设置参数
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 = 352;
pCodecCtx->height = 288;
pCodecCtx->time_base = {1, 25};
pCodecCtx->framerate = {25, 1};
pCodecCtx->bit_rate = 400000;
pCodecCtx->gop_size = 50;
//[5]
//[6] --寻找编码器并打开编码器
pCodec = avcodec_find_encoder(AV_CODEC_ID_FLV1);
if (!pCodec)
{
cout << "no right encoder!" << endl;
return -1;
}
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
{
cout << "open encoder fail!" << endl;
return -1;
}
//[6]
//输出格式信息
av_dump_format(pFormatCtx, 0, output_rtmp_url, 1);
//初始化帧
AVFrame *picture = av_frame_alloc();
picture->width = pCodecCtx->width;
picture->height = pCodecCtx->height;
picture->format = pCodecCtx->pix_fmt;
av_frame_get_buffer(picture, 32);
size = avpicture_get_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
picture_buf = (uint8_t*)av_malloc(size);
avpicture_fill((AVPicture*)picture, picture_buf, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
//[7] --写头文件
avformat_write_header(pFormatCtx, NULL);
//[7]
//[8] --循环编码每一帧
AVPacket pkt; //创建已编码帧
int frame_count = 0;
while (!feof(in_file)) {
// 读取一帧 YUV 数据
uint8_t yuv_buf[pCodecCtx->width * pCodecCtx->height * 3 / 2];
size_t read_size = fread(yuv_buf, 1, pCodecCtx->width * pCodecCtx->height * 3 / 2, in_file);
if (read_size <= 0) {
break;
}
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
// 将 YUV 数据编码为 H.264
memcpy(picture->data[0], yuv_buf, pCodecCtx->width * pCodecCtx->height);
memcpy(picture->data[1], yuv_buf + pCodecCtx->width * pCodecCtx->height, pCodecCtx->width * pCodecCtx->height / 4);
memcpy(picture->data[2], yuv_buf + pCodecCtx->width * pCodecCtx->height * 5 / 4, pCodecCtx->width * pCodecCtx->height / 4);
picture->pts = frame_count;
int got_picture = 0;
//编码
int ret = avcodec_encode_video2(pCodecCtx, &pkt, picture, &got_picture);
if (ret < 0)
{
cout << "encoder fail!" << endl;
return -1;
}
if (!got_picture)
{
ret = 0;
break;
}
cout << "encoder success! " <<picture->pts<< endl;
// parpare packet for muxing
pkt.stream_index = video_st->index;
pkt.pts = frame_count * (pCodecCtx->time_base.den) / ((pCodecCtx->time_base.num) * 25);
pkt.dts = pkt.pts;
av_packet_rescale_ts(&pkt, pCodecCtx->time_base, video_st->time_base);
pkt.pos = -1;
ret = av_interleaved_write_frame(pFormatCtx, &pkt);
if(ret < 0)
break;
av_free_packet(&pkt);
frame_count++;
usleep(30*1000);
}
//[8]
//[9] --写文件尾
av_write_trailer(pFormatCtx);
//[9]
//释放内存
if (video_st)
{
avcodec_close(video_st->codec);
av_free(picture);
av_free(picture_buf);
}
if (pFormatCtx)
{
avio_close(pFormatCtx->pb);
avformat_free_context(pFormatCtx);
}
fclose(in_file);
return 0;
}
压缩一半的方式推送本地yuv文件 代码:
#include <stdio.h>
#include <unistd.h>
#include <iostream>
extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
};
using namespace std;
const char* input_file = "/mnt/hgfs/shareVM/BigBuckBunny_CIF_24fps.yuv";
const char* output_rtmp_url = "rtmp://10.10.18.94:1935/live/test";
const int fps = 25;
int main(int argc, char *argv[]) {
AVFormatContext *pFormatCtx = nullptr;
AVCodecContext *pCodecCtx = nullptr;
//打开视频文件
FILE *in_file = fopen(input_file, "rb");
if (!in_file) {
cout << "can not open file!" << endl;
return -1;
}
//[1] --注册所有ffmpeg组件
avcodec_register_all();
av_register_all();
//[2] --初始化AVFormatContext结构体,根据文件名获取到合适的封装格式
avformat_alloc_output_context2(&pFormatCtx, NULL, "flv", output_rtmp_url);
AVOutputFormat *fmt = pFormatCtx->oformat;
//[3] --打开文件
if (avio_open(&pFormatCtx->pb, output_rtmp_url, AVIO_FLAG_READ_WRITE)) {
cout << "output file open fail!";
return -1;
}
//[3]
//[4] --初始化视频码流
AVStream *video_st = avformat_new_stream(pFormatCtx, 0);
if (video_st == NULL)
{
printf("failed allocating output stram\n");
avio_close(pFormatCtx->pb);
avformat_free_context(pFormatCtx);
return -1;
}
video_st->time_base.num = 1;
video_st->time_base.den = fps;
//[4]
struct SwsContext* swsContext = sws_getContext(352, 288, AV_PIX_FMT_YUV420P,
352 / 2, 288 / 2, AV_PIX_FMT_YUV420P,
SWS_BICUBIC, NULL, NULL, NULL);
if(swsContext == NULL) {
printf("failed sws_getContext\n");
avio_close(pFormatCtx->pb);
avformat_free_context(pFormatCtx);
return -1;
}
//[5] --编码器Context设置参数
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 = 352 / 2;
pCodecCtx->height = 288 / 2;
pCodecCtx->time_base = {1, fps};
pCodecCtx->framerate = {fps, 1};
pCodecCtx->bit_rate = 400000;
pCodecCtx->gop_size = 50;
//[5]
//[6] --寻找编码器并打开编码器
AVCodec *pCodec = avcodec_find_encoder(AV_CODEC_ID_FLV1);
if (!pCodec)
{
cout << "no right encoder!" << endl;
return -1;
}
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
{
cout << "open encoder fail!" << endl;
avformat_free_context(pFormatCtx);
return -1;
}
//[6]
//输出格式信息
av_dump_format(pFormatCtx, 0, output_rtmp_url, 1);
//初始化帧
AVFrame *originalFrame = av_frame_alloc();
originalFrame->width = 352;
originalFrame->height = 288;
originalFrame->format = pCodecCtx->pix_fmt;
av_frame_get_buffer(originalFrame, 32);
int originalFrame_size = avpicture_get_size(pCodecCtx->pix_fmt, 352, 288);
uint8_t* originalFrame_buf = (uint8_t*)av_malloc(originalFrame_size);
avpicture_fill((AVPicture*)originalFrame, originalFrame_buf, pCodecCtx->pix_fmt, 352, 288);
AVFrame *compressFrame = av_frame_alloc();
compressFrame->width = pCodecCtx->width;
compressFrame->height = pCodecCtx->height;
compressFrame->format = pCodecCtx->pix_fmt;
av_frame_get_buffer(compressFrame, 32);
int compressFrame_size = avpicture_get_size((AVPixelFormat)compressFrame->format, compressFrame->width, compressFrame->height);
uint8_t* compressFrame_buf = (uint8_t*)av_malloc(compressFrame_size);
avpicture_fill((AVPicture*)compressFrame, compressFrame_buf, (AVPixelFormat)compressFrame->format, compressFrame->width, compressFrame->height);
//[7] --写头文件
avformat_write_header(pFormatCtx, NULL);
//[7]
//[8] --循环编码每一帧
AVPacket pkt; //创建已编码帧
int frame_count = 0;
while (!feof(in_file)) {
// 读取一帧 YUV 数据
uint8_t yuv_buf[352 * 288 * 3 / 2];
size_t read_size = fread(yuv_buf, 1, 352 * 288 * 3 / 2, in_file);
if (read_size <= 0) {
break;
}
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
// 将 YUV 数据编码为 H.264
memcpy(originalFrame->data[0], yuv_buf, 352 * 288);
memcpy(originalFrame->data[1], yuv_buf + 352 * 288, 352 * 288 / 4);
memcpy(originalFrame->data[2], yuv_buf + 352 * 288 * 5 / 4, 352 * 288 / 4);
originalFrame->pts = compressFrame->pts = frame_count;
int got_picture = 0;
sws_scale(swsContext, (const uint8_t* const*)originalFrame->data, originalFrame->linesize, 0,
288, compressFrame->data, compressFrame->linesize);
//编码
int ret = avcodec_encode_video2(pCodecCtx, &pkt, compressFrame, &got_picture);
if (ret < 0)
{
cout << "encoder fail!" << endl;
return -1;
}
if (got_picture)
{
cout << "encoder success! " <<compressFrame->pts<< endl;
// parpare packet for muxing
pkt.stream_index = video_st->index;
pkt.pts = frame_count * (pCodecCtx->time_base.den) / ((pCodecCtx->time_base.num) * fps);
pkt.dts = pkt.pts;
av_packet_rescale_ts(&pkt, pCodecCtx->time_base, video_st->time_base);
pkt.pos = -1;
ret = av_interleaved_write_frame(pFormatCtx, &pkt);
if(ret < 0)
break;
}
av_free_packet(&pkt);
frame_count++;
usleep(30 * 1000);
}
//[8]
//[9] --写文件尾
av_write_trailer(pFormatCtx);
//[9]
//释放内存
if (video_st)
{
avcodec_close(video_st->codec);
av_free(originalFrame);
av_free(originalFrame_buf);
av_free(compressFrame);
av_free(compressFrame_buf);
}
if (pFormatCtx)
{
avio_close(pFormatCtx->pb);
avformat_free_context(pFormatCtx);
}
fclose(in_file);
return 0;
}