基于vs2017 vc++ ffmpeg4.0.2下测试
ffmpeg 环境配置请百度(vs2017 ffmpeg )图像和声音请安装screencapturer便于查找
部分方法在https://blog.csdn.net/Java_lilin/article/details/85118365中查找
头文件参考上篇教程
static int test6() {
const char* filename = "C:\\Users\\lilin\\Desktop\\1.mp4";
AVFormatContext *oc = NULL;
avformat_alloc_output_context2(&oc, NULL, NULL, filename);
if (oc == NULL) {
printf("AVFormatContext init fail");
return -1;
}
AVOutputFormat *fmt = oc->oformat;
fmt->video_codec = AV_CODEC_ID_H264;
AVCodec *encodec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!encodec) {
printf("not found encoder for H264");
avcodec_get_name(AV_CODEC_ID_H264);
return -1;
}
AVStream *st = avformat_new_stream(oc, encodec);
st->id = oc->nb_streams - 1;
//test3daima
/*AVCodec *encodec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!encodec) {
printf("not found encoder for h264");
avcodec_get_name(AV_CODEC_ID_H264);
return -1;
}*/
AVCodecContext *enctx = avcodec_alloc_context3(encodec);
enctx->codec_id = AV_CODEC_ID_H264;
enctx->bit_rate = 8000000;//码率
enctx->width = 1920;
enctx->height = 1080;
AVRational base; base.num = 1; base.den = 15;//帧率
enctx->time_base = base;
enctx->gop_size = 12;
enctx->max_b_frames = 0;
enctx->pix_fmt = AV_PIX_FMT_YUV420P;//h264必须
enctx->gop_size = 12;
enctx->max_b_frames = 0;
//减少延迟
av_opt_set(enctx->priv_data, "preset", "superfast", 0);
av_opt_set(enctx->priv_data, "tune", "zerolatency", 0);
//播放器播放不出来
if (fmt->flags&AVFMT_GLOBALHEADER) {
enctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
AVDictionary* opt = NULL;
int ret = avcodec_open2(enctx, encodec, &opt);
av_dict_free(&opt);
if (ret < 0) {
printf("not open video codec");
return -1;
}
//add关联 把编辑器参数传递给输出流
avcodec_parameters_from_context(st->codecpar, enctx);
av_dump_format(oc, 0, filename, 1);//打印输出流
//打开写头信息
if (!(fmt->flags&AVFMT_NOFILE)) {
ret = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE);
if (ret < 0) {
printf("无法输出到指定位置");
return -1;
}
}
/*write stram header if any*/
opt = NULL;
ret = avformat_write_header(oc, &opt);
av_dict_free(&opt);
if (ret < 0) {
printf("open output file error");
return -1;
}
//添加test1的代码 begin
AVFormatContext *formatCtx = avformat_alloc_context();
AVInputFormat *ifmt = av_find_input_format("gdigrab");//设备类型
//AVInputFormat *ifmt = av_find_input_format("dshow");//设备类型
AVDictionary* options = NULL;
//av_dict_set(&options, "video_size","1920*1080",0);//大小 默认全部
av_dict_set(&options, "framerate", "15", 0);//帧lu
if (avformat_open_input(&formatCtx, "desktop", ifmt, &options) != 0) {
//if (avformat_open_input(&formatCtx, "video=Integrated Camera", ifmt, &options) != 0) {
printf("open input device fail\n");
return -1;
}
av_dict_free(&options);
if (avformat_find_stream_info(formatCtx, NULL) < 0) {
printf("avformat_find_stream_info faill\n");
return -1;
}
if (formatCtx->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) {
printf("no find stream info\n");
return -1;
}
//查找解密器
AVCodec *codec = avcodec_find_decoder(formatCtx->streams[0]->codecpar->codec_id);
if (codec == NULL) {
printf("codec not found\n");
return -1;
}
AVCodecContext *ctx = avcodec_alloc_context3(codec);
avcodec_parameters_to_context(ctx, formatCtx->streams[0]->codecpar);
if (avcodec_open2(ctx, codec, NULL) < 0) {
printf("codec not open\n");
return -1;
}
printf("pix format is %d\n", formatCtx->streams[0]->codecpar->format);//==AVPixelFormat->AV_PIX_FMT_BGRA
AVFrame *frame = alloc_picture((AVPixelFormat)formatCtx->streams[0]->codecpar->format, formatCtx->streams[0]->codecpar->width, formatCtx->streams[0]->codecpar->height);
//图像缩放
SwsContext *img_convert_ctx = sws_getContext(formatCtx->streams[0]->codecpar->width, formatCtx->streams[0]->codecpar->height, (AVPixelFormat)formatCtx->streams[0]->codecpar->format,
enctx->width, enctx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
//目标
AVFrame *yupframe = alloc_picture(AV_PIX_FMT_YUV420P, enctx->width, enctx->height);
//FILE *h264file = NULL;
//fopen_s(&h264file, "C:\\Users\\lilin\\Desktop\\1.h264", "wb");//ffplay -stats -f h264 1.h264
int64_t nexttps = 0;
int64_t num = 100;
while (num--) {
AVPacket packet = { 0 };
av_init_packet(&packet);
if (av_read_frame(formatCtx, &packet) >= 0) {
avcodec_send_packet(ctx, &packet);
if (avcodec_receive_frame(ctx, frame) < 0) {
printf("decode error\n");
}
else {
printf("采集到图片");
//转换 AV_PIX_FMT_BGRA to AV_PIX_FMT_YUV420P
sws_scale(img_convert_ctx, (const unsigned char* const*)frame->data, frame->linesize, 0, frame->height, yupframe->data, yupframe->linesize);
if (nexttps == 0) { yupframe->pts = av_gettime(); }
else { yupframe->pts = nexttps; }
nexttps = yupframe->pts + 1000000LL * enctx->time_base.num / enctx->time_base.den;
{
AVRational base; base.num = 1; base.den = 1000000LL;//帧率
//转换回去去压缩器的时基
yupframe->pts = av_rescale_q(yupframe->pts, base, enctx->time_base);
}
//开始压缩
avcodec_send_frame(enctx, yupframe);
AVPacket pkt = { 0 };
av_init_packet(&pkt);
ret = avcodec_receive_packet(enctx, &pkt);
if (ret == 0) {//需去掉前面4个才是标准h264流
//压缩成功
//char nal_stat[] = { 0,0,0,1 };
//fwrite(nal_stat, 4, 1, h264file);
//fwrite(pkt.data + 4, pkt.size - 4, 1, h264file);
write_frame(oc,&enctx->time_base,st,&pkt);
}
av_packet_unref(&pkt);
}
av_packet_unref(&packet);
}
}
//关闭liou
av_write_trailer(oc);
av_frame_free(&frame);
av_frame_free(&yupframe);
avcodec_free_context(&ctx);
avformat_close_input(&formatCtx);
//end
avcodec_free_context(&enctx);
//fclose(h264file);
//关闭liou
avformat_close_input(&oc);
}
int main()
{
printf("ok:%d\n", avcodec_version());
avdevice_register_all();
test6();
}
讨论群261074724