2

我有这个在 C 中使用的代码示例:

//#define  UINT64_C  (uint64_t);

#pragma comment(lib, "Gdi32.lib")
#pragma comment(lib, "User32.lib")
#pragma comment(lib, "gdiplus.lib")

#include <windows.h>
#include <gdiplus.h>
#include <GdiPlusEnums.h>

using namespace Gdiplus;


extern "C" {

#include  "libavcodec\avcodec.h"
#include "libavutil\mathematics.h"
//#include "libavcodec\avcodec.h"

WCHAR *fname;
AVCodec *codec;
AVCodecContext *c= NULL;
int i, ret, x, y, got_output;
int total_frame_counter;
FILE *f;
AVFrame *frame;
AVPacket pkt;
int codec_id;
uint8_t endcode[] = { 0, 0, 1, 0xb7 };
int errn;

void Encoder_init()
{
   avcodec_register_all();
    /* find the mpeg1 video encoder */

   codec_id = CODEC_ID_MPEG1VIDEO;

    codec = avcodec_find_encoder(CODEC_ID_MPEG1VIDEO);
    if (!codec) {
        fprintf(stderr, "Codec not found\n");
        exit(1);
    }
    c = avcodec_alloc_context3(codec);
    if (!c) {
        fprintf(stderr, "Could not allocate video codec context\n");
        exit(1);
    }
    /* put sample parameters */
    c->bit_rate = 400000;
    /* resolution must be a multiple of two */
    c->width = 352;
    c->height = 288;
    /* frames per second */
    
   //c->time_base= (AVRational){1,25};
   c->time_base.num=1;c->time_base.den=25;
   
    c->gop_size = 10; /* emit one intra frame every ten frames */
    c->max_b_frames=1;
   c->pix_fmt = AV_PIX_FMT_YUV420P;
   /*
    if(codec_id == AV_CODEC_ID_H264)
        av_opt_set(c->priv_data, "preset", "slow", 0);
      */
}

const char *Encoder_GetCodecName( int id )
{
   
   return avcodec_get_name( (AVCodecID)id );
}

然后我在 C++ 中有一个头文件:

const char *Encoder_GetCodecName( int id );

然后我有另一个 C++ 头文件,我正在使用它GetCodecName()来获取列表:

List<String^> ^GetCodecs()
   {
      List<String^> ^l = gcnew List<String^>;

      String ^s;

      for (int i=0;i<3333;i++)
      {
      s = gcnew String(Encoder_GetCodecName( i ));
      l->Add(s);
      }

      return l;
   }

但是我现在i<3333这样做了,可能其中一个索引是空的,因为编解码器少于 3333 个?

那么如何获取/计算 ffmpeg 库中有多少编解码器,所以我将执行以下操作:

i < codecs.Length

不使用3333

4

2 回答 2

6

ffmpeg/avconv 有一个选项 -codecs 从 cmdutils.c 运行 show_codecs()

它以下列格式列出所有内容:

Codecs:
 D..... = Decoding supported
 .E.... = Encoding supported
 ..V... = Video codec
 ..A... = Audio codec
 ..S... = Subtitle codec
 ...S.. = Supports draw_horiz_band
 ....D. = Supports direct rendering method 1
 .....T = Supports weird frame truncation
 ------
 D V D  4xm             4X Movie
 D V D  8bps            QuickTime 8BPS video
 D A D  8svx_exp        8SVX exponential
 D A D  8svx_fib        8SVX fibonacci
 D V D  FRWU            Forward Uncompressed
  EV    a64multi        Multicolor charset for Commodore 64
  EV    a64multi5       Multicolor charset for Commodore 64, extended with 5th color (colram)
 DEA D  aac             Advanced Audio Coding
 D A D  aac_latm        AAC LATM (Advanced Audio Codec LATM syntax)
 D V D  aasc            Autodesk RLE
 DEA D  ac3             ATSC A/52A (AC-3)
  EA    ac3_fixed       ATSC A/52A (AC-3)
 D A D  adpcm_4xm       ADPCM 4X Movie
 DEA D  adpcm_adx       SEGA CRI ADX ADPCM
 D A D  adpcm_ct        ADPCM Creative Technology
...

您可以使用 cmdutils.c 中的 show_codecs() 作为模板来获取您需要的内容

于 2013-05-04T06:28:50.523 回答
5

AVCodecID是一个枚举。它定义了有限数量的值。然而,很多这些值不是连续的,值之间有几个差距,而且还有一些值可以很好地进入 6 位数字(最高为 0x21000 即 135168)。libav 的 API 中没有找到最高可用AVCodecID值的机制,所以如果你想坚持使用 ID 循环,那么你需要相当多地增加循环计数器。此外,avcodec_get_name()返回"unknown_codec"未知 ID,因此您需要在将它们添加到列表之前将其过滤掉。或者,您可以将一条语句与已知 ID 值switch的硬编码语句合并到循环中。case

更好的方法是根本不循环遍历 ID,而是循环遍历已注册的编解码器本身。调用av_codec_next()以获取指向第一个注册AVCodec结构的指针。AVCodecnamelong_name领域。然后av_codec_next()再次调用以获取下一个AVCodec,依此类推,直到它返回一个 NULL 指针。 该文档指出:

AVCodec* av_codec_next ( const AVCodec * c )

如果 c 为 NULL,则返回第一个注册的编解码器,如果 c 为非 NULL,则返回 c 之后的下一个注册编解码器,如果 c 是最后一个,则返回 NULL。

通过直接访问AVCodec结构,您的循环将运行得更快、更准确,并且还可以让您区分可能共享通用名称的编码器和解码器。

尝试这样的事情:

__declspec(thread) AVCodec* current_codec = NULL;
    
const char* Encoder_GetNextCodecName()
{
    current_codec = av_codec_next(current_codec);
    while (current_codec != NULL)
    {
        /* this is optional...
        if (!av_codec_is_encoder(current_codec))
        {
            current_codec = av_codec_next(current_codec);
            continue;
        }
        */
        return current_codec->name;
    }
    return "";
}
    
const char* Encoder_GetFirstCodecName()
{
    current_codec = NULL;
    return Encoder_GetNextCodecName();
}
List<String^> ^GetCodecs()
{
    List<String^> ^l = gcnew List<String^>;
    
    String ^s = gcnew String(Encoder_GetFirstCodecName());
    while (!String.IsNullOrEmpty(s))
    {
        l->Add(s);
        s = gcnew String(Encoder_GetNextCodecName());
    }
    
    return l;
}

更新:正如av_codec_next()几年前已弃用的那样,您可以av_codec_iterate()改用,例如:

__declspec(thread) void* iterate_data = NULL;
    
const char* Encoder_GetNextCodecName()
{
    AVCodec* current_codec = av_codec_iterate(&iterate_data);
    while (current_codec != NULL)
    {
        /* this is optional...
        if (!av_codec_is_encoder(current_codec))
        {
            current_codec = av_codec_iterate(&iterate_data);
            continue;
        }
        */
        return current_codec->name;
    }
    return "";
}

const char* Encoder_GetFirstCodecName()
{
    iterate_data = NULL;
    return Encoder_GetNextCodecName();
}
于 2013-05-04T04:44:24.313 回答