c++ - 使用最新的 ffmpeg API (2017) 创建视频

标签 c++ ffmpeg

我已经开始学习如何使用 ffmpeg,它对所有教程和可用示例(如 this)进行了严重的弃用。 .

我正在寻找创建输出视频的代码。

不幸的是,大部分good examples专注于从文件中读取而不是创建文件。

Here ,我发现了一个弃用的例子,我花了很长时间来修复它的错误,直到它变成了这样:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>

extern "C" {
        #include <libavcodec/avcodec.h>
        #include <libavformat/avformat.h>
        #include <libswscale/swscale.h>
        #include <libavformat/avio.h>
        #include <libavutil/opt.h>
}

#define WIDTH 800
#define HEIGHT 480
#define STREAM_NB_FRAMES  ((int)(STREAM_DURATION * FRAME_RATE))
#define FRAME_RATE 24
#define PIXEL_FORMAT AV_PIX_FMT_YUV420P
#define STREAM_DURATION 5.0 //seconds
#define BIT_RATE 400000

#define AV_CODEC_FLAG_GLOBAL_HEADER (1 << 22)
#define CODEC_FLAG_GLOBAL_HEADER AV_CODEC_FLAG_GLOBAL_HEADER
#define AVFMT_RAWPICTURE 0x0020

using namespace std;

static int sws_flags = SWS_BICUBIC;

AVFrame *picture, *tmp_picture;
uint8_t *video_outbuf;
int frame_count, video_outbuf_size;


/****** IF LINUX ******/
inline int sprintf_s(char* buffer, size_t sizeOfBuffer, const char* format, ...)
{
    va_list ap;
    va_start(ap, format);
    int result = vsnprintf(buffer, sizeOfBuffer, format, ap);
    va_end(ap);
    return result;
}

/****** IF LINUX ******/
template<size_t sizeOfBuffer>
inline int sprintf_s(char (&buffer)[sizeOfBuffer], const char* format, ...)
{
    va_list ap;
    va_start(ap, format);
    int result = vsnprintf(buffer, sizeOfBuffer, format, ap);
    va_end(ap);
    return result;
}


static void closeVideo(AVFormatContext *oc, AVStream *st)
{
    avcodec_close(st->codec);
    av_free(picture->data[0]);
    av_free(picture);
    if (tmp_picture)
    {
        av_free(tmp_picture->data[0]);
        av_free(tmp_picture);
    }
    av_free(video_outbuf);
}

static AVFrame *alloc_picture(enum AVPixelFormat pix_fmt, int width, int height)
{
    AVFrame *picture;
    uint8_t *picture_buf;
    int size;

    picture = av_frame_alloc();
    if(!picture)
        return NULL;
    size = avpicture_get_size(pix_fmt, width, height);
    picture_buf = (uint8_t*)(av_malloc(size));
    if (!picture_buf)
    {
        av_free(picture);
        return NULL;
    }
    avpicture_fill((AVPicture *) picture, picture_buf, pix_fmt, WIDTH, HEIGHT);
    return picture;
}

static void openVideo(AVFormatContext *oc, AVStream *st)
{
    AVCodec *codec;
    AVCodecContext *c;

    c = st->codec;
    if(c->idct_algo == AV_CODEC_ID_H264)
        av_opt_set(c->priv_data, "preset", "slow", 0);

    codec = avcodec_find_encoder(c->codec_id);
    if(!codec)
    {
        std::cout << "Codec not found." << std::endl;
        std::cin.get();std::cin.get();exit(1);
    }

    if(codec->id == AV_CODEC_ID_H264)
        av_opt_set(c->priv_data, "preset", "medium", 0);

    if(avcodec_open2(c, codec, NULL) < 0)
    {
        std::cout << "Could not open codec." << std::endl;
        std::cin.get();std::cin.get();exit(1);
    }
    video_outbuf = NULL;
    if(!(oc->oformat->flags & AVFMT_RAWPICTURE))
    {
        video_outbuf_size = 200000;
        video_outbuf = (uint8_t*)(av_malloc(video_outbuf_size));
    }
    picture = alloc_picture(c->pix_fmt, c->width, c->height);
    if(!picture)
    {
        std::cout << "Could not allocate picture" << std::endl;
        std::cin.get();exit(1);
    }
    tmp_picture = NULL;
    if(c->pix_fmt != AV_PIX_FMT_YUV420P)
    {
        tmp_picture = alloc_picture(AV_PIX_FMT_YUV420P, WIDTH, HEIGHT);
        if(!tmp_picture)
        {
            std::cout << " Could not allocate temporary picture" << std::endl;
            std::cin.get();exit(1);
        }
    }
}


static AVStream* addVideoStream(AVFormatContext *context, enum AVCodecID codecID)
{
    AVCodecContext *codec;
    AVStream *stream;
    stream = avformat_new_stream(context, NULL);
    if(!stream)
    {
        std::cout << "Could not alloc stream." << std::endl;
        std::cin.get();exit(1);
    }

    codec = stream->codec;
    codec->codec_id = codecID;
    codec->codec_type = AVMEDIA_TYPE_VIDEO;

    // sample rate
    codec->bit_rate = BIT_RATE;
    // resolution must be a multiple of two
    codec->width = WIDTH;
    codec->height = HEIGHT;
    codec->time_base.den = FRAME_RATE; // stream fps
    codec->time_base.num = 1;
    codec->gop_size = 12; // intra frame every twelve frames at most
    codec->pix_fmt = PIXEL_FORMAT;
    if(codec->codec_id == AV_CODEC_ID_MPEG2VIDEO)
        codec->max_b_frames = 2; // for testing, B frames

    if(codec->codec_id == AV_CODEC_ID_MPEG1VIDEO)
        codec->mb_decision = 2;

    if(context->oformat->flags & AVFMT_GLOBALHEADER)
        codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

    return stream;
}

static void fill_yuv_image(AVFrame *pict, int frame_index, int width, int height)
{
    int x, y, i;
    i = frame_index;

    /* Y */
    for(y=0;y<height;y++) {
        for(x=0;x<width;x++) {
            pict->data[0][y * pict->linesize[0] + x] = x + y + i * 3;
        }
    }

    /* Cb and Cr */
    for(y=0;y<height/2;y++) {
        for(x=0;x<width/2;x++) {
            pict->data[1][y * pict->linesize[1] + x] = 128 + y + i * 2;
            pict->data[2][y * pict->linesize[2] + x] = 64 + x + i * 5;
        }
    }
}

static void write_video_frame(AVFormatContext *oc, AVStream *st)
{
    int out_size, ret;
    AVCodecContext *c;
    static struct SwsContext *img_convert_ctx;
    c = st->codec;

    if(frame_count >= STREAM_NB_FRAMES)
    {

    }
    else
    {
        if(c->pix_fmt != AV_PIX_FMT_YUV420P)
        {
            if(img_convert_ctx = NULL)
            {
                img_convert_ctx = sws_getContext(WIDTH, HEIGHT, AV_PIX_FMT_YUV420P, WIDTH, HEIGHT,
                                                c->pix_fmt, sws_flags, NULL, NULL, NULL);
                if(img_convert_ctx == NULL)
                {
                    std::cout << "Cannot initialize the conversion context" << std::endl;
                    std::cin.get();exit(1);
                }
            }
            fill_yuv_image(tmp_picture, frame_count, WIDTH, HEIGHT);
            sws_scale(img_convert_ctx, tmp_picture->data, tmp_picture->linesize, 0, HEIGHT,
                        picture->data, picture->linesize);
        }
        else
        {
            fill_yuv_image(picture, frame_count, WIDTH, HEIGHT);
        }
    }

    if (oc->oformat->flags & AVFMT_RAWPICTURE)
    {
        /* raw video case. The API will change slightly in the near
           futur for that */
        AVPacket pkt;
        av_init_packet(&pkt);

        pkt.flags |= AV_PKT_FLAG_KEY;
        pkt.stream_index= st->index;
        pkt.data= (uint8_t *)picture;
        pkt.size= sizeof(AVPicture);

        ret = av_interleaved_write_frame(oc, &pkt);
    }
    else
    {
        /* encode the image */
        out_size = avcodec_encode_video(c, video_outbuf, video_outbuf_size, picture);
        /* if zero size, it means the image was buffered */
        if (out_size > 0)
        {
            AVPacket pkt;
            av_init_packet(&pkt);

            if (c->coded_frame->pts != AV_NOPTS_VALUE)
                pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base);
            if(c->coded_frame->key_frame)
                pkt.flags |= AV_PKT_FLAG_KEY;
            pkt.stream_index= st->index;
            pkt.data= video_outbuf;
            pkt.size= out_size;
            /* write the compressed frame in the media file */
            ret = av_interleaved_write_frame(oc, &pkt);
        } else {
            ret = 0;
        }
    }
    if (ret != 0) {
        std::cout << "Error while writing video frames" << std::endl;
        std::cin.get();exit(1);
    }
    frame_count++;
}

int main ( int argc, char *argv[] )
{
    const char* filename = "test.h264";
    AVOutputFormat *outputFormat;
    AVFormatContext *context;
    AVCodecContext *codec;
    AVStream *videoStream;
    double videoPTS;

    // init libavcodec, register all codecs and formats
    av_register_all(); 
    // auto detect the output format from the name
    outputFormat = av_guess_format(NULL, filename, NULL);
    if(!outputFormat)
    {
        std::cout << "Cannot guess output format! Using mpeg!" << std::endl;
        std::cin.get();
        outputFormat = av_guess_format(NULL, "h263" , NULL);
    }
    if(!outputFormat)
    {
        std::cout << "Could not find suitable output format." << std::endl;
        std::cin.get();exit(1);
    }

    context = avformat_alloc_context();
    if(!context)
    {
        std::cout << "Cannot allocate avformat memory." << std::endl;
        std::cin.get();exit(1);
    }
    context->oformat = outputFormat;
    sprintf_s(context->filename, sizeof(context->filename), "%s", filename);
    std::cout << "Is '" << context->filename << "' = '" << filename << "'" << std::endl;


    videoStream = NULL;
    outputFormat->audio_codec = AV_CODEC_ID_NONE;
    videoStream = addVideoStream(context, outputFormat->video_codec);

    /* still needed?
    if(av_set_parameters(context, NULL) < 0)
    {
        std::cout << "Invalid output format parameters." << std::endl;
        exit(0);
    }*/

    av_dump_format(context, 0, filename, 1);

    if(videoStream)
        openVideo(context, videoStream);

    if(!outputFormat->flags & AVFMT_NOFILE)
    {
        if(avio_open(&context->pb, filename, AVIO_FLAG_READ_WRITE) < 0)
        {
            std::cout << "Could not open " << filename << std::endl;
            std::cin.get();exit(1);
        }
    }

    avformat_write_header(context, 0);

    while(true)
    {
        if(videoStream)
            videoPTS = (double) videoStream->pts.val * videoStream->time_base.num / videoStream->time_base.den;
        else
            videoPTS = 0.;

        if((!videoStream || videoPTS >= STREAM_DURATION))
        {
            break;
        }
        write_video_frame(context, videoStream);
    }
    av_write_trailer(context);
    if(videoStream)
        closeVideo(context, videoStream);
    for(int i = 0; i < context->nb_streams; i++)
    {
        av_freep(&context->streams[i]->codec);
        av_freep(&context->streams[i]);
    }

    if(!(outputFormat->flags & AVFMT_NOFILE))
    {
        avio_close(context->pb);
    }
    av_free(context);
    std::cin.get();
    return 0;
}

编译:

g++ -I ./FFmpeg/ video.cpp -L fflibs -lavcodec -lavformat

代码有两个错误:

video.cpp:249:84: error: ‘avcodec_encode_video’ was not declared in this scope
         out_size = avcodec_encode_video(c, video_outbuf, video_outbuf_size, picture);
                                                                                    ^


video.cpp: In function ‘int main(int, char**)’:
video.cpp:342:46: error: ‘AVStream {aka struct AVStream}’ has no member named ‘pts’
             videoPTS = (double) videoStream->pts.val * videoStream->time_base.num / videoStream->time_base.den;
                                              ^

以及大量弃用警告。

video.cpp: In function ‘void closeVideo(AVFormatContext*, AVStream*)’:
video.cpp:60:23: warning: ‘AVStream::codec’ is deprecated [-Wdeprecated-declarations]
     avcodec_close(st->codec);
                       ^
In file included from video.cpp:9:0:
./FFmpeg/libavformat/avformat.h:876:21: note: declared here
     AVCodecContext *codec;
                     ^
video.cpp:60:23: warning: ‘AVStream::codec’ is deprecated [-Wdeprecated-declarations]
     avcodec_close(st->codec);
                       ^
In file included from video.cpp:9:0:
./FFmpeg/libavformat/avformat.h:876:21: note: declared here
     AVCodecContext *codec;
                     ^
video.cpp:60:23: warning: ‘AVStream::codec’ is deprecated [-Wdeprecated-declarations]
     avcodec_close(st->codec);
                       ^
In file included from video.cpp:9:0:
./FFmpeg/libavformat/avformat.h:876:21: note: declared here
     AVCodecContext *codec;
                     ^
video.cpp: In function ‘AVFrame* alloc_picture(AVPixelFormat, int, int)’:
video.cpp:80:12: warning: ‘int avpicture_get_size(AVPixelFormat, int, int)’ is deprecated [-Wdeprecated-declarations]
     size = avpicture_get_size(pix_fmt, width, height);
            ^
In file included from video.cpp:8:0:
./FFmpeg/libavcodec/avcodec.h:5228:5: note: declared here
 int avpicture_get_size(enum AVPixelFormat pix_fmt, int width, int height);
     ^
video.cpp:80:12: warning: ‘int avpicture_get_size(AVPixelFormat, int, int)’ is deprecated [-Wdeprecated-declarations]
     size = avpicture_get_size(pix_fmt, width, height);
            ^
In file included from video.cpp:8:0:
./FFmpeg/libavcodec/avcodec.h:5228:5: note: declared here
 int avpicture_get_size(enum AVPixelFormat pix_fmt, int width, int height);
     ^
video.cpp:80:53: warning: ‘int avpicture_get_size(AVPixelFormat, int, int)’ is deprecated [-Wdeprecated-declarations]
     size = avpicture_get_size(pix_fmt, width, height);
                                                     ^
In file included from video.cpp:8:0:
./FFmpeg/libavcodec/avcodec.h:5228:5: note: declared here
 int avpicture_get_size(enum AVPixelFormat pix_fmt, int width, int height);
     ^
video.cpp:87:5: warning: ‘int avpicture_fill(AVPicture*, const uint8_t*, AVPixelFormat, int, int)’ is deprecated [-Wdeprecated-declarations]
     avpicture_fill((AVPicture *) picture, picture_buf, pix_fmt, WIDTH, HEIGHT);
     ^
In file included from video.cpp:8:0:
./FFmpeg/libavcodec/avcodec.h:5213:5: note: declared here
 int avpicture_fill(AVPicture *picture, const uint8_t *ptr,
     ^
video.cpp:87:5: warning: ‘int avpicture_fill(AVPicture*, const uint8_t*, AVPixelFormat, int, int)’ is deprecated [-Wdeprecated-declarations]
     avpicture_fill((AVPicture *) picture, picture_buf, pix_fmt, WIDTH, HEIGHT);
     ^
In file included from video.cpp:8:0:
./FFmpeg/libavcodec/avcodec.h:5213:5: note: declared here
 int avpicture_fill(AVPicture *picture, const uint8_t *ptr,
     ^
video.cpp:87:78: warning: ‘int avpicture_fill(AVPicture*, const uint8_t*, AVPixelFormat, int, int)’ is deprecated [-Wdeprecated-declarations]
     avpicture_fill((AVPicture *) picture, picture_buf, pix_fmt, WIDTH, HEIGHT);
                                                                              ^
In file included from video.cpp:8:0:
./FFmpeg/libavcodec/avcodec.h:5213:5: note: declared here
 int avpicture_fill(AVPicture *picture, const uint8_t *ptr,
     ^
video.cpp: In function ‘void openVideo(AVFormatContext*, AVStream*)’:
video.cpp:96:13: warning: ‘AVStream::codec’ is deprecated [-Wdeprecated-declarations]
     c = st->codec;
             ^
In file included from video.cpp:9:0:
./FFmpeg/libavformat/avformat.h:876:21: note: declared here
     AVCodecContext *codec;
                     ^
video.cpp:96:13: warning: ‘AVStream::codec’ is deprecated [-Wdeprecated-declarations]
     c = st->codec;
             ^
In file included from video.cpp:9:0:
./FFmpeg/libavformat/avformat.h:876:21: note: declared here
     AVCodecContext *codec;
                     ^
video.cpp:96:13: warning: ‘AVStream::codec’ is deprecated [-Wdeprecated-declarations]
     c = st->codec;
             ^
In file included from video.cpp:9:0:
./FFmpeg/libavformat/avformat.h:876:21: note: declared here
     AVCodecContext *codec;
                     ^
video.cpp: In function ‘AVStream* addVideoStream(AVFormatContext*, AVCodecID)’:
video.cpp:151:21: warning: ‘AVStream::codec’ is deprecated [-Wdeprecated-declarations]
     codec = stream->codec;
                     ^
In file included from video.cpp:9:0:
./FFmpeg/libavformat/avformat.h:876:21: note: declared here
     AVCodecContext *codec;
                     ^
video.cpp:151:21: warning: ‘AVStream::codec’ is deprecated [-Wdeprecated-declarations]
     codec = stream->codec;
                     ^
In file included from video.cpp:9:0:
./FFmpeg/libavformat/avformat.h:876:21: note: declared here
     AVCodecContext *codec;
                     ^
video.cpp:151:21: warning: ‘AVStream::codec’ is deprecated [-Wdeprecated-declarations]
     codec = stream->codec;
                     ^
In file included from video.cpp:9:0:
./FFmpeg/libavformat/avformat.h:876:21: note: declared here
     AVCodecContext *codec;
                     ^
video.cpp: In function ‘void write_video_frame(AVFormatContext*, AVStream*)’:
video.cpp:202:13: warning: ‘AVStream::codec’ is deprecated [-Wdeprecated-declarations]
     c = st->codec;
             ^
In file included from video.cpp:9:0:
./FFmpeg/libavformat/avformat.h:876:21: note: declared here
     AVCodecContext *codec;
                     ^
video.cpp:202:13: warning: ‘AVStream::codec’ is deprecated [-Wdeprecated-declarations]
     c = st->codec;
             ^
In file included from video.cpp:9:0:
./FFmpeg/libavformat/avformat.h:876:21: note: declared here
     AVCodecContext *codec;
                     ^
video.cpp:202:13: warning: ‘AVStream::codec’ is deprecated [-Wdeprecated-declarations]
     c = st->codec;
             ^
In file included from video.cpp:9:0:
./FFmpeg/libavformat/avformat.h:876:21: note: declared here
     AVCodecContext *codec;
                     ^
video.cpp:256:20: warning: ‘AVCodecContext::coded_frame’ is deprecated [-Wdeprecated-declarations]
             if (c->coded_frame->pts != AV_NOPTS_VALUE)
                    ^
In file included from video.cpp:8:0:
./FFmpeg/libavcodec/avcodec.h:2723:35: note: declared here
     attribute_deprecated AVFrame *coded_frame;
                                   ^
video.cpp:256:20: warning: ‘AVCodecContext::coded_frame’ is deprecated [-Wdeprecated-declarations]
             if (c->coded_frame->pts != AV_NOPTS_VALUE)
                    ^
In file included from video.cpp:8:0:
./FFmpeg/libavcodec/avcodec.h:2723:35: note: declared here
     attribute_deprecated AVFrame *coded_frame;
                                   ^
video.cpp:256:20: warning: ‘AVCodecContext::coded_frame’ is deprecated [-Wdeprecated-declarations]
             if (c->coded_frame->pts != AV_NOPTS_VALUE)
                    ^
In file included from video.cpp:8:0:
./FFmpeg/libavcodec/avcodec.h:2723:35: note: declared here
     attribute_deprecated AVFrame *coded_frame;
                                   ^
video.cpp:257:42: warning: ‘AVCodecContext::coded_frame’ is deprecated [-Wdeprecated-declarations]
                 pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base);
                                          ^
In file included from video.cpp:8:0:
./FFmpeg/libavcodec/avcodec.h:2723:35: note: declared here
     attribute_deprecated AVFrame *coded_frame;
                                   ^
video.cpp:257:42: warning: ‘AVCodecContext::coded_frame’ is deprecated [-Wdeprecated-declarations]
                 pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base);
                                          ^
In file included from video.cpp:8:0:
./FFmpeg/libavcodec/avcodec.h:2723:35: note: declared here
     attribute_deprecated AVFrame *coded_frame;
                                   ^
video.cpp:257:42: warning: ‘AVCodecContext::coded_frame’ is deprecated [-Wdeprecated-declarations]
                 pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base);
                                          ^
In file included from video.cpp:8:0:
./FFmpeg/libavcodec/avcodec.h:2723:35: note: declared here
     attribute_deprecated AVFrame *coded_frame;
                                   ^
video.cpp:258:19: warning: ‘AVCodecContext::coded_frame’ is deprecated [-Wdeprecated-declarations]
             if(c->coded_frame->key_frame)
                   ^
In file included from video.cpp:8:0:
./FFmpeg/libavcodec/avcodec.h:2723:35: note: declared here
     attribute_deprecated AVFrame *coded_frame;
                                   ^
video.cpp:258:19: warning: ‘AVCodecContext::coded_frame’ is deprecated [-Wdeprecated-declarations]
             if(c->coded_frame->key_frame)
                   ^
In file included from video.cpp:8:0:
./FFmpeg/libavcodec/avcodec.h:2723:35: note: declared here
     attribute_deprecated AVFrame *coded_frame;
                                   ^
video.cpp:258:19: warning: ‘AVCodecContext::coded_frame’ is deprecated [-Wdeprecated-declarations]
             if(c->coded_frame->key_frame)
                   ^
In file included from video.cpp:8:0:
./FFmpeg/libavcodec/avcodec.h:2723:35: note: declared here
     attribute_deprecated AVFrame *coded_frame;
                                   ^
video.cpp:357:40: warning: ‘AVStream::codec’ is deprecated [-Wdeprecated-declarations]
         av_freep(&context->streams[i]->codec);
                                        ^
In file included from video.cpp:9:0:
./FFmpeg/libavformat/avformat.h:876:21: note: declared here
     AVCodecContext *codec;
                     ^
video.cpp:357:40: warning: ‘AVStream::codec’ is deprecated [-Wdeprecated-declarations]
         av_freep(&context->streams[i]->codec);
                                        ^
In file included from video.cpp:9:0:
./FFmpeg/libavformat/avformat.h:876:21: note: declared here
     AVCodecContext *codec;
                     ^
video.cpp:357:40: warning: ‘AVStream::codec’ is deprecated [-Wdeprecated-declarations]
         av_freep(&context->streams[i]->codec);
                                        ^
In file included from video.cpp:9:0:
./FFmpeg/libavformat/avformat.h:876:21: note: declared here
     AVCodecContext *codec;
                     ^
video.cpp:337:38: warning: ignoring return value of ‘int avformat_write_header(AVFormatContext*, AVDictionary**)’, declared with attribute warn_unused_result [-Wunused-result]
     avformat_write_header(context, 0);
                                      ^

我还定义了几个宏来重新定义那些被省略的。在现代 ffmpeg API 中,它们必须被替换。

有人可以帮我解决错误和弃用警告以符合最近的 ffmpeg API 吗?

最佳答案

由于 st->codec 这种代码方式在 ffmpeg 4.0+ 版本中已经被弃用,新的​​方式应该重写如下。

AVFormatContext *ifmt_ctx = NULL;

// ... record sth to ifmt_ctx here ...

AVCodec *codec = avcodec_find_decoder(ifmt_ctx->streams[i]->codecpar->codec_id);
AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);

我在我的项目中成功编译了它们。

关于c++ - 使用最新的 ffmpeg API (2017) 创建视频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47321509/

相关文章:

c++ - 打开不截断的二进制输出文件流

c++ - 如何使 C++ 继承保留访问说明符

awk - FFMPEG 使用 MSVC 在 Windows 上构建 - 制作失败

android - 如何在 Android 上发现帧缓冲区宽度?

c++ - 我用 Gstreamer MSVC 1.16.1 构建 opencv 3.4,现在 imread 和 VideoCapture 不起作用

java - 卡卡杜 JPEG 压缩库

C++ 获取所有正在运行的进程及其名称

c++ - 拆分表达式但保留分隔符

assembly - 将ffmpeg中的x86 asm和inline-asm编译成WebAssembly的问题

visual-studio - amd64 编译器在 Visual Studio 2022 中的位置 |使用 NVENC 编译 FFmpeg