ffmpeg4教程5:采集桌面图像(desktop)压缩为MP4

基于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

猜你喜欢

转载自blog.csdn.net/Java_lilin/article/details/85119904
今日推荐