zoukankan      html  css  js  c++  java
  • 将 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
    ");
    }
    
    
    #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
    ", 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
    ", input_file);
            printf("in-error
    ");
            return -1;
        }
        //Output bitstream
        fp_out = fopen(output_file, "wb");
        if (!fp_out) 
        {
            printf("Error: Could not open %s
    ", output_file);
            printf("out-error
    ");
            return -1;
        }
    
    
        avcodec_register_all();
        av_register_all();
    
    
        pCodec = avcodec_find_encoder(codec_id);
        if (!pCodec)
        {
            printf("Error: Codec not found
    ");
            return -1;
        }
    
    
        pCodecCtx = avcodec_alloc_context3(pCodec);
        if (!pCodecCtx) 
        {
            printf("Error: Could not allocate video codec context
    ");
            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
    ");
            return -1;
        }
    
    
        pFrame = av_frame_alloc();
        if (!pFrame) 
        {
            printf("Error: Could not allocate video frame
    ");
            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
    ");
            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!
    ");
                return -1;
            }
            if(got_output)
            {
                fwrite(pkt.data, 1, pkt.size, fp_out);
                av_free_packet(&pkt);
            }
    
    
    
        }while(isHasFrame);
    
    
        //printf("3--------------
    ");
        //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!
    ");
                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
    ", channel, second, usecond);
    
    
        //printf("4--------------
    ");
        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

  • 相关阅读:
    微信小程序倒计时,小程序60秒倒计时,小程序倒计时防止重复点击
    微信小程序嵌套h5页面,h5页面返回小程序,小程序和h5的页面和交互方法,h5点击分享小程序页面
    LeetCode—— 括号生成
    LeetCode—— 合并两个有序链表
    LeetCode—— 有效的括号
    LeetCode—— 删除链表的倒数第N个节点
    LeetCode—— 四数之和
    LeetCode—— 电话号码的字母组合
    LeetCode—— 最接近的三数之和
    ***LeetCode—— 三数之和
  • 原文地址:https://www.cnblogs.com/standardzero/p/12553157.html
Copyright © 2011-2022 走看看