VP8 C / C ++源代码,如何将ARGB格式的帧编码为帧而不是文件

问题描述

我正在尝试开始使用VP8 library,而不是构建in the standard way they tell you to,我只是将所有主文件和“ encoder”文件夹加载到了新的Visual Studio C ++中DLL项目,只是将C文件包含在外部“ C” dll导出函数中,到目前为止,该函数可以很好地进行构建等。我只是不知道从何处开始使用C ++ API将3帧ARGB数据编码为一个非常基本的视频,只是入门

我可以找到的唯一示例是在名为simple_encoder.c的示例文件夹中,尽管其前提是它们已经在另一个文件中加载并解析其帧然后进行转换,所以看起来有点复杂,我只是希望能够传递几个ARGB帧的字节数组并输出非常简单的VP8视频

我见过How to encode series of images into VP8 using WebM VP8 Encoder API? (C/C++),但是接受的答案只是链接the build instructions和引用the general specification of the vp8 format,我能找到的最接近的是the example encoding parameters,但我只想这样做一切都来自C ++,除了认的simple_encoder.c之外,我似乎找不到其他示例了?

仅举一些我认为我理解的相关部分,但仍需要更多帮助

//in int main...
...
vpx_image_t raw;
if (!vpx_img_alloc(&raw,VPX_IMG_FMT_I420,info.frame_width,info.frame_height,1)) {
    //"Failed to allocate image." error
}

所以我想我大部分都理解这一部分,VPX_IMG_FMT_I420是唯一不在此文件生成的部分,而是在vpx_image.h中首先生成

#define VPX_IMG_FMT_PLANAR 
//then after...
typedef enum vpx_img_fmt {
    VPX_IMG_FMT_NONE,VPX_IMG_FMT_RGB24,/**< 24 bit per pixel packed RGB */
    ///some other formats....
    VPX_IMG_FMT_ARGB,/**< 32 bit packed ARGB,alpha=255 */

    VPX_IMG_FMT_YV12    = VPX_IMG_FMT_PLANAR | VPX_IMG_FMT_UV_FLIP | 1,/**< planar YVU */
    VPX_IMG_FMT_I420    = VPX_IMG_FMT_PLANAR | 2,} vpx_img_fmt_t; /**< alias for enum vpx_img_fmt */

所以我想我的问题的一部分已经通过编写它而得到了回答,其中一种格式是VPX_IMG_FMT_ARGB,尽管我不在其定义的位置,但是我想在上面的代码中我将其替换为

const VpxInterface *encoder = get_vpx_encoder_by_name("v8");

vpx_image_t raw;
VpxVideoInfo info = { 0,{ 0,0 } };

info.frame_width = 1920;
info.frame_height = 1080;
info.codec_fourcc = encoder->fourcc;
info.time_base.numerator = 1;
info.time_base.denominator = 24;

bool didIt = vpx_img_alloc(&raw,VPX_IMG_FMT_ARGB,info.frame_height/*example width and height*/,1)
//check didIt..

vpx_codec_enc_cfg_t cfg;
vpx_codec_ctx_t codec;
vpx_codec_err_t res;

res = vpx_codec_enc_config_default(encoder->codec_interface(),&cfg,0);
//check if !res for error

cfg.g_w = info.frame_width;
cfg.g_h = info.frame_height;
cfg.g_timebase.num = info.time_base.numerator;
cfg.g_timebase.den = info.time_base.denominator;
cfg.rc_target_bitrate = 200;

VpxVideoWriter *writer = NULL;

writer = vpx_video_writer_open(outfile_arg,kContainerIVF,&info);
//check if !writer for error

bool startIt = vpx_codec_enc_init(&codec,encoder->codec_interface(),0);
//not even sure where codec was set actually..


//check !startIt for error starting

//Now the next part in the original is where it reads from the input file,but instead
//I need to pass in an array of some ARGB byte arrays..
//thing is,in the next step they use a while loop for 
//vpx_img_read(&raw,fopen("path/to/YV12formatVideo","rb"))
//to set the contents of the raw vpx image allocated earlier,then
//they call another program that writes it to the writer object,//but I don't kNow how to read the actual ARGB data directly into the raw image
//without using fopen,so that's one question (review at end)

//so I'll just put a placeholder here for the **question**

//assuming I have an array of byte arrays stored individually
//for simplicity sake
int size = 1920 * 1080 * 4;

uint8_t imgOne[size] = {/*some big byte array*/};
uint8_t imgTwo[size] = {/*some big byte array*/};
uint8_t imgThree[size] = {/*some big byte array*/};

uint8_t *images[] = {imgOne,imgTwo,imgThree};

int framesDone = 0;
int maxFrames = 3;

//so Now I can replace the while loop with a filler function 
//until I find out how to set the raw image with ARGB data
while(framesDone < maxFrames) {
    magicalFunctionToSetARGBOfRawImage(&raw,images[framesDone]);
    
    encode_frame(&codec,&raw,framesDone,writer);
    
    framesDone++;
}

//Now apparently it needs to be flushed after

while(encode_frame(&codec,-1,writer)){}
vpx_img_free(&raw);
bool isDestroyed = vpx_codec_destroy(&codec);
//check if !isDestroyed for error

//Now we gotta define the encode_Frames function,but simpler 
//(and make it above other function for reference purposes 
//or in header

static int encode_frame(
     vpx_codex_ctx_t *coydek,vpx_image_t pic,int currentFrame,int flags,VpxVideoWriter *koysayv/*writer*/
) {
    //Now to substitute their encodeFrame function for
    //the actual raw calls to simplify things
    const DidIt = vpx_codec_encode(
        coydek,pic,currentFrame,1,//duration I think
        flags,//whatever that is
        VPX_DL_REALTIME//different than simlpe_encoder
    );
    
    if(!DidIt) return;//error here
    
    vpx_codec_iter_t iter = 0;
    const vpx_codec_cx_pkt_t *pkt = 0;
    int gotthings = 0;
    
    while(
        (pkt = vpx_codec_get_cx_data(
            coydek,&iter
        )) != 0
    ) {
        gotthings = 1;
        
        if(
            pkt->kind 
            == VPX_CODEC_CX_FRAME_PKT //don't exactly
            //understand this part
        ) {
            const 
            int 
            keyframe = (
                pkt
                    ->
                    data
                    .frame
                    .flags 
                    & 
                    VPX_FRAME_IS_KEY
            ) != 0; //don'texactly understand the
            //& operator here or how it gets the keyframe
            
            bool wroteFrame = vpx_video_writer_write_frame(
                koysayv,pkt->data.frame.buf
                //I'm guessing this is the encoded 
                //frame data,pkt->data.frame.sz,pkt->data.frame.pts
            );
            
            if(!wroteFrame) return; //error
        }
    }
    
    return gotthings;
}

尽管如此,但我不知道该如何阅读 如上所述,将ARGB数据放入RAW图像缓冲区本身 上面,在原始示例中,他们使用 vpx_img_read(&raw,fopen("path/to/file","rb")) 但是如果我从字节数组本身开始 那我要用什么功能代替文件呢?

我觉得可以通过vpx_img_read found in tools_common.c函数的源代码解决它:

int vpx_img_read(vpx_image_t *img,FILE *file) {
  int plane;

  for (plane = 0; plane < 3; ++plane) {
    unsigned char *buf = img->planes[plane];
    const int stride = img->stride[plane];
    const int w = vpx_img_plane_width(img,plane) *
                  ((img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1);
    const int h = vpx_img_plane_height(img,plane);
    int y;

    for (y = 0; y < h; ++y) {
      if (fread(buf,w,file) != (size_t)w) return 0;
      buf += stride;
    }
  }

  return 1;
}

尽管我个人没有足够的经验来了解如何获取单帧ARGB数据,但我认为关键部分是fread(buf,file),它似乎将file的部分读入{{1} }代表buf,我认为通过读入buf会自动读取到img->planes[plane];,但我不确定是否是这种情况,也不确定如何替换文件中的fread只需要一个容易加载到内存中的再见数组...

解决方法

VPX_IMG_FMT_ARGB 未定义,因为 libvpx 不支持(据我所知)。要使用此库压缩图像,您必须首先将其转换为支持的格式之一,例如 I420 (VPX_IMG_FMT_I420)。这里的代码(不是我的):https://gist.github.com/racerxdl/8164330 对 RGB 格式做得很好。如果您不想使用 libswscale 进行从 RGB 到 I420 的转换,您可以执行以下操作(此代码将 RGBA 字节数组转换为可由 libvpx 使用的 I420 vpx_image):

    unsigned int   tx       = <width of your image>
    unsigned int   ty       = <height of your image>
    unsigned char *image    = <array of bytes : RGBARGBA... of size ty*tx*4>
    vpx_image_t   *imageVpx = <result that must have been properly initialized by libvpx>

    imageVpx->stride[VPX_PLANE_U    ] = tx/2;
    imageVpx->stride[VPX_PLANE_V    ] = tx/2;
    imageVpx->stride[VPX_PLANE_Y    ] = tx;
    imageVpx->stride[VPX_PLANE_ALPHA] = tx;
    imageVpx->planes[VPX_PLANE_U    ] = new unsigned char[ty*tx/4];
    imageVpx->planes[VPX_PLANE_V    ] = new unsigned char[ty*tx/4];
    imageVpx->planes[VPX_PLANE_Y    ] = new unsigned char[ty*tx  ];
    imageVpx->planes[VPX_PLANE_ALPHA] = new unsigned char[ty*tx  ];

    unsigned char *planeY  = imageVpx->planes[VPX_PLANE_Y    ];
    unsigned char *planeU  = imageVpx->planes[VPX_PLANE_U    ];
    unsigned char *planeV  = imageVpx->planes[VPX_PLANE_V    ];
    unsigned char *planeA  = imageVpx->planes[VPX_PLANE_ALPHA];

    for (unsigned int y=0; y<ty; y++)
    {
        if (!(y % 2))
        {
            for (unsigned int x=0; x<tx; x+=2)
            {
                int r = *image++;
                int g = *image++;
                int b = *image++;
                int a = *image++;

                *planeY++ = max(0,min(255,(( 66*r + 129*g +  25*b) >> 8) + 16));
                *planeU++ = max(0,((-38*r + -74*g + 112*b) >> 8) + 128));
                *planeV++ = max(0,((112*r + -94*g + -18*b) >> 8) + 128));
                *planeA++ = a;

                r = *image++;
                g = *image++;
                b = *image++;
                a = *image++;

                *planeA++ = a;
                *planeY++ = max(0,((66*r + 129*g + 25*b) >> 8) + 16));
            }
        }
        else
        {
            for (unsigned int x=0; x<tx; x++)
            {
                int const r = *image++;
                int const g = *image++;
                int const b = *image++;
                int const a = *image++;

                *planeA++ = a;
                *planeY++ = max(0,((66*r + 129*g + 25*b) >> 8) + 16));
            }
        }
    }

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...