[FFmpeg-devel] [PATCH 7/8] examples: opengl_device

Timothy Gu timothygu99 at gmail.com
Sat Feb 22 23:57:28 CET 2014


On Sat, Feb 22, 2014 at 2:33 PM, Lukasz Marek <lukasz.m.luki at gmail.com> wrote:
> example shows how to setup opengl device using control message API
>
> Signed-off-by: Lukasz Marek <lukasz.m.luki at gmail.com>
> ---
>  .gitignore                   |   1 +
>  doc/examples/Makefile        |   1 +
>  doc/examples/opengl_device.c | 258 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 260 insertions(+)
>  create mode 100644 doc/examples/opengl_device.c
>
> diff --git a/.gitignore b/.gitignore
> index 1e87a8f..47be421 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -42,6 +42,7 @@
>  /doc/examples/filtering_video
>  /doc/examples/metadata
>  /doc/examples/muxing
> +/doc/examples/opengl_device
>  /doc/examples/pc-uninstalled
>  /doc/examples/remuxing
>  /doc/examples/resampling_audio
> diff --git a/doc/examples/Makefile b/doc/examples/Makefile
> index 1553bab..e55081e 100644
> --- a/doc/examples/Makefile
> +++ b/doc/examples/Makefile
> @@ -18,6 +18,7 @@ EXAMPLES=       avio_reading                       \
>                  filtering_audio                    \
>                  metadata                           \
>                  muxing                             \
> +                opengl_device                      \
>                  remuxing                           \
>                  resampling_audio                   \
>                  scaling_video                      \
> diff --git a/doc/examples/opengl_device.c b/doc/examples/opengl_device.c
> new file mode 100644
> index 0000000..bb066d5
> --- /dev/null
> +++ b/doc/examples/opengl_device.c
> @@ -0,0 +1,258 @@
> +

License boilerplate. Examples are usually BSD, but LGPL is OK. See the
other examples.

> +#include <SDL/SDL.h>
> +#include <libavutil/log.h>
> +#include <libavutil/pixdesc.h>
> +#include <libavutil/opt.h>
> +#include <libavformat/avformat.h>
> +#include <libavdevice/avdevice.h>
> +
> +SDL_Surface *g_surface = NULL;
> +
> +
> +static int recreate_sdl_window(int width, int height)
> +{
> +    g_surface = SDL_SetVideoMode(width, height, 32, SDL_OPENGL | SDL_RESIZABLE);
> +    if (!g_surface) {
> +        av_log(NULL, AV_LOG_ERROR, "Unable to set video mode: %s\n", SDL_GetError());
> +        return AVERROR_EXTERNAL;
> +    }
> +    return 0;
> +}
> +
> +static int av_cold create_sdl_window(int width, int height)
> +{
> +    int ret;
> +    if (SDL_Init(SDL_INIT_VIDEO)) {
> +        av_log(NULL, AV_LOG_ERROR, "Unable to initialize SDL: %s\n", SDL_GetError());
> +        return AVERROR_EXTERNAL;
> +    }
> +    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
> +    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
> +    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
> +    SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
> +    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
> +    if ((ret = recreate_sdl_window(width, height)) < 0)
> +        return ret;
> +    SDL_WM_SetCaption("OpenGL example", NULL);
> +    return 0;
> +}
> +
> +static int message_from_device_handler(struct AVFormatContext *s, int type,
> +                                       void *data, size_t data_size)
> +{
> +    switch ((enum AVDevToAppMessageType) type) {
> +    case AV_DEV_TO_APP_CREATE_WINDOW_BUFFER:
> +        if (!g_surface) {
> +            AVDeviceRect rect;
> +            int ret;
> +            if (data)
> +                rect = *(AVDeviceRect *)data;
> +            else {
> +                rect.x = rect.y = 0;
> +                rect.width = 640;
> +                rect.height = 480;
> +            }
> +            if ((ret = create_sdl_window(rect.width, rect.height)) < 0)
> +                return ret;
> +            avdevice_app_to_dev_control_message(s, AV_APP_TO_DEV_WINDOW_SIZE, &rect, sizeof(rect));
> +        }
> +        return 0;
> +    case AV_DEV_TO_APP_DESTROY_WINDOW_BUFFER:
> +        SDL_Quit();
> +        g_surface = NULL;
> +        return 0;
> +    case AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER:
> +        //SDL 1.2 doesn't required it (no such API),
> +        //but you need to make OpenGL context current here.
> +        return 0;
> +    case AV_DEV_TO_APP_DISPLAY_WINDOW_BUFFER:
> +        SDL_GL_SwapBuffers();
> +        return 0;
> +    default:
> +        break;
> +    }
> +    return AVERROR(ENOSYS);
> +}
> +
> +int set_video_configuration(AVFormatContext *oc)
> +{
> +    int ret;
> +    AVDictionary *opts = NULL;
> +    AVDeviceCapabilitiesQuery *query = NULL;
> +    AVDeviceInfoList *devices = NULL;
> +
> +    av_dict_set(&opts, "no_window", "1", 0);
> +    ret = avdevice_capabilities_create(&query, oc, &opts);
> +    av_dict_free(&opts);
> +    if (ret < 0) {
> +        if (ret == AVERROR(ENOSYS))
> +            av_log(oc, AV_LOG_ERROR, "Device doesn't provide this API.\n");
> +        else
> +            av_log(oc, AV_LOG_ERROR, "Error occurred.\n");
> +        return ret;
> +    }
> +
> +    if ((ret = avdevice_list_devices(oc, &devices)) < 0)
> +        goto fail;
> +    if (!devices->nb_devices) {
> +        av_log(oc, AV_LOG_WARNING, "No devices found");
> +        ret = -1;
> +        goto fail;
> +    }
> +    if (devices->default_device < 0)
> +        devices->default_device = 0;
> +
> +    av_log(oc, AV_LOG_INFO, "Using device: %s\n", devices->devices[devices->default_device]->device_description);
> +    av_opt_set(query, "device_name",
> +               devices->devices[devices->default_device]->device_name, 0);
> +    avdevice_free_list_devices(&devices);
> +
> +    /* Try to set wanted configuration and try to apply it.
> +       It is also good practice to query each parameter before setting it to check
> +       if value is valid. */
> +
> +    /* This example use fake frame with size 256x256. Set window and frame size. */
> +    av_opt_set_image_size(query, "window_size", 256, 256, 0);
> +    av_opt_set_image_size(query, "frame_size", 256, 256, 0);
> +    //Set codec to raw video
> +    av_opt_set_int(query, "codec", AV_CODEC_ID_RAWVIDEO, 0);
> +    //60 frames per second, fps is ignored by OpenGL device, but it can be set
> +    av_opt_set_q(query, "fps", (AVRational){60, 1}, 0);
> +    //set RGB24 format: each component is 1 byte long and no alpha
> +    av_opt_set_int(query, "format", AV_PIX_FMT_RGB24, 0);
> +
> +    ret = avdevice_capabilities_apply(query, oc, AVDEVICE_STRATEGY_APPLY_IF_VALID);
> +    if (!ret) {
> +        av_log(oc, AV_LOG_ERROR, "Provided configuration is wrong!\n");
> +        ret = -1;
> +        goto fail;
> +    } else if (ret < 0) {
> +        av_log(oc, AV_LOG_ERROR, "Error occurred\n");
> +        goto fail;
> +    } else
> +        av_log(oc, AV_LOG_INFO, "Configuration accepted!\n");
> +
> +    avdevice_capabilities_free(&query, oc);
> +
> +    return 0;
> +  fail:
> +    avdevice_capabilities_free(&query, oc);
> +    avdevice_free_list_devices(&devices);
> +    return ret;
> +}
> +
> +static int add_fake_stream(AVFormatContext *oc)
> +{
> +    AVStream *stream = avformat_new_stream(oc, NULL);
> +    if (!stream)
> +        return AVERROR(ENOMEM);
> +    stream->codec->codec_id            = AV_CODEC_ID_RAWVIDEO;
> +    stream->codec->width               = 256;
> +    stream->codec->height              = 256;
> +    stream->codec->sample_aspect_ratio = (AVRational) { 1, 1 };
> +    stream->codec->pix_fmt             = AV_PIX_FMT_RGB24;
> +    stream->codec->codec_type          = AVMEDIA_TYPE_VIDEO;
> +    stream->time_base = stream->codec->time_base = (AVRational) { 1, 1 };
> +    return 0;
> +}
> +
> +static AVFrame* prepare_fake_picture()
> +{
> +    static int rot = 128;
> +    static int dir = 1;
> +    int x, y;
> +    AVFrame *frame = av_frame_alloc();
> +    rot += dir;
> +    if (rot > 200)
> +        dir = -1;
> +    else if (rot < 56)
> +        dir = 1;
> +    if (frame) {
> +        frame->width = frame->height = 256;
> +        frame->format = AV_PIX_FMT_RGB24;
> +        if (av_frame_get_buffer(frame, 256) < 0) {
> +            av_frame_unref(frame);
> +            return NULL;
> +        }
> +        for (y = 0; y < 256; y++)
> +             for (x = 0; x < 256; x++) {
> +                 int color = sqrt(FFABS(x - rot) * FFABS(x - rot) + FFABS(y - rot) * FFABS(y - rot));
> +                 color = FFMAX(FFMIN(255, color), 10);
> +                 frame->data[0][y * frame->linesize[0] + x * 3    ] = color;
> +                 frame->data[0][y * frame->linesize[0] + x * 3 + 1] = color / 4;
> +                 frame->data[0][y * frame->linesize[0] + x * 3 + 2] = color / 4;
> +
> +             }
> +    }
> +    return frame;
> +}
> +
> +int main(int argc, char **argv)
> +{
> +    int ret, quit = 0;
> +    AVFormatContext *oc;
> +    AVDeviceRect message_data = { 0 };
> +
> +    //av_log_set_level(AV_LOG_DEBUG);
> +
> +    av_register_all();
> +    avdevice_register_all();
> +
> +    /* allocate the output media context */
> +    ret = avformat_alloc_output_context2(&oc, NULL, "opengl", NULL);
> +    if (ret < 0 || !oc) {
> +        av_log(NULL, AV_LOG_ERROR, "Could not allocate output format context.\n");
> +        return 1;
> +    }
> +
> +    av_format_set_control_message_cb(oc, message_from_device_handler);
> +
> +    if (set_video_configuration(oc) < 0)
> +        return 1;
> +
> +    if (add_fake_stream(oc) < 0)
> +        return 1;
> +
> +    if (avformat_write_header(oc, NULL) < 0)
> +        return 1;
> +
> +    while (!quit) {
> +        SDL_Event event;
> +        SDL_PumpEvents();
> +        while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_ALLEVENTS) > 0) {
> +            switch (event.type) {
> +            case SDL_QUIT:
> +                quit = 1;
> +            case SDL_KEYDOWN:
> +                switch (event.key.keysym.sym) {
> +                case SDLK_ESCAPE:
> +                case SDLK_q:
> +                    quit = 1;
> +                default:
> +                    break;
> +                }
> +                return 0;
> +            case SDL_VIDEORESIZE:
> +                if ((ret = recreate_sdl_window(event.resize.w, event.resize.h)) < 0)
> +                    quit = 1;
> +                message_data.width = g_surface->w;
> +                message_data.height = g_surface->h;
> +                avdevice_app_to_dev_control_message(oc, AV_APP_TO_DEV_WINDOW_SIZE,
> +                                                    &message_data, sizeof(message_data));
> +                break;
> +            default:
> +                break;
> +            }
> +        }
> +        if (av_write_uncoded_frame(oc, 0, prepare_fake_picture()) < 0) {
> +            av_log(NULL, AV_LOG_ERROR, "av_write_uncoded_frame failed.\n");
> +            quit = 1;
> +        }
> +        SDL_Delay(10);
> +    }
> +
> +    av_write_trailer(oc);
> +    avformat_free_context(oc);
> +
> +    return 0;
> +}
> --
> 1.8.3.2
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


More information about the ffmpeg-devel mailing list