From 77f47b2c311f3b0332855c869ebae065250029bb Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Wed, 21 Apr 2010 17:56:08 +0300 Subject: [PATCH] oxframe based on oggplayer, gst was hanging to often --- .bzrignore | 1 + Makefile | 34 ++++++++ oxframe.c | 242 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 277 insertions(+) create mode 100644 .bzrignore create mode 100644 Makefile create mode 100644 oxframe.c diff --git a/.bzrignore b/.bzrignore new file mode 100644 index 0000000..29d51a9 --- /dev/null +++ b/.bzrignore @@ -0,0 +1 @@ +oxframe diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0da8749 --- /dev/null +++ b/Makefile @@ -0,0 +1,34 @@ +PROG = oxframe +SRC = oxframe.c + +PREFIX ?= /usr/local +BINDIR ?= ${PREFIX}/bin +MAN1DIR ?= ${PREFIX}/man/man1 + +CC ?= gcc +CFLAGS ?= -D_FILE_OFFSET_BITS=64 +CFLAGS += -Wall -ffast-math -fsigned-char + +INSTALL = install + +INCLUDEFLAGS ?= `pkg-config --cflags oggplay` `imlib2-config --cflags` +LINKFLAGS ?= -L${PREFIX}/lib +#LINKFLAGS += `pkg-config --libs oggplay` `imlib2-config --libs` +LINKFLAGS += `imlib2-config --libs` -L/usr/local/lib /usr/local/lib/liboggplay.a -loggz -lfishsound -ltheora -lvorbisenc -lvorbis -lm -logg -lkate -lpthread + + +all: ${PROG} + + + +${PROG}: ${SRC} + ${CC} -Wall -Wno-parentheses -O3 -fforce-addr -fomit-frame-pointer -finline-functions -funroll-loops ${CFLAGS} ${INCLUDEFLAGS} -o ${PROG} $< ${LINKFLAGS} + +install: ${PROG} + ${INSTALL} -c -m 555 -o root -g bin ${PROG} ${BINDIR} + test -d ${MAN1DIR} || ${INSTALL} -d -o root ${MAN1DIR} + ${INSTALL} -c -m 444 -o root -g bin ${MAN} ${MAN1DIR} + +clean: + -@rm -f ${PROG} *~ core *.core + diff --git a/oxframe.c b/oxframe.c new file mode 100644 index 0000000..968ec51 --- /dev/null +++ b/oxframe.c @@ -0,0 +1,242 @@ +/* -*- tab-width:2;c-file-style:"cc-mode"; -*- */ +/* + * oxframe.c -- dump frame from a theora file + * Copyright (C) 20010 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with This program. If not, see . + */ + +#include +#include +#include +#include + +#include + +#include +#include + + +static const char *output = NULL; + +long frame_pos = 0; +int image_width = -1, image_height = -1; + +const char *optstring = "h:x:y:p:i:o:"; +struct option options [] = { + {"help",required_argument,NULL,'h'}, + {"width",required_argument,NULL,'x'}, + {"height",required_argument,NULL,'y'}, + {"pos",required_argument,NULL,'p'}, + {"input",required_argument,NULL,'i'}, + {"output",required_argument,NULL,'o'}, + {NULL,0,NULL,0} + +}; + +static void usage(void){ + fprintf(stderr, + "Usage: oxframe [options]\n\n" + "Options: \n\n" + " -h, --help show this help message and exit\n" + " -x WIDTH, --width=WIDTH\n" + " scale image to given width\n" + " -y HEIGHT, --height=HEIGHT\n" + " scale image to given height\n" + " -p POS, --pos=POS frame position in seconds, float\n" + " -i INPUT, --input=INPUT\n" + " video input\n" + " -o OUTPUT, --output=OUTPUT\n" + " path to save frame to, jpg, png supported\n" + " (defaults to png)\n" + ); + exit(0); +} + +void write_png_file(OggPlayRGBChannels *data) { + + Imlib_Image *frame = NULL, + *image = NULL; + + frame = imlib_create_image_using_data(data->rgb_width, data->rgb_height, + (unsigned int *)data->ptro); + + if (image_width > 0 && image_height < 0) { + image_height = data->rgb_height * image_width / data->rgb_width; + } + if (image_height > 0 && image_width < 0) { + image_width = data->rgb_width * image_height / data->rgb_height; + } + if (image_width > 0) { + image = imlib_create_image(image_width, image_height); + imlib_context_set_image(image); + imlib_blend_image_onto_image(frame, 0, + 0, 0, data->rgb_width, data->rgb_height, + 0, 0, + image_width, image_height); + } else { + imlib_context_set_image(frame); + } + + if (strstr(&(output[strlen(output)-4]), ".jpg") == NULL) + imlib_image_set_format("png"); + else + imlib_image_set_format("jpg"); + imlib_save_image(output); + imlib_free_image_and_decache(); + + imlib_context_set_image(frame); + imlib_free_image_and_decache(); + imlib_context_set_image(image); + imlib_free_image_and_decache(); +} + +void write_frame (OggPlay * player, int track_num, + OggPlayVideoData * video_data) { + + OggPlayYUVChannels from; + OggPlayRGBChannels to; + + from.ptry = video_data->y; + from.ptru = video_data->u; + from.ptrv = video_data->v; + oggplay_get_video_y_size(player, track_num, &(from.y_width), + &(from.y_height)); + oggplay_get_video_uv_size(player, track_num, &(from.uv_width), + &(from.uv_height)); + + /* + printf("size: %dx%d %dx%d\n", from.y_width, from.y_height, from.uv_width, + from.uv_height); + */ + to.ptro = malloc(from.y_width * from.y_height * 4); + to.rgb_width = from.y_width; + to.rgb_height = from.y_height; + + oggplay_yuv2bgra (&from, &to); + + write_png_file(&to); + free(to.ptro); +} + +int dump_frame_callback (OggPlay *player, int num_tracks, + OggPlayCallbackInfo **track_info, void *user) { + + int i; + OggPlayDataHeader ** headers; + OggPlayVideoData * video_data; + OggPlayDataType type; + + for (i = 0; i < num_tracks; i++) { + type = oggplay_callback_info_get_type(track_info[i]); + headers = oggplay_callback_info_get_headers(track_info[i]); + + switch (type) { + case OGGPLAY_INACTIVE: + break; + case OGGPLAY_YUV_VIDEO: + if (oggplay_callback_info_get_required(track_info[i]) < 1) { + fprintf(stderr, "oops\n"); + break; + } + long pt = oggplay_callback_info_get_presentation_time(headers[0]); + //printf("time: %ld\n", pt); + if (pt >= frame_pos) { + video_data = oggplay_callback_info_get_video_data(headers[0]); + write_frame(player, i, video_data); + exit(0); + } + break; + default: + break; + } + } + + return 0; +} + +int main (int argc, char * argv[]) { + + int c,long_option_index; + OggPlay * player; + OggPlayReader * reader = NULL; + int i; + int fps_num = 25; + int fps_denom = 1; + int granuleshift = 6; + long max_num, offset; + + while(1) { + c=getopt_long(argc, argv, optstring, options, &long_option_index); + if(c == EOF) + break; + + switch(c) { + case 'h': + usage(); + break; + case 'x': + image_width = atoi(optarg); + break; + case 'y': + image_height = atoi(optarg); + break; + case 'p': + frame_pos = 1000 * atof(optarg); + break; + case 'i': + reader = oggplay_file_reader_new(optarg); + break; + case 'o': + output = optarg; + break; + } + } + + if(argc < 3) { + usage(); + } + + player = oggplay_open_with_reader(reader); + + if (player == NULL) { + fprintf (stderr, "could not initialise oggplay with this file\n"); + exit (1); + } + + for (i = 0; i < oggplay_get_num_tracks (player); i++) { + if (oggplay_get_track_type (player, i) == OGGZ_CONTENT_THEORA) { + oggplay_set_callback_num_frames (player, i, 1); + oggplay_get_video_fps(player, i, &fps_denom, &fps_num); + } + oggplay_set_track_active(player, i); + } + oggplay_set_data_callback(player, dump_frame_callback, NULL); + + max_num = ((1<< granuleshift) - 1); + offset = 1000* max_num * fps_denom / fps_num; + + //ogg_int64_t duration = oggplay_get_duration(player); + + if(frame_pos - offset > 0) { + if (oggplay_seek(player, frame_pos - offset) == E_OGGPLAY_CANT_SEEK) { + fprintf (stderr, "failed to seeek to %ld\n", frame_pos); + exit (1); + } + } + oggplay_start_decoding(player); + oggplay_close (player); + + return 0; +}