oxframe based on oggplayer, gst was hanging to often
This commit is contained in:
commit
77f47b2c31
3 changed files with 277 additions and 0 deletions
1
.bzrignore
Normal file
1
.bzrignore
Normal file
|
@ -0,0 +1 @@
|
||||||
|
oxframe
|
34
Makefile
Normal file
34
Makefile
Normal file
|
@ -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
|
||||||
|
|
242
oxframe.c
Normal file
242
oxframe.c
Normal file
|
@ -0,0 +1,242 @@
|
||||||
|
/* -*- tab-width:2;c-file-style:"cc-mode"; -*- */
|
||||||
|
/*
|
||||||
|
* oxframe.c -- dump frame from a theora file
|
||||||
|
* Copyright (C) 20010 <j@mailb.org>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <oggplay/oggplay.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <Imlib2.h>
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
Loading…
Reference in a new issue