FFMPEG C++封装(二)

4 详细设计

这章是FFMPEG C++封装库的详细设计。

4.1 Init

该模块初始化FFMPEG库。

4.1.1 Init定义

namespace media
{
namespace sdk
{
void  MEDIASDK_EXPORT Init();
}
}

函数说明:

  • Init 初始化FFMPEG库,该函数可调用多次。

4.1.2 Init实现

namespace media
{
namespace sdk
{
void Init()
{
    static bool isInit = false;
    if(isInit)
        return;
    isInit = true;
    avcodec_register_all();
    avfilter_register_all();
    av_register_all();
    avformat_network_init();
    Report(false);
}
}
}

函数流程:

  • 注册支持的全部编码器(codec)。
  • 注册支持的全部过滤器(filter)。
  • 注册支持的全部封包格式(format)。
  • 初始化支持的网络。
  • 默认关闭打印输出。

4.2 Utils

该模块提供FFMPEG库的工具函数。

4.2.1 Utils定义

namespace media
{
namespace sdk
{
void MEDIASDK_EXPORT Report(bool on);

void MEDIASDK_EXPORT Formats();
void MEDIASDK_EXPORT Codecs(bool encoder);
void MEDIASDK_EXPORT Bsfs();
void MEDIASDK_EXPORT Protocols();
void MEDIASDK_EXPORT Filters();
void MEDIASDK_EXPORT PixFmts();
void MEDIASDK_EXPORT SampleFmts();

int64_t MEDIASDK_EXPORT Time();
int64_t MEDIASDK_EXPORT NoPtsValue();
int64_t MEDIASDK_EXPORT ToTime(int64_t const& pts, Rational const& timebase);

std::vector<std::string> MEDIASDK_EXPORT DisplayCardNames();
}
}

4.2.2 Utils实现

4.2.2.1 Report
void Report(bool on)
{
	if(on)
		av_log_set_callback(log_callback_help);		
	else
		av_log_set_callback(log_callback_null);
}

函数说明:

  • 如果需要打印,设置一个可打印新的callback.
  • 如果不要打印,设置一个不可打印的callback.
4.2.2.2 Formats
void Formats()
{
    AVInputFormat *ifmt  = NULL;
    AVOutputFormat *ofmt = NULL;
    const char *last_name;

    printf("File formats:\n"
           " D. = Demuxing supported\n"
           " .E = Muxing supported\n"
           " --\n");
    last_name = "000";
    for (;;) {
        int decode = 0;
        int encode = 0;
        const char *name      = NULL;
        const char *long_name = NULL;

        while ((ofmt = (AVOutputFormat *)av_oformat_next(ofmt))) {
            if ((name == NULL || strcmp(ofmt->name, name) < 0) &&
                strcmp(ofmt->name, last_name) > 0) {
                name      = ofmt->name;
                long_name = ofmt->long_name;
                encode    = 1;
            }
        }
        while ((ifmt = (AVInputFormat *)av_iformat_next(ifmt))) {
            if ((name == NULL || strcmp(ifmt->name, name) < 0) &&
                strcmp(ifmt->name, last_name) > 0) {
                name      = ifmt->name;
                long_name = ifmt->long_name;
                encode    = 0;
            }
            if (name && strcmp(ifmt->name, name) == 0)
                decode = 1;
        }
        if (name == NULL)
            break;
        last_name = name;

        printf(" %s%s %-15s %s\n",
               decode ? "D" : " ",
               encode ? "E" : " ",
               name,
            long_name ? long_name:" ");
    }
}

函数流程:

  • 遍历输出格式和输入格式
  • 打印名字和长名字
  • 输入格式作为解复用(Demux)打印
  • 输出格式作为复用(Mux)打印
4.2.2.3 Codecs
void Codecs(bool encoder)
{
    const AVCodecDescriptor **codecs;
    unsigned i, nb_codecs = get_codecs_sorted(&codecs);

    printf("%s:\n"
           " V..... = Video\n"
           " A..... = Audio\n"
           " S..... = Subtitle\n"
           " .F.... = Frame-level multithreading\n"
           " ..S... = Slice-level multithreading\n"
           " ...X.. = Codec is experimental\n"
           " ....B. = Supports draw_horiz_band\n"
           " .....D = Supports direct rendering method 1\n"
           " ------\n",
           encoder ? "Encoders" : "Decoders");
    for (i = 0; i < nb_codecs; i++) {
        const AVCodecDescriptor *desc = codecs[i];
        const AVCodec *codec = NULL;

        while ((codec = next_codec_for_id(desc->id, codec, encoder))) {
            printf(" %c", get_media_type_char(desc->type));
            printf((codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) ? "F" : ".");
            printf((codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) ? "S" : ".");
            printf((codec->capabilities & AV_CODEC_CAP_EXPERIMENTAL)  ? "X" : ".");
            printf((codec->capabilities & AV_CODEC_CAP_DRAW_HORIZ_BAND)?"B" : ".");
            printf((codec->capabilities & AV_CODEC_CAP_DR1)           ? "D" : ".");

            printf(" %-20s %s", codec->name, codec->long_name ? codec->long_name : "");
            if (strcmp(codec->name, desc->name))
                printf(" (codec %s)", desc->name);

            printf("\n");
        }
    }
    av_free(codecs);
}

函数流程:

  • 遍历支持的编解码器
  • 按照视频,音频,字幕,帧级多线程,切片级多线程,实验性,支持画横条,支持直接渲染等格式打印
4.2.2.4 Bsfs
void Bsfs()
{
    const AVBitStreamFilter *bsf = 0;
    void *opaque = NULL;

    printf("Bitstream filters:\n");
    while ((bsf = av_bsf_iterate(&opaque)))
        printf("%s\n", bsf->name);
    printf("\n");
}

函数流程:

  • 遍历支持的Bitstream过滤器
  • 打印过滤器名称
4.2.2.5 Protocols
void Protocols()
{
    void *opaque = NULL;
    const char *name;

    printf("Supported file protocols:\n"
           "Input:\n");
    while ((name = avio_enum_protocols(&opaque, 0)))
        printf("%s\n", name);
    printf("Output:\n");
    while ((name = avio_enum_protocols(&opaque, 1)))
        printf("%s\n", name);
}

函数流程:

  • 遍历支持的输入/输出协议
  • 打印协议名称
4.2.2.6 Filters
void Filters()
{
    const AVFilter *filter = NULL;
    char descr[64], *descr_cur;
    void *opaque = NULL;
    int i, j;
    const AVFilterPad *pad;

    printf("Filters:\n"
           "  T.. = Timeline support\n"
           "  .S. = Slice threading\n"
           "  ..C = Command support\n"
           "  A = Audio input/output\n"
           "  V = Video input/output\n"
           "  N = Dynamic number and/or type of input/output\n"
           "  | = Source or sink filter\n");
    while ((filter = av_filter_iterate(&opaque))) {
        descr_cur = descr;
        for (i = 0; i < 2; i++) {
            if (i) {
                *(descr_cur++) = '-';
                *(descr_cur++) = '>';
            }
            pad = i ? filter->outputs : filter->inputs;
            for (j = 0; pad && avfilter_pad_get_name(pad, j); j++) {
                if (descr_cur >= descr + sizeof(descr) - 4)
                    break;
                *(descr_cur++) = get_media_type_char(avfilter_pad_get_type(pad, j));
            }
            if (!j)
                *(descr_cur++) = ((!i && (filter->flags & AVFILTER_FLAG_DYNAMIC_INPUTS)) ||
                                  ( i && (filter->flags & AVFILTER_FLAG_DYNAMIC_OUTPUTS))) ? 'N' : '|';
        }
        *descr_cur = 0;
        printf(" %c%c%c %-17s %-10s %s\n",
               filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE ? 'T' : '.',
               filter->flags & AVFILTER_FLAG_SLICE_THREADS    ? 'S' : '.',
               filter->process_command                        ? 'C' : '.',
               filter->name, descr, filter->description);
    }
}

函数流程:

  • 遍历支持的过滤器
  • 按照时间线,切片线程,命令支持,音频输入/输出,视频输入/输出和源/显示类型打印。
4.2.2.7 PixFmts
void PixFmts()
{
    const AVPixFmtDescriptor *pix_desc = NULL;

    printf("Pixel formats:\n"
           "I.... = Supported Input  format for conversion\n"
           ".O... = Supported Output format for conversion\n"
           "..H.. = Hardware accelerated format\n"
           "...P. = Paletted format\n"
           "....B = Bitstream format\n"
           "FLAGS NAME            NB_COMPONENTS BITS_PER_PIXEL\n"
           "-----\n");

#if !CONFIG_SWSCALE
#   define sws_isSupportedInput(x)  0
#   define sws_isSupportedOutput(x) 0
#endif

    while ((pix_desc = av_pix_fmt_desc_next(pix_desc))) {
        enum AVPixelFormat av_unused pix_fmt = av_pix_fmt_desc_get_id(pix_desc);
        printf("%c%c%c%c%c %-16s       %d            %2d\n",
               sws_isSupportedInput (pix_fmt)              ? 'I' : '.',
               sws_isSupportedOutput(pix_fmt)              ? 'O' : '.',
               pix_desc->flags & AV_PIX_FMT_FLAG_HWACCEL   ? 'H' : '.',
               pix_desc->flags & AV_PIX_FMT_FLAG_PAL       ? 'P' : '.',
               pix_desc->flags & AV_PIX_FMT_FLAG_BITSTREAM ? 'B' : '.',
               pix_desc->name,
               pix_desc->nb_components,
               av_get_bits_per_pixel(pix_desc));
    }
}

函数流程:

  • 遍历支持的像素格式
  • 按照输入,输出,硬件支持,调色板和位流类型打印。
4.2.2.8 SampleFmts
void SampleFmts()
{
    int i;
    char fmt_str[128];
    for (i = -1; i < AV_SAMPLE_FMT_NB; i++)
        printf("%s\n", av_get_sample_fmt_string(fmt_str, sizeof(fmt_str), (enum AVSampleFormat)i));
}

函数流程:

  • 遍历支持的音频采样格式
  • 打印音频采样格式
4.2.2.9 Time
int64_t Time()
{
	return av_gettime();
}
4.2.2.10 NoPtsValue
int64_t NoPtsValue()
{
	return AV_NOPTS_VALUE;
}

函数说明:

  • 返回无效时间戳
4.2.2.11 ToTime
int64_t ToTime(int64_t const& pts, Rational const& timebase)
{
    AVRational tb1 = {timebase.num, timebase.den};
    AVRational tb2 = {1, AV_TIME_BASE};
    return av_rescale_q(pts, tb1, tb2);
}

函数说明:

  • 将以1/AV_TIME_BASE秒为单位的时间戳转换位以timebase为单位的时间戳
  • AV_TIME_BASE值为1000000
4.2.2.12 DisplayCardNames
std::vector<std::string> DisplayCardNames()
{
    std::vector<std::string> displayNames;
    IDXGIFactory * pFactory;

    HRESULT hr = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)(&pFactory));
    if(FAILED(hr))
        return displayNames;

    IDXGIAdapter * pAdapter;
    int iAdapterNum = 0;
    while(pFactory->EnumAdapters(iAdapterNum, &pAdapter) != DXGI_ERROR_NOT_FOUND)
    {
        DXGI_ADAPTER_DESC desc;
        pAdapter->GetDesc(&desc);
        std::wstring aa(desc.Description);
        displayNames.push_back(WStringToString(aa));
        ++iAdapterNum;
    }
    return displayNames;
}

函数流程:

  • 遍历系统中显卡名称
  • 将显卡名称放入数组并返回

示例

namespace mediasdk = media::sdk;
int main(int argc, char* argv[])
{
    mediasdk::Init();

    mediasdk::Formats();//打印支持的文件格式(封包格式).
    mediasdk::Codecs(true);//打印支持编码器.
    mediasdk::Codecs(false);//打印支持的解码器.
    mediasdk::Protocols();//打印支持的协议.
    mediasdk::Filters();//打印支持过滤器.
    mediasdk::PixFmts();//打印支持像素格式.
    mediasdk::SampleFmts();//打印支持采样格式.
    std::vector<std::string> names = media::sdk::DisplayCardNames();
    for(name: names)
        std::cout << "Display card: " << name << std::endl;
    return 0;
}

未完待续…

上一篇:软考 - 系统架构设计师 - 形式化方法


下一篇:【神经网络】得分函数,损失函数~