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