最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++使用FFmpeg實現(xiàn)YUV數(shù)據(jù)編碼轉(zhuǎn)視頻文件

 更新時間:2023年06月21日 10:02:12   作者:音視頻開發(fā)老舅  
這篇文章主要介紹了C++如何使用FFmpeg實現(xiàn)把一個YUV原始視頻數(shù)據(jù)(時間序列圖像)經(jīng)過h264編碼為視頻碼流,然后在使用mp4封裝格式封裝,感興趣的可以了解一下

本文中實現(xiàn)的一個小功能是把一個YUV原始視頻數(shù)據(jù)(時間序列圖像)經(jīng)過h264編碼為視頻碼流,然后在使用mp4封裝格式封裝。

編碼&封裝的流程圖如下:

使用ffmpeg編碼流程

1、首先使用av_register_all()函數(shù)注冊所有的編碼器和復(fù)用器(理解為格式封裝器)。該步驟必須放在所有ffmpeg代碼前第一個執(zhí)行

2、avformat_alloc_output_context2():初始化包含有輸出碼流(AVStream)和解復(fù)用器(AVInputFormat)的AVFormatContext

3、avio_open( )打開輸出文件

4、av_new_stream() 創(chuàng)建視頻碼流 該函數(shù)生成一個空AVstream 該結(jié)構(gòu)存放編碼后的視頻碼流 。視頻碼流被拆分為AVPacket新式保存在AVStream中。

5、設(shè)置編碼器信息,該步驟主要是為AVCodecContext(從AVStream->codec 獲取指針)結(jié)構(gòu)體設(shè)置一些參數(shù),包括codec_id、codec_type、width、height、pix_fmt ..... 根據(jù)編碼器的不同,還要額外設(shè)置一些參數(shù)(如 h264 要設(shè)置qmax、qmin、qcompress參數(shù)才能正常使用h264編碼)

6、查找并打開編碼器,根據(jù)前一步設(shè)置的編碼器參數(shù)信息,來查找初始化一個編碼其,并將其打開。用到函數(shù)為av_fine_encoder()和av_open2()。

7、寫頭文件 avformat_write_header()。這一步主要是將封裝格式的信息寫入文件頭部位置。

8、編碼幀。用到的函數(shù) avcodec_encode_video2() 將AVFrame編碼為AVPacket

9、在寫入文件之前 還需要做一件事情就是設(shè)置AVPacket一些信息。這些信息關(guān)乎最后封裝格式能否被正確讀取。后面回詳細講述該部分內(nèi)容

10、編碼幀寫入文件 av_write_frame()

11、flush_encoder():輸入的像素數(shù)據(jù)讀取完成后調(diào)用此函數(shù)。用于輸出編碼器中剩余的AVPacket。

12、av_write_trailer():寫文件尾(對于某些沒有文件頭的封裝格式,不需要此函數(shù)。比如說MPEG2TS)。

源碼

#include <stdio.h>
#include "pch.h"
#include <iostream>
extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
#include <libavformat/avformat.h>  
};
using namespace std;
int flush_encoder(AVFormatContext *fmt_ctx, unsigned int stream_index);
int YUV2H264()
{
    AVFormatContext *pFormatCtx = nullptr;
    AVOutputFormat *fmt = nullptr;
    AVStream *video_st = nullptr;
    AVCodecContext *pCodecCtx = nullptr;
    AVCodec *pCodec = nullptr;
    uint8_t *picture_buf = nullptr;
    AVFrame *picture = nullptr;
    int size;
    //打開視頻文件
    FILE *in_file = fopen("111.yuv", "rb");
    if (!in_file) {
        cout << "can not open file!" << endl;
        return -1;
    }
    //352x288
    int in_w = 352, in_h = 288;
    int framenum = 50;
    const char* out_file = "111.H264";
    //[1] --注冊所有ffmpeg組件
    avcodec_register_all();
    av_register_all();
    //[2] --初始化AVFormatContext結(jié)構(gòu)體,根據(jù)文件名獲取到合適的封裝格式
    avformat_alloc_output_context2(&pFormatCtx, NULL, NULL, out_file);
    fmt = pFormatCtx->oformat;
    //[3] --打開文件
    if (avio_open(&pFormatCtx->pb, out_file, AVIO_FLAG_READ_WRITE)) {
        cout << "output file open fail!";
        return -1;
    }
    //[3]
    //[4] --初始化視頻碼流
    video_st = avformat_new_stream(pFormatCtx, 0);
    if (video_st == NULL)
    {
        printf("failed allocating output stram\n");
        return -1;
    }
    video_st->time_base.num = 1;
    video_st->time_base.den = 25;
    //[4]
    //[5] --編碼器Context設(shè)置參數(shù)
    pCodecCtx = video_st->codec;
    pCodecCtx->codec_id = fmt->video_codec;
    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;
    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;
    //[5]
    //[6] --尋找編碼器并打開編碼器
    pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
    if (!pCodec)
    {
        cout << "no right encoder!" << endl;
        return -1;
    }
    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
    {
        cout << "open encoder fail!" << endl;
        return -1;
    }
    //[6]
    //輸出格式信息
    av_dump_format(pFormatCtx, 0, out_file, 1);
    //初始化幀
    picture = av_frame_alloc();
    picture->width = pCodecCtx->width;
    picture->height = pCodecCtx->height;
    picture->format = pCodecCtx->pix_fmt;
    size = avpicture_get_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
    picture_buf = (uint8_t*)av_malloc(size);
    avpicture_fill((AVPicture*)picture, picture_buf, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
    //[7] --寫頭文件
    avformat_write_header(pFormatCtx, NULL);
    //[7]
    AVPacket pkt; //創(chuàng)建已編碼幀
    int y_size = pCodecCtx->width*pCodecCtx->height;
    av_new_packet(&pkt, size * 3);
    //[8] --循環(huán)編碼每一幀
    for (int i = 0; i < framenum; i++)
    {
        //讀入YUV
        if (fread(picture_buf, 1, y_size * 3 / 2, in_file) < 0)
        {
            cout << "read file fail!" << endl;
            return -1;
        }
        else if (feof(in_file))
            break;
        picture->data[0] = picture_buf; //亮度Y
        picture->data[1] = picture_buf + y_size; //U
        picture->data[2] = picture_buf + y_size * 5 / 4; //V
        //AVFrame PTS
        picture->pts = i;
        int got_picture = 0;
        //編碼
        int ret = avcodec_encode_video2(pCodecCtx, &pkt, picture, &got_picture);
        if (ret < 0)
        {
            cout << "encoder fail!" << endl;
            return -1;
        }
        if (got_picture == 1)
        {
            cout << "encoder success!" << endl;
            // parpare packet for muxing
            pkt.stream_index = video_st->index;
            av_packet_rescale_ts(&pkt, pCodecCtx->time_base, video_st->time_base);
            pkt.pos = -1;
            ret = av_interleaved_write_frame(pFormatCtx, &pkt);
            av_free_packet(&pkt);
        }
    }
    //[8]
    //[9] --Flush encoder
    int ret = flush_encoder(pFormatCtx, 0);
    if (ret < 0)
    {
        cout << "flushing encoder failed!" << endl;
        goto end;
    }
    //[9]
    //[10] --寫文件尾
    av_write_trailer(pFormatCtx);
    //[10]
end:
    //釋放內(nèi)存
    if (video_st)
    {
        avcodec_close(video_st->codec);
        av_free(picture);
        av_free(picture_buf);
    }
    if (pFormatCtx)
    {
        avio_close(pFormatCtx->pb);
        avformat_free_context(pFormatCtx);
    }
    fclose(in_file);
    return 0;
}
int flush_encoder(AVFormatContext *fmt_ctx, unsigned int stream_index)
{
    int ret;
    int got_frame;
    AVPacket enc_pkt;
    if (!(fmt_ctx->streams[stream_index]->codec->codec->capabilities & AV_CODEC_CAP_DELAY))
        return 0;
    while (1) {
        printf("Flushing stream #%u encoder\n", stream_index);
        enc_pkt.data = NULL;
        enc_pkt.size = 0;
        av_init_packet(&enc_pkt);
        ret = avcodec_encode_video2(fmt_ctx->streams[stream_index]->codec, &enc_pkt,
            NULL, &got_frame);
        av_frame_free(NULL);
        if (ret < 0)
            break;
        if (!got_frame)
        {
            ret = 0; break;
        }
        cout << "success encoder 1 frame" << endl;
        // parpare packet for muxing
        enc_pkt.stream_index = stream_index;
        av_packet_rescale_ts(&enc_pkt,
            fmt_ctx->streams[stream_index]->codec->time_base,
            fmt_ctx->streams[stream_index]->time_base);
        ret = av_interleaved_write_frame(fmt_ctx, &enc_pkt);
        if (ret < 0)
            break;
    }
    return ret;
}
int H2642MP4() {
    AVOutputFormat *ofmt = NULL;
    //Input AVFormatContext and Output AVFormatContext
    AVFormatContext *ifmt_ctx_v = NULL, *ifmt_ctx_a = NULL, *ofmt_ctx = NULL;
    AVPacket pkt;
    int ret, i;
    int videoindex_v = 0, videoindex_out = 0;
    int frame_index = 0;
    int64_t cur_pts_v = 0, cur_pts_a = 0;
    const char *in_filename_v = "111.H264";
    const char *out_filename = "222.mp4";//Output file URL
    av_register_all();
    //Input
    if ((ret = avformat_open_input(&ifmt_ctx_v, in_filename_v, 0, 0)) < 0) {
        printf("Could not open input file.");
        goto end;
    }
    if ((ret = avformat_find_stream_info(ifmt_ctx_v, 0)) < 0) {
        printf("Failed to retrieve input stream information");
        goto end;
    }
    printf("===========Input Information==========\n");
    av_dump_format(ifmt_ctx_v, 0, in_filename_v, 0);
    //av_dump_format(ifmt_ctx_a, 0, in_filename_a, 0);
    printf("======================================\n");
    //Output
    avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
    if (!ofmt_ctx) {
        printf("Could not create output context\n");
        ret = AVERROR_UNKNOWN;
        goto end;
    }
    ofmt = ofmt_ctx->oformat;
    printf("ifmt_ctx_v->nb_streams=%d\n", ifmt_ctx_v->nb_streams);
    for (i = 0; i < ifmt_ctx_v->nb_streams; i++) {
        //Create output AVStream according to input AVStream
        //if(ifmt_ctx_v->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
        {
            AVStream *in_stream = ifmt_ctx_v->streams[i];
            AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);
            videoindex_v = i;
            if (!out_stream) {
                printf("Failed allocating output stream\n");
                ret = AVERROR_UNKNOWN;
                goto end;
            }
            videoindex_out = out_stream->index;
            //Copy the settings of AVCodecContext
            if (avcodec_copy_context(out_stream->codec, in_stream->codec) < 0) {
                printf("Failed to copy context from input to output stream codec context\n");
                goto end;
            }
            out_stream->codec->codec_tag = 0;
            if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
                out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
            //break;
        }
    }
    printf("==========Output Information==========\n");
    av_dump_format(ofmt_ctx, 0, out_filename, 1);
    printf("======================================\n");
    //Open output file
    if (!(ofmt->flags & AVFMT_NOFILE)) {
        if (avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE) < 0) {
            printf("Could not open output file '%s'", out_filename);
            goto end;
        }
    }
    //Write file header
    if (avformat_write_header(ofmt_ctx, NULL) < 0) {
        printf("Error occurred when opening output file\n");
        goto end;
    }
    while (1) {
        AVFormatContext *ifmt_ctx;
        int stream_index = 0;
        AVStream *in_stream, *out_stream;
        //Get an AVPacket
        //if(av_compare_ts(cur_pts_v,ifmt_ctx_v->streams[videoindex_v]->time_base,cur_pts_a,ifmt_ctx_a->streams[audioindex_a]->time_base) <= 0)
        {
            ifmt_ctx = ifmt_ctx_v;
            stream_index = videoindex_out;
            if (av_read_frame(ifmt_ctx, &pkt) >= 0) {
                do {
                    in_stream = ifmt_ctx->streams[pkt.stream_index];
                    out_stream = ofmt_ctx->streams[stream_index];
                    printf("stream_index==%d,pkt.stream_index==%d,videoindex_v=%d\n", stream_index, pkt.stream_index, videoindex_v);
                    if (pkt.stream_index == videoindex_v) {
                        //FIX:No PTS (Example: Raw H.264)
                        //Simple Write PTS
                        if (pkt.pts == AV_NOPTS_VALUE) {
                            printf("frame_index==%d\n", frame_index);
                            //Write PTS
                            AVRational time_base1 = in_stream->time_base;
                            //Duration between 2 frames (us)
                            int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(in_stream->r_frame_rate);
                            //Parameters
                            pkt.pts = (double)(frame_index*calc_duration) / (double)(av_q2d(time_base1)*AV_TIME_BASE);
                            pkt.dts = pkt.pts;
                            pkt.duration = (double)calc_duration / (double)(av_q2d(time_base1)*AV_TIME_BASE);
                            frame_index++;
                        }
                        cur_pts_v = pkt.pts;
                        break;
                    }
                } while (av_read_frame(ifmt_ctx, &pkt) >= 0);
            }
            else {
                break;
            }
        }
        //Convert PTS/DTS
        pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
        pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
        pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
        pkt.pos = -1;
        pkt.stream_index = stream_index;
        printf("Write 1 Packet. size:%5d\tpts:%lld\n", pkt.size, pkt.pts);
        //Write
        if (av_interleaved_write_frame(ofmt_ctx, &pkt) < 0) {
            printf("Error muxing packet\n");
            break;
        }
        av_free_packet(&pkt);
    }
    //Write file trailer
    av_write_trailer(ofmt_ctx);
end:
    avformat_close_input(&ifmt_ctx_v);
    //avformat_close_input(&ifmt_ctx_a);
    /* close output */
    if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
        avio_close(ofmt_ctx->pb);
    avformat_free_context(ofmt_ctx);
    if (ret < 0 && ret != AVERROR_EOF) {
        printf("Error occurred.\n");
        return -1;
    }
    return 0;
}
int main(int argc, char *argv[]) {
    // 先將YUV文件轉(zhuǎn)換為H264文件
    YUV2H264();
    // 在將H264轉(zhuǎn)封裝為MP4
    H2642MP4();
}

總結(jié)其流程,其實就是一個編碼+轉(zhuǎn)封裝的流程。

補充

音視頻轉(zhuǎn)碼與轉(zhuǎn)封裝的區(qū)別:

音視頻轉(zhuǎn)碼和轉(zhuǎn)封裝的不同之處在于音視頻轉(zhuǎn)碼會占用大量的計算資源,而轉(zhuǎn)封裝主要是將音頻數(shù)據(jù)或者視頻數(shù)據(jù)取出,然后封裝成另外一種封裝格式。

轉(zhuǎn)封裝主要占用的IO資源,而轉(zhuǎn)碼主要是占用CPU資源,同時轉(zhuǎn)碼也會使用更多的內(nèi)存資源。

到此這篇關(guān)于C++使用FFmpeg實現(xiàn)YUV數(shù)據(jù)編碼轉(zhuǎn)視頻文件的文章就介紹到這了,更多相關(guān)FFmpeg YUV轉(zhuǎn)視頻內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 淺析順序結(jié)構(gòu)存儲的棧

    淺析順序結(jié)構(gòu)存儲的棧

    這篇文章主要介紹了順序結(jié)構(gòu)存儲的棧,有需要的朋友可以參考一下
    2014-01-01
  • C/C++連接MySQL并發(fā)送SQL請求的實戰(zhàn)指南

    C/C++連接MySQL并發(fā)送SQL請求的實戰(zhàn)指南

    本文將聚焦于 如何使用 C/C++ 連接 MySQL 并發(fā)送 SQL 請求,涵蓋從環(huán)境準(zhǔn)備到執(zhí)行查詢的完整流程,并提供可直接運行的示例代碼,希望對大家有所幫助
    2026-02-02
  • Opencv圖像處理之輪廓外背景顏色改變

    Opencv圖像處理之輪廓外背景顏色改變

    這篇文章主要為大家詳細介紹了Opencv圖像處理之輪廓外背景顏色改變,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • C語言數(shù)據(jù)結(jié)構(gòu)之堆、堆排序的分析及實現(xiàn)

    C語言數(shù)據(jù)結(jié)構(gòu)之堆、堆排序的分析及實現(xiàn)

    堆是一個近似完全二叉樹的結(jié)構(gòu),并同時滿足堆積的性質(zhì),下面這篇文章主要給大家介紹了關(guān)于C語言數(shù)據(jù)結(jié)構(gòu)之堆、堆排序的分析及實現(xiàn)的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-04-04
  • c++中vector的使用和模擬實現(xiàn)

    c++中vector的使用和模擬實現(xiàn)

    這篇文章主要介紹了c++中vector的使用和模擬實現(xiàn),本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • 如何用C寫一個web服務(wù)器之I/O多路復(fù)用

    如何用C寫一個web服務(wù)器之I/O多路復(fù)用

    本文主要介紹了如何用C寫一個web服務(wù)器之I/O多路復(fù)用,本次選擇了 I/O 模型的優(yōu)化,因為它是服務(wù)器的基礎(chǔ),這個先完成的話,后面的優(yōu)化就可以選擇各個模塊來進行,不必進行全局化的改動了。
    2021-05-05
  • 手把手帶你學(xué)習(xí)C++的運算符

    手把手帶你學(xué)習(xí)C++的運算符

    這篇文章主要為大家介紹了C++運算符,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助,希望能夠給你帶來幫助
    2021-11-11
  • 深入理解C++的對象模型

    深入理解C++的對象模型

    本文在介紹C++使用的對象模型之前,先介紹了2種對象模型:簡單對象模型(a simple object model)和表格驅(qū)動對象模型(a table-driven object model),這樣介紹對后面的內(nèi)容更有幫助,有需要的小伙伴們可以參考學(xué)習(xí)。
    2016-08-08
  • 深入理解C語言中使用頻率較高的指針與數(shù)組

    深入理解C語言中使用頻率較高的指針與數(shù)組

    在C語言中要說到哪一部分最難搞,首當(dāng)其沖就是指針,指針永遠是個讓人又愛又恨的東西,用好了可以事半功倍,用不好就會有改不完的bug和通不完的宵,下面這篇文章主要給大家介紹了關(guān)于C語言中使用頻率較高的指針與數(shù)組的相關(guān)資料,需要的朋友可以參考下
    2022-03-03
  • 探討C語言中關(guān)鍵字volatile的含義

    探討C語言中關(guān)鍵字volatile的含義

    本篇文章是對C語言中關(guān)鍵字volatile的含義進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05

最新評論

时尚| 乌兰县| 正镶白旗| 开化县| 顺义区| 梅州市| 郑州市| 德江县| 曲麻莱县| 新晃| 安吉县| 鄂托克旗| 八宿县| 紫金县| 广元市| 临沧市| 平昌县| 吴桥县| 天峻县| 台前县| 凌云县| 建平县| 泾阳县| 揭西县| 金堂县| 林州市| 鄯善县| 韩城市| 泗洪县| 陈巴尔虎旗| 曲周县| 万盛区| 潞城市| 澜沧| 辽源市| 新干县| 新沂市| 南投市| 贞丰县| 林周县| 遂昌县|