SDL2.0的SDL_Overlay替代方案

16

我一直在尝试学习ffmpeg的以下教程:http://dranger.com/ffmpeg/tutorial02.html

但是,当我尝试使用gcc编译时,会得到以下输出:

root:/Users/mbrodeur/Downloads/HACKATHON CONTENT/Tutorials-> gcc -o tutorial02 tutorial02.c -lavutil -lavformat -lavcodec -lz -lavutil -lm -lswscale -D_THREAD_SAFE -lSDL2
tutorial02.c: In function ‘main’:
tutorial02.c:41: error: ‘SDL_Overlay’ undeclared (first use in this function)
tutorial02.c:41: error: (Each undeclared identifier is reported only once
tutorial02.c:41: error: for each function it appears in.)
tutorial02.c:41: error: ‘bmp’ undeclared (first use in this function)
tutorial02.c:98: warning: assignment makes pointer from integer without a cast
tutorial02.c:110: error: ‘SDL_YV12_OVERLAY’ undeclared (first use in this function)

现在我看到SDL_Overlay在SDL2中不再使用,因此问题就在这里。我已经四处查找,但似乎找不到任何有用的东西。是否有SDL_Overlay的替代品?它是否必要?

SDL_Overlay在以下情况下使用:

SDL_Overlay     *bmp;
bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height,
                       SDL_YV12_OVERLAY, screen);

无关紧要,但您可能想看一下本教程的更新源代码版本。 - llogan
谢谢,我不知道那个页面存在。不幸的是,更新后的源代码仍然没有解决我的问题。 - Disco Globeulon
1
你更新了教程并让代码与sdl2一起工作了吗?如果是的话,能分享一下吗?提前感谢。 :D - jofra
4个回答

32

我已经更新了教程,使其与SDL 2.0.1兼容。它将SDL_Overlay替换为YV12格式的SDL_Texture。

int main(int argc, char *argv[]) {
    AVFormatContext *pFormatCtx = NULL;
    int videoStream;
    unsigned i;
    AVCodecContext *pCodecCtxOrig = NULL;
    AVCodecContext *pCodecCtx = NULL;
    AVCodec *pCodec = NULL;
    AVFrame *pFrame = NULL;
    AVPacket packet;
    int frameFinished;
    struct SwsContext *sws_ctx = NULL;
    SDL_Event event;
    SDL_Window *screen;
    SDL_Renderer *renderer;
    SDL_Texture *texture;
    Uint8 *yPlane, *uPlane, *vPlane;
    size_t yPlaneSz, uvPlaneSz;
    int uvPitch;

    if (argc < 2) {
        fprintf(stderr, "Usage: test <file>\n");
        exit(1);
    }
    // Register all formats and codecs
    av_register_all();

    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
        fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
        exit(1);
    }

    // Open video file
    if (avformat_open_input(&pFormatCtx, argv[1], NULL, NULL) != 0)
        return -1; // Couldn't open file

    // Retrieve stream information
    if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
        return -1; // Couldn't find stream information

    // Dump information about file onto standard error
    av_dump_format(pFormatCtx, 0, argv[1], 0);

    // Find the first video stream
    videoStream = -1;
    for (i = 0; i < pFormatCtx->nb_streams; i++)
        if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
            videoStream = i;
            break;
        }
    if (videoStream == -1)
        return -1; // Didn't find a video stream

    // Get a pointer to the codec context for the video stream
    pCodecCtxOrig = pFormatCtx->streams[videoStream]->codec;
    // Find the decoder for the video stream
    pCodec = avcodec_find_decoder(pCodecCtxOrig->codec_id);
    if (pCodec == NULL) {
        fprintf(stderr, "Unsupported codec!\n");
        return -1; // Codec not found
    }

    // Copy context
    pCodecCtx = avcodec_alloc_context3(pCodec);
    if (avcodec_copy_context(pCodecCtx, pCodecCtxOrig) != 0) {
        fprintf(stderr, "Couldn't copy codec context");
        return -1; // Error copying codec context
    }

    // Open codec
    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
        return -1; // Could not open codec

    // Allocate video frame
    pFrame = av_frame_alloc();

    // Make a screen to put our video
    screen = SDL_CreateWindow(
            "FFmpeg Tutorial",
            SDL_WINDOWPOS_UNDEFINED,
            SDL_WINDOWPOS_UNDEFINED,
            pCodecCtx->width,
            pCodecCtx->height,
            0
        );

    if (!screen) {
        fprintf(stderr, "SDL: could not create window - exiting\n");
        exit(1);
    }

    renderer = SDL_CreateRenderer(screen, -1, 0);
    if (!renderer) {
        fprintf(stderr, "SDL: could not create renderer - exiting\n");
        exit(1);
    }

    // Allocate a place to put our YUV image on that screen
    texture = SDL_CreateTexture(
            renderer,
            SDL_PIXELFORMAT_YV12,
            SDL_TEXTUREACCESS_STREAMING,
            pCodecCtx->width,
            pCodecCtx->height
        );
    if (!texture) {
        fprintf(stderr, "SDL: could not create texture - exiting\n");
        exit(1);
    }

    // initialize SWS context for software scaling
    sws_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
            pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
            AV_PIX_FMT_YUV420P,
            SWS_BILINEAR,
            NULL,
            NULL,
            NULL);

    // set up YV12 pixel array (12 bits per pixel)
    yPlaneSz = pCodecCtx->width * pCodecCtx->height;
    uvPlaneSz = pCodecCtx->width * pCodecCtx->height / 4;
    yPlane = (Uint8*)malloc(yPlaneSz);
    uPlane = (Uint8*)malloc(uvPlaneSz);
    vPlane = (Uint8*)malloc(uvPlaneSz);
    if (!yPlane || !uPlane || !vPlane) {
        fprintf(stderr, "Could not allocate pixel buffers - exiting\n");
        exit(1);
    }

    uvPitch = pCodecCtx->width / 2;
    while (av_read_frame(pFormatCtx, &packet) >= 0) {
        // Is this a packet from the video stream?
        if (packet.stream_index == videoStream) {
            // Decode video frame
            avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);

            // Did we get a video frame?
            if (frameFinished) {
                AVPicture pict;
                pict.data[0] = yPlane;
                pict.data[1] = uPlane;
                pict.data[2] = vPlane;
                pict.linesize[0] = pCodecCtx->width;
                pict.linesize[1] = uvPitch;
                pict.linesize[2] = uvPitch;

                // Convert the image into YUV format that SDL uses
                sws_scale(sws_ctx, (uint8_t const * const *) pFrame->data,
                        pFrame->linesize, 0, pCodecCtx->height, pict.data,
                        pict.linesize);

                SDL_UpdateYUVTexture(
                        texture,
                        NULL,
                        yPlane,
                        pCodecCtx->width,
                        uPlane,
                        uvPitch,
                        vPlane,
                        uvPitch
                    );

                SDL_RenderClear(renderer);
                SDL_RenderCopy(renderer, texture, NULL, NULL);
                SDL_RenderPresent(renderer);

            }
        }

        // Free the packet that was allocated by av_read_frame
        av_free_packet(&packet);
        SDL_PollEvent(&event);
        switch (event.type) {
        case SDL_QUIT:
            SDL_DestroyTexture(texture);
            SDL_DestroyRenderer(renderer);
            SDL_DestroyWindow(screen);
            SDL_Quit();
            exit(0);
            break;
        default:
            break;
        }

    }

    // Free the YUV frame
    av_frame_free(&pFrame);
    free(yPlane);
    free(uPlane);
    free(vPlane);

    // Close the codec
    avcodec_close(pCodecCtx);
    avcodec_close(pCodecCtxOrig);

    // Close the video file
    avformat_close_input(&pFormatCtx);

    return 0;
}

3
你更新了其他教程吗?能分享一下吗?我正在使用SDL 2.0,因为在1.2下载文件中找不到所需的包含文件。对你的努力点一个赞。 - user5000935
#include <stdio.h> #include <windows.h> #include <iostream> extern "C" { #include "libavcodec\avcodec.h" #include "libavformat\avformat.h" #include "libswscale\swscale.h" #include "libswresample\swresample.h" #include "sdl/SDL.h" } #pragma comment(lib, "SDL2.lib") #pragma comment(lib, "SDL2main.lib") #pragma comment(lib, "SDL2test.lib") #pragma comment(lib, "avcodec.lib") #pragma comment(lib, "avdevice.lib") #pragma comment(lib, "avfilter.lib") #pragma comment(lib, "avformat.lib") #pragma comment(lib, "avutil.lib") #pragma comment(lib, "swscale.lib") - Sorry IwontTell

5

尝试使用与解码帧布局和平面相匹配的YUV像素格式使用SDL_CreateTexture()

或者使用libswscaleffmpeg的YUV缓冲区转换为RGB。

编辑:SDL2 >= 2.0.1具有SDL_UpdateYUVTexture(),可更新平面YUV纹理,因此您不必再手动合并libav的缓冲区。


这是一个相当慢的函数,适用于静态纹理。似乎不太适合视频? - Mike Versteeg
在SDL_UpdateTexture(https://wiki.libsdl.org/SDL_UpdateTexture)中,它与您上面链接的内容相关联(我假设这意味着它源自SDL_UpdateTexture)。我对OpenGL还很陌生,但认为写入纹理是最快的方法之一,所以我和您一样感到惊讶。也许SDL的实现本身就很慢?无论如何,这似乎不是问题的正确答案,因为我认为OP想要显示视频。 - Mike Versteeg

2
我也遇到了这个问题。由于我不知道如何在SDL2.0中替换SDL_Overlay,所以我一直使用SDL 1.2。如果你使用的是Mac 10.10,可以使用此补丁http://www.emaculation.com/doku.php/compiling_sheepshaver_basilisk#tidbitspatch < no-CGDirectPaletteRef.patch 然后,在/src/video/x11/SDL_x11sym.h中,将第168和169行替换为以下内容: SDL_X11_SYM(int,_XData32,(Display *dpy,register _Xconst long *data,unsigned len),(dpy,data,len),return) SDL_X11_SYM(void,_XRead32,(Display *dpy,register long *data,long len),(dpy,data,len), return) 这对我有效。

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接