/* XMPS - X MPEG Player System * Copyright (C) 1999 Damien Chavarria * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public Licensse as published by * the Free Software Foundation; either version 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * avi_system.c : avi system plugin. * */ /********************************************************************* * INCLUDES * *********************************************************************/ #include "avi_system.h" /********************************************************************* * VARIABLES * *********************************************************************/ typedef struct { xmps_media_plugin_t *media; avi_t *AVI; unsigned int current_frame; double frame_rate; unsigned int frame_size; unsigned long frequency; unsigned long sample_size; xmps_data_t *video_stream; xmps_data_t *audio_stream; xmps_time_t *time_info; } avi_data_t; /********************************************************************* * FUNCTIONS * *********************************************************************/ /* * get_system_info : MANDATORY * * Used by the plugin_center to get a pointer to the system object. * */ xmps_system_plugin_t *get_system_info(void) { xmps_system_plugin_t *system; system = (xmps_system_plugin_t *) malloc(sizeof(xmps_system_plugin_t)); system->name = "AVI"; system->data = (void *) malloc(sizeof(avi_data_t)); system->open = avi_open; system->get = avi_get; system->set = avi_set; system->read = avi_read; system->seek = avi_seek; system->close = avi_close; ((avi_data_t *) system->data)->AVI = NULL; ((avi_data_t *) system->data)->time_info = (xmps_time_t *) malloc(sizeof(xmps_time_t)); ((avi_data_t *) system->data)->video_stream = (xmps_data_t *) malloc(sizeof(xmps_data_t)); ((avi_data_t *) system->data)->audio_stream = (xmps_data_t *) malloc(sizeof(xmps_data_t)); ((avi_data_t *) system->data)->frame_size = 200000; return system; } /* * plugin functions * */ /* * avi_open : * * - returns 1 if the open is successfull, returns 0 otherwise. */ unsigned int avi_open(xmps_system_plugin_t *system) { if(system == NULL) { return 0; } return 1; } /* * avi_get_info: * * - returns a list of xmps_video_format * corresponding to the available output formats. */ void* avi_get(xmps_system_plugin_t *system, unsigned int flag, void *arg) { avi_data_t *data; if(system == NULL) { return 0; } data = (avi_data_t *) system->data; if(data == NULL) { return 0; } switch(flag) { case XMPS_FLAG_TIME_INFO: if(data->AVI == NULL) { return NULL; } if(data->frame_rate != 0) { data->time_info->current_time = data->current_frame / data->frame_rate; data->time_info->total_time = AVI_video_frames(data->AVI) /data->frame_rate; } else { data->time_info->current_time = 0; data->time_info->total_time = 1; } return data->time_info; break; case XMPS_FLAG_FRAMERATE: return (void *) &data->frame_rate; break; case XMPS_FLAG_VIDEO_BUFFER_SIZE: data->frame_size = AVI_frame_size(data->AVI, data->current_frame); return (void *) &data->frame_size; break; case XMPS_FLAG_OUTPUT_LIST: { GList *list = NULL; if(data->AVI == NULL) { return NULL; } if(AVI_has_video(data->AVI)) { data->video_stream->type = XMPS_DATA_VIDEO_COMP; data->video_stream->id = 1; data->video_stream->video_compression = AVI_video_compressor(data->AVI); data->video_stream->video_info.width = AVI_video_width (data->AVI); data->video_stream->video_info.height = AVI_video_height(data->AVI); data->video_stream->user_data = (void *) &data->AVI->bitmapinfoheader; data->video_stream->plugin_type = XMPS_PLUGIN_SYSTEM; data->video_stream->plugin = system; list = g_list_prepend(list, data->video_stream); } if(AVI_has_audio(data->AVI)) { data->audio_stream->type = XMPS_DATA_AUDIO_COMP; data->audio_stream->id = 2; switch(AVI_audio_format(data->AVI)) { case WAVE_FORMAT_PCM: data->audio_stream->audio_compression = "WAVE"; break; case WAVE_FORMAT_MPEGLAYER3: data->audio_stream->audio_compression = "MPG3"; break; default: data->audio_stream->audio_compression = "NONE"; break; } switch(AVI_audio_bits(data->AVI)) { case 8: data->audio_stream->audio_info.format.type = XMPS_AUDIO_FORMAT_U8; data->audio_stream->audio_info.format.bit_count = 8; break; case 16: default: data->audio_stream->audio_info.format.type = XMPS_AUDIO_FORMAT_S16; data->audio_stream->audio_info.format.bit_count = 16; break; } data->audio_stream->audio_info.sample_size = AVI_sampsize(data->AVI); data->audio_stream->audio_info.frequency = AVI_audio_rate(data->AVI); data->audio_stream->audio_info.channels = AVI_audio_channels(data->AVI); data->audio_stream->plugin_type = XMPS_PLUGIN_SYSTEM; data->audio_stream->plugin = system; list = g_list_prepend(list, data->audio_stream); } return (void *) list; } break; default: break; } return NULL; } /* avi_set : * * - update video surface when it changed, * performs loop/unloop change. */ unsigned int avi_set(xmps_system_plugin_t *system, unsigned int flag, void *arg) { avi_data_t *data; if(system == NULL) { return 0; } data = (avi_data_t *) system->data; if(data == NULL) { return 0; } switch(flag) { case XMPS_FLAG_INPUT: { xmps_data_t *data_stream; data_stream = (xmps_data_t *) arg; if(data_stream != NULL && data_stream->type == XMPS_DATA_RAW && data_stream->plugin_type == XMPS_PLUGIN_MEDIA) { XMPS_DEBUG("we try to read from %s media", ((xmps_media_plugin_t *) data_stream->plugin)->name); if(data->AVI != NULL) { XMPS_DEBUG("already opened"); return 0; } data->media = (xmps_media_plugin_t *) data_stream->plugin; if(data->media == NULL) { XMPS_DEBUG("open : NULL media"); return 0; } data->AVI = AVI_open_input(data->media, 1); if(data->AVI == NULL) { XMPS_DEBUG(AVI_strerror()); return 0; } data->current_frame = 0; data->frame_rate = AVI_frame_rate(data->AVI); /* * this fixes sync on * some bad-codec AVIs */ if(data->frame_rate == 23) data->frame_rate = 24; XMPS_DEBUG("AVI : frame rate = %f", data->frame_rate); XMPS_DEBUG("AVI : FOURCC code = %c%c%c%c = %d", (char) (data->AVI->bitmapinfoheader.biCompression) & 0xFF, (char) (data->AVI->bitmapinfoheader.biCompression >> 8) & 0xFF, (char) (data->AVI->bitmapinfoheader.biCompression >> 16) & 0xFF, (char) (data->AVI->bitmapinfoheader.biCompression >> 24) & 0xFF, (int) data->AVI->bitmapinfoheader.biCompression); return 1; } return 0; } break; default: break; } return 0; } /* * avi_read : * * - only needed for audio stream * */ int avi_read(xmps_system_plugin_t *system, unsigned int stream_id, void *buffer, long size) { avi_data_t *data; if(system == NULL) { return 0; } data = (avi_data_t *) system->data; if(data == NULL) { return 0; } switch(stream_id) { case 1: if(data->current_frame >= AVI_video_frames(data->AVI) - 1) { return -1; } data->frame_size = AVI_read_frame(data->AVI, (char *) buffer); data->current_frame++; return data->frame_size; break; case 2: return AVI_read_audio(data->AVI, buffer, size); break; } return 1; } /* * avi_seek : * * - performs seeking. * restart playback if needed. */ unsigned int avi_seek(xmps_system_plugin_t *system, unsigned int stream_id, unsigned int pos, xmps_seeking_method_t method) { long frame; double ratio; long audio_bytes; avi_data_t *data; if(system == NULL) { return 0; } data = (avi_data_t *) system->data; if(data == NULL) { return 0; } if(data->AVI == NULL) { return 0; } XMPS_DEBUG("seeking"); switch(method) { case XMPS_SEEK_PERCENT: /* * compute the desired * frame number * */ frame = (long) (pos * AVI_video_frames(data->AVI) / 100); /* * and go to the next * keyframe. * */ while(!AVI_is_keyframe(data->AVI, frame)) { frame++; } /* * now set video * position. * */ XMPS_DEBUG("seeking to frame %d", (int) frame); AVI_set_video_position(data->AVI, frame); data->current_frame = frame; /* * calculate what ratio * it corresponds to * */ if(AVI_has_audio(data->AVI)) { ratio = (double) ((double) frame / (double) AVI_video_frames(data->AVI)); XMPS_DEBUG("audio ratio is %f", ratio); /* * and set audio * position * */ audio_bytes = (long) (ratio * AVI_audio_bytes(data->AVI)); audio_bytes += (audio_bytes % 4); AVI_set_audio_position(data->AVI, audio_bytes); return 1; } break; default: break; } return 1; } /* * avi_close : * * - performs cleanup; * */ unsigned int avi_close(xmps_system_plugin_t *system) { avi_data_t *data; if(system == NULL) { return 0; } data = (avi_data_t *) system->data; if(data == NULL) { return 0; } if(data->AVI == NULL) { return 0; } XMPS_DEBUG("avi closing"); AVI_close(data->AVI); data->AVI = NULL; return 1; }