/* -*- 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, duration = 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(); if (image_width > 0) { 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; offset = (1000 * max_num * fps_denom) / fps_num; /* duration = oggplay_get_duration(player); fprintf(stderr, "seek to: %ld duration: %ld\n", frame_pos, (long)duration); */ 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; }