FFmpeg与音视频流媒体工程开发相关

[FFmpeg C/C++]AVFrame转PNG

2020-04-23  本文已影响0人  _小老虎_

最终Pkt直接写入文件也可以,总之都是压缩编码的。


static int EncodeYUVToPNG(AVFrame* pictureFrame, const char* OutputFileName, int in_w, int in_h) {
    AVFormatContext *pFormatCtx = NULL;
    AVStream *video_st = NULL;
    AVCodecContext* pCodecCtx = NULL;

    AVCodec *pCodec = NULL;
    AVPacket *pkt = NULL;          //编码后数据,如jpeg等

    fflush(stdout);

    pFormatCtx = avformat_alloc_context();
    avformat_alloc_output_context2(&pFormatCtx, NULL, NULL, OutputFileName);
//    // 创建并初始化一个和该url相关的AVIOContext
//    if (avio_open(&pFormatCtx->pb, OutputFileName, AVIO_FLAG_READ_WRITE) < 0) {
//        printf("Couldn't open output file");
//        return -1;
//    }
//    pFormatCtx->oformat = av_guess_format("mjpeg", NULL, NULL);

    struct SwsContext *swCtx = sws_getContext(pictureFrame->width,
                                        pictureFrame->height,
                                        AV_PIX_FMT_YUV420P,
                                        in_w,
                                        in_h,
                                        AV_PIX_FMT_RGB24,
                                        SWS_FAST_BILINEAR, 0, 0, 0);

    AVFrame * rgbFrame = av_frame_alloc();
    rgbFrame->width = in_w;
    rgbFrame->height = in_h;
    rgbFrame->format = AV_PIX_FMT_RGB24;

    avpicture_alloc((AVPicture *)rgbFrame, AV_PIX_FMT_RGB24, in_w, in_h);
    sws_scale(swCtx, pictureFrame->data, pictureFrame->linesize, 0, pictureFrame->height, rgbFrame->data, rgbFrame->linesize);

    // 获取编解码上下文信息
    pCodecCtx = avcodec_alloc_context3(NULL);
//    pCodecCtx->codec_id = pFormatCtx->oformat->video_codec;
    pCodecCtx->codec_id = AV_CODEC_ID_PNG;
    pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
    pCodecCtx->pix_fmt = AV_PIX_FMT_RGB24;
    pCodecCtx->width = in_w;
    pCodecCtx->height = in_h;
    pCodecCtx->time_base = (AVRational){1, 30};

    //print log info;
    av_dump_format(pFormatCtx, 0, OutputFileName, 1);

    pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
    if (!pCodec) {
        printf("Codec not found.");
        return -1;
    }

    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
        printf("Could not open codec.\n");
        return -1;
    }

    // start encoder
    int ret = avcodec_send_frame(pCodecCtx, rgbFrame);

    pkt = av_packet_alloc();
    av_new_packet(pkt, in_w*in_h*3);

    //Read encoded data from the encoder.
    ret = avcodec_receive_packet(pCodecCtx, pkt);

    video_st = avformat_new_stream(pFormatCtx, 0);
    if (video_st == NULL) {
        return -1;
    }

    //Write Header
    avformat_write_header(pFormatCtx, NULL);

    //Write body
    av_write_frame(pFormatCtx, pkt);

    //Write Trailer
    av_write_trailer(pFormatCtx);

    printf("Encode Successful.\n");

    av_packet_unref(pkt);               //av_packet_alloc()
    av_frame_free(&rgbFrame);       //av_frame_alloc()
    avformat_free_context(pFormatCtx);  //avformat_alloc_context()

    pkt = NULL;
    rgbFrame = NULL;
    pFormatCtx = NULL;

    return 0;
}
   #define CHECK_ERR(ERR) {if ((ERR)<0) return -1; }

    int convert_first_frame_to_png(std::string const & inputVideoFileName, std::string const & outputPngName)
    {
        av_register_all();
        avcodec_register_all();

        ::AVFormatContext * ctx = NULL;
        int err = avformat_open_input(&ctx, inputVideoFileName.c_str(), NULL, NULL);
        CHECK_ERR(err);
        err = av_find_stream_info(ctx);
        CHECK_ERR(err);

        AVCodec * codec = NULL;
        int strm = av_find_best_stream(ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0);

        AVCodecContext * codecCtx = ctx->streams[strm]->codec;
        err = avcodec_open2(codecCtx, codec, NULL);
        CHECK_ERR(err);

        SwsContext * swCtx = sws_getContext(codecCtx->width, 
            codecCtx->height, 
            codecCtx->pix_fmt, 
            codecCtx->width, 
            codecCtx->height, 
            PIX_FMT_RGB24, 
            SWS_FAST_BILINEAR, 0, 0, 0);

        for (;;)
        {
            AVPacket pkt;
            err = av_read_frame(ctx, &pkt);
            CHECK_ERR(err);

            if (pkt.stream_index == strm)
            {
                int got = 0;
                AVFrame * frame = avcodec_alloc_frame();
                err = avcodec_decode_video2(codecCtx, frame, &got, &pkt);
                CHECK_ERR(err);

                if (got)
                {
                    AVFrame * rgbFrame = avcodec_alloc_frame();
                    avpicture_alloc((AVPicture *)rgbFrame, PIX_FMT_RGB24, codecCtx->width, codecCtx->height);
                    sws_scale(swCtx, frame->data, frame->linesize, 0, frame->height, rgbFrame->data, rgbFrame->linesize);

                    AVCodec *outCodec = avcodec_find_encoder(CODEC_ID_PNG);
                    AVCodecContext *outCodecCtx = avcodec_alloc_context3(codec);
                    if (!codecCtx) 
                        return -1;                  

                    outCodecCtx->width = codecCtx->width;
                    outCodecCtx->height = codecCtx->height;
                    outCodecCtx->pix_fmt = PIX_FMT_RGB24;
                    outCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
                    outCodecCtx->time_base.num = codecCtx->time_base.num;
                    outCodecCtx->time_base.den = codecCtx->time_base.den;

                    if (!outCodec || avcodec_open2(outCodecCtx, outCodec, NULL) < 0) {
                        return -1;
                    }

                    AVPacket outPacket;
                    av_init_packet(&outPacket);
                    outPacket.size = 0;
                    outPacket.data = NULL;
                    int gotFrame = 0;
                    int ret = avcodec_encode_video2(outCodecCtx, &outPacket, rgbFrame, &gotFrame);
                    if (ret >= 0 && gotFrame)
                    {
                        FILE * outPng = fopen(outputPngName.c_str(), "wb");
                        fwrite(outPacket.data, outPacket.size, 1, outPng);
                        fclose(outPng);
                    }

                    avcodec_close(outCodecCtx);
                    av_free(outCodecCtx);

                    break;
                }
                avcodec_free_frame(&frame);
            }
        }
    }
上一篇 下一篇

猜你喜欢

热点阅读