00001
00002
00003
00004
00005
00006
00007
00008
00009
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00030
00031 #ifdef USE_THEORA
00032
00033
00034
00035
00036
00037 #include <stdlib.h>
00038 #include <stdio.h>
00039 #include <string.h>
00040
00041 #include "stratagus.h"
00042 #include "video.h"
00043 #include "sound.h"
00044 #include "sound_server.h"
00045 #include "movie.h"
00046 #include "network.h"
00047 #include "iocompat.h"
00048 #include "iolib.h"
00049
00050 #include "SDL.h"
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060 extern SDL_Surface *TheScreen;
00061 static bool MovieStop;
00062
00063
00064
00065
00066
00071 static void MovieCallbackButtonPressed(unsigned dummy)
00072 {
00073 MovieStop = true;
00074 }
00075
00076 static void MovieCallbackButtonReleased(unsigned dummy)
00077 {
00078 }
00079
00080 static void MovieCallbackKeyPressed(unsigned dummya, unsigned dummyb)
00081 {
00082 MovieStop = true;
00083 }
00084
00085
00086 static void MovieCallbackKeyReleased(unsigned dummya, unsigned dummyb)
00087 {
00088 }
00089
00090 static void MovieCallbackKeyRepeated(unsigned dummya, unsigned dummyb)
00091 {
00092 }
00093
00094 static void MovieCallbackMouseMove(int dummya, int dummyb)
00095 {
00096 }
00097
00098 static void MovieCallbackMouseExit(void)
00099 {
00100 }
00101
00105 static int OutputTheora(OggData *data, SDL_Overlay *yuv_overlay, SDL_Rect *rect)
00106 {
00107 int i;
00108 yuv_buffer yuv;
00109 int crop_offset;
00110
00111 theora_decode_YUVout(&data->tstate, &yuv);
00112
00113 if (SDL_MUSTLOCK(TheScreen)) {
00114 if (SDL_LockSurface(TheScreen) < 0) {
00115 return - 1;
00116 }
00117 }
00118
00119 if (SDL_LockYUVOverlay(yuv_overlay) < 0) {
00120 return -1;
00121 }
00122
00123 crop_offset = data->tinfo.offset_x + yuv.y_stride * data->tinfo.offset_y;
00124 for (i = 0; i < yuv_overlay->h; ++i) {
00125 memcpy(yuv_overlay->pixels[0] + yuv_overlay->pitches[0] * i,
00126 yuv.y + crop_offset + yuv.y_stride * i, yuv_overlay->w);
00127 }
00128
00129 crop_offset = (data->tinfo.offset_x / 2) + (yuv.uv_stride) *
00130 (data->tinfo.offset_y / 2);
00131 for (i = 0; i < yuv_overlay->h / 2; ++i) {
00132 memcpy(yuv_overlay->pixels[1] + yuv_overlay->pitches[1] * i,
00133 yuv.v + yuv.uv_stride * i, yuv_overlay->w / 2);
00134 memcpy(yuv_overlay->pixels[2] + yuv_overlay->pitches[2] * i,
00135 yuv.u + crop_offset + yuv.uv_stride * i, yuv_overlay->w / 2);
00136 }
00137
00138 if (SDL_MUSTLOCK(TheScreen)) {
00139 SDL_UnlockSurface(TheScreen);
00140 }
00141 SDL_UnlockYUVOverlay(yuv_overlay);
00142
00143 SDL_DisplayYUVOverlay(yuv_overlay, rect);
00144
00145 return 0;
00146 }
00147
00151 static int TheoraProcessData(OggData *data)
00152 {
00153 ogg_packet packet;
00154
00155 while (1) {
00156 if (ogg_stream_packetout(&data->vstream, &packet) != 1) {
00157 if (OggGetNextPage(&data->page, &data->sync, data->File)) {
00158
00159 return -1;
00160 }
00161
00162 ogg_stream_pagein(&data->vstream, &data->page);
00163 } else {
00164 theora_decode_packetin(&data->tstate, &packet);
00165 return 0;
00166 }
00167 }
00168 }
00169
00170
00178 int PlayMovie(const std::string &name)
00179 {
00180 OggData data;
00181 CFile f;
00182 SDL_Rect rect;
00183 SDL_Overlay *yuv_overlay;
00184 CSample *sample;
00185 const EventCallback *old_callbacks;
00186 EventCallback callbacks;
00187 unsigned int start_ticks;
00188 int need_data;
00189 int diff;
00190 char buffer[PATH_MAX];
00191
00192 LibraryFileName(name.c_str(), buffer, sizeof(buffer));
00193
00194 if (f.open(buffer, CL_OPEN_READ) == -1) {
00195 fprintf(stderr, "Can't open file `%s'\n", name.c_str());
00196 return -1;
00197 }
00198
00199 memset(&data, 0, sizeof(data));
00200 if (OggInit(&f, &data) || !data.video) {
00201 OggFree(&data);
00202 f.close();
00203 return -1;
00204 }
00205
00206 data.File = &f;
00207
00208 if (data.tinfo.frame_width * 300 / 4 > data.tinfo.frame_height * 100) {
00209 rect.w = Video.Width;
00210 rect.h = Video.Width * data.tinfo.frame_height / data.tinfo.frame_width;
00211 rect.x = 0;
00212 rect.y = (Video.Height - rect.h) / 2;
00213 } else {
00214 rect.w = Video.Height * data.tinfo.frame_width / data.tinfo.frame_height;
00215 rect.h = Video.Height;
00216 rect.x = (Video.Width - rect.w) / 2;
00217 rect.y = 0;
00218 }
00219
00220 yuv_overlay = SDL_CreateYUVOverlay(data.tinfo.frame_width,
00221 data.tinfo.frame_height, SDL_YV12_OVERLAY, TheScreen);
00222
00223 if (yuv_overlay == NULL) {
00224 fprintf(stderr, "SDL_CreateYUVOverlay: %s\n", SDL_GetError());
00225 OggFree(&data);
00226 f.close();
00227 return 0;
00228 }
00229
00230 StopMusic();
00231 if ((sample = LoadVorbis(buffer, PlayAudioStream))) {
00232 if ((sample->Channels != 1 && sample->Channels != 2) ||
00233 sample->SampleSize != 16) {
00234 fprintf(stderr, "Unsupported sound format in movie\n");
00235 delete sample;
00236 SDL_FreeYUVOverlay(yuv_overlay);
00237 OggFree(&data);
00238 f.close();
00239 return 0;
00240 }
00241 PlayMusic(sample);
00242 }
00243
00244 callbacks.ButtonPressed = MovieCallbackButtonPressed;
00245 callbacks.ButtonReleased = MovieCallbackButtonReleased;
00246 callbacks.MouseMoved = MovieCallbackMouseMove;
00247 callbacks.MouseExit = MovieCallbackMouseExit;
00248 callbacks.KeyPressed = MovieCallbackKeyPressed;
00249 callbacks.KeyReleased = MovieCallbackKeyReleased;
00250 callbacks.KeyRepeated = MovieCallbackKeyRepeated;
00251 callbacks.NetworkEvent = NetworkEvent;
00252
00253 old_callbacks = GetCallbacks();
00254 SetCallbacks(&callbacks);
00255
00256 Invalidate();
00257 RealizeVideoMemory();
00258
00259 MovieStop = false;
00260 start_ticks = SDL_GetTicks();
00261 need_data = 1;
00262 while (!MovieStop) {
00263 if (need_data) {
00264 if (TheoraProcessData(&data)) {
00265 break;
00266 }
00267 need_data = 0;
00268 }
00269
00270 diff = SDL_GetTicks() - start_ticks - static_cast<int>(
00271 theora_granule_time(&data.tstate, data.tstate.granulepos) * 1000);
00272
00273 if (diff > 100) {
00274
00275 need_data = 1;
00276 continue;
00277 }
00278 if (diff > 0) {
00279 OutputTheora(&data, yuv_overlay, &rect);
00280 need_data = 1;
00281 }
00282
00283 WaitEventsOneFrame();
00284 }
00285
00286 StopMusic();
00287 SDL_FreeYUVOverlay(yuv_overlay);
00288
00289 OggFree(&data);
00290 f.close();
00291
00292 SetCallbacks(old_callbacks);
00293
00294 return 0;
00295 }
00296
00297 #else
00298
00299 #include <string>
00300 #include <string.h>
00301
00309 int PlayMovie(const std::string &name)
00310 {
00311 if (strstr(name.c_str(), ".ogg") || strstr(name.c_str(), ".avi")) {
00312 return 0;
00313 }
00314 return -1;
00315 }
00316
00317 #endif
00318