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

基于vs2017 vc++  ffmpeg4.0.2下测试

ffmpeg 环境配置请百度(vs2017 ffmpeg )图像和声音请安装screencapturer便于查找

部分方法在https://blog.csdn.net/Java_lilin/article/details/85118365中查找

 头文件参考上篇教程

static int test3() {
    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 = 320;
    enctx->height = 240;

    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);

    AVDictionary* opt = NULL;
    int ret = avcodec_open2(enctx, encodec,&opt);
    av_dict_free(&opt);

    if (ret < 0) {
        printf("not open video codec");
        return -1;
    }
//    AVFormatContext *formatctx = avformat_alloc_context();

    //添加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);
                }
                av_packet_unref(&pkt); 
            }
            av_packet_unref(&packet);
        }
    }
    av_frame_free(&frame);
    av_frame_free(&yupframe);
    avcodec_free_context(&ctx);
    avformat_close_input(&formatCtx); 

    //end
    avcodec_free_context(&enctx);

    fclose(h264file);
}

int main()
{
    printf("ok:%d\n", avcodec_version());
    avdevice_register_all(); 
    test3();//视频采集h264压缩

}

讨论群261074724

猜你喜欢

转载自blog.csdn.net/Java_lilin/article/details/85119632