【初学ffmpeg】ffmpeg编码yuv420p为h264

通过ffmpeg的demo修改的

Mingw Cygwin 皆可编译通过

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>

extern "C" {
    #include <libavcodec/avcodec.h>
    #include <libavutil/opt.h>
    #include <libavutil/imgutils.h>
}

static void encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt,
                   FILE *outfile)
{
    int ret;

    /* send the frame to the encoder */
    if (frame)
        fprintf(stderr, "Send frame %3lld\n", frame->pts);

    ret = avcodec_send_frame(enc_ctx, frame);
    if (ret < 0) {
        fprintf(stderr, "Error sending a frame for encoding\n");
        exit(1);
    }

    while (ret >= 0) {
        ret = avcodec_receive_packet(enc_ctx, pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
            return;
        else if (ret < 0) {
            fprintf(stderr, "Error during encoding\n");
            exit(1);
        }

        fprintf(stderr, "Write packet %3lld(size=%5d)\n", pkt->pts, pkt->size);
        fwrite(pkt->data, 1, pkt->size, outfile);
        av_packet_unref(pkt);
    }
}

int main(int argc, char **argv)
{
    const AVCodec *codec;
    AVCodecContext *pCodecCtx= NULL;
    int i, ret, x, y;
    FILE *outfp, *infp;
    AVFrame *pFrame;
    AVPacket *packet;

    const char *infile = "D:\\test.yuv";
    const char *outfile = "D:\\out.264";
    int width = 768, height = 432;    //输入yuv的分辨率
    if(width%2 != 0 || height %2 != 0) {
        fprintf(stderr, "resolution must be a multiple of two\n");
        exit(0);
    }

    /* find the encoder */
//    codec = avcodec_find_encoder_by_name("h264_amf");     //amd 硬编码
//    codec = avcodec_find_encoder_by_name("h264_nvenc");   //nvdia 硬编码
//    codec = avcodec_find_encoder_by_name("h264_qsv");     //intel 硬编码
    codec = avcodec_find_encoder(AV_CODEC_ID_H264);      //软编码
    if (!codec) {
        fprintf(stderr, "Codec not found\n");
        exit(1);
    }
    printf("fullname = %s\n", codec->long_name);

    pCodecCtx = avcodec_alloc_context3(codec);
    if (!pCodecCtx) {
        fprintf(stderr, "Could not allocate video codec context\n");
        exit(1);
    }

    packet = av_packet_alloc();
    if (!packet)
        exit(1);

    /* put sample parameters */
    pCodecCtx->bit_rate = 2000000;
    /* resolution must be a multiple of two */
    pCodecCtx->width = width;
    pCodecCtx->height = height;
    /* frames per second */
    pCodecCtx->time_base = (AVRational){1, 25};
    pCodecCtx->framerate = (AVRational){25, 1};

    /* emit one intra frame every ten frames
     * check frame pict_type before passing frame
     * to encoder, if frame->pict_type is AV_PICTURE_TYPE_I
     * then gop_size is ignored and the output of encoder
     * will always be I frame irrespective to gop_size
     */
    pCodecCtx->gop_size = 20;
    pCodecCtx->max_b_frames = 0;
#if 1
    //YUV420P格式
    pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
#else
    //intel硬编时选择NV12格式
    pCodecCtx->pix_fmt = AV_PIX_FMT_NV12;
#endif
    //ultrafast superfast veryfast faster fast medium slow slower veryslow placebo  速度越慢质量越好
    if (codec->id == AV_CODEC_ID_H264)
        av_opt_set(pCodecCtx->priv_data, "preset", "veryslow", 0);

    /* open it */
    ret = avcodec_open2(pCodecCtx, codec, NULL);
    if (ret < 0) {
        fprintf(stderr, "Could not open codec, ret = %d\n", ret);
        exit(1);
    }

    infp = fopen(infile, "rb");
    if (!infp) {
        fprintf(stderr, "Could not open %s\n", infile);
        exit(1);
    }
    outfp = fopen(outfile, "wb");
    if (!outfp) {
        fprintf(stderr, "Could not open %s\n", outfile);
        fclose(infp);
        exit(1);
    }

    pFrame = av_frame_alloc();
    if (!pFrame) {
        fprintf(stderr, "Could not allocate video frame\n");
        exit(1);
    }
    pFrame->format = pCodecCtx->pix_fmt;
    pFrame->width  = pCodecCtx->width;
    pFrame->height = pCodecCtx->height;

    ret = av_frame_get_buffer(pFrame, 0);
    if (ret < 0) {
        fprintf(stderr, "Could not allocate the video frame data\n");
        exit(1);
    }

    int rsize = width*height + width*height/2;
    uint8_t * rbuf = new uint8_t[rsize];
    for (i = 0; ; i++) {
        fflush(stdout);

        memset(rbuf, 0, rsize);
        uint8_t *ptr = rbuf;
        ret = fread(rbuf, 1, rsize, infp);
        if(ret != rsize) {
            break;
        }

        /* make sure the frame data is writable */
        ret = av_frame_make_writable(pFrame);
        if (ret < 0)
            exit(1);

        /* prepare a dummy image */
        memcpy(pFrame->data[0], rbuf,  width*height);
#if 1
        //YUV420P格式
        memcpy(pFrame->data[1], rbuf+width*height, width*height/4);
        memcpy(pFrame->data[2], rbuf+width*height+width*height/4, width*height/4);
#else
        //NV12格式
        uint8_t *uptr = rbuf + width*height, *vptr = rbuf + width*height*5/4;
        uint8_t *dst = &pFrame->data[1][0];
        for (int ii = 0; ii < height*width/4; ii++) {
            *dst++ = *uptr++;
            *dst++ = *vptr++;
        }
#endif
        pFrame->pts = i;

        /* encode the image */
        encode(pCodecCtx, pFrame, packet, outfp);
    }

    /* flush the encoder */
    encode(pCodecCtx, NULL, packet, outfp);
    fclose(outfp);
    fclose(infp);

    avcodec_free_context(&pCodecCtx);
    av_frame_free(&pFrame);
    av_packet_free(&packet);

    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值