[C++] 纯文本查看 复制代码
int RGB2RTSP(Mat frame, const int WIDTH, const int HEIGHT, const int FPS)
{
// namedWindow("video");
//获取视频帧的尺寸
int inWidth = WIDTH;
int inHeight = HEIGHT;
int fps = FPS;
//输出封装器和视频流配置
// fmtctx = avformat_alloc_context();
// //Guess Format
// fmt = av_guess_format(NULL, outUrl, NULL);
// fmtctx->oformat = fmt;
ret = avformat_alloc_output_context2(&fmtctx, NULL, "h264", outUrl);
fmt = fmtctx->oformat;
if(!fmtctx)
{
printf("output error\n");
return -1;
}
// fmt = av_guess_format(NULL, outUrl, NULL);
// fmtctx->oformat = fmt;
// printf("output format %s\n",fmt);
//添加视频流 视音频流对应的结构体,用于视音频编解码。
//找到编码器
avcodec_alloc_context3(video_codec);
video_codec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!video_codec)
{
printf("Can`t find h264 encoder!");
}
AVStream *video_st = avformat_new_stream(fmtctx, 0);
if (video_st == NULL)
{
printf("avformat_new_stream failed");
}
// video_st->id = fmtctx->nb_streams-1; //add
//附加标志,这个一定要设置
video_st->codecpar->codec_tag = 0;
if (fmtctx->oformat->flags & AVFMT_GLOBALHEADER)
video_st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
//从编码器复制参数
av_dump_format(fmtctx, 0, outUrl, 1);
//Open output URL
if (!(fmtctx->flags & AVFMT_NOFILE))
{
ret = avio_open(&fmtctx->pb,outUrl, AVIO_FLAG_WRITE);
if(ret < 0)
{
printf("Failed to open output file! \n");
return -1;
}
}
//写入封装头
if(avformat_write_header(fmtctx, NULL) < 0)
{
printf("write header failed\n");
return -1;
}
//初始化编码
// c = video_st->codec;
//创建编码器
c = avcodec_alloc_context3(video_codec);
if (!c)
{
printf("avcodec_alloc_context3 failed!");
}
//配置编码器参数
c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; //全局参数
c->codec_id = video_codec->id;
c->codec_type = AVMEDIA_TYPE_VIDEO;
c->thread_count = 8;
c->bit_rate = 50 * 1024 * 8;//压缩后每秒视频的bit位大小 50kB
c->width = inWidth;
c->height = inHeight;
c->pix_fmt = AV_PIX_FMT_YUV420P;
c->time_base = { 1,fps };
c->framerate = { fps,1 };
//画面组的大小,多少帧一个关键帧
c->gop_size = 10;
c->max_b_frames = 3;
c->qmin = 10;
c->qmax = 51;
// Set Option
AVDictionary *param = 0;
//H.264
av_dict_set(¶m, "preset", "slow", 0);
av_dict_set(¶m, "tune", "zerolatency", 0);
//打开编码器
if(avcodec_open2(c, video_codec, ¶m) < 0)
{
printf("Failed to open encoder! \n");
return -1;
}
printf("avcodec_open2 success!\n");
// int vpts = 0;
// imshow("video", frame);
// waitKey(1);
//初始化格式转换上下文
vsc = sws_getCachedContext(vsc,
inWidth, inHeight, AV_PIX_FMT_BGR24, //源宽、高、像素格式
inWidth, inHeight, AV_PIX_FMT_YUV420P,//目标宽、高、像素格式
SWS_BICUBIC, // 尺寸变化使用算法
0, 0, 0
);
if (!vsc)
{
printf("sws_getCachedContext failed!");
}
//初始化输出的数据结构。未压缩的数据
yuv = av_frame_alloc();
yuv->format = AV_PIX_FMT_YUV420P;
yuv->width = inWidth;
yuv->height = inHeight;
yuv->pts = 0;
//分配yuv空间
ret = av_frame_get_buffer(yuv, 32);
picture_size = avpicture_get_size(AV_PIX_FMT_YUV420P, OUTWIDTH, OUTHEIGHT);
uint8_t* picture_buf = (uint8_t *)av_malloc(picture_size);
avpicture_fill((AVPicture *)yuv, picture_buf, c->pix_fmt, c->width, c->height);
///rgb to yuv
//输入的数据结构
uint8_t *indata[AV_NUM_DATA_POINTERS] = { 0 };
//indata[0] bgrbgrbgr
//plane indata[0] bbbbb indata[1]ggggg indata[2]rrrrr
indata[0] = frame.data;
int insize[AV_NUM_DATA_POINTERS] = { 0 };
//一行(宽)数据的字节数
insize[0] = frame.cols * frame.elemSize();
int h = sws_scale(vsc, indata, insize, 0, frame.rows, //源数据
yuv->data, yuv->linesize);
if (h <= 0)
{
printf("transmode error");
return 1;
}
//cout << h << " " << flush;
//存储压缩数据(视频对应H.264等码流数据,音频对应AAC/MP3等码流数据)
// pack = av_packet_alloc();
av_new_packet(&pkt, picture_size);
///h264编码
yuv->pts = vpts;
vpts++;
int got_output;
ret = avcodec_encode_video2(c, &pkt, yuv, &got_output);
if(ret < 0)
{
printf("Failed to encode \n");
return -1;
}
printf("ret: %i\n",ret);
if(got_output == 1)
{
printf("encoded successed\n");
waitKey();
pkt.stream_index = video_st->index;
ret = av_write_frame(fmtctx, &pkt);
av_free_packet(&pkt);
}
//Flush Encoder
// ret = flush_encoder(fmtctx,0);
// if (ret < 0)
// {
// printf("Flushing encoder failed\n");
// return -1;
// }
//Write file trailer
av_write_trailer(fmtctx);
if (video_st)
{
av_free(yuv);
av_free(picture_buf);
}
// ret = avcodec_send_frame(vc, yuv);
// if (ret != 0)
// return 1;
// ret = avcodec_receive_packet(vc, pack);
// if (ret == 0 || pack->size > 0)
// {
// printf("pack size: %d\n", pack->size);
// }
// else
// {
// printf("encoded error\n");
// return 1;
// }
// AVRational rate = {1, FPS};
// printf("pre pack pts: %d\n", pack->pts);
// printf("vc time_base: %d\n", vc->time_base);
// printf("vs time_base: %d\n", vs->time_base);
// //计算pts dts和duration。
//// pack.pts = av_rescale_q(pack.pts, vc->time_base, vs->time_base);
// pack->pts = av_rescale_q(pack->pts,rate,vs->time_base);
// printf("pack pts: %d\n", pack->pts);
// ret = av_interleaved_write_frame(ic, pack);
//// ret = av_write_frame(ic, &pack);
// if (ret == 0)
// {
// printf("#");
// }
// sws_freeContext(vsc);
// vsc = NULL;
// avio_closep(&ic->pb);
// avcodec_free_context(&vc);
//getchar();
return 0;
}