日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

最简单的基于FFmpeg的编码器-纯净版(不包含libavformat)

發(fā)布時間:2024/4/11 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 最简单的基于FFmpeg的编码器-纯净版(不包含libavformat) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

=====================================================

最簡單的基于FFmpeg的視頻編碼器文章列表:

最簡單的基于FFMPEG的視頻編碼器(YUV編碼為H.264)

最簡單的基于FFmpeg的視頻編碼器-更新版(YUV編碼為HEVC(H.265))

最簡單的基于FFmpeg的編碼器-純凈版(不包含libavformat)

=====================================================


本文記錄一個更加“純凈”的基于FFmpeg的視頻編碼器。此前記錄過一個基于FFmpeg的視頻編碼器:

?《最簡單的基于FFmpeg的視頻編碼器-更新版(YUV編碼為HEVC(H.265))》

這個視頻編碼器調(diào)用了FFmpeg中的libavformat和libavcodec兩個庫完成了視頻編碼工作。但是這不是一個“純凈”的編碼器。上述兩個庫中l(wèi)ibavformat完成封裝格式處理,而libavcodec完成編碼工作。一個“純凈”的編碼器,理論上說只需要使用libavcodec就足夠了,并不需要使用libavformat。本文記錄的編碼器就是這樣的一個“純凈”的編碼器,它僅僅通過調(diào)用libavcodec將YUV數(shù)據(jù)編碼為H.264/HEVC等格式的壓縮視頻碼流。


流程圖

僅使用libavcodec(不使用libavformat)編碼視頻的流程如下圖所示。


流程圖中關(guān)鍵函數(shù)的作用如下所列:

avcodec_register_all():注冊所有的編解碼器。
avcodec_find_encoder():查找編碼器。
avcodec_alloc_context3():為AVCodecContext分配內(nèi)存。
avcodec_open2():打開編碼器。
avcodec_encode_video2():編碼一幀數(shù)據(jù)。
兩個存儲數(shù)據(jù)的結(jié)構(gòu)體如下所列:
AVFrame:存儲一幀未編碼的像素數(shù)據(jù)。
AVPacket:存儲一幀壓縮編碼數(shù)據(jù)。

對比

簡單記錄一下這個只使用libavcodec的“純凈版”視頻編碼器和使用libavcodec+libavformat的視頻編碼器的不同。

PS:使用libavcodec+libavformat的編碼器參考文章?《最簡單的基于FFmpeg的視頻編碼器-更新版(YUV編碼為HEVC(H.265))》

(1) 下列與libavformat相關(guān)的函數(shù)在“純凈版”視頻編碼器中都不存在。
av_register_all():注冊所有的編解碼器,復用/解復用器等等組件。其中調(diào)用了avcodec_register_all()注冊所有編解碼器相關(guān)的組件。
avformat_alloc_context():創(chuàng)建AVFormatContext結(jié)構(gòu)體。
avformat_alloc_output_context2():初始化一個輸出流。
avio_open():打開輸出文件。
avformat_new_stream():創(chuàng)建AVStream結(jié)構(gòu)體。avformat_new_stream()中會調(diào)用avcodec_alloc_context3()創(chuàng)建AVCodecContext結(jié)構(gòu)體。
avformat_write_header():寫文件頭。
av_write_frame():寫編碼后的文件幀。
av_write_trailer():寫文件尾。 (2) 新增了如下幾個函數(shù)
avcodec_register_all():只注冊編解碼器有關(guān)的組件。

avcodec_alloc_context3():創(chuàng)建AVCodecContext結(jié)構(gòu)體。

可以看出,相比于“完整”的編碼器,這個純凈的編碼器函數(shù)調(diào)用更加簡單,功能相對少一些,相對來說更加的“輕量”。


源代碼

  • /**
  • * 最簡單的基于FFmpeg的視頻編碼器(純凈版)
  • * Simplest FFmpeg Video Encoder Pure
  • *
  • * 雷霄驊 Lei Xiaohua
  • * leixiaohua1020@126.com
  • * 中國傳媒大學/數(shù)字電視技術(shù)
  • * Communication University of China / Digital TV Technology
  • * http://blog.csdn.net/leixiaohua1020
  • *
  • * 本程序?qū)崿F(xiàn)了YUV像素數(shù)據(jù)編碼為視頻碼流(H264,MPEG2,VP8等等)。
  • * 它僅僅使用了libavcodec(而沒有使用libavformat)。
  • * 是最簡單的FFmpeg視頻編碼方面的教程。
  • * 通過學習本例子可以了解FFmpeg的編碼流程。
  • * This software encode YUV420P data to video bitstream
  • * (Such as H.264, H.265, VP8, MPEG2 etc).
  • * It only uses libavcodec to encode video (without libavformat)
  • * It's the simplest video encoding software based on FFmpeg.
  • * Suitable for beginner of FFmpeg
  • */
  • #include <stdio.h>
  • #define __STDC_CONSTANT_MACROS
  • #ifdef _WIN32
  • //Windows
  • extern "C"
  • {
  • #include "libavutil/opt.h"
  • #include "libavcodec/avcodec.h"
  • #include "libavutil/imgutils.h"
  • };
  • #else
  • //Linux...
  • #ifdef __cplusplus
  • extern "C"
  • {
  • #endif
  • #include <libavutil/opt.h>
  • #include <libavcodec/avcodec.h>
  • #include <libavutil/imgutils.h>
  • #ifdef __cplusplus
  • };
  • #endif
  • #endif
  • //test different codec
  • #define TEST_H264 1
  • #define TEST_HEVC 0
  • int main(int argc, char* argv[])
  • {
  • AVCodec *pCodec;
  • AVCodecContext *pCodecCtx= NULL;
  • int i, ret, got_output;
  • FILE *fp_in;
  • FILE *fp_out;
  • AVFrame *pFrame;
  • AVPacket pkt;
  • int y_size;
  • int framecnt=0;
  • char filename_in[]="../ds_480x272.yuv";
  • #if TEST_HEVC
  • AVCodecID codec_id=AV_CODEC_ID_HEVC;
  • char filename_out[]="ds.hevc";
  • #else
  • AVCodecID codec_id=AV_CODEC_ID_H264;
  • char filename_out[]="ds.h264";
  • #endif
  • int in_w=480,in_h=272;
  • int framenum=100;
  • avcodec_register_all();
  • pCodec = avcodec_find_encoder(codec_id);
  • if (!pCodec) {
  • printf("Codec not found\n");
  • return -1;
  • }
  • pCodecCtx = avcodec_alloc_context3(pCodec);
  • if (!pCodecCtx) {
  • printf("Could not allocate video codec context\n");
  • return -1;
  • }
  • pCodecCtx->bit_rate = 400000;
  • pCodecCtx->width = in_w;
  • pCodecCtx->height = in_h;
  • pCodecCtx->time_base.num=1;
  • pCodecCtx->time_base.den=25;
  • pCodecCtx->gop_size = 10;
  • pCodecCtx->max_b_frames = 1;
  • pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
  • if (codec_id == AV_CODEC_ID_H264)
  • av_opt_set(pCodecCtx->priv_data, "preset", "slow", 0);
  • if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
  • printf("Could not open codec\n");
  • return -1;
  • }
  • pFrame = av_frame_alloc();
  • if (!pFrame) {
  • printf("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("Could not allocate raw picture buffer\n");
  • return -1;
  • }
  • //Input raw data
  • fp_in = fopen(filename_in, "rb");
  • if (!fp_in) {
  • printf("Could not open %s\n", filename_in);
  • return -1;
  • }
  • //Output bitstream
  • fp_out = fopen(filename_out, "wb");
  • if (!fp_out) {
  • printf("Could not open %s\n", filename_out);
  • return -1;
  • }
  • y_size = pCodecCtx->width * pCodecCtx->height;
  • //Encode
  • for (i = 0; i < framenum; i++) {
  • av_init_packet(&pkt);
  • pkt.data = NULL; // packet data will be allocated by the encoder
  • pkt.size = 0;
  • //Read raw YUV data
  • if (fread(pFrame->data[0],1,y_size,fp_in)<= 0|| // Y
  • fread(pFrame->data[1],1,y_size/4,fp_in)<= 0|| // U
  • fread(pFrame->data[2],1,y_size/4,fp_in)<= 0){ // V
  • return -1;
  • }else if(feof(fp_in)){
  • break;
  • }
  • pFrame->pts = i;
  • /* encode the image */
  • ret = avcodec_encode_video2(pCodecCtx, &pkt, pFrame, &got_output);
  • if (ret < 0) {
  • printf("Error encoding frame\n");
  • return -1;
  • }
  • if (got_output) {
  • printf("Succeed to encode frame: %5d\tsize:%5d\n",framecnt,pkt.size);
  • framecnt++;
  • fwrite(pkt.data, 1, pkt.size, fp_out);
  • av_free_packet(&pkt);
  • }
  • }
  • //Flush Encoder
  • for (got_output = 1; got_output; i++) {
  • ret = avcodec_encode_video2(pCodecCtx, &pkt, NULL, &got_output);
  • if (ret < 0) {
  • printf("Error encoding frame\n");
  • return -1;
  • }
  • if (got_output) {
  • printf("Flush Encoder: Succeed to encode 1 frame!\tsize:%5d\n",pkt.size);
  • fwrite(pkt.data, 1, pkt.size, fp_out);
  • av_free_packet(&pkt);
  • }
  • }
  • fclose(fp_out);
  • avcodec_close(pCodecCtx);
  • av_free(pCodecCtx);
  • av_freep(&pFrame->data[0]);
  • av_frame_free(&pFrame);
  • return 0;
  • }

  • 運行結(jié)果

    通過設(shè)定定義在程序開始的宏,確定需要使用的編碼器。

  • //test different codec
  • #define TEST_H264 0
  • #define TEST_HEVC 1

  • 當TEST_H264設(shè)置為1的時候,編碼H.264文件“ds.h264”。
    當TEST_HEVC設(shè)置為1的時候,解碼HEVC文件“ds.hevc”。
    輸入文件是“ds_480x272.yuv”。

    程序運行的截圖如下所示。


    輸入的YUV文件如下圖所示。


    輸出的HEVC文件如下圖所示。



    下載

    Simplest ffmpeg encoder pure工程被作為子工程添加到了simplest ffmpeg video encoder工程中。新版的simplest ffmpeg video encoder的信息如下。


    Simplest ffmpeg video encoder

    項目主頁

    SourceForge:https://sourceforge.net/projects/simplestffmpegvideoencoder/

    Github:https://github.com/leixiaohua1020/simplest_ffmpeg_video_encoder

    開源中國:http://git.oschina.net/leixiaohua1020/simplest_ffmpeg_video_encoder



    本程序?qū)崿F(xiàn)了YUV像素數(shù)據(jù)編碼為視頻碼流(H.265,H264,MPEG2,VP8等等)。

    是最簡單的FFmpeg視頻編碼方面的教程。

    它包含以下兩個子項目:

    simplest_ffmpeg_video_encoder:最簡單的基于FFmpeg的視頻編碼器。使用libavcodec和libavformat編碼并且封裝視頻。
    simplest_ffmpeg_video_encoder_pure:最簡單的基于FFmpeg的視頻編碼器-純凈版。僅使用libavcodec編碼視頻,不使用libavformat。

    version 1.1

    CSDN下載地址:http://download.csdn.net/detail/leixiaohua1020/8322003


    更新-1.2 (2015.2.13)=========================================

    這次考慮到了跨平臺的要求,調(diào)整了源代碼。經(jīng)過這次調(diào)整之后,源代碼可以在以下平臺編譯通過:

    VC++:打開sln文件即可編譯,無需配置。

    cl.exe:打開compile_cl.bat即可命令行下使用cl.exe進行編譯,注意可能需要按照VC的安裝路徑調(diào)整腳本里面的參數(shù)。編譯命令如下。

    ::VS2010 Environment call "D:\Program Files\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" ::include @set INCLUDE=include;%INCLUDE% ::lib @set LIB=lib;%LIB% ::compile and link cl simplest_ffmpeg_video_encoder_pure.cpp /link avcodec.lib avutil.lib /OPT:NOREF

    MinGW:MinGW命令行下運行compile_mingw.sh即可使用MinGW的g++進行編譯。編譯命令如下。

    g++ simplest_ffmpeg_video_encoder_pure.cpp -g -o simplest_ffmpeg_video_encoder_pure.exe \ -I /usr/local/include -L /usr/local/lib \ -lavcodec -lavutil

    GCC:Linux或者MacOS命令行下運行compile_gcc.sh即可使用GCC進行編譯。編譯命令如下。

    gcc simplest_ffmpeg_video_encoder_pure.cpp -g -o simplest_ffmpeg_video_encoder_pure.out \ -I /usr/local/include -L /usr/local/lib -lavcodec -lavutil


    PS:相關(guān)的編譯命令已經(jīng)保存到了工程文件夾中

    CSDN下載地址: http://download.csdn.net/detail/leixiaohua1020/8444967

    SourceForge上已經(jīng)更新。


    總結(jié)

    以上是生活随笔為你收集整理的最简单的基于FFmpeg的编码器-纯净版(不包含libavformat)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。