/*
* 一笑奈何
* cn-yixiaonaihe.blog.csdn.net
*/
#include <iostream>
#include <thread>
extern "C" {
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
}
using namespace std;
static double r2d(AVRational r)
{
return r.den == 0 ? 0 : (double)r.num / (double)r.den;
}
void XSleep(int ms)
{
//c++ 11
chrono::milliseconds du(ms);
this_thread::sleep_for(du);
}
int main(int argc, char *argv[])
{
cout << "Test Demux FFmpeg.club" << endl;
const char *url = "test.rgb";
const char *outfile = "test.mov";
//初始化封装库
av_register_all();
//初始化网络库 (可以打开rtsp rtmp http 协议的流媒体视频)
avformat_network_init();
//注册解码器
avcodec_register_all();
FILE *fp = fopen(url,"rb");
int width = 1920;
int height = 1080;
int fps = 25;
static int i = 0;
char errorbuf[1024];
if (!fp)
{
cout << "open FILE failed!" << endl;
fclose(fp);
return -1;
}
AVCodec *codec=avcodec_find_encoder(AV_CODEC_ID_H264);
if (!codec)
{
cout << "avcodec_find_encoder No" << endl;
return -1;
}
AVCodecContext *c = avcodec_alloc_context3(codec);
if (!c)
{
cout << "avcodec_alloc_context3 No" << endl;
return -1;
}
c->bit_rate = 400000000;
c->width = width;
c->height = height;
c->time_base = { 1,fps };
c->framerate = { fps,1 };
c->gop_size = 50;
c->max_b_frames = 0;
c->pix_fmt = AV_PIX_FMT_YUV420P;
c->codec_id = AV_CODEC_ID_H264;
c->thread_count = 8;
//全局编码
c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
int ret = avcodec_open2(c, codec, 0);
if (ret < 0)
{
cout << "avcodec_open2 No" << endl;
return -1;
}
cout << "avcodec_open2 OK" << endl;
//2 create out context
AVFormatContext *oc = nullptr;
avformat_alloc_output_context2(&oc, 0, 0, outfile);
//3 add video stream
AVStream *st = avformat_new_stream(oc, NULL);
//st->codec = c;
st->id = 0;
st->codecpar->codec_tag = 0;
avcodec_parameters_from_context(st->codecpar,c);
cout << "========================" << endl;
av_dump_format(oc, 0, outfile, 1);
cout << "========================" << endl;
//4 rgb to yuv
SwsContext *ctx = NULL;
ctx = sws_getCachedContext(ctx,
width, height, AV_PIX_FMT_BGRA,
width, height, AV_PIX_FMT_YUV420P,
SWS_BICUBIC,NULL,NULL,NULL);
//输入的空间
unsigned char *rgb = new unsigned char[width * height * 4];
//输出的空间
AVFrame *yuv = av_frame_alloc();
yuv->format = AV_PIX_FMT_YUV420P;
yuv->width = width;
yuv->height = height;
//分配空间
ret=av_frame_get_buffer(yuv, 32);
if (ret < 0)
{
cout << "av_frame_get_buffer No" << endl;
return -1;
}
//5 wirte mp4 head
//写入文件头信息
ret = avio_open(&oc->pb, outfile, AVIO_FLAG_WRITE);//打开输出文件IO
if (ret < 0)
{
cout << "avio_open failed" << endl;
getchar();
return -1;
}
ret = avformat_write_header(oc, NULL);
if (ret < 0)
{
cout << "avformat_write_header failed" << endl;
getchar();
}
int p = 0;
for (;;)
{
int len = fread(rgb, 1, width * height * 4, fp);
if (len <= 0)break;
uint8_t *indata[AV_NUM_DATA_POINTERS] = { 0 };
indata[0] = rgb;
int inlinesize[AV_NUM_DATA_POINTERS] = { 0 };
inlinesize[0] = width * 4;//*4字节数
int h=sws_scale(ctx, indata, inlinesize, 0, height,
yuv->data,
yuv->linesize);
if (h <= 0)
break;
//6 encode frame
yuv->pts = p;
p = p + 3600;
//yuv->pict_type = AV_PICTURE_TYPE_I;
ret=avcodec_send_frame(c, yuv);
if (ret != 0)
{
continue;
}
AVPacket pkt;
av_init_packet(&pkt);
//一次发送可能多次接收
ret = avcodec_receive_packet(c, &pkt);
if (ret != 0)
{
av_strerror(ret, errorbuf, sizeof(errorbuf));
cout << "avcodec_receive_packet NO ->" << errorbuf << " "<<ret<<endl;
cout << " Number :" << i << " "<<ret<<endl;
i++;
continue;
}
//av_write_frame(oc, &pkt);
//av_packet_unref(&pkt);
av_interleaved_write_frame(oc, &pkt);
cout << "<" << pkt.size << ">";
}
//写入视频索引尾部信息
av_write_trailer(oc);
//主动关闭后才可以把缓冲区的内容写到文件
avio_close(oc->pb);
//清理封装输出上下文
avformat_free_context(oc);
//关闭编码器
avcodec_close(c);
//清理编码器上下文
avcodec_free_context(&c);
//清理视频重采样上下文
sws_freeContext(ctx);
delete rgb;
fclose(fp);
cout << "==================end===============" << endl;
return 0;
}
【FFMPEG应用篇】基于FFmpeg的RGB格式封装MOV文件
于 2020-11-01 13:14:57 首次发布