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