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

Lukasz Marek lukasz.m.luki at gmail.com
Sat Feb 22 23:33:41 CET 2014


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 @@
+
+#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



More information about the ffmpeg-devel mailing list