将 YUV 数据 编码为 h.264 格式

首先需要确保FFMPEG是否已经安装libx264

废话少说,直接贴上代码。
encode_yuv.c

#include <stdio.h>
#include <stdbool.h>


#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavutil/imgutils.h>


#include <time.h>
#include <pthread.h>


void usage(void)
{
    printf("./encode_yuv input_file.yuv width height bitrate channel_num\n");
}


#define MAX_CHANNEL_NUM    (4)


static struct timeval s_start_time[MAX_CHANNEL_NUM];
static struct timeval s_end_time[MAX_CHANNEL_NUM];




void Timer_SetStartTime(int channel)
{
    gettimeofday(&s_start_time[channel]);
}




void Timer_SetEndTime(int channel)
{
    gettimeofday(&s_end_time[channel]);
}




void Timer_GetIntervalTime(int channel, unsigned int *sec, unsigned int *usec)
{
    unsigned int  second;
    unsigned int  usecond;
    second = s_end_time[channel].tv_sec - s_start_time[channel].tv_sec;
    if(s_end_time[channel].tv_usec >= s_start_time[channel].tv_usec)
    {
        usecond = s_end_time[channel].tv_usec - s_start_time[channel].tv_usec;
    }
    else
    {
        usecond = 1000000 + s_end_time[channel].tv_usec - s_start_time[channel].tv_usec;
        second = second - 1;
    }


    *sec = second;
    *usec = usecond;
}


struct FileInfo
{
    int channel;
    int in_w;
    int in_h;
    int bitrate;
    char input_file[128];
    char output_file[128];
};


void * EncodeTask2(void *arg)
{
    struct FileInfo stFileInfo;
    int second;
    int usecond;
    int channel;

    memcpy(&stFileInfo, arg, sizeof(stFileInfo));

    char cmd[1024];

    //ffmpeg -s 720x576 -pix_fmt yuv420p -i vi_chn_4_720_576_p420_39.yuv -r 25 -vcodec mpeg2video out.mpeg
    snprintf(cmd, 1024, "ffmpeg -s %dx%d -pix_fmt yuv420p -i %s -vcodec mpeg2video -b:v %dk -r 25 %s", stFileInfo.in_w, stFileInfo.in_h, stFileInfo.input_file, stFileInfo.bitrate, stFileInfo.output_file);

    channel = stFileInfo.channel;

    Timer_SetStartTime(channel);
    system(cmd);
    Timer_SetEndTime(channel);
    Timer_GetIntervalTime(channel, &second, &usecond);

    printf("channel: %d, encode 100 frame use %d s %d us\n", channel, second, usecond);

    return NULL;
}


void * EncodeTask(void *arg)
{
    struct FileInfo stFileInfo;

    memcpy(&stFileInfo, arg, sizeof(stFileInfo));


    Encode(stFileInfo.channel, stFileInfo.input_file, stFileInfo.output_file, stFileInfo.in_w, stFileInfo.in_h);

    return NULL;
}




int Encode(int channel, char *input_file, char *output_file, int in_w, int in_h)
{


    int second;
    int usecond;

    AVCodec *pCodec;
    AVCodecContext *pCodecCtx= NULL;
    int i, ret, got_output;
    FILE *fp_in;
    FILE *fp_out;
    AVFrame *pFrame;
    AVPacket pkt;
    int y_size;
    //enum AVCodecID codec_id=AV_CODEC_ID_H264;
    enum AVCodecID codec_id=AV_CODEC_ID_MPEG2VIDEO;

    //Input raw data
    fp_in = fopen(input_file, "rb");
    if (!fp_in) 
    {
        printf("Error: Could not open %s\n", input_file);
        printf("in-error\n");
        return -1;
    }
    //Output bitstream
    fp_out = fopen(output_file, "wb");
    if (!fp_out) 
    {
        printf("Error: Could not open %s\n", output_file);
        printf("out-error\n");
        return -1;
    }


    avcodec_register_all();
    av_register_all();


    pCodec = avcodec_find_encoder(codec_id);
    if (!pCodec)
    {
        printf("Error: Codec not found\n");
        return -1;
    }


    pCodecCtx = avcodec_alloc_context3(pCodec);
    if (!pCodecCtx) 
    {
        printf("Error: Could not allocate video codec context\n");
        return -1;
    }

    pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
    pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
    pCodecCtx->width=in_w;
    pCodecCtx->height=in_h;
    pCodecCtx->time_base.num = 1;
    pCodecCtx->time_base.den = 25;
    pCodecCtx->bit_rate = 400000;
    pCodecCtx->gop_size = 12;
    pCodecCtx->codec_id = AV_CODEC_ID_MPEG2VIDEO;


    if(pCodecCtx->codec_id == AV_CODEC_ID_H264)
    {
        pCodecCtx->qmin = 10;
        pCodecCtx->qmax = 51;
        pCodecCtx->qcompress = 0.6;
    }
    if (pCodecCtx->codec_id == AV_CODEC_ID_MPEG2VIDEO)
        pCodecCtx->max_b_frames = 2;
    if (pCodecCtx->codec_id == AV_CODEC_ID_MPEG1VIDEO)
        pCodecCtx->mb_decision = 2;


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


    pFrame = av_frame_alloc();
    if (!pFrame) 
    {
        printf("Error: Could not allocate video frame\n");
        return -1;
    }
    pFrame->format = pCodecCtx->pix_fmt;
    pFrame->width  = pCodecCtx->width;
    pFrame->height = pCodecCtx->height;


    ret = av_image_alloc(pFrame->data, pFrame->linesize, pCodecCtx->width, 
    pCodecCtx->height, pCodecCtx->pix_fmt, 16);
    if (ret < 0) 
    {
        printf("Error: Could not allocate raw picture buffer\n");
        return -1;
    }

    int count = 0;
    y_size = pCodecCtx->width * pCodecCtx->height;

    Timer_SetStartTime(channel);
    //Encode
    bool isHasFrame = true;
    do
    {
        isHasFrame = (!((fread(pFrame->data[0], 1, y_size, fp_in) <= 0) 
                        ||(fread(pFrame->data[1], 1, y_size/4, fp_in) <= 0)
                        ||(fread(pFrame->data[2], 1, y_size/4, fp_in) <= 0)));
        if(!isHasFrame)
        {
            break;
        }
        av_init_packet(&pkt);
        pkt.data = NULL;
        pkt.size = 0;
        i++;
        pFrame->pts = i;
        got_output = 0;
        ret = avcodec_encode_video2(pCodecCtx, &pkt, pFrame, &got_output);
        if(ret < 0)
        {
            printf("Error: encode a frame failed!\n");
            return -1;
        }
        if(got_output)
        {
            fwrite(pkt.data, 1, pkt.size, fp_out);
            av_free_packet(&pkt);
        }



    }while(isHasFrame);


    //printf("3--------------\n");
    //Flush Encoder
    for(got_output = 1; got_output; i++) 
    {
        ret = avcodec_encode_video2(pCodecCtx, &pkt, NULL, &got_output);
        if (ret < 0) 
        {
            printf("Error: encode a frame failed!\n");
            return -1;
        }
        if (got_output) 
        {
            fwrite(pkt.data, 1, pkt.size, fp_out);
            av_free_packet(&pkt);
        }

    }

    Timer_SetEndTime(channel);

    Timer_GetIntervalTime(channel, &second, &usecond);

    printf("channel: %d, encode 100 frame use %d s %d us\n", channel, second, usecond);


    //printf("4--------------\n");
    fclose(fp_out);
    avcodec_close(pCodecCtx);
    av_free(pCodecCtx);
    av_freep(&pFrame->data[0]);
    av_frame_free(&pFrame);




}




int main(int argc, char* argv[])
{
    if(argc != 6)
    {
        usage();
        return -1;
    }


    char *input_file = argv[1];
    //char *output_file = argv[4];
    int in_w = atoi(argv[2]);
    int in_h = atoi(argv[3]);
    int bitrate = atoi(argv[4]);
    int channel_num = atoi(argv[5]);
    //char output_file[128]
    char cmd[1024];
    pthread_t tid;


    struct FileInfo arstFileInfo[MAX_CHANNEL_NUM];
    int i = 0;

    for(i = 0; i < channel_num; ++i)
    {
        arstFileInfo[i].channel = i;
        arstFileInfo[i].in_w = in_w;
        arstFileInfo[i].in_h = in_h;
        arstFileInfo[i].bitrate = bitrate;
        strcpy(arstFileInfo[i].input_file, input_file);
        snprintf(arstFileInfo[i].output_file, 128, "/tmp/test%d.mpeg", i);
        snprintf(cmd, 1024, "rm %s", arstFileInfo[i].output_file);
        system(cmd);
    }

    for(i = 0; i < channel_num; ++i)
    {
        //pthread_create(&tid, NULL, EncodeTask2, (void *)(&arstFileInfo[i]));
        pthread_create(&tid, NULL, EncodeTask, (void *)(&arstFileInfo[i]));
    }

    while(1)
    {
        sleep(1);
    }

    return 0;
}

说明:指定的宽高应该需要和yuv的宽高一致。
编译gcc encode_yuv.c -L./lib -lavutil -lavcodec -lswresample -lavformat -lpthread -I./include -o encode_yuv

posted @ 2020-03-23 16:47  standardzero  阅读(839)  评论(0编辑  收藏  举报