[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