Mercurial > mm7
annotate Media/MediaPlayer.cpp @ 2575:a76d408c5132 tip
DrawTranslucent -> DrawTextureGrayShade
Removed old texture drawing stuff
author | a.parshin |
---|---|
date | Wed, 09 Mar 2016 01:39:52 +0200 |
parents | 0c67be4ec900 |
children |
rev | line source |
---|---|
2502 | 1 #define _CRTDBG_MAP_ALLOC |
2567 | 2 #define _CRT_SECURE_NO_WARNINGS |
2502 | 3 #include <stdlib.h> |
4 #include <crtdbg.h> | |
5 #include <vector> | |
6 #include <deque> | |
7 | |
2541 | 8 #include "Engine/Engine.h" |
2572
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
9 #include "Engine/AssetsManager.h" |
2502 | 10 |
11 #include "IO/Mouse.h" | |
12 #include "GUI/GUIWindow.h" | |
13 #include "Media/Audio/OpenALSoundProvider.h" | |
14 #include "MediaPlayer.h" | |
15 #include "Media/Video/Bink_Smacker.h" | |
16 #include "Media/Audio/AudioPlayer.h" | |
17 #include "Engine/Timer.h" | |
18 #include "Engine/Graphics/Render.h" | |
2508 | 19 #include "Engine/MMT.h" |
2502 | 20 |
2541 | 21 #include "Game/MainMenu.h" |
22 | |
2502 | 23 |
24 #pragma comment(lib, "Version.lib") | |
25 | |
2541 | 26 |
2502 | 27 using namespace Media; |
28 | |
29 Media::MPlayer *pMediaPlayer = nullptr; | |
30 Media::IMovie *pMovie_Track; | |
31 Media::ITrack *pAudio_Track; | |
32 Movie *movie; | |
33 | |
34 int mSourceID; | |
35 | |
36 void PlayMovie(const wchar_t * pFilename); | |
37 void PlayAudio(const wchar_t * pFilename); | |
38 void LoadMovie(const char *); | |
39 | |
40 class MemoryStream | |
41 { | |
42 public: | |
43 inline MemoryStream(void *data, size_t data_size) | |
44 { | |
45 this->data_size = data_size; | |
46 this->data = data; | |
47 this->current_pos = 0; | |
48 } | |
49 inline MemoryStream() | |
50 { | |
51 this->data_size = 0; | |
52 this->data = nullptr; | |
53 this->current_pos = 0; | |
54 } | |
55 | |
56 inline ~MemoryStream() | |
57 { | |
58 //Log::Warning(L"Destructor: data delete %u", data); | |
59 if (data) | |
60 delete [] data; | |
61 } | |
62 | |
63 inline size_t Write(void *buffer, size_t num_bytes) | |
64 { | |
65 if (!data) | |
66 { | |
67 data_size = 32 + num_bytes; | |
68 data = new char[data_size]; | |
69 //Log::Warning(L"new data %u", data); | |
70 current_pos = 0; | |
71 } | |
72 else if (current_pos + num_bytes >= data_size) | |
73 { | |
74 int new_data_size = data_size + num_bytes + data_size / 8 + 4; | |
75 auto new_data = new char[new_data_size]; | |
76 //Log::Warning(L"new new_data %u", new_data); | |
77 | |
78 memcpy(new_data, data, data_size); | |
79 //Log::Warning(L"data delete %u", data); | |
80 delete [] data; | |
81 | |
82 data_size = new_data_size; | |
83 data = new_data; | |
84 } | |
85 memcpy((char *)data + current_pos, buffer, num_bytes); | |
86 current_pos += num_bytes; | |
87 return num_bytes; | |
88 } | |
89 | |
90 inline size_t Read(void *buffer, size_t num_bytes) | |
91 { | |
92 size_t read_size = min(num_bytes, data_size - current_pos); | |
93 if (read_size) | |
94 { | |
95 memcpy(buffer, (char *)data + current_pos, read_size); | |
96 current_pos += read_size; | |
97 } | |
98 return read_size; | |
99 } | |
100 | |
101 inline void Reset() | |
102 { | |
103 current_pos = 0; | |
104 } | |
105 inline void SeekToEnd() | |
106 { | |
107 current_pos = data_size; | |
108 } | |
109 | |
110 inline size_t Unwind(size_t bytes) | |
111 { | |
112 if (bytes > current_pos) | |
113 current_pos = 0; | |
114 else | |
115 current_pos -= bytes; | |
116 return current_pos; | |
117 } | |
118 | |
119 inline size_t Rewind(size_t bytes) | |
120 { | |
121 if (current_pos + bytes >= data_size) | |
122 current_pos = data_size; | |
123 else | |
124 current_pos += bytes; | |
125 return current_pos; | |
126 } | |
127 | |
128 inline size_t Size() const {return data_size;} | |
129 inline size_t Current() const {return current_pos;} | |
130 inline void *Ptr() const {return data;} | |
131 | |
132 private: | |
133 void *data; | |
134 size_t data_size; | |
135 size_t current_pos; | |
136 }; | |
137 | |
138 OpenALSoundProvider *provider = nullptr; | |
139 | |
140 static int av_num_bytes_per_sample(AVSampleFormat sample_fmt) | |
141 { | |
142 switch (sample_fmt) | |
143 { | |
144 case AV_SAMPLE_FMT_U8: | |
145 case AV_SAMPLE_FMT_U8P: | |
146 return 1; | |
147 | |
148 case AV_SAMPLE_FMT_S16: | |
149 case AV_SAMPLE_FMT_S16P: | |
150 return 2; | |
151 | |
152 case AV_SAMPLE_FMT_S32: | |
153 case AV_SAMPLE_FMT_S32P: | |
154 case AV_SAMPLE_FMT_FLT: | |
155 case AV_SAMPLE_FMT_FLTP: | |
156 return 4; | |
157 | |
158 case AV_SAMPLE_FMT_DBL: | |
159 case AV_SAMPLE_FMT_DBLP: | |
160 return 8; | |
161 | |
162 default: | |
163 case AV_SAMPLE_FMT_NONE: | |
164 Error("Invalid av sample format: %u", sample_fmt); | |
165 } | |
166 return 0; | |
167 } | |
168 | |
169 struct AVStreamWrapper | |
170 { | |
171 inline AVStreamWrapper() | |
172 { | |
173 this->type = AVMEDIA_TYPE_UNKNOWN; | |
174 this->stream_idx = -1; | |
175 this->stream = nullptr; | |
176 this->dec = nullptr; | |
177 this->dec_ctx = nullptr; | |
178 } | |
179 | |
180 inline void Release() | |
181 { | |
182 type = AVMEDIA_TYPE_UNKNOWN; | |
183 stream_idx = -1; | |
184 stream = nullptr; | |
185 dec = nullptr; | |
186 if (dec_ctx) | |
187 { | |
188 // Close the codec | |
189 avcodec_close(dec_ctx); | |
190 Log::Warning(L"close decoder context file\n"); | |
191 dec_ctx = nullptr; | |
192 } | |
193 } | |
194 | |
195 AVMediaType type; | |
196 int stream_idx; | |
197 AVStream *stream; | |
198 AVCodec *dec; | |
199 AVCodecContext *dec_ctx; | |
200 }; | |
201 | |
202 struct AVAudioStream: public AVStreamWrapper | |
203 { | |
204 inline AVAudioStream():AVStreamWrapper() | |
205 { | |
206 this->bytes_per_sample = 0; | |
207 this->bytes_per_second = 0; | |
208 } | |
209 | |
210 int bytes_per_sample; | |
211 int bytes_per_second; | |
212 }; | |
213 | |
214 struct AVVideoStream: public AVStreamWrapper | |
215 { | |
216 inline AVVideoStream(): AVStreamWrapper() | |
217 { | |
218 this->frames_per_second = 0.0; | |
219 } | |
220 | |
221 double frames_per_second; | |
222 }; | |
223 | |
224 static bool av_open_stream(AVFormatContext *format_ctx, AVMediaType type, AVStreamWrapper *out_stream) | |
225 { | |
226 int stream_idx = av_find_best_stream(format_ctx, type, -1, -1, nullptr, 0); | |
227 if (stream_idx >= 0) | |
228 { | |
229 auto stream = format_ctx->streams[stream_idx]; | |
230 auto dec_ctx = stream->codec; | |
231 | |
232 // Find the decoder for the video stream | |
233 auto dec = avcodec_find_decoder(dec_ctx->codec_id); | |
234 if (dec) | |
235 { | |
236 // Open codec | |
237 if (avcodec_open2(dec_ctx, dec, nullptr) >= 0) | |
238 { | |
239 out_stream->type = type; | |
240 out_stream->stream_idx = stream_idx; | |
241 out_stream->stream = stream; | |
242 out_stream->dec = dec; | |
243 out_stream->dec_ctx = dec_ctx; | |
244 return true; | |
245 } | |
246 fprintf(stderr, "ffmpeg: Could not open codec\n"); | |
247 return false; | |
248 } | |
249 fprintf(stderr, "ffmpeg: Unable to open codec\n"); | |
250 return false; | |
251 } | |
252 fprintf(stderr, "ffmpeg: Didn't find a stream\n"); | |
253 return false; | |
254 } | |
255 | |
256 static bool av_open_audio_stream(AVFormatContext *format_ctx, AVAudioStream *out_stream) | |
257 { | |
2504 | 258 if (av_open_stream(format_ctx, AVMEDIA_TYPE_AUDIO, out_stream)) |
259 //return Error("Audio stream not found"), false; | |
2502 | 260 |
261 // we support only 2-channel audio for now | |
262 //if (out_stream->dec_ctx->channels != 2) | |
263 //{ | |
264 // out_stream->Release(); | |
265 // return Error("Unsupported number of channels: %u", out_stream->dec_ctx->channels), false; | |
266 //} | |
2504 | 267 { |
2502 | 268 out_stream->bytes_per_sample = av_num_bytes_per_sample(out_stream->dec_ctx->sample_fmt); |
269 out_stream->bytes_per_second = out_stream->dec_ctx->channels * out_stream->dec_ctx->sample_rate * out_stream->bytes_per_sample; | |
2504 | 270 } |
2502 | 271 return true; |
272 } | |
273 | |
274 static bool av_open_video_stream(AVFormatContext *format_ctx, AVVideoStream *out_stream) | |
275 { | |
276 if (!av_open_stream(format_ctx, AVMEDIA_TYPE_VIDEO, out_stream)) | |
2524 | 277 { |
278 Error("Video stream not found"); | |
279 false; | |
280 } | |
2502 | 281 |
282 out_stream->frames_per_second = (double)out_stream->dec_ctx->time_base.den / (double)out_stream->dec_ctx->time_base.num; | |
283 return true; | |
284 } | |
285 | |
286 void InterleaveAudioData(MemoryStream *stream, AVSampleFormat src_format, int num_channels, int num_samples, uint8_t **channels) | |
287 { | |
288 unsigned int bytes_per_sample; | |
289 switch (src_format) | |
290 { | |
291 case AV_SAMPLE_FMT_U8: | |
292 case AV_SAMPLE_FMT_U8P: | |
293 __debugbreak(); | |
294 | |
295 case AV_SAMPLE_FMT_S16: | |
296 bytes_per_sample = sizeof(__int16); | |
297 stream->Write(channels[0], num_channels * num_samples * bytes_per_sample); | |
298 break; | |
299 | |
300 case AV_SAMPLE_FMT_S16P: | |
301 { | |
302 bytes_per_sample = sizeof(__int16); | |
303 for (int i = 0; i < num_samples; ++i) | |
304 for (int j = 0; j < num_channels; ++j) | |
305 stream->Write(channels[j] + i * bytes_per_sample, bytes_per_sample); | |
306 } | |
307 break; | |
308 | |
309 case AV_SAMPLE_FMT_FLT: | |
310 { | |
311 SwrContext *converter = swr_alloc(); | |
312 av_opt_set_int(converter, "in_channel_layout", av_get_default_channel_layout(2), 0); | |
313 //av_opt_set_int(converter, "in_sample_rate", sample_ra, 0); | |
314 av_opt_set_sample_fmt(converter, "in_sample_fmt", AV_SAMPLE_FMT_FLT, 0); | |
315 | |
316 av_opt_set_int(converter, "out_channel_layout", av_get_default_channel_layout(2), 0); | |
317 //av_opt_set_int(converter, "out_sample_rate", dst_sample_rate, 0); | |
318 av_opt_set_sample_fmt(converter, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); | |
319 | |
320 if (swr_init(converter) < 0) | |
321 { | |
2540 | 322 Log::Warning(L"swr_init: failed"); |
323 //__debugbreak(); | |
2502 | 324 swr_free(&converter); |
325 return; | |
326 } | |
327 | |
328 uint8_t **dst_channels; | |
329 int dst_linesize[8]; | |
330 //int dst_nb_channels = av_get_channel_layout_nb_channels(dst_channel_layout); | |
331 if (av_samples_alloc_array_and_samples(&dst_channels, dst_linesize, 2, num_channels * num_samples, AV_SAMPLE_FMT_S16, 0) < 0) | |
332 { | |
2540 | 333 Log::Warning(L"av_samples_alloc_array_and_samples: failed"); |
334 //__debugbreak(); | |
2502 | 335 swr_free(&converter); |
336 return; | |
337 } | |
338 | |
339 if (swr_convert(converter, dst_channels, num_channels * num_samples, (const uint8_t **)channels, num_channels * num_samples) >= 0) //Invalid partial memory access, Uninitialized memory access | |
340 | |
2540 | 341 stream->Write(dst_channels[0], num_channels * num_samples * sizeof(__int16)); |
2502 | 342 else |
2540 | 343 //__debugbreak(); |
344 Log::Warning(L"swr_convert: failed"); | |
2502 | 345 |
346 av_free(dst_channels[0]); | |
347 swr_free(&converter); | |
348 } | |
349 break; | |
350 | |
351 default: | |
352 __debugbreak(); | |
353 //if (Resample(next_frame->avframe, next_frame->avframe->channel_layout, next_frame->avframe->sample_rate, | |
354 // av_get_default_channel_layout(2), next_frame->avframe->sample_rate, AV_SAMPLE_FMT_S16P, resampled_data)) | |
355 } | |
356 } | |
357 | |
358 const uint16_t ff_wma_critical_freqs[25] = { | |
359 100, 200, 300, 400, 510, 630, 770, 920, | |
360 1080, 1270, 1480, 1720, 2000, 2320, 2700, 3150, | |
361 3700, 4400, 5300, 6400, 7700, 9500, 12000, 15500, | |
362 24500, | |
363 }; | |
364 extern const uint16_t ff_wma_critical_freqs[25]; | |
365 static float quant_table[96]; | |
366 | |
367 bool DecodeAudioFrame(AVCodecContext *dec_ctx, AVPacket *avpacket, AVFrame *avframe, MemoryStream *out_audio_data, int *out_num_audio_samples) | |
368 { | |
369 volatile int decoded = false; | |
370 do | |
371 { | |
372 if (avcodec_decode_audio4(dec_ctx, avframe, (int *)&decoded, avpacket) < 0) //Uninitialized portail memory access | |
373 { | |
374 log("Cannot decode audio frame\n"); | |
375 return false; | |
376 } | |
377 | |
378 if (!decoded) | |
2508 | 379 { |
2502 | 380 log("Cannot decode audio frame in one piece\n"); |
2508 | 381 break; |
382 } | |
383 | |
2502 | 384 } while (!decoded); |
385 | |
386 switch (dec_ctx->codec_id) | |
387 { | |
388 case AV_CODEC_ID_BINKAUDIO_DCT: | |
389 { | |
390 __debugbreak(); | |
391 } | |
392 case AV_CODEC_ID_BINKAUDIO_RDFT: | |
393 {//pts samples dpts | |
394 // 0 960 | |
395 //17280 960 17280 18x960 | |
396 //18240 960 960 1x960 | |
397 //20160 960 1920 2x960 | |
398 //21120 960 960 1x960 | |
399 //23040 960 1920 2x960 | |
400 /*static int bink_next_pts = 0; | |
401 | |
402 // there's a gap in the sound - fill empty samples in | |
403 if (bink_next_pts < avpacket->pts) | |
404 { | |
405 short silence[1024]; | |
406 memset(silence, 0, sizeof(silence)); | |
407 | |
408 int samples_to_fill = /*dec_ctx->channels * (avpacket->pts - bink_next_pts); | |
409 while (samples_to_fill > 0) | |
410 { | |
411 int samples_to_fill_this_step = samples_to_fill >= 1024 ? 1024 : samples_to_fill; | |
412 out_audio_data->Write(silence, samples_to_fill_this_step * sizeof(short)); | |
413 | |
414 samples_to_fill -= samples_to_fill_this_step; | |
415 } | |
416 } | |
417 | |
418 bink_next_pts = avpacket->pts + /*dec_ctx->channels * avframe->nb_samples; */ | |
419 | |
420 AVFrame frame; | |
421 int first; | |
422 int version_b; | |
423 int frame_len; | |
424 int overlap_len; | |
425 int block_size; | |
426 int num_bands; | |
427 unsigned int *bands; | |
428 float root; | |
429 int sample_rate = dec_ctx->sample_rate; | |
430 int sample_rate_half; | |
431 int i; | |
432 int frame_len_bits; | |
433 int channels; | |
434 | |
435 //compresses audio in chunks of varying sizes depending on sample rate: | |
436 // if sample rate < 22050, frame size is 2048 samples | |
437 // if sample rate < 44100, frame size is 4096 samples | |
438 // else, frame size is 8192 samples | |
439 | |
440 | |
441 /* determine frame length */ | |
442 if (dec_ctx->sample_rate < 22050) | |
443 frame_len_bits = 9; | |
444 else if (dec_ctx->sample_rate < 44100) | |
445 frame_len_bits = 10; | |
446 else | |
447 frame_len_bits = 11; | |
448 | |
449 if (dec_ctx->channels < 1 || dec_ctx->channels > 2) | |
450 { | |
451 av_log(dec_ctx, AV_LOG_ERROR, "invalid number of channels: %d\n", dec_ctx->channels); | |
452 return AVERROR_INVALIDDATA; | |
453 } | |
454 | |
455 version_b = dec_ctx->extradata_size >= 4 && dec_ctx->extradata[3] == 'b'; | |
456 if (version_b) | |
457 __debugbreak(); | |
458 | |
459 if (dec_ctx->codec->id == AV_CODEC_ID_BINKAUDIO_RDFT) | |
460 { | |
461 // audio is already interleaved for the RDFT format variant | |
462 dec_ctx->sample_fmt = AV_SAMPLE_FMT_FLT; | |
463 sample_rate *= dec_ctx->channels; | |
464 channels = 1; | |
465 if (!version_b) | |
466 frame_len_bits += av_log2(dec_ctx->channels); | |
467 } | |
468 else | |
469 { | |
470 channels = dec_ctx->channels; | |
471 dec_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP; | |
472 } | |
473 | |
474 frame_len = 1 << frame_len_bits; //2048 | |
475 | |
476 //a frame is windowed with the previous frame; the size of the window is frame size / 16 | |
477 overlap_len = frame_len / 16; //128 | |
478 block_size = (frame_len - overlap_len) * channels; //1920 | |
479 | |
480 //compute half the sample rate as (sample rate + 1) / 2; | |
481 //initialize an array of band frequencies corresponding to an array of 25 critical frequencies (same as WMA, apparently), | |
482 // any for which the critical frequencies are less than half the sample rate | |
483 | |
484 sample_rate_half = (sample_rate + 1) / 2; //22050 | |
485 if (dec_ctx->codec->id == AV_CODEC_ID_BINKAUDIO_RDFT) | |
486 root = 2.0 / (sqrt(float(frame_len)) * 32768.0); | |
487 else | |
488 root = frame_len / (sqrt(float(frame_len)) * 32768.0); | |
489 for (i = 0; i < 96; i++) | |
490 { | |
491 /* constant is result of 0.066399999/log10(M_E) */ | |
492 quant_table[i] = expf(i * 0.15289164787221953823f) * root; | |
493 } | |
494 | |
495 /* calculate number of bands */ | |
496 //bands calculation: | |
497 //bands[0] = 1; | |
498 //foreach (i in 1..# of bands-1): | |
499 //bands[i] = crit_freq[i-1] * (frame length / 2) / (sample rate / 2); | |
500 //bands[# of bands] = frame length / 2 | |
501 for (num_bands = 1; num_bands < 25; num_bands++) | |
502 if (sample_rate_half <= ff_wma_critical_freqs[num_bands - 1]) | |
503 break; | |
504 | |
505 bands = (unsigned int *)(av_malloc((num_bands + 1) * sizeof(*bands))); | |
506 if (!bands) | |
507 return AVERROR(ENOMEM); | |
508 | |
509 /* populate bands data */ | |
510 bands[0] = 2; | |
511 for (i = 1; i < num_bands; i++) | |
512 bands[i] = (ff_wma_critical_freqs[i - 1] * frame_len / sample_rate_half) & ~1; | |
513 bands[num_bands] = frame_len; | |
514 | |
515 first = 1; | |
516 | |
517 //ff_rdft_init(&trans.rdft, frame_len_bits, DFT_C2R); | |
518 | |
519 avcodec_get_frame_defaults(&frame); | |
520 dec_ctx->coded_frame = &frame; | |
521 } | |
522 break; | |
523 /* | |
524 case AV_CODEC_ID_SMACKAUDIO: | |
525 { | |
526 static int smack_debug_next_audio_time = 0; | |
527 if (smack_debug_next_audio_time != packet->pts) | |
528 { | |
529 Error("There's a gap in the sound before frame %u\n", num_audio_frames); | |
530 __debugbreak(); // there's a gap in the sound | |
531 } | |
532 | |
533 int num_actual_data_channels = 0; | |
534 switch (dec_ctx->sample_fmt) | |
535 { | |
536 case AV_SAMPLE_FMT_U8: | |
537 case AV_SAMPLE_FMT_S16: | |
538 case AV_SAMPLE_FMT_S32: | |
539 case AV_SAMPLE_FMT_FLT: | |
540 case AV_SAMPLE_FMT_DBL: | |
541 num_actual_data_channels = 1; | |
542 break; | |
543 | |
544 case AV_SAMPLE_FMT_U8P: | |
545 case AV_SAMPLE_FMT_S16P: | |
546 case AV_SAMPLE_FMT_S32P: | |
547 case AV_SAMPLE_FMT_FLTP: | |
548 case AV_SAMPLE_FMT_DBLP: | |
549 num_actual_data_channels = dec_ctx->channels; | |
550 break; | |
551 | |
552 default: | |
553 case AV_SAMPLE_FMT_NONE: | |
554 case AV_SAMPLE_FMT_NB: | |
555 __debugbreak(); | |
556 } | |
557 | |
558 smack_debug_next_audio_time += dec_ctx->channels * frame->nb_samples * bytes_per_sample; | |
559 Assert(frame->avframe->linesize[0] == audio.dec_ctx->channels * frame->avframe->nb_samples * audio.bytes_per_sample / num_actual_data_channels, | |
560 "Smack audio size mismatch in frame %u in %s\n", audio_num_read_frames, movie_filename); | |
561 | |
562 frame->play_time = (double)frame->avpacket->pts / (double)audio.bytes_per_second; | |
563 } | |
564 break; | |
565 | |
566 case AV_CODEC_ID_MP3: | |
567 { | |
568 static int mp3_samples_decoded_so_far = 0; | |
569 static int mp3_prev_samples_count = frame->avframe->nb_samples; // mp3 seems to always feed same amount of samples | |
570 frame->play_time = (double)mp3_samples_decoded_so_far / (double)audio.dec_ctx->sample_rate; | |
571 | |
572 mp3_samples_decoded_so_far += frame->avframe->nb_samples; | |
573 Assert(mp3_prev_samples_count == frame->avframe->nb_samples, | |
574 "MP3 audio have variable sample count in frame %u in %s\n", audio_num_read_frames, movie_filename); | |
575 } | |
576 break; | |
577 | |
578 default: | |
579 { | |
580 __debugbreak(); | |
581 double samples_per_second = (double)audio.dec_ctx->time_base.den / (double)audio.dec_ctx->time_base.num; | |
582 double play_length = frame->avframe->nb_samples / samples_per_second; | |
583 frame->play_time = (double)frame->avpacket->pts / samples_per_second; | |
584 } | |
585 break;*/ | |
586 } | |
587 | |
588 if (!avframe->channel_layout) | |
589 { | |
590 log("Audio channel layout not specified, rolling back to default\n"); | |
591 avframe->channel_layout = av_get_default_channel_layout(dec_ctx->channels); | |
592 } | |
593 | |
594 *out_num_audio_samples = dec_ctx->channels * avframe->nb_samples; | |
595 InterleaveAudioData(out_audio_data, dec_ctx->sample_fmt, | |
596 dec_ctx->channels, avframe->nb_samples, avframe->data); | |
597 return true; | |
598 } | |
599 | |
600 bool LoadAudioTrack(AVFormatContext *format_ctx, AVCodecContext *dec_ctx, int audio_stream_idx, MemoryStream *out_audio_stream, int *out_num_audio_frames, int *out_num_audio_samples) | |
601 { | |
602 out_audio_stream->Reset(); | |
603 | |
604 AVFrame *frame = avcodec_alloc_frame(); | |
605 | |
606 AVPacket *packet = new AVPacket; | |
607 av_init_packet(packet); | |
608 | |
609 int num_audio_frames = 0; | |
610 int num_audio_samples = 0; | |
611 | |
612 while (av_read_frame(format_ctx, packet) >= 0) | |
613 { | |
614 // Is this a packet from the audio stream? | |
615 if (packet->stream_index != audio_stream_idx) | |
616 { | |
617 //log("Suspicious stream id %u in %s", packet->stream_index, filenamea); | |
618 continue; | |
619 } | |
620 | |
621 // Decode audio frame | |
622 int num_samples_decoded; | |
623 DecodeAudioFrame(dec_ctx, packet, frame, out_audio_stream, &num_samples_decoded); | |
624 | |
625 num_audio_samples += num_samples_decoded; | |
626 num_audio_frames++; | |
627 } | |
628 *out_num_audio_frames = num_audio_frames; | |
629 *out_num_audio_samples = num_audio_samples; | |
630 | |
631 avcodec_free_frame(&frame); | |
632 delete frame; | |
633 av_free_packet(packet); | |
634 delete packet; | |
635 | |
636 return true; | |
637 } | |
638 | |
639 class Track: public Media::ITrack | |
640 { | |
641 public: | |
642 inline Track() | |
643 { | |
644 this->format_ctx = nullptr; | |
645 this->audio_num_samples = 0; | |
646 } | |
647 | |
648 void Release() | |
649 { | |
650 ReleaseAvcodec(); | |
651 } | |
652 | |
653 void ReleaseAvcodec() | |
654 { | |
655 audio.Release(); | |
656 if (format_ctx) | |
657 { | |
658 av_close_input_file(format_ctx); | |
659 Log::Warning(L"close audio format context file\n"); | |
660 format_ctx = nullptr; | |
661 } | |
662 } | |
663 | |
664 bool LoadAudio(const wchar_t *filename) | |
665 { | |
666 char filenamea[1024]; | |
667 sprintf(filenamea, "%S", filename); | |
668 // Open audio file | |
669 if (avformat_open_input(&format_ctx, filenamea, nullptr, nullptr) >= 0) | |
670 { | |
671 // Retrieve stream information | |
672 if (avformat_find_stream_info(format_ctx, nullptr) >= 0) | |
673 { | |
674 // Dump information about file onto standard error | |
675 av_dump_format(format_ctx, 0, filenamea, 0); | |
676 | |
677 if (!av_open_audio_stream(format_ctx, &audio)) | |
678 { | |
679 Error("Cannot open strack: %s", filenamea); | |
680 return Release(), false; | |
681 } | |
682 | |
683 MemoryStream audio_plain_data; | |
684 int num_audio_frames; | |
685 int num_audio_samples; | |
686 | |
687 if (LoadAudioTrack(format_ctx, audio.dec_ctx, audio.stream_idx, &audio_plain_data, &num_audio_frames, &num_audio_samples)) | |
688 { | |
689 /*#ifdef _DEBUG | |
690 char debug_filename[1024]; | |
691 sprintf(debug_filename, "%s.wav", filenamea); | |
692 FILE *wav = fopen(debug_filename, "w+b"); | |
693 | |
694 extern void write_wav_header(FILE *wav, int channel_count = 2, int sample_rate = 22050, int bytes_per_sample = 2); | |
695 write_wav_header(wav, audio.dec_ctx->channels, audio.dec_ctx->sample_rate, audio.bytes_per_sample); | |
696 | |
697 fwrite(audio_plain_data.Ptr(), audio_plain_data.Current(), 1, wav); | |
698 | |
699 extern void fix_wav_header(FILE *wav, int wav_bytes_in_stream); | |
700 fix_wav_header(wav, audio_plain_data.Current()); | |
701 #endif*/ | |
702 | |
703 device_buffer = provider->CreateTrack16(audio.dec_ctx->channels, audio.dec_ctx->sample_rate, 2, num_audio_samples, audio_plain_data.Ptr()); | |
704 | |
705 Release(); | |
706 return true; | |
707 } | |
708 } | |
709 Release(); | |
710 fprintf(stderr, "ffmpeg: Unable to find stream info\n"); | |
711 return false; | |
712 } | |
713 fprintf(stderr, "ffmpeg: Unable to open input file\n"); | |
714 return false; | |
715 } | |
716 | |
717 virtual void Play(bool loop) | |
718 { | |
719 provider->PlayTrack16(device_buffer, loop); | |
720 mSourceID = device_buffer->source_id; | |
721 } | |
722 | |
723 protected: | |
724 AVFormatContext *format_ctx; | |
725 AVAudioStream audio; | |
726 int audio_num_samples; | |
727 | |
728 bool stopped; | |
729 | |
730 OpenALSoundProvider::TrackBuffer *device_buffer; | |
731 }; | |
732 | |
733 class Movie: public Media::IMovie | |
734 { | |
735 public: | |
736 inline Movie() | |
737 { | |
738 this->movie_filename[0] = 0; | |
739 this->width = 0; | |
740 this->height = 0; | |
741 this->format_ctx = nullptr; | |
742 this->end_of_file = false; | |
743 this->playback_time = 0.0; | |
744 | |
745 this->num_audio_frames = 0; | |
746 this->num_audio_samples = 0; | |
747 | |
748 this->last_resampled_frame_num = -1; | |
749 memset(last_resampled_frame_data, 0, sizeof(last_resampled_frame_data)); | |
750 memset(last_resampled_frame_linesize, 0, sizeof(last_resampled_frame_linesize)); | |
751 | |
752 audio_data_in_device = nullptr; | |
753 decoding_packet = nullptr; | |
754 ioBuffer = nullptr; | |
755 format_ctx = nullptr; | |
756 avioContext = nullptr; | |
757 } | |
758 | |
759 virtual ~Movie() {} | |
760 | |
761 virtual void Release() | |
762 { | |
763 ReleaseAVCodec(); | |
764 | |
765 if (audio_data_in_device) | |
766 provider->DeleteStreamingTrack(&audio_data_in_device); | |
767 } | |
768 | |
769 inline void ReleaseAVCodec() | |
770 { | |
771 audio.Release(); | |
772 video.Release(); | |
773 | |
774 if (format_ctx) | |
775 { | |
776 // Close the video file | |
777 av_close_input_file(format_ctx); | |
778 Log::Warning(L"close video format context file\n"); | |
779 format_ctx = nullptr; | |
780 } | |
781 if(avioContext) | |
782 { | |
783 av_free(avioContext); | |
784 avioContext = nullptr; | |
785 } | |
786 if (ioBuffer) | |
787 { | |
788 //av_free(ioBuffer); | |
789 ioBuffer = nullptr; | |
790 } | |
791 av_free_packet(decoding_packet); | |
792 delete decoding_packet; | |
793 avcodec_free_frame(&decoding_frame); | |
794 delete decoding_frame; | |
795 if (last_resampled_frame_data[0]) | |
796 av_freep(&last_resampled_frame_data[0]); | |
797 | |
798 } | |
799 | |
800 bool Load(const wchar_t *filename, int dst_width, int dst_height, int cache_ms) //Çàãðóçêà | |
801 { | |
802 char filenamea[1024]; | |
803 sprintf(filenamea, "%S", filename); | |
804 sprintf(movie_filename, "%S", filename); | |
805 | |
806 width = dst_width; | |
807 height = dst_height; | |
808 // Open video file | |
809 if (avformat_open_input(&format_ctx, filenamea, nullptr, nullptr) >= 0) | |
810 { | |
811 // Retrieve stream information | |
812 if (avformat_find_stream_info(format_ctx, nullptr) >= 0) | |
813 { | |
814 // Dump information about file onto standard error | |
815 av_dump_format(format_ctx, 0, filenamea, 0); | |
816 | |
2504 | 817 /*if (!av_open_audio_stream(format_ctx, &audio)) |
2502 | 818 { |
819 Error("Cannot open audio stream: %s", filenamea); | |
820 return Release(), false; | |
2504 | 821 }*/ |
822 av_open_audio_stream(format_ctx, &audio); | |
2502 | 823 |
824 if (!av_open_video_stream(format_ctx, &video)) | |
825 { | |
826 Error("Cannot open video stream: %s", filenamea); | |
827 return Release(), false; | |
828 } | |
829 | |
830 //Ritor1: include | |
831 if (_stricmp("binkvideo", video.dec->name) ) | |
832 { | |
833 pMediaPlayer->current_movie_width = video.dec_ctx->width; | |
834 pMediaPlayer->current_movie_height = video.dec_ctx->height; | |
835 } | |
836 else | |
837 { | |
838 pMediaPlayer->current_movie_width = width; | |
839 pMediaPlayer->current_movie_height = height; | |
840 } | |
841 // | |
842 decoding_packet = new AVPacket; | |
843 av_init_packet(decoding_packet); | |
844 | |
845 // Allocate video frame | |
846 decoding_frame = avcodec_alloc_frame(); | |
847 | |
2504 | 848 if (audio.stream_idx >= 0) |
849 audio_data_in_device = provider->CreateStreamingTrack16(audio.dec_ctx->channels, audio.dec_ctx->sample_rate, 2); | |
2502 | 850 return true; |
851 } | |
852 fprintf(stderr, "ffmpeg: Unable to find stream info\n"); | |
853 return Release(), false; | |
854 } | |
855 fprintf(stderr, "ffmpeg: Unable to open input file\n"); | |
856 return Release(), false; | |
857 } | |
858 | |
859 bool LoadFromLOD(HANDLE h, int readFunction(void*, uint8_t*, int), int64_t seekFunction(void*, int64_t, int), int width, int height) | |
860 { | |
861 if (!ioBuffer) | |
862 ioBuffer = (unsigned char *)av_malloc(0x4000 + FF_INPUT_BUFFER_PADDING_SIZE); // can get av_free()ed by libav | |
863 if (!avioContext) | |
864 avioContext = avio_alloc_context(ioBuffer, 0x4000, 0, h, readFunction, NULL, seekFunction); | |
865 if (!format_ctx) | |
866 format_ctx = avformat_alloc_context(); | |
867 format_ctx->pb = avioContext; | |
868 return Load(L"dummyFilename", width, height, 0); | |
869 } | |
870 | |
871 virtual void GetNextFrame(double dt, void *dst_surface) | |
872 { | |
873 playback_time += dt; | |
874 | |
875 AVPacket *avpacket = decoding_packet; | |
876 AVFrame *avframe = decoding_frame; | |
877 | |
878 avcodec_get_frame_defaults(avframe); | |
879 | |
880 int desired_frame_number = floor(playback_time * video.dec_ctx->time_base.den / video.dec_ctx->time_base.num + 0.5); | |
881 if (last_resampled_frame_num == desired_frame_number) | |
882 { | |
883 memcpy(dst_surface, last_resampled_frame_data[0], pMediaPlayer->current_movie_height * last_resampled_frame_linesize[0]); | |
884 return; | |
885 } | |
886 | |
887 volatile int frameFinished = false; | |
888 | |
889 // keep reading packets until we hit the end or find a video packet | |
890 do | |
891 { | |
892 if (pMediaPlayer->loop_current_file) | |
893 { | |
894 //Now seek back to the beginning of the stream | |
895 if (video.dec_ctx->frame_number >= video.stream->duration - 1 ) | |
896 pMediaPlayer->bPlaying_Movie = false; | |
897 } | |
898 if (av_read_frame(format_ctx, avpacket) < 0) | |
899 { | |
900 // probably movie is finished | |
901 pMediaPlayer->bPlaying_Movie = false; | |
902 av_free_packet(avpacket); | |
903 return; | |
904 } | |
905 // Is this a packet from the video stream? | |
906 // audio packet - queue into playing | |
907 if (avpacket->stream_index == audio.stream_idx) | |
908 { | |
909 MemoryStream audio_data; | |
910 if (DecodeAudioFrame(audio.dec_ctx, avpacket, avframe, &audio_data, &num_audio_samples)) | |
911 provider->Stream16(audio_data_in_device, num_audio_samples, audio_data.Ptr()); | |
912 //continue; | |
913 } | |
914 | |
915 // Decode video frame | |
916 // video packet - decode & maybe show | |
917 else if (avpacket->stream_index == video.stream_idx) | |
918 { | |
919 do | |
920 { | |
921 if (avcodec_decode_video2(video.dec_ctx, avframe, (int *)&frameFinished, avpacket) < 0) | |
922 __debugbreak(); | |
923 } while (!frameFinished); | |
924 } | |
925 else __debugbreak(); // unknown stream | |
926 } | |
927 while (avpacket->stream_index != video.stream_idx || | |
928 avpacket->pts != desired_frame_number); | |
929 | |
930 if (frameFinished) | |
931 { | |
932 if (last_resampled_frame_data[0]) | |
933 av_freep(&last_resampled_frame_data[0]); | |
934 | |
935 AVPixelFormat rescaled_format = AV_PIX_FMT_RGB32; | |
936 uint8_t *rescaled_data[4] = {nullptr, nullptr, nullptr, nullptr}; | |
937 int rescaled_linesize[4] = {0, 0, 0, 0}; | |
938 | |
939 if (av_image_alloc(rescaled_data, rescaled_linesize, pMediaPlayer->current_movie_width, pMediaPlayer->current_movie_height, rescaled_format, 1) >= 0) | |
940 { | |
941 SwsContext *converter = sws_getContext(avframe->width, avframe->height, (AVPixelFormat)avframe->format, | |
942 pMediaPlayer->current_movie_width, pMediaPlayer->current_movie_height, rescaled_format, | |
943 SWS_BICUBIC, nullptr, nullptr, nullptr); | |
944 sws_scale(converter, avframe->data, avframe->linesize, 0, avframe->height, rescaled_data, rescaled_linesize); | |
945 sws_freeContext(converter); | |
946 | |
947 memcpy(dst_surface, rescaled_data[0], pMediaPlayer->current_movie_height * rescaled_linesize[0]); | |
948 | |
949 last_resampled_frame_num = desired_frame_number; | |
950 memcpy(last_resampled_frame_data, rescaled_data, sizeof(rescaled_data)); | |
951 memcpy(last_resampled_frame_linesize, rescaled_linesize, sizeof(rescaled_linesize)); | |
952 } | |
953 } | |
954 else | |
955 memset(dst_surface, 0, width * pMediaPlayer->current_movie_height * 4); | |
956 | |
957 // Free the packet that was allocated by av_read_frame | |
958 av_free_packet(avpacket); | |
959 } | |
960 | |
961 virtual void Play() | |
962 { | |
963 } | |
964 | |
965 protected: | |
966 char movie_filename[256]; | |
967 int width; | |
968 int height; | |
969 bool stopped; | |
970 AVFormatContext *format_ctx; | |
971 double playback_time; | |
972 bool end_of_file; | |
973 | |
974 AVPacket *decoding_packet; | |
975 AVFrame *decoding_frame; | |
976 | |
977 AVAudioStream audio; | |
978 int num_audio_frames; | |
979 int num_audio_samples; | |
980 unsigned char *ioBuffer; | |
981 AVIOContext *avioContext; | |
982 OpenALSoundProvider::StreamingTrackBuffer *audio_data_in_device; | |
983 | |
984 AVVideoStream video; | |
985 int last_resampled_frame_num; | |
986 uint8_t *last_resampled_frame_data[4]; | |
987 int last_resampled_frame_linesize[4]; | |
988 }; | |
989 | |
990 ITrack *MPlayer::LoadTrack(const wchar_t *filename) | |
991 { | |
992 auto audio_track = new Track; | |
993 Log::Warning(L"allocation dynamic memory for audio_track\n"); | |
994 if (!audio_track->LoadAudio(filename)) | |
995 { | |
996 delete audio_track; | |
997 Log::Warning(L"delete dynamic memory for audio_track\n"); | |
998 audio_track = nullptr; | |
999 } | |
1000 return audio_track; | |
1001 } | |
1002 | |
1003 IMovie *MPlayer::LoadMovie(const wchar_t *filename, int width, int height, int cache_ms) //Çàãðóçèòü âèäåî | |
1004 { | |
1005 movie = new Movie; | |
1006 Log::Warning(L"allocation dynamic memory for movie\n"); | |
1007 if (!movie->Load(filename, width, height, cache_ms)) | |
1008 { | |
1009 delete movie; | |
1010 Log::Warning(L"delete dynamic memory for movie\n"); | |
1011 movie = nullptr; | |
1012 } | |
1013 return movie; | |
1014 } | |
1015 | |
1016 | |
1017 //for video///////////////////////////////////////////////////////////////// | |
1018 | |
1019 //----- (004BE9D8) -------------------------------------------------------- | |
1020 void MPlayer::Initialize(OSWindow *target_window) | |
1021 { | |
2519 | 1022 window = target_window; |
1023 | |
2572
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
1024 hVidFile = INVALID_HANDLE_VALUE; |
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
1025 |
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
1026 uNumMightVideoHeaders = 0; |
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
1027 pMightVideoHeaders = nullptr; |
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
1028 |
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
1029 uNumMagicVideoHeaders = 0; |
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
1030 pMagicVideoHeaders = nullptr; |
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
1031 |
2519 | 1032 if (bNoVideo) |
1033 return; | |
1034 | |
2502 | 1035 DWORD NumberOfBytesRead; // [sp+10h] [bp-4h]@9 |
1036 | |
1037 | |
1038 unsigned int uBinkVersionMajor = -1, | |
1039 uBinkVersionMinor = -1; | |
1040 //GetDllVersion(L"BINKW32.DLL", &uBinkVersionMajor, &uBinkVersionMinor); | |
1041 //uBinkVersion = (unsigned __int64)uBinkVersionMajor << 32 | uBinkVersionMinor; | |
1042 | |
1043 strcpy(pTmpBuf.data(), "anims\\might7.vid"); | |
1044 hMightVid = CreateFileW(L"anims\\might7.vid", GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0x8000080, 0); | |
1045 if ( hMightVid == INVALID_HANDLE_VALUE ) | |
1046 { | |
1047 sprintf(pTmpBuf2.data(), "Can't open file - anims\\%s.smk", pTmpBuf.data()); | |
1048 MessageBoxA(0, pTmpBuf2.data(), "Video File Error", 0); | |
1049 return; | |
1050 } | |
1051 strcpy(pTmpBuf.data(), "anims\\magic7.vid"); | |
1052 hMagicVid = CreateFileW(L"anims\\magic7.vid", GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0x8000080, 0); | |
1053 if ( hMagicVid == INVALID_HANDLE_VALUE ) | |
1054 { | |
1055 if ( !bCanLoadFromCD ) | |
1056 { | |
1057 sprintf(pTmpBuf2.data(), "Can't open file - anims\\%s.smk", pTmpBuf.data()); | |
1058 MessageBoxA(0, pTmpBuf2.data(), "Video File Error", 0); | |
1059 return; | |
1060 } | |
1061 sprintf(pTmpBuf2.data(), "%c:\\%s", (unsigned __int8)cMM7GameCDDriveLetter, pTmpBuf.data()); | |
1062 hMagicVid = CreateFileA(pTmpBuf2.data(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0x8000080, 0); | |
1063 if ( hMagicVid == (HANDLE)INVALID_HANDLE_VALUE ) | |
1064 { | |
1065 sprintf(pTmpBuf2.data(), "Can't open file - %s", pTmpBuf.data()); | |
1066 MessageBoxA(0, pTmpBuf2.data(), "Video File Error", 0); | |
1067 return; | |
1068 } | |
1069 } | |
1070 ReadFile(hMightVid, &uNumMightVideoHeaders, 4, &NumberOfBytesRead, 0); | |
1071 ReadFile(hMagicVid, &uNumMagicVideoHeaders, 4, &NumberOfBytesRead, 0); | |
1072 pMightVideoHeaders = (MovieHeader *)malloc(sizeof(MovieHeader) * uNumMightVideoHeaders + 2); | |
1073 pMagicVideoHeaders = (MovieHeader *)malloc(sizeof(MovieHeader) * uNumMagicVideoHeaders + 2); | |
1074 ReadFile(hMightVid, pMightVideoHeaders, 44 * uNumMightVideoHeaders, &NumberOfBytesRead, 0); | |
1075 ReadFile(hMagicVid, pMagicVideoHeaders, 44 * uNumMagicVideoHeaders, &NumberOfBytesRead, 0); | |
1076 } | |
1077 | |
1078 //----- (004BF411) -------------------------------------------------------- | |
1079 void MPlayer::OpenFullscreenMovie(const char *pFilename, unsigned int bLoop/*, int ScreenSizeFlag*/) | |
1080 { | |
1081 if (!this->bPlaying_Movie) | |
1082 { | |
1083 pEventTimer->Pause(); | |
2510 | 1084 if ( use_music_folder ) |
1085 alSourcePause(mSourceID); | |
1086 else if (pAudioPlayer->hAILRedbook) | |
1087 AIL_redbook_pause(pAudioPlayer->hAILRedbook); | |
2502 | 1088 |
1089 bStopBeforeSchedule = false; | |
1090 bFirstFrame = false; | |
1091 this->bLoopPlaying = bLoop; | |
1092 LoadMovie(pFilename); | |
1093 return; | |
1094 } | |
1095 } | |
1096 | |
1097 //----- (004BF28F) -------------------------------------------------------- | |
1098 void MPlayer::OpenHouseMovie(const char *pMovieName, unsigned int a3_1) | |
1099 { | |
1100 if (!this->bPlaying_Movie) | |
1101 { | |
1102 //Prepare(); | |
1103 pEventTimer->Pause(); | |
2510 | 1104 if ( use_music_folder ) |
1105 alSourcePause(mSourceID); | |
1106 else if (pAudioPlayer->hAILRedbook) | |
2502 | 1107 AIL_redbook_pause(pAudioPlayer->hAILRedbook); |
1108 | |
1109 bStopBeforeSchedule = false; | |
1110 bFirstFrame = false; | |
1111 | |
1112 this->bLoopPlaying = a3_1; | |
1113 /*if ( LOBYTE(this->field_104) == 1 ) | |
1114 { | |
1115 MessageBoxA(nullptr, "Unsupported Bink playback!", "E:\\WORK\\MSDEV\\MM7\\MM7\\Code\\Video.cpp:925", 0); | |
1116 return; | |
1117 }*/ | |
1118 | |
1119 LoadMovie(pMovieName); | |
1120 time_video_begin = GetTickCount(); | |
1121 } | |
1122 } | |
1123 | |
1124 //----- (004BE70E) -------------------------------------------------------- | |
1125 void MPlayer::FullscreenMovieLoop(const char *pMovieName, int a2/*, int ScreenSizeFlag, int a4*/) | |
1126 { | |
1127 int v4; // ebp@1 | |
1128 MSG Msg; // [sp+Ch] [bp-1Ch]@12 | |
1129 | |
1130 v4 = a2; | |
1131 if ( dword_6BE364_game_settings_1 & (GAME_SETTINGS_NO_HOUSE_ANIM | GAME_SETTINGS_NO_INTRO) || | |
1132 bNoVideo) | |
1133 return; | |
1134 | |
1135 if ( a2 == 2 ) | |
1136 v4 = 0; | |
1137 ShowCursor(0); | |
1138 OpenFullscreenMovie(pMovieName, 0); | |
1139 bPlaying_Movie = 1; | |
1140 field_44 = v4; | |
1141 pRenderer->ClearTarget(0); | |
2541 | 1142 current_screen_type = SCREEN_VIDEO; |
2502 | 1143 |
1144 auto hwnd = pMediaPlayer->window->GetApiHandle(); | |
1145 | |
1146 RECT rc_client; | |
1147 GetClientRect(hwnd, &rc_client); | |
1148 int client_width = rc_client.right - rc_client.left, | |
1149 client_height = rc_client.bottom - rc_client.top; | |
1150 | |
1151 HDC dc = GetDC(hwnd); | |
1152 HDC back_dc = CreateCompatibleDC(dc); | |
1153 HBITMAP back_bmp = CreateCompatibleBitmap(dc, client_width, client_height); | |
1154 auto frame_buffer = new char[client_width * client_height * 4]; | |
1155 SelectObject(back_dc, back_bmp); | |
1156 | |
1157 DWORD t = GetTickCount(); | |
1158 | |
1159 bPlaying_Movie = true; | |
1160 | |
1161 while (true) | |
1162 { | |
1163 if (pMediaPlayer->bStopBeforeSchedule) | |
1164 break; | |
1165 while (PeekMessageA(&Msg, hwnd, 0, 0, PM_REMOVE)) | |
1166 { | |
1167 if (Msg.message == WM_QUIT) | |
2541 | 1168 Engine_DeinitializeAndTerminate(0); |
2502 | 1169 if (Msg.message == WM_PAINT) |
1170 break; | |
1171 TranslateMessage(&Msg); | |
1172 DispatchMessageA(&Msg); | |
1173 } | |
1174 | |
1175 double dt = (GetTickCount() - t) / 1000.0; | |
1176 t = GetTickCount(); | |
1177 | |
1178 pMovie_Track->GetNextFrame(dt, frame_buffer); | |
1179 | |
1180 if (!bPlaying_Movie) | |
1181 break; | |
1182 | |
1183 if (frame_buffer) | |
1184 { | |
1185 // draw to hwnd | |
1186 BITMAPINFO bmi; | |
1187 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); | |
1188 bmi.bmiHeader.biWidth = client_width; | |
1189 bmi.bmiHeader.biHeight = -client_height; | |
1190 bmi.bmiHeader.biPlanes = 1; | |
1191 bmi.bmiHeader.biBitCount = 32; | |
1192 bmi.bmiHeader.biCompression = BI_RGB; | |
1193 bmi.bmiHeader.biSizeImage = 0; | |
1194 bmi.bmiHeader.biXPelsPerMeter = 0; | |
1195 bmi.bmiHeader.biYPelsPerMeter = 0; | |
1196 bmi.bmiHeader.biClrUsed = 0; | |
1197 bmi.bmiHeader.biClrImportant = 0; | |
1198 GetDIBits(back_dc, back_bmp, 0, client_height, 0, &bmi, DIB_RGB_COLORS); | |
1199 SetDIBits(back_dc, back_bmp, 0, client_height, frame_buffer, &bmi, DIB_RGB_COLORS); | |
1200 BitBlt(dc, 0, 0, client_width, client_height, back_dc, 0, 0, SRCCOPY); | |
1201 } | |
1202 | |
2541 | 1203 MainMenu_EventLoop(); |
2502 | 1204 |
1205 if (pMediaPlayer->bStopBeforeSchedule == 1) | |
1206 Sleep(1000); | |
1207 } | |
1208 delete [] frame_buffer; | |
1209 DeleteObject(back_bmp); | |
1210 DeleteObject(back_dc); | |
1211 ReleaseDC(hwnd, dc); | |
1212 | |
1213 pMediaPlayer->Unload(); | |
1214 | |
1215 //if (a4 == 1) | |
2541 | 1216 current_screen_type = SCREEN_GAME; |
2502 | 1217 |
1218 pMediaPlayer->bPlaying_Movie = false; | |
1219 | |
1220 ShowCursor(1); | |
1221 | |
2541 | 1222 /*if ( current_screen_type == SCREEN_VIDEO ) |
1223 current_screen_type = SCREEN_GAME;*/ | |
2502 | 1224 } |
1225 | |
1226 void MPlayer::HouseMovieLoop() | |
1227 { | |
1228 if (pMovie_Track && !bNoVideo) | |
1229 { | |
1230 pRenderer->BeginScene(); | |
1231 pMouse->DrawCursorToTarget(); | |
1232 | |
1233 Log::Warning(L"smacker"); | |
1234 loop_current_file = true; | |
1235 pRenderer->BeginScene(); | |
1236 if (!bPlaying_Movie)//reload | |
1237 { | |
1238 unsigned int width = game_viewport_width; | |
1239 unsigned int height = game_viewport_height; | |
1240 MovieRelease(); | |
1241 | |
1242 SetFilePointer(hVidFile, uOffset, nullptr, FILE_BEGIN); | |
1243 pMovie_Track = nullptr; | |
1244 Log::Warning(L"reload pMovie_Track"); | |
1245 pMovie_Track = pMediaPlayer->LoadMovieFromLOD(hVidFile, &readFunction, &seekFunction, width, height); | |
1246 bPlaying_Movie = true; | |
1247 } | |
1248 //else | |
1249 //{ | |
1250 double dt = (GetTickCount() - time_video_begin) / 1000.0; | |
1251 //dt = 1.0/15.0; | |
1252 time_video_begin = GetTickCount(); | |
1253 | |
1254 //log("dt=%.5f\n", dt); | |
1255 | |
1256 auto image = new char[current_movie_width * current_movie_height * 4]; | |
1257 | |
1258 pMovie_Track->GetNextFrame(dt, image); | |
1259 | |
1260 int image_array[460 * 344];//game_viewport_width * game_viewport_height | |
1261 if (image) | |
1262 { | |
1263 memcpy(image_array, image, sizeof (image_array)); | |
1264 for (unsigned int y = 8; y < 8 + game_viewport_height; ++y)//êîîðäèíàòû ìåñòîïîëîæåíèÿ âèäåîðîëèêà | |
1265 { | |
1266 for (unsigned int x = 8; x < 8 + game_viewport_width; ++x) | |
1267 { | |
1268 auto p = (unsigned __int32 *)pRenderer->pTargetSurface + x + y * pRenderer->uTargetSurfacePitch; | |
1269 *p = image_array[((x - 8) + ((y - 8)*game_viewport_width))]; | |
1270 } | |
1271 } | |
1272 delete[] image; | |
1273 } | |
1274 //} | |
1275 pRenderer->EndScene(); | |
1276 pMouse->ReadCursorWithItem(); | |
1277 pRenderer->EndScene(); | |
1278 } | |
1279 } | |
1280 | |
1281 //----- (004BF73A) -------------------------------------------------------- | |
1282 void MPlayer::SelectMovieType() | |
1283 { | |
1284 char Source[32]; // [sp+Ch] [bp-40h]@1 | |
1285 | |
1286 strcpy(Source, this->pCurrentMovieName); | |
1287 pMediaPlayer->Unload(); | |
1288 if ( this->uMovieType == 1 ) | |
1289 OpenHouseMovie(Source, LOBYTE(this->bLoopPlaying)); | |
1290 else if ( this->uMovieType == 2 ) | |
1291 OpenFullscreenMovie(Source, LOBYTE(this->bLoopPlaying)); | |
1292 else | |
1293 __debugbreak(); | |
1294 } | |
1295 | |
1296 void MPlayer::LoadMovie(const char *pFilename) | |
1297 { | |
1298 char pVideoNameBik[120]; // [sp+Ch] [bp-28h]@2 | |
1299 char pVideoNameSmk[120]; // [sp+Ch] [bp-28h]@2 | |
1300 | |
1301 sprintf(pVideoNameBik, "%s.bik", pFilename); | |
1302 sprintf(pVideoNameSmk, "%s.smk", pFilename); | |
1303 for (uint i = 0; i < uNumMightVideoHeaders; ++i) | |
1304 { | |
1305 if (!_stricmp(pVideoNameSmk, pMightVideoHeaders[i].pVideoName)) | |
1306 { | |
1307 hVidFile = hMightVid; | |
1308 uOffset = pMightVideoHeaders[i].uFileOffset; | |
1309 uSize = pMightVideoHeaders[i + 1].uFileOffset - uOffset; | |
1310 this->uMovieType = 2; | |
1311 } | |
1312 } | |
1313 for (uint i = 0; i < uNumMagicVideoHeaders; ++i) | |
1314 { | |
1315 if (!_stricmp(pVideoNameBik, pMagicVideoHeaders[i].pVideoName)) | |
1316 { | |
1317 hVidFile = hMagicVid; | |
1318 uOffset = pMagicVideoHeaders[i].uFileOffset; | |
1319 uSize = pMagicVideoHeaders[i + 1].uFileOffset - uOffset; | |
1320 this->uMovieType = 1; | |
1321 } | |
1322 if (!_stricmp(pVideoNameSmk, pMagicVideoHeaders[i].pVideoName)) | |
1323 { | |
1324 hVidFile = hMagicVid; | |
1325 uOffset = pMagicVideoHeaders[i].uFileOffset; | |
1326 uSize = pMagicVideoHeaders[i + 1].uFileOffset - uOffset; | |
1327 this->uMovieType = 2; | |
1328 } | |
1329 } | |
2572
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
1330 if (hVidFile == INVALID_HANDLE_VALUE) |
2502 | 1331 { |
1332 pMediaPlayer->Unload(); | |
1333 MessageBoxA(0, "MediaPlayer error", "MediaPlayer Error", 0); | |
1334 return; | |
1335 } | |
1336 | |
1337 SetFilePointer(hVidFile, uOffset, 0, FILE_BEGIN); | |
1338 strcpy(this->pCurrentMovieName, pFilename); | |
1339 | |
1340 auto hwnd = pMediaPlayer->window->GetApiHandle(); | |
1341 RECT rc_client; | |
1342 GetClientRect(hwnd, &rc_client); | |
1343 int client_width = rc_client.right - rc_client.left, | |
1344 client_height = rc_client.bottom - rc_client.top; | |
1345 | |
1346 pMovie_Track = pMediaPlayer->LoadMovieFromLOD(hVidFile, &readFunction, &seekFunction, client_width, client_height); | |
1347 } | |
1348 | |
1349 //----- (004BF794) -------------------------------------------------------- | |
1350 void MPlayer::ShowMM7IntroVideo_and_LoadingScreen() | |
1351 { | |
1352 pMediaPlayer->bStopBeforeSchedule = false; | |
1353 // pMediaPlayer->pResetflag = 0; | |
1354 bGameoverLoop = true; | |
1355 if (!bNoVideo) | |
1356 { | |
1357 pRenderer->PresentBlackScreen(); | |
1358 if ( !pMediaPlayer->bStopBeforeSchedule ) | |
1359 PlayFullscreenMovie(MOVIE_Intro, true); | |
1360 } | |
1361 | |
2572
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
1362 Image *tex = assets->GetImage_PCXFromIconsLOD(L"mm6title.pcx"); |
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
1363 |
2502 | 1364 pRenderer->BeginScene(); |
2572
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
1365 pRenderer->DrawTextureNew(0, 0, tex); |
2502 | 1366 |
1367 //LoadFonts_and_DrawCopyrightWindow(); | |
1368 DrawMM7CopyrightWindow(); | |
1369 | |
1370 pRenderer->EndScene(); | |
1371 pRenderer->Present(); | |
1372 | |
2572
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
1373 tex->Release(); |
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
1374 tex = nullptr; |
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
1375 |
2502 | 1376 #ifndef _DEBUG |
1377 Sleep(1500); // let the copyright window stay for a while | |
1378 #endif | |
1379 | |
2572
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
1380 if (!bNoSound) |
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
1381 pAudioPlayer->PlayMusicTrack(MUSIC_MainMenu); |
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
1382 |
2502 | 1383 bGameoverLoop = false; |
1384 } | |
1385 | |
1386 //----- (004BEBD7) -------------------------------------------------------- | |
1387 void MPlayer::Unload() | |
1388 { | |
1389 bPlaying_Movie = false; | |
1390 uMovieType = 0; | |
1391 memset(pCurrentMovieName, 0, 0x40); | |
2510 | 1392 if ( !bGameoverLoop && pMediaPlayer->current_movie_width == 460) |
1393 { | |
1394 if ( use_music_folder ) | |
1395 alSourcePlay(mSourceID); | |
1396 else if ( pAudioPlayer->hAILRedbook ) | |
1397 AIL_redbook_resume(pAudioPlayer->hAILRedbook); | |
1398 } | |
2502 | 1399 pEventTimer->Resume(); |
1400 | |
2572
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
1401 if (pMovie_Track) |
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
1402 { |
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
1403 pMovie_Track->Release(); |
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
1404 delete pMovie_Track; |
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
1405 } |
2502 | 1406 pMovie_Track = nullptr; |
1407 } | |
1408 | |
1409 int MPlayer::readFunction(void* opaque, uint8_t* buf, int buf_size) | |
1410 { | |
1411 HANDLE stream = (HANDLE)opaque; | |
1412 //int numBytes = stream->read((char*)buf, buf_size); | |
1413 int numBytes; | |
1414 ReadFile(stream, (char *)buf, buf_size, (LPDWORD)&numBytes, NULL); | |
1415 return numBytes; | |
1416 } | |
1417 | |
1418 int64_t MPlayer::seekFunction(void* opaque, int64_t offset, int whence) | |
1419 { | |
1420 if (whence == AVSEEK_SIZE) | |
1421 return pMediaPlayer->uSize; | |
1422 HANDLE h = (HANDLE)opaque; | |
1423 LARGE_INTEGER li; | |
1424 li.QuadPart = offset; | |
1425 | |
1426 if (!SetFilePointerEx(h, li, (PLARGE_INTEGER)&li, FILE_BEGIN)) | |
1427 return -1; | |
1428 return li.QuadPart; | |
1429 } | |
1430 | |
1431 //for video////////////////////////////////////////////////////////////////// | |
1432 | |
1433 | |
1434 | |
1435 IMovie *MPlayer::LoadMovieFromLOD(HANDLE h, int readFunction(void*, uint8_t*, int), int64_t seekFunction(void*, int64_t, int), int width, int height) | |
1436 { | |
1437 movie = new Movie; | |
1438 Log::Warning(L"allocation dynamic memory for movie\n"); | |
1439 if (movie) | |
1440 { | |
1441 if (movie->LoadFromLOD(h, readFunction, seekFunction, width, height)) | |
1442 return movie; | |
1443 delete movie; | |
1444 Log::Warning(L"delete dynamic memory for movie\n"); | |
1445 } | |
1446 return nullptr; | |
1447 } | |
1448 | |
1449 void MovieRelease() | |
1450 { | |
1451 movie->Release(); | |
1452 delete movie; | |
1453 Log::Warning(L"delete dynamic memory for movie\n"); | |
1454 movie = nullptr; | |
1455 } | |
1456 | |
1457 | |
1458 //for audio/////////////////////////////////////////////////////// | |
1459 //----- (004AB818) -------------------------------------------------------- | |
1460 void MPlayer::LoadAudioSnd() | |
1461 { | |
1462 DWORD NumberOfBytesRead; // [sp+Ch] [bp-4h]@3 | |
1463 | |
1464 hAudioSnd = CreateFileA("Sounds\\Audio.snd", GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0x8000080u, 0); | |
1465 if (hAudioSnd == INVALID_HANDLE_VALUE) | |
1466 { | |
1467 Log::Warning(L"Can't open file: %s", L"Sounds\\Audio.snd"); | |
1468 return; | |
1469 } | |
1470 | |
1471 ReadFile(hAudioSnd, &uNumSoundHeaders, 4, &NumberOfBytesRead, 0); | |
1472 pSoundHeaders = nullptr; | |
1473 pSoundHeaders = (SoundHeader *)malloc(52 * uNumSoundHeaders + 2); | |
1474 ReadFile(hAudioSnd, pSoundHeaders, 52 * uNumSoundHeaders, &NumberOfBytesRead, 0); | |
1475 } | |
1476 //for audio/////////////////////////////////////////////////////// | |
1477 | |
1478 void av_logger(void *, int, const char *format, va_list args) | |
1479 { | |
1480 va_list va; | |
1481 va_start(va, format); | |
1482 char msg[256]; | |
1483 vsprintf(msg, format, va); | |
1484 va_end(va); | |
1485 | |
1486 log("av: %s", msg); | |
1487 } | |
1488 | |
1489 MPlayer::MPlayer() | |
1490 { | |
1491 bPlaying_Movie = false; | |
1492 | |
1493 static int libavcodec_initialized = false; | |
1494 | |
1495 if (!libavcodec_initialized) | |
1496 { | |
1497 av_log_set_callback(av_logger); | |
1498 avcodec_register_all(); | |
1499 | |
1500 // Register all available file formats and codecs | |
1501 av_register_all(); | |
1502 | |
1503 libavcodec_initialized = true; | |
1504 } | |
1505 | |
1506 bStopBeforeSchedule = false; | |
1507 pMovie_Track = nullptr; | |
1508 | |
1509 if (!provider) | |
1510 { | |
1511 provider = new OpenALSoundProvider; | |
1512 Log::Warning(L"allocation dynamic memory for provider\n"); | |
1513 provider->Initialize(); | |
1514 } | |
1515 LoadAudioSnd(); | |
1516 } | |
1517 | |
1518 MPlayer::~MPlayer() | |
1519 { | |
1520 delete provider; | |
1521 Log::Warning(L"delete dynamic memory for provider\n"); | |
1522 | |
1523 bStopBeforeSchedule = false; | |
1524 // pResetflag = 0; | |
2572
d87bfbd3bb3b
Step towards unification of Texture and RGBTexture (class Image)
a.parshin
parents:
2567
diff
changeset
|
1525 // pVideoFrame.Release(); |
2502 | 1526 } |
1527 | |
1528 void PlayAudio(const wchar_t * pFilename) | |
1529 { | |
1530 pAudio_Track = pMediaPlayer->LoadTrack(pFilename); | |
1531 pAudio_Track->Play(); | |
1532 delete pAudio_Track; | |
1533 Log::Warning(L"delete dynamic memory for pAudio_Track\n"); | |
1534 pAudio_Track = nullptr; | |
1535 } | |
1536 | |
1537 void PlayMovie(const wchar_t * pFilename) | |
1538 { | |
1539 Media::IMovie *Movie_track = pMediaPlayer->LoadMovie(pFilename, 640, 480, 0); | |
1540 Movie_track->Play(); | |
1541 } | |
1542 |