0
|
1 #pragma once
|
1802
|
2 #include "OSWindow.h"
|
1262
|
3 #include "Texture.h"
|
0
|
4
|
|
5
|
|
6
|
|
7
|
|
8 #pragma pack(push, 1)
|
|
9
|
|
10
|
|
11
|
|
12 struct _BINK
|
|
13 {
|
|
14 int uWidth;
|
|
15 int uHeight;
|
|
16 };
|
|
17
|
|
18 struct _BINK_1_5_21_0: public _BINK
|
|
19 {
|
|
20 int uNumFrames;
|
|
21 int uCurrentFrame;
|
|
22 int Data1;
|
|
23 int uFrameRate;
|
|
24 int field_18[3];
|
|
25 int uFlags;
|
|
26 };
|
|
27
|
|
28 struct _BINK_3_0_0_0: public _BINK
|
|
29 {
|
|
30 int unk_0;
|
|
31 int unk_1;
|
|
32 int uNumFrames;
|
|
33 int uCurrentFrame;
|
|
34 int _unk2;
|
|
35 int _unk_[10];
|
|
36 };
|
|
37
|
|
38
|
|
39 struct _BINKBUF
|
|
40 {
|
|
41 int uWidth;
|
|
42 int uHeight;
|
|
43 int field_8;
|
|
44 int field_C;
|
|
45 int uBinkDDSurfaceType;
|
|
46 void *pDDrawSurfaceData;
|
|
47 int uDDrawSurfacePitch;
|
|
48 int field_1C;
|
|
49 int field_20;
|
1802
|
50 int target_width;
|
|
51 int target_height;
|
0
|
52 int field_2C;
|
|
53 int field_30;
|
|
54 int field_34;
|
|
55 int field_38;
|
|
56 int field_3C;
|
|
57 int field_40;
|
|
58 int field_44;
|
|
59 struct IDirectDrawSurface *pTargetDDrawSurface;
|
|
60 int field_4C;
|
|
61 int uRectX;
|
|
62 int uRectY;
|
|
63 HWND hWnd;
|
|
64 int field_5C;
|
|
65 float field_60;
|
|
66 float field_64;
|
|
67 int field_68;
|
|
68 int field_6C;
|
|
69 void *pDDrawSurfaceData_;
|
|
70 int field_74;
|
|
71 int field_78;
|
|
72 };
|
|
73 struct _BINKBUF_1_5_21_0: public _BINKBUF
|
|
74 {
|
|
75 int field_7C;
|
|
76 int field_80;
|
|
77 int field_84;
|
|
78 int field_88;
|
|
79 int field_8C;
|
|
80 int field_90;
|
|
81 int field_94;
|
|
82 int field_98;
|
|
83 int field_9C;
|
|
84 int field_A0;
|
|
85 };
|
|
86
|
|
87 struct _BINKBUF_3_0_0_0: public _BINKBUF
|
|
88 {
|
|
89 };
|
|
90 #pragma pack(pop)
|
|
91
|
|
92
|
|
93
|
|
94
|
|
95 #pragma pack(push, 1)
|
|
96 struct MovieHeader
|
|
97 {
|
|
98 char pVideoName[40];
|
|
99 unsigned int uFileOffset;
|
|
100 };
|
|
101 #pragma pack(pop)
|
|
102
|
|
103
|
|
104
|
|
105
|
|
106
|
1458
|
107 void ShowIntroVideo_and_LoadingScreen();
|
0
|
108
|
2134
|
109 extern "C"
|
|
110 {
|
|
111 #include "lib/libavcodec/avcodec.h"
|
|
112 #include "lib/libavformat/avformat.h"
|
|
113 #include "lib/libavutil/avutil.h"
|
|
114 #include "lib/libavutil/imgutils.h"
|
|
115 #include "lib/libswscale/swscale.h"
|
|
116 #include "lib/libswresample/swresample.h"
|
|
117 #include "lib/libavutil/opt.h"
|
|
118 //#include "libavutil/samplefmt.h"
|
|
119 }
|
|
120 #pragma comment(lib, "avcodec.lib")
|
|
121 #pragma comment(lib, "avformat.lib")
|
|
122 #pragma comment(lib, "avutil.lib")
|
|
123 #pragma comment(lib, "swscale.lib")
|
|
124 #pragma comment(lib, "swresample.lib")
|
|
125
|
|
126 #include "lib/OpenAL/al.h"
|
|
127 #include "lib/OpenAL/alc.h"
|
|
128 #pragma comment(lib, "OpenAL32.lib")
|
|
129
|
|
130
|
|
131
|
|
132 template<int MAX_SAMPLES_BUFFERS>
|
|
133 class OpenALSoundProviderGeneric
|
|
134 {
|
|
135 public:
|
|
136 inline OpenALSoundProviderGeneric()
|
|
137 {
|
|
138 this->device = nullptr;
|
|
139 this->context = nullptr;
|
|
140 this->samples_current_buffer = 0;
|
|
141
|
|
142 this->samples_source_id = -1;
|
|
143 for (int i = 0; i < MAX_SAMPLES_BUFFERS; ++i)
|
|
144 samples_buffer_id[i] = -1;
|
|
145 }
|
|
146
|
|
147 inline bool Initialize()
|
|
148 {
|
|
149 auto device_names = alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER);
|
|
150 if (!device_names)
|
|
151 device_names = alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
|
|
152 if (device_names)
|
|
153 {
|
|
154 for (auto device_name = device_names; device_name[0]; device_name += strlen(device_name))
|
|
155 {
|
|
156 continue;
|
|
157 }
|
|
158 }
|
|
159
|
|
160 device = alcOpenDevice(nullptr);
|
|
161 if (!device || CheckError())
|
|
162 return false;
|
|
163
|
|
164 context = alcCreateContext(device, nullptr);
|
|
165 if (!context || CheckError())
|
|
166 return Release(), false;
|
|
167
|
|
168 alcMakeContextCurrent(context);
|
|
169
|
|
170 bool eax2 = alIsExtensionPresent("EAX2.0");
|
|
171 bool eax3 = alIsExtensionPresent("EAX3.0");
|
|
172 bool eax4 = alIsExtensionPresent("EAX4.0");
|
|
173 bool eax5 = alIsExtensionPresent("EAX5.0");
|
|
174
|
|
175 auto vendor = alGetString(AL_VERSION);
|
|
176 auto version = alGetString(AL_VERSION);
|
|
177 auto extensions = alcGetString(device, ALC_EXTENSIONS);
|
|
178
|
|
179 alGenBuffers(MAX_SAMPLES_BUFFERS, samples_buffer_id);
|
|
180 if (CheckError())
|
|
181 return Release(), false;
|
|
182
|
|
183 alGenSources(1, &samples_source_id);
|
|
184 if (CheckError())
|
|
185 return Release(), false;
|
|
186
|
|
187 float sound_pos[] = { 0.0f, 0.0f, 0.0f };
|
|
188 alSourcefv(samples_source_id, AL_POSITION, sound_pos);
|
|
189 alSourcei(samples_source_id, AL_LOOPING, AL_FALSE);
|
|
190
|
|
191 return true;
|
|
192 }
|
|
193
|
|
194 void Release()
|
|
195 {
|
|
196 if (samples_source_id != -1)
|
|
197 {
|
|
198 alDeleteSources(1, &samples_source_id);
|
|
199 samples_source_id = -1;
|
|
200 }
|
|
201
|
|
202 for (int i = 0; i < MAX_SAMPLES_BUFFERS; ++i)
|
|
203 {
|
|
204 if (samples_buffer_id[i] != -1)
|
|
205 alDeleteBuffers(1, &samples_buffer_id[i]);
|
|
206 samples_buffer_id[i] = -1;
|
|
207 }
|
|
208
|
|
209 alcMakeContextCurrent(nullptr);
|
|
210 if (context)
|
|
211 {
|
|
212 alcDestroyContext(context);
|
|
213 context = nullptr;
|
|
214 }
|
|
215 if (device)
|
|
216 {
|
|
217 alcCloseDevice(device);
|
|
218 device = nullptr;
|
|
219 }
|
|
220 }
|
|
221
|
|
222
|
|
223
|
|
224
|
|
225
|
|
226
|
|
227
|
|
228
|
|
229 void PlaySample(int num_channels, int sample_rate, int num_samples, void *samples)
|
|
230 {
|
|
231 //char msg[256];sprintf(msg, "chan %u rate %5u num %5u ptr %p\n", num_channels, sample_rate, num_samples, samples);
|
|
232 //log(msg);
|
|
233 ALenum sound_format;
|
|
234 switch (num_channels)
|
|
235 {
|
|
236 case 1: sound_format = AL_FORMAT_MONO16; break;
|
|
237 case 2: sound_format = AL_FORMAT_STEREO16; break;
|
|
238 default:
|
|
239 if (bool multichannel = alIsExtensionPresent("AL_EXT_MCFORMATS"))
|
|
240 {
|
|
241 switch (num_channels)
|
|
242 {
|
|
243 case 4: sound_format = alGetEnumValue("AL_FORMAT_QUAD16"); break;
|
|
244 case 6: sound_format = alGetEnumValue("AL_FORMAT_51CHN16"); break;
|
|
245 case 7: sound_format = alGetEnumValue("AL_FORMAT_61CHN16"); break;
|
|
246 case 8: sound_format = alGetEnumValue("AL_FORMAT_71CHN16"); break;
|
|
247 }
|
|
248 }
|
|
249 __debugbreak();
|
|
250 }
|
|
251
|
|
252 float listener_pos[] = { 0.0f, 0.0f, 0.0f };
|
|
253 float listener_vel[] = { 0.0f, 0.0f, 0.0f };
|
|
254 float listener_orientation[] = { 0.0f, 0.0f, -1.0f, // direction
|
|
255 0.0f, 1.0f, 0.0f }; // up vector
|
|
256 alListenerfv(AL_POSITION, listener_pos);
|
|
257 alListenerfv(AL_VELOCITY, listener_vel);
|
|
258 alListenerfv(AL_ORIENTATION, listener_orientation);
|
|
259
|
|
260 unsigned int *next_buffer = samples_buffer_id + samples_current_buffer;
|
|
261
|
|
262 alBufferData(*next_buffer, sound_format, samples, num_samples * sizeof(__int16), sample_rate);
|
|
263 CheckError();
|
|
264
|
|
265
|
|
266 int num_processed_buffers;
|
|
267 alGetSourcei(samples_source_id, AL_BUFFERS_PROCESSED, &num_processed_buffers);
|
|
268 while (num_processed_buffers)
|
|
269 {
|
|
270 unsigned int processed_buffers_id[4];
|
|
271 alSourceUnqueueBuffers(samples_source_id, min(4, num_processed_buffers), processed_buffers_id);
|
|
272 CheckError();
|
|
273 alGetSourcei(samples_source_id, AL_BUFFERS_PROCESSED, &num_processed_buffers);
|
|
274 }
|
|
275
|
|
276 int num_queued_buffers;
|
|
277 alGetSourcei(samples_source_id, AL_BUFFERS_QUEUED, &num_queued_buffers);
|
|
278 if (num_queued_buffers >= MAX_SAMPLES_BUFFERS)
|
|
279 {
|
|
280 __debugbreak();
|
|
281 }
|
|
282
|
|
283 alSourceQueueBuffers(samples_source_id, 1, next_buffer);
|
|
284 CheckError();
|
|
285
|
|
286 int status;
|
|
287 alGetSourcei(samples_source_id, AL_SOURCE_STATE, &status);
|
|
288 if (status != AL_PLAYING)
|
|
289 {
|
|
290 alSourcePlay(samples_source_id);
|
|
291 CheckError();
|
|
292 }
|
|
293
|
|
294 if (++samples_current_buffer >= MAX_SAMPLES_BUFFERS)
|
|
295 samples_current_buffer = 0;
|
|
296 }
|
|
297
|
|
298
|
|
299
|
|
300 protected:
|
|
301 ALCdevice *device;
|
|
302 ALCcontext *context;
|
|
303 unsigned int samples_buffer_id[MAX_SAMPLES_BUFFERS];
|
|
304 unsigned int samples_source_id;
|
|
305 int samples_current_buffer;
|
|
306
|
|
307
|
|
308 bool CheckError()
|
|
309 {
|
|
310 ALenum code = alcGetError(device);
|
|
311 if (code != ALC_NO_ERROR)
|
|
312 {
|
|
313 DWORD w;
|
|
314 const char *message = alcGetString(device, code);
|
|
315 WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), message, lstrlenA(message), &w, nullptr);
|
|
316 return true;
|
|
317 }
|
|
318 return false;
|
|
319 }
|
|
320 };
|
|
321 typedef OpenALSoundProviderGeneric<16> OpenALSoundProvider;
|
|
322
|
|
323
|
|
324
|
|
325 void av_logger(void *, int, const char *format, va_list args);
|
|
326
|
|
327
|
|
328
|
|
329 #include <memory>
|
|
330 using std::tr1::shared_ptr;
|
|
331 using std::tr1::make_shared;
|
|
332
|
|
333 class MultimediaFrame
|
|
334 {
|
|
335 public:
|
|
336 typedef shared_ptr<MultimediaFrame> Ptr;
|
|
337 inline MultimediaFrame(AVMediaType type, AVPacket *packet, AVCodecContext *dec_ctx)
|
|
338 {
|
|
339 this->type = type;
|
|
340 this->f = nullptr;
|
|
341 this->p = packet;
|
|
342 this->dec_ctx = dec_ctx;
|
|
343 }
|
|
344 virtual ~MultimediaFrame() { return; }
|
|
345
|
|
346
|
|
347 AVMediaType Type() const { return type; }
|
|
348 AVFrame *GetAVFrame() { return f; }
|
|
349
|
|
350 virtual int Decode() = 0;
|
|
351 virtual void *GetData() = 0;
|
|
352 virtual int GetDataPitch() = 0;
|
|
353
|
|
354
|
|
355 protected:
|
|
356 AVMediaType type;
|
|
357 AVFrame *f;
|
|
358 AVPacket *p;
|
|
359 AVCodecContext *dec_ctx;
|
|
360 };
|
|
361
|
|
362
|
|
363
|
|
364 class MultimediaVideoFrame : public MultimediaFrame
|
|
365 {
|
|
366 public:
|
|
367 inline MultimediaVideoFrame(AVMediaType type, AVPacket *packet, AVCodecContext *dec_ctx, int width, int height) :
|
|
368 MultimediaFrame(type, packet, dec_ctx)
|
|
369 {
|
|
370 this->width = width;
|
|
371 this->height = height;
|
|
372 this->rescaled_data[0] = nullptr;
|
|
373 this->rescaled_linesize[0] = 0;
|
|
374 }
|
|
375 virtual ~MultimediaVideoFrame()
|
|
376 {
|
|
377 av_freep(&rescaled_data);
|
|
378 av_frame_free(&f);
|
|
379 }
|
|
380
|
|
381 int Decode() override
|
|
382 {
|
|
383 f = avcodec_alloc_frame();
|
|
384 avcodec_get_frame_defaults(f);
|
|
385
|
|
386 volatile int done = false;
|
|
387 do
|
|
388 {
|
|
389 int ret;
|
|
390 if ((ret = avcodec_decode_video2(dec_ctx, f, (int *)&done, p)) < 0)
|
|
391 return ret;
|
|
392 } while (!done);
|
|
393 if (Rescale(f, width, height, AV_PIX_FMT_RGB32, rescaled_data, rescaled_linesize))
|
|
394 return 0;
|
|
395 else return -1;
|
|
396 }
|
|
397
|
|
398 virtual void *GetData() { return rescaled_data[0]; }
|
|
399 virtual int GetDataPitch() { return rescaled_linesize[0]; }
|
|
400
|
|
401 protected:
|
|
402 int width;
|
|
403 int height;
|
|
404 uint8_t *rescaled_data[8];
|
|
405 int rescaled_linesize[8];
|
|
406
|
|
407 bool Rescale(AVFrame *frame, int dst_width, int dst_height, AVPixelFormat format, uint8_t **out_data, int *out_linesize)
|
|
408 {
|
|
409 if (av_image_alloc(out_data, out_linesize, dst_width, dst_height, format, 1) < 0)
|
|
410 return false;
|
|
411
|
|
412 SwsContext *converter = sws_getContext(frame->width, frame->height, (AVPixelFormat)frame->format,
|
|
413 dst_width, dst_height, format,
|
|
414 SWS_BICUBIC, nullptr, nullptr, nullptr);
|
|
415 sws_scale(converter, frame->data, frame->linesize, 0, frame->height, out_data, out_linesize);
|
|
416 sws_freeContext(converter);
|
|
417
|
|
418 return true;
|
|
419 }
|
|
420 };
|
|
421
|
|
422
|
|
423
|
|
424 class MultimediaAudioFrame : public MultimediaFrame
|
|
425 {
|
|
426 public:
|
|
427 inline MultimediaAudioFrame(AVMediaType type, AVPacket *packet, AVCodecContext *dec_ctx) :
|
|
428 MultimediaFrame(type, packet, dec_ctx)
|
|
429 {
|
|
430 this->resampled_data = nullptr;
|
|
431 }
|
|
432 virtual ~MultimediaAudioFrame()
|
|
433 {
|
|
434 av_free(resampled_data);
|
|
435 av_frame_free(&f);
|
|
436 }
|
|
437
|
|
438 int Decode() override
|
|
439 {
|
|
440 f = avcodec_alloc_frame();
|
|
441 avcodec_get_frame_defaults(f);
|
|
442
|
|
443 volatile int done = false;
|
|
444 do
|
|
445 {
|
|
446 int ret;
|
|
447 if ((ret = avcodec_decode_audio4(dec_ctx, f, (int *)&done, p)) < 0)
|
|
448 return ret;
|
|
449 } while (!done);
|
|
450 if (Resample(f, f->channel_layout, f->sample_rate,
|
|
451 f->channel_layout, f->sample_rate, AV_SAMPLE_FMT_S16, &resampled_data))
|
|
452 return 0;
|
|
453 else return -1;
|
|
454 }
|
|
455
|
|
456 virtual void *GetData() { return resampled_data; }
|
|
457 virtual int GetDataPitch() { return 2 * f->nb_samples; }
|
|
458
|
|
459 protected:
|
|
460 uint8_t *resampled_data;
|
|
461
|
|
462 bool Resample(AVFrame *frame,
|
|
463 int64_t src_channel_layout, int src_sample_rate,
|
|
464 int64_t dst_channel_layout, int dst_sample_rate, AVSampleFormat dst_format, uint8_t **out_data)
|
|
465 {
|
|
466 SwrContext *converter = swr_alloc();
|
|
467
|
|
468 av_opt_set_int(converter, "in_channel_layout", src_channel_layout, 0);
|
|
469 av_opt_set_int(converter, "in_sample_rate", src_sample_rate, 0);
|
|
470 av_opt_set_sample_fmt(converter, "in_sample_fmt", (AVSampleFormat)frame->format, 0);
|
|
471
|
|
472 av_opt_set_int(converter, "out_channel_layout", dst_channel_layout, 0);
|
|
473 av_opt_set_int(converter, "out_sample_rate", dst_sample_rate, 0);
|
|
474 av_opt_set_sample_fmt(converter, "out_sample_fmt", dst_format, 0);
|
|
475
|
|
476 if (swr_init(converter) < 0)
|
|
477 return false;
|
|
478
|
|
479 int dst_nb_samples;
|
|
480 int max_dst_nb_samples = dst_nb_samples = av_rescale_rnd(frame->nb_samples, dst_sample_rate, src_channel_layout, AV_ROUND_UP);
|
|
481
|
|
482 uint8_t **dst_data;
|
|
483 int dst_linesize;
|
|
484 int dst_nb_channels = av_get_channel_layout_nb_channels(dst_channel_layout);
|
|
485 if (av_samples_alloc_array_and_samples(&dst_data, &dst_linesize, dst_nb_channels, dst_nb_samples, dst_format, 0) < 0)
|
|
486 {
|
|
487 swr_free(&converter);
|
|
488 return false;
|
|
489 }
|
|
490
|
|
491 dst_nb_samples = av_rescale_rnd(swr_get_delay(converter, src_sample_rate) + frame->nb_samples, dst_sample_rate, src_sample_rate, AV_ROUND_UP);
|
|
492 if (dst_nb_samples > max_dst_nb_samples)
|
|
493 {
|
|
494 av_free(dst_data[0]);
|
|
495 if (av_samples_alloc(dst_data, &dst_linesize, dst_nb_channels, dst_nb_samples, dst_format, 1) < 0)
|
|
496 {
|
|
497 swr_free(&converter);
|
|
498 return false;
|
|
499 }
|
|
500 max_dst_nb_samples = dst_nb_samples;
|
|
501 }
|
|
502
|
|
503
|
|
504 if (swr_convert(converter, dst_data, dst_nb_samples, (const uint8_t **)frame->data, frame->nb_samples) < 0)
|
|
505 {
|
|
506 av_free(dst_data[0]);
|
|
507 swr_free(&converter);
|
|
508 return false;
|
|
509 }
|
|
510
|
|
511 *out_data = dst_data[0];
|
|
512 return true;
|
|
513 }
|
|
514 };
|
|
515
|
|
516
|
|
517 template<int NUM_PRECACHED_FRAMES>
|
|
518 class MovieCached
|
|
519 {
|
|
520 public:
|
|
521 bool Stopped() const { return stopped; }
|
|
522
|
|
523 protected:
|
|
524 friend class MultimediaPlayer;
|
|
525 inline MovieCached(OpenALSoundProvider *sound_provider)
|
|
526 {
|
|
527 this->format_ctx = nullptr;
|
|
528 this->sound_provider = sound_provider;
|
|
529 this->stopped = false;
|
|
530
|
|
531 this->video_stream_idx = -1;
|
|
532 this->video_stream = nullptr;
|
|
533 this->video_stream_dec = nullptr;
|
|
534 this->video_stream_dec_ctx = nullptr;
|
|
535
|
|
536 this->audio_stream_idx = -1;
|
|
537 this->audio_stream = nullptr;
|
|
538 this->audio_stream_dec = nullptr;
|
|
539 this->audio_stream_dec_ctx = nullptr;
|
|
540 }
|
|
541
|
|
542 bool Load(const char *video_filename, int width, int height)
|
|
543 {
|
|
544 this->width = width;
|
|
545 this->height = height;
|
|
546
|
|
547 if (avformat_open_input(&format_ctx, video_filename, nullptr, nullptr) >= 0)
|
|
548 {
|
|
549 if (avformat_find_stream_info(format_ctx, nullptr) >= 0)
|
|
550 {
|
|
551 av_dump_format(format_ctx, 0, video_filename, 0);
|
|
552
|
|
553 video_stream_idx = OpenStream(AVMEDIA_TYPE_VIDEO, &video_stream, &video_stream_dec, &video_stream_dec_ctx);
|
|
554 if (video_stream_idx < 0)
|
|
555 return Release(), false;
|
|
556
|
|
557 audio_stream_idx = OpenStream(AVMEDIA_TYPE_AUDIO, &audio_stream, &audio_stream_dec, &audio_stream_dec_ctx);
|
|
558 if (audio_stream_idx < 0)
|
|
559 return Release(), false;
|
|
560
|
|
561 strcpy(movie_name, video_filename);
|
|
562 packet = new AVPacket;
|
|
563 av_init_packet(packet);
|
|
564 return true;
|
|
565 }
|
|
566 }
|
|
567 return Release(), false;
|
|
568 }
|
|
569
|
|
570 bool Release()
|
|
571 {
|
|
572 if (format_ctx)
|
|
573 {
|
|
574 avformat_free_context(format_ctx);
|
|
575 format_ctx = nullptr;
|
|
576 }
|
|
577 if (packet)
|
|
578 {
|
|
579 av_free_packet(packet);
|
|
580 delete packet;
|
|
581 packet = nullptr;
|
|
582 }
|
|
583
|
|
584 if (video_stream_idx >= 0)
|
|
585 {
|
|
586 video_stream_idx = -1;
|
|
587 video_stream = nullptr;
|
|
588 video_stream_dec = nullptr;
|
|
589 avcodec_close(video_stream_dec_ctx);
|
|
590 video_stream_dec_ctx = nullptr;
|
|
591 }
|
|
592
|
|
593 if (audio_stream_idx >= 0)
|
|
594 {
|
|
595 audio_stream_idx = -1;
|
|
596 audio_stream = nullptr;
|
|
597 audio_stream_dec = nullptr;
|
|
598 avcodec_close(audio_stream_dec_ctx);
|
|
599 }
|
|
600 return true;
|
|
601 }
|
|
602
|
|
603
|
|
604 int OpenStream(AVMediaType type, AVStream **out_stream, AVCodec **out_dec, AVCodecContext **out_dec_ctx)
|
|
605 {
|
|
606 int stream_idx = av_find_best_stream(format_ctx, type, -1, -1, nullptr, 0);
|
|
607 if (stream_idx < 0)
|
|
608 return stream_idx;
|
|
609
|
|
610 auto stream = format_ctx->streams[stream_idx];
|
|
611 auto dec_ctx = stream->codec;
|
|
612 auto dec = avcodec_find_decoder(dec_ctx->codec_id);
|
|
613 if (dec)
|
|
614 {
|
|
615 if (avcodec_open2(dec_ctx, dec, nullptr) >= 0)
|
|
616 {
|
|
617 *out_stream = stream;
|
|
618 *out_dec = dec;
|
|
619 *out_dec_ctx = dec_ctx;
|
|
620 return stream_idx;
|
|
621 }
|
|
622 }
|
|
623 return -1;
|
|
624 }
|
|
625
|
|
626
|
|
627 MultimediaFrame::Ptr GetNextFrame()
|
|
628 {
|
|
629 packet->data = nullptr;
|
|
630 packet->size = 0;
|
|
631
|
|
632 volatile int got_frame = false;
|
|
633 do
|
|
634 {
|
|
635 if (av_read_frame(format_ctx, packet) < 0)
|
|
636 {
|
|
637 stopped = true;
|
|
638 return nullptr;
|
|
639 }
|
|
640 } while (packet->stream_index != video_stream_idx &&
|
|
641 packet->stream_index != audio_stream_idx);
|
|
642
|
|
643 if (packet->stream_index == video_stream_idx)
|
|
644 return MultimediaFrame::Ptr(new MultimediaVideoFrame(AVMEDIA_TYPE_VIDEO, packet, video_stream_dec_ctx, width, height));
|
|
645 else if (packet->stream_index == audio_stream_idx)
|
|
646 return MultimediaFrame::Ptr(new MultimediaAudioFrame(AVMEDIA_TYPE_AUDIO, packet, audio_stream_dec_ctx));
|
|
647 return nullptr;
|
|
648 }
|
|
649
|
|
650
|
|
651
|
|
652 char movie_name[256];
|
|
653 int width;
|
|
654 int height;
|
|
655 bool stopped;
|
|
656 AVFormatContext *format_ctx;
|
|
657 //AVFrame *frame;
|
|
658 AVPacket *packet;
|
|
659 //MultimediaFrame *frames[NUM_PRECACHED_FRAMES];
|
|
660 OpenALSoundProvider *sound_provider;
|
|
661
|
|
662 int video_stream_idx;
|
|
663 AVStream *video_stream;
|
|
664 AVCodec *video_stream_dec;
|
|
665 AVCodecContext *video_stream_dec_ctx;
|
|
666
|
|
667 int audio_stream_idx;
|
|
668 AVStream *audio_stream;
|
|
669 AVCodec *audio_stream_dec;
|
|
670 AVCodecContext *audio_stream_dec_ctx;
|
|
671 };
|
|
672 typedef MovieCached<10> Movie;
|
|
673
|
|
674
|
|
675
|
|
676
|
|
677 class MultimediaPlayer
|
|
678 {
|
|
679 public:
|
|
680 inline MultimediaPlayer()
|
|
681 {
|
|
682 }
|
|
683
|
|
684 bool Initialize()
|
|
685 {
|
|
686 if (!libavcodec_initialized)
|
|
687 {
|
|
688 av_log_set_callback(Logger);
|
|
689 avcodec_register_all();
|
|
690 av_register_all();
|
|
691
|
|
692 libavcodec_initialized = true;
|
|
693 }
|
|
694
|
|
695 sound_provider = new OpenALSoundProvider;
|
|
696 sound_provider->Initialize();
|
|
697
|
|
698 return true;
|
|
699 }
|
|
700
|
|
701
|
|
702 Movie *LoadMovie(const char *filename, int width, int height)
|
|
703 {
|
|
704 auto movie = new Movie(sound_provider);
|
|
705 if (movie)
|
|
706 {
|
|
707 if (movie->Load(filename, width, height))
|
|
708 {
|
|
709 current_movie_width = width;
|
|
710 current_movie_height = height;
|
|
711 return current_movie = movie;
|
|
712 }
|
|
713 delete movie;
|
|
714 }
|
|
715 return nullptr;
|
|
716 }
|
|
717
|
|
718
|
|
719 inline char *DoFrame()
|
|
720 {
|
|
721 if (!current_movie)
|
|
722 return nullptr;
|
|
723
|
|
724 while (true)
|
|
725 {
|
|
726 auto frame = current_movie->GetNextFrame();
|
|
727 if (!frame)
|
|
728 return nullptr;
|
|
729
|
|
730 if (frame->Type() == AVMEDIA_TYPE_AUDIO)
|
|
731 {
|
|
732 uint8_t *data;
|
|
733 if (frame->Decode() >= 0)
|
|
734 {
|
|
735 auto f = frame->GetAVFrame();
|
|
736 sound_provider->PlaySample(f->channels, f->sample_rate, f->nb_samples, frame->GetData());
|
|
737 Sleep(20);
|
|
738 continue;
|
|
739 }
|
|
740 }
|
|
741 else if (frame->Type() == AVMEDIA_TYPE_VIDEO)
|
|
742 {
|
|
743 uint8_t *dst_data[4] = { 0 };
|
|
744 int dst_linesize[4] = { 0 };
|
|
745 if (frame->Decode() >= 0)
|
|
746 {
|
|
747 auto image = new char[current_movie_width * current_movie_height * 4];
|
|
748 memcpy(image, frame->GetData(), current_movie_height * frame->GetDataPitch());
|
|
749
|
|
750 return image;
|
|
751 }
|
|
752 }
|
|
753 return nullptr;
|
|
754 }
|
|
755 }
|
|
756
|
|
757
|
|
758
|
|
759 protected:
|
|
760 static void Logger(void *, int, const char *format, va_list args);
|
|
761
|
|
762 OpenALSoundProvider *sound_provider;
|
|
763 Movie *current_movie;
|
|
764 int current_movie_width;
|
|
765 int current_movie_height;
|
|
766
|
|
767 static bool libavcodec_initialized;
|
|
768 };
|
|
769
|
|
770
|
|
771
|
0
|
772
|
|
773
|
|
774
|
|
775 #pragma pack(push, 1)
|
|
776 struct VideoPlayer
|
|
777 {
|
1262
|
778 VideoPlayer();
|
0
|
779 //----- (004BECBD) --------------------------------------------------------
|
|
780 virtual ~VideoPlayer()
|
|
781 {
|
|
782 bStopBeforeSchedule = false;
|
165
|
783 pResetflag = 0;
|
0
|
784 pVideoFrame.Release();
|
|
785 }
|
|
786
|
|
787 void PlayDeathMovie();
|
|
788 unsigned int SmackCheckSurfaceFromat();
|
1802
|
789 void Initialize(OSWindow *window);
|
0
|
790 void Prepare();
|
|
791 void Unload();
|
|
792 void FastForwardToFrame(unsigned int uFrameNum);
|
1802
|
793 void BinkDrawFrame(int a3, int a4);
|
|
794 void BinkUpdatePalette() {}
|
|
795 void SmackDrawFrame(int a3, int a4);
|
|
796 void SmackUpdatePalette();
|
0
|
797 _BINK *OpenBink(const char *pName);
|
|
798 struct _SMACK *OpenSmack(const char *pFilename);
|
898
|
799 void OpenHouseMovie(const char *pMovieName, unsigned int a3_1);//0x4BF28F
|
0
|
800 bool AnyMovieLoaded();
|
898
|
801 void OpenGlobalMovie(const char *pFilename, unsigned int bLoop, int a4);
|
0
|
802 void _4BF5B2();
|
898
|
803 void SelectMovieType();//0x4BF73A
|
1802
|
804 _BINKBUF *CreateBinkBuffer(unsigned int uWidth, unsigned int uHeight, char a4);
|
|
805 void _inlined_in_463149();
|
0
|
806
|
1802
|
807 static void MovieLoop(const char *pMovieName, int a2, int a3, int a4);
|
0
|
808
|
|
809
|
|
810 RGBTexture pVideoFrame;
|
|
811 struct _SMACK *pSmackerMovie;
|
|
812 struct _SMACKBUF *pSmackerBuffer;
|
|
813 char *pSomeSmackerBuffer;
|
|
814 int field_34;
|
|
815 MovieHeader *pMightVideoHeaders;
|
|
816 MovieHeader *pMagicVideoHeaders;
|
165
|
817 int pResetflag;
|
0
|
818 int field_44;
|
|
819 unsigned int uNumMightVideoHeaders;
|
|
820 unsigned int uNumMagicVideoHeaders;
|
|
821 int uBinkDirectDrawSurfaceType;
|
|
822 int field_54;
|
|
823 unsigned int bPlayingMovie;
|
|
824 unsigned int bFirstFrame;
|
|
825 unsigned int bUsingSmackerMMX;
|
|
826 unsigned int bLoopPlaying;
|
|
827 int field_68;
|
|
828 unsigned int bStopBeforeSchedule;
|
1802
|
829 //HWND hWindow;
|
|
830 OSWindow *window;
|
0
|
831 struct _SMACKBLIT *pSmackMovieBlit;
|
|
832 HANDLE hMightVid;
|
|
833 HANDLE hMagicVid;
|
|
834 _BINK *pBinkMovie;
|
|
835 _BINKBUF *pBinkBuffer;
|
|
836 char field_88[20];
|
|
837 unsigned int uMovieFormat;
|
|
838 int dword_0000A0;
|
|
839 char pCurrentMovieName[64];
|
|
840 char pVideoFrameTextureFilename[32];
|
323
|
841 int field_104;
|
0
|
842 };
|
|
843 #pragma pack(pop)
|
|
844
|
|
845
|
|
846
|
|
847
|
|
848
|
|
849 extern VideoPlayer *pVideoPlayer;
|