[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