Mercurial > mm7
comparison MediaPlayer.cpp @ 2324:b2e3ac05f2b3
Merge
author | Grumpy7 |
---|---|
date | Thu, 27 Mar 2014 23:30:02 +0100 |
parents | 9987f93d7e1f |
children | 182effc4b0ee |
comparison
equal
deleted
inserted
replaced
2323:983b8c995127 | 2324:b2e3ac05f2b3 |
---|---|
1 extern "C" | |
2 { | |
3 #include "lib/libavcodec/avcodec.h" | |
4 #include "lib/libavformat/avformat.h" | |
5 #include "lib/libavutil/avutil.h" | |
6 #include "lib/libavutil/imgutils.h" | |
7 #include "lib/libswscale/swscale.h" | |
8 #include "lib/libswresample/swresample.h" | |
9 #include "lib/libavutil/opt.h" | |
10 } | |
11 #pragma comment(lib, "avcodec.lib") | |
12 #pragma comment(lib, "avformat.lib") | |
13 #pragma comment(lib, "avutil.lib") | |
14 #pragma comment(lib, "swscale.lib") | |
15 #pragma comment(lib, "swresample.lib") | |
16 | |
17 #include <vector> | |
18 #include <deque> | |
19 | |
20 #include "stuff.h" | |
21 #include "OpenALSoundProvider.h" | |
22 | |
23 #include "MediaPlayer.h" | |
24 using namespace Media; | |
25 | |
26 | |
27 class MemoryStream | |
28 { | |
29 public: | |
30 inline MemoryStream(void *data, size_t data_size) | |
31 { | |
32 this->data_size = data_size; | |
33 this->data = data; | |
34 this->current_pos = 0; | |
35 } | |
36 inline MemoryStream() | |
37 { | |
38 this->data_size = 0; | |
39 this->data = nullptr; | |
40 this->current_pos = 0; | |
41 } | |
42 | |
43 inline ~MemoryStream() | |
44 { | |
45 if (data) | |
46 delete [] data; | |
47 } | |
48 | |
49 inline size_t Write(void *buffer, size_t num_bytes) | |
50 { | |
51 if (!data) | |
52 { | |
53 data_size = 32 + num_bytes; | |
54 data = new char[data_size]; | |
55 current_pos = 0; | |
56 } | |
57 else if (current_pos + num_bytes >= data_size) | |
58 { | |
59 int new_data_size = data_size + num_bytes + data_size / 8 + 4; | |
60 auto new_data = new char[new_data_size]; | |
61 | |
62 memcpy(new_data, data, data_size); | |
63 delete [] data; | |
64 | |
65 data_size = new_data_size; | |
66 data = new_data; | |
67 } | |
68 memcpy((char *)data + current_pos, buffer, num_bytes); | |
69 current_pos += num_bytes; | |
70 return num_bytes; | |
71 } | |
72 | |
73 inline size_t Read(void *buffer, size_t num_bytes) | |
74 { | |
75 size_t read_size = min(num_bytes, data_size - current_pos); | |
76 if (read_size) | |
77 { | |
78 memcpy(buffer, (char *)data + current_pos, read_size); | |
79 current_pos += read_size; | |
80 } | |
81 return read_size; | |
82 } | |
83 | |
84 inline void Reset() | |
85 { | |
86 current_pos = 0; | |
87 } | |
88 inline void SeekToEnd() | |
89 { | |
90 current_pos = data_size; | |
91 } | |
92 | |
93 inline size_t Unwind(size_t bytes) | |
94 { | |
95 if (bytes > current_pos) | |
96 current_pos = 0; | |
97 else | |
98 current_pos -= bytes; | |
99 return current_pos; | |
100 } | |
101 | |
102 inline size_t Rewind(size_t bytes) | |
103 { | |
104 if (current_pos + bytes >= data_size) | |
105 current_pos = data_size; | |
106 else | |
107 current_pos += bytes; | |
108 return current_pos; | |
109 } | |
110 | |
111 inline size_t Size() const {return data_size;} | |
112 inline size_t Current() const {return current_pos;} | |
113 inline void *Ptr() const {return data;} | |
114 | |
115 private: | |
116 void *data; | |
117 size_t data_size; | |
118 size_t current_pos; | |
119 }; | |
120 | |
121 | |
122 | |
123 | |
124 OpenALSoundProvider *provider = nullptr; | |
125 | |
126 | |
127 | |
128 static int av_num_bytes_per_sample(AVSampleFormat sample_fmt) | |
129 { | |
130 switch (sample_fmt) | |
131 { | |
132 case AV_SAMPLE_FMT_U8: | |
133 case AV_SAMPLE_FMT_U8P: | |
134 return 1; | |
135 | |
136 case AV_SAMPLE_FMT_S16: | |
137 case AV_SAMPLE_FMT_S16P: | |
138 return 2; | |
139 | |
140 case AV_SAMPLE_FMT_S32: | |
141 case AV_SAMPLE_FMT_S32P: | |
142 case AV_SAMPLE_FMT_FLT: | |
143 case AV_SAMPLE_FMT_FLTP: | |
144 return 4; | |
145 | |
146 case AV_SAMPLE_FMT_DBL: | |
147 case AV_SAMPLE_FMT_DBLP: | |
148 return 8; | |
149 | |
150 default: | |
151 case AV_SAMPLE_FMT_NONE: | |
152 Error("Invalid av sample format: %u", sample_fmt); | |
153 } | |
154 return 0; | |
155 } | |
156 | |
157 | |
158 | |
159 struct AVStreamWrapper | |
160 { | |
161 inline AVStreamWrapper() | |
162 { | |
163 this->type = AVMEDIA_TYPE_UNKNOWN; | |
164 this->stream_idx = -1; | |
165 this->stream = nullptr; | |
166 this->dec = nullptr; | |
167 this->dec_ctx = nullptr; | |
168 } | |
169 | |
170 inline void Release() | |
171 { | |
172 type = AVMEDIA_TYPE_UNKNOWN; | |
173 stream_idx = -1; | |
174 stream = nullptr; | |
175 dec = nullptr; | |
176 if (dec_ctx) | |
177 { | |
178 avcodec_close(dec_ctx); | |
179 dec_ctx = nullptr; | |
180 } | |
181 } | |
182 | |
183 AVMediaType type; | |
184 int stream_idx; | |
185 AVStream *stream; | |
186 AVCodec *dec; | |
187 AVCodecContext *dec_ctx; | |
188 }; | |
189 | |
190 struct AVAudioStream: public AVStreamWrapper | |
191 { | |
192 inline AVAudioStream(): | |
193 AVStreamWrapper() | |
194 { | |
195 this->bytes_per_sample = 0; | |
196 this->bytes_per_second = 0; | |
197 } | |
198 | |
199 int bytes_per_sample; | |
200 int bytes_per_second; | |
201 }; | |
202 | |
203 struct AVVideoStream: public AVStreamWrapper | |
204 { | |
205 inline AVVideoStream(): | |
206 AVStreamWrapper() | |
207 { | |
208 this->frames_per_second = 0.0; | |
209 } | |
210 | |
211 double frames_per_second; | |
212 }; | |
213 | |
214 static bool av_open_stream(AVFormatContext *format_ctx, AVMediaType type, AVStreamWrapper *out_stream) | |
215 { | |
216 int stream_idx = av_find_best_stream(format_ctx, type, -1, -1, nullptr, 0); | |
217 if (stream_idx >= 0) | |
218 { | |
219 auto stream = format_ctx->streams[stream_idx]; | |
220 auto dec_ctx = stream->codec; | |
221 auto dec = avcodec_find_decoder(dec_ctx->codec_id); | |
222 if (dec) | |
223 { | |
224 if (avcodec_open2(dec_ctx, dec, nullptr) >= 0) | |
225 { | |
226 out_stream->type = type; | |
227 out_stream->stream_idx = stream_idx; | |
228 out_stream->stream = stream; | |
229 out_stream->dec = dec; | |
230 out_stream->dec_ctx = dec_ctx; | |
231 return true; | |
232 } | |
233 } | |
234 } | |
235 return false; | |
236 } | |
237 | |
238 static bool av_open_audio_stream(AVFormatContext *format_ctx, AVAudioStream *out_stream) | |
239 { | |
240 if (!av_open_stream(format_ctx, AVMEDIA_TYPE_AUDIO, out_stream)) | |
241 return Error("Audio stream not found"), false; | |
242 | |
243 // we support only 2-channel audio for now | |
244 if (out_stream->dec_ctx->channels != 2) | |
245 { | |
246 out_stream->Release(); | |
247 return Error("Unsupported number of channels: %u", out_stream->dec_ctx->channels), false; | |
248 } | |
249 | |
250 out_stream->bytes_per_sample = av_num_bytes_per_sample(out_stream->dec_ctx->sample_fmt); | |
251 out_stream->bytes_per_second = out_stream->dec_ctx->channels * out_stream->dec_ctx->sample_rate * out_stream->bytes_per_sample; | |
252 | |
253 return true; | |
254 } | |
255 | |
256 static bool av_open_video_stream(AVFormatContext *format_ctx, AVVideoStream *out_stream) | |
257 { | |
258 if (!av_open_stream(format_ctx, AVMEDIA_TYPE_VIDEO, out_stream)) | |
259 return Error("Video stream not found"), false; | |
260 | |
261 out_stream->frames_per_second = (double)out_stream->dec_ctx->time_base.den / (double)out_stream->dec_ctx->time_base.num; | |
262 return true; | |
263 } | |
264 | |
265 | |
266 | |
267 void InterleaveAudioData(MemoryStream *stream, AVSampleFormat src_format, int num_channels, int num_samples, uint8_t **channels) | |
268 { | |
269 unsigned int bytes_per_sample; | |
270 switch (src_format) | |
271 { | |
272 case AV_SAMPLE_FMT_U8: | |
273 case AV_SAMPLE_FMT_U8P: | |
274 __debugbreak(); | |
275 | |
276 case AV_SAMPLE_FMT_S16: | |
277 bytes_per_sample = sizeof(__int16); | |
278 stream->Write(channels[0], num_channels * num_samples * bytes_per_sample); | |
279 break; | |
280 | |
281 case AV_SAMPLE_FMT_S16P: | |
282 { | |
283 bytes_per_sample = sizeof(__int16); | |
284 for (int i = 0; i < num_samples; ++i) | |
285 for (int j = 0; j < num_channels; ++j) | |
286 stream->Write(channels[j] + i * bytes_per_sample, bytes_per_sample); | |
287 } | |
288 break; | |
289 | |
290 case AV_SAMPLE_FMT_FLT: | |
291 { | |
292 SwrContext *converter = swr_alloc(); | |
293 av_opt_set_int(converter, "in_channel_layout", av_get_default_channel_layout(2), 0); | |
294 //av_opt_set_int(converter, "in_sample_rate", sample_ra, 0); | |
295 av_opt_set_sample_fmt(converter, "in_sample_fmt", AV_SAMPLE_FMT_FLT, 0); | |
296 | |
297 av_opt_set_int(converter, "out_channel_layout", av_get_default_channel_layout(2), 0); | |
298 //av_opt_set_int(converter, "out_sample_rate", dst_sample_rate, 0); | |
299 av_opt_set_sample_fmt(converter, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); | |
300 | |
301 if (swr_init(converter) < 0) | |
302 { | |
303 __debugbreak(); | |
304 swr_free(&converter); | |
305 return; | |
306 } | |
307 | |
308 uint8_t **dst_channels; | |
309 int dst_linesize[8]; | |
310 //int dst_nb_channels = av_get_channel_layout_nb_channels(dst_channel_layout); | |
311 if (av_samples_alloc_array_and_samples(&dst_channels, dst_linesize, 2, num_channels * num_samples, AV_SAMPLE_FMT_S16, 0) < 0) | |
312 { | |
313 __debugbreak(); | |
314 swr_free(&converter); | |
315 return; | |
316 } | |
317 | |
318 if (swr_convert(converter, dst_channels, num_channels * num_samples, (const uint8_t **)channels, num_channels * num_samples) >= 0) | |
319 stream->Write(dst_channels[0], num_channels * num_samples * sizeof(__int16)); | |
320 else | |
321 __debugbreak(); | |
322 | |
323 av_free(dst_channels[0]); | |
324 swr_free(&converter); | |
325 } | |
326 break; | |
327 | |
328 default: | |
329 __debugbreak(); | |
330 //if (Resample(next_frame->avframe, next_frame->avframe->channel_layout, next_frame->avframe->sample_rate, | |
331 // av_get_default_channel_layout(2), next_frame->avframe->sample_rate, AV_SAMPLE_FMT_S16P, resampled_data)) | |
332 } | |
333 } | |
334 | |
335 | |
336 | |
337 bool DecodeAudioFrame(AVCodecContext *dec_ctx, AVPacket *avpacket, AVFrame *avframe, MemoryStream *out_audio_data, int *out_num_audio_samples) | |
338 { | |
339 volatile int decoded = false; | |
340 do | |
341 { | |
342 if (avcodec_decode_audio4(dec_ctx, avframe, (int *)&decoded, avpacket) < 0) | |
343 { | |
344 log("Cannot decode audio frame\n"); | |
345 return false; | |
346 } | |
347 | |
348 if (!decoded) | |
349 log("Cannot decode audio frame in one piece\n"); | |
350 } while (!decoded); | |
351 | |
352 switch (dec_ctx->codec_id) | |
353 { | |
354 case AV_CODEC_ID_BINKAUDIO_RDFT: | |
355 {//pts samples dpts | |
356 // 0 960 | |
357 //17280 960 17280 18x960 | |
358 //18240 960 960 1x960 | |
359 //20160 960 1920 2x960 | |
360 //21120 960 960 1x960 | |
361 //23040 960 1920 2x960 | |
362 static int bink_next_pts = 0; | |
363 | |
364 // there's a gap in the sound - fill empty samples in | |
365 if (bink_next_pts < avpacket->pts) | |
366 { | |
367 short silence[1024]; | |
368 memset(silence, 0, sizeof(silence)); | |
369 | |
370 int samples_to_fill = /*dec_ctx->channels * */(avpacket->pts - bink_next_pts); | |
371 while (samples_to_fill > 0) | |
372 { | |
373 int samples_to_fill_this_step = samples_to_fill >= 1024 ? 1024 : samples_to_fill; | |
374 out_audio_data->Write(silence, samples_to_fill_this_step * sizeof(short)); | |
375 | |
376 samples_to_fill -= samples_to_fill_this_step; | |
377 } | |
378 } | |
379 | |
380 bink_next_pts = avpacket->pts + /*dec_ctx->channels * */avframe->nb_samples; | |
381 } | |
382 break; | |
383 /* | |
384 case AV_CODEC_ID_SMACKAUDIO: | |
385 { | |
386 static int smack_debug_next_audio_time = 0; | |
387 if (smack_debug_next_audio_time != packet->pts) | |
388 { | |
389 Error("There's a gap in the sound before frame %u\n", num_audio_frames); | |
390 __debugbreak(); // there's a gap in the sound | |
391 } | |
392 | |
393 int num_actual_data_channels = 0; | |
394 switch (dec_ctx->sample_fmt) | |
395 { | |
396 case AV_SAMPLE_FMT_U8: | |
397 case AV_SAMPLE_FMT_S16: | |
398 case AV_SAMPLE_FMT_S32: | |
399 case AV_SAMPLE_FMT_FLT: | |
400 case AV_SAMPLE_FMT_DBL: | |
401 num_actual_data_channels = 1; | |
402 break; | |
403 | |
404 case AV_SAMPLE_FMT_U8P: | |
405 case AV_SAMPLE_FMT_S16P: | |
406 case AV_SAMPLE_FMT_S32P: | |
407 case AV_SAMPLE_FMT_FLTP: | |
408 case AV_SAMPLE_FMT_DBLP: | |
409 num_actual_data_channels = dec_ctx->channels; | |
410 break; | |
411 | |
412 default: | |
413 case AV_SAMPLE_FMT_NONE: | |
414 case AV_SAMPLE_FMT_NB: | |
415 __debugbreak(); | |
416 } | |
417 | |
418 smack_debug_next_audio_time += dec_ctx->channels * frame->nb_samples * bytes_per_sample; | |
419 Assert(frame->avframe->linesize[0] == audio.dec_ctx->channels * frame->avframe->nb_samples * audio.bytes_per_sample / num_actual_data_channels, | |
420 "Smack audio size mismatch in frame %u in %s\n", audio_num_read_frames, movie_filename); | |
421 | |
422 frame->play_time = (double)frame->avpacket->pts / (double)audio.bytes_per_second; | |
423 } | |
424 break; | |
425 | |
426 case AV_CODEC_ID_MP3: | |
427 { | |
428 static int mp3_samples_decoded_so_far = 0; | |
429 static int mp3_prev_samples_count = frame->avframe->nb_samples; // mp3 seems to always feed same amount of samples | |
430 frame->play_time = (double)mp3_samples_decoded_so_far / (double)audio.dec_ctx->sample_rate; | |
431 | |
432 mp3_samples_decoded_so_far += frame->avframe->nb_samples; | |
433 Assert(mp3_prev_samples_count == frame->avframe->nb_samples, | |
434 "MP3 audio have variable sample count in frame %u in %s\n", audio_num_read_frames, movie_filename); | |
435 } | |
436 break; | |
437 | |
438 default: | |
439 { | |
440 __debugbreak(); | |
441 double samples_per_second = (double)audio.dec_ctx->time_base.den / (double)audio.dec_ctx->time_base.num; | |
442 double play_length = frame->avframe->nb_samples / samples_per_second; | |
443 frame->play_time = (double)frame->avpacket->pts / samples_per_second; | |
444 } | |
445 break;*/ | |
446 } | |
447 | |
448 if (!avframe->channel_layout) | |
449 { | |
450 log("Audio channel layout not specified, rolling back to default\n"); | |
451 avframe->channel_layout = av_get_default_channel_layout(dec_ctx->channels); | |
452 } | |
453 | |
454 *out_num_audio_samples = dec_ctx->channels * avframe->nb_samples; | |
455 InterleaveAudioData(out_audio_data, dec_ctx->sample_fmt, | |
456 dec_ctx->channels, avframe->nb_samples, avframe->data); | |
457 return true; | |
458 } | |
459 | |
460 | |
461 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) | |
462 { | |
463 out_audio_stream->Reset(); | |
464 | |
465 AVFrame *frame = avcodec_alloc_frame(); | |
466 AVPacket *packet = new AVPacket; | |
467 av_init_packet(packet); | |
468 | |
469 int num_audio_frames = 0; | |
470 int num_audio_samples = 0; | |
471 while (av_read_frame(format_ctx, packet) >= 0) | |
472 { | |
473 if (packet->stream_index != audio_stream_idx) | |
474 { | |
475 //log("Suspicious stream id %u in %s", packet->stream_index, filenamea); | |
476 continue; | |
477 } | |
478 | |
479 int num_samples_decoded; | |
480 DecodeAudioFrame(dec_ctx, packet, frame, out_audio_stream, &num_samples_decoded); | |
481 | |
482 num_audio_samples += num_samples_decoded; | |
483 num_audio_frames++; | |
484 } | |
485 *out_num_audio_frames = num_audio_frames; | |
486 *out_num_audio_samples = num_audio_samples; | |
487 | |
488 avcodec_free_frame(&frame); | |
489 delete packet; | |
490 | |
491 return true; | |
492 } | |
493 | |
494 | |
495 class Track: public Media::ITrack | |
496 { | |
497 public: | |
498 inline Track() | |
499 { | |
500 this->format_ctx = nullptr; | |
501 this->audio_num_samples = 0; | |
502 } | |
503 | |
504 void Release() | |
505 { | |
506 ReleaseAvcodec(); | |
507 } | |
508 | |
509 void ReleaseAvcodec() | |
510 { | |
511 audio.Release(); | |
512 if (format_ctx) | |
513 { | |
514 av_close_input_file(format_ctx); | |
515 format_ctx = nullptr; | |
516 } | |
517 } | |
518 | |
519 bool Load(const wchar_t *filename) | |
520 { | |
521 char filenamea[1024]; | |
522 sprintf(filenamea, "%S", filename); | |
523 | |
524 if (avformat_open_input(&format_ctx, filenamea, nullptr, nullptr) >= 0) | |
525 { | |
526 if (avformat_find_stream_info(format_ctx, nullptr) >= 0) | |
527 { | |
528 av_dump_format(format_ctx, 0, filenamea, 0); | |
529 | |
530 if (!av_open_audio_stream(format_ctx, &audio)) | |
531 { | |
532 Error("Cannot open strack: %s", filenamea); | |
533 return Release(), false; | |
534 } | |
535 | |
536 MemoryStream audio_plain_data; | |
537 int num_audio_frames; | |
538 int num_audio_samples; | |
539 if (LoadAudioTrack(format_ctx, audio.dec_ctx, audio.stream_idx, &audio_plain_data, &num_audio_frames, &num_audio_samples)) | |
540 { | |
541 /*#ifdef _DEBUG | |
542 char debug_filename[1024]; | |
543 sprintf(debug_filename, "%s.wav", filenamea); | |
544 FILE *wav = fopen(debug_filename, "w+b"); | |
545 | |
546 extern void write_wav_header(FILE *wav, int channel_count = 2, int sample_rate = 22050, int bytes_per_sample = 2); | |
547 write_wav_header(wav, audio.dec_ctx->channels, audio.dec_ctx->sample_rate, audio.bytes_per_sample); | |
548 | |
549 fwrite(audio_plain_data.Ptr(), audio_plain_data.Current(), 1, wav); | |
550 | |
551 extern void fix_wav_header(FILE *wav, int wav_bytes_in_stream); | |
552 fix_wav_header(wav, audio_plain_data.Current()); | |
553 #endif*/ | |
554 | |
555 device_buffer = provider->CreateTrack16(audio.dec_ctx->channels, audio.dec_ctx->sample_rate, 2, num_audio_samples, audio_plain_data.Ptr()); | |
556 | |
557 ReleaseAvcodec(); | |
558 return true; | |
559 } | |
560 } | |
561 Release(); | |
562 } | |
563 return false; | |
564 } | |
565 | |
566 virtual void Play(bool loop) | |
567 { | |
568 provider->PlayTrack16(device_buffer, loop); | |
569 } | |
570 | |
571 | |
572 protected: | |
573 AVFormatContext *format_ctx; | |
574 AVAudioStream audio; | |
575 int audio_num_samples; | |
576 | |
577 OpenALSoundProvider::TrackBuffer *device_buffer; | |
578 }; | |
579 | |
580 | |
581 | |
582 class Movie: public Media::IMovie | |
583 { | |
584 public: | |
585 inline Movie() | |
586 { | |
587 this->movie_filename[0] = 0; | |
588 this->width = 0; | |
589 this->height = 0; | |
590 this->format_ctx = nullptr; | |
591 this->end_of_file = false; | |
592 this->playback_time = 0.0; | |
593 | |
594 this->num_audio_frames = 0; | |
595 this->num_audio_samples = 0; | |
596 | |
597 this->last_resampled_frame_num = -1; | |
598 memset(last_resampled_frame_data, 0, sizeof(last_resampled_frame_data)); | |
599 memset(last_resampled_frame_linesize, 0, sizeof(last_resampled_frame_linesize)); | |
600 } | |
601 | |
602 | |
603 inline void Release() | |
604 { | |
605 ReleaseAVCodec(); | |
606 } | |
607 | |
608 inline void ReleaseAVCodec() | |
609 { | |
610 audio.Release(); | |
611 video.Release(); | |
612 if (format_ctx) | |
613 { | |
614 av_close_input_file(format_ctx); | |
615 format_ctx = nullptr; | |
616 } | |
617 } | |
618 | |
619 bool Load(const wchar_t *filename, int dst_width, int dst_height, int cache_ms) | |
620 { | |
621 char filenamea[1024]; | |
622 sprintf(filenamea, "%S", filename); | |
623 sprintf(movie_filename, "%S", filename); | |
624 | |
625 width = dst_width; | |
626 height = dst_height; | |
627 if (avformat_open_input(&format_ctx, filenamea, nullptr, nullptr) >= 0) | |
628 { | |
629 if (avformat_find_stream_info(format_ctx, nullptr) >= 0) | |
630 { | |
631 av_dump_format(format_ctx, 0, filenamea, 0); | |
632 | |
633 if (!av_open_audio_stream(format_ctx, &audio)) | |
634 { | |
635 Error("Cannot open audio stream: %s", filenamea); | |
636 return Release(), false; | |
637 } | |
638 | |
639 if (!av_open_video_stream(format_ctx, &video)) | |
640 { | |
641 Error("Cannot open video stream: %s", filenamea); | |
642 return Release(), false; | |
643 } | |
644 | |
645 decoding_packet = new AVPacket; | |
646 av_init_packet(decoding_packet); | |
647 | |
648 decoding_frame = avcodec_alloc_frame(); | |
649 | |
650 audio_data_in_device = provider->CreateStreamingTrack16(audio.dec_ctx->channels, audio.dec_ctx->sample_rate, 2); | |
651 | |
652 return true; | |
653 } | |
654 } | |
655 return false; | |
656 } | |
657 | |
658 virtual void Play() | |
659 { | |
660 } | |
661 | |
662 virtual void GetNextFrame(double dt, void *dst_surface)// рисует сразу на экран | |
663 { | |
664 playback_time += dt;//изменение времени | |
665 | |
666 AVPacket *avpacket = decoding_packet; | |
667 AVFrame *avframe = decoding_frame; | |
668 avcodec_get_frame_defaults(avframe); | |
669 | |
670 int desired_frame_number = floor(playback_time * video.dec_ctx->time_base.den / video.dec_ctx->time_base.num + 0.5); | |
671 if (last_resampled_frame_num == desired_frame_number) | |
672 { | |
673 memcpy(dst_surface, last_resampled_frame_data[0], height * last_resampled_frame_linesize[0]); | |
674 return; | |
675 } | |
676 | |
677 volatile int decoded = false; | |
678 do | |
679 { | |
680 if (av_read_frame(format_ctx, avpacket) < 0) //воспроизведение завершено | |
681 { | |
682 // probably movie is finished | |
683 __debugbreak(); | |
684 } | |
685 | |
686 // audio packet - queue into playing | |
687 if (avpacket->stream_index == audio.stream_idx) | |
688 { | |
689 MemoryStream audio_data; | |
690 if (DecodeAudioFrame(audio.dec_ctx, avpacket, avframe, &audio_data, &num_audio_samples)) | |
691 provider->Stream16(audio_data_in_device, num_audio_samples, audio_data.Ptr()); | |
692 } | |
693 // video packet - decode & maybe show | |
694 else if (avpacket->stream_index == video.stream_idx) | |
695 { | |
696 do | |
697 { | |
698 if (avcodec_decode_video2(video.dec_ctx, avframe, (int *)&decoded, avpacket) < 0) | |
699 __debugbreak(); | |
700 } while (!decoded); | |
701 } | |
702 | |
703 } while (avpacket->stream_index != video.stream_idx || | |
704 avpacket->pts != desired_frame_number); | |
705 | |
706 if (decoded) | |
707 { | |
708 if (last_resampled_frame_data[0]) | |
709 av_freep(&last_resampled_frame_data[0]); | |
710 | |
711 AVPixelFormat rescaled_format = AV_PIX_FMT_RGB32; | |
712 uint8_t *rescaled_data[4] = {nullptr, nullptr, nullptr, nullptr}; | |
713 int rescaled_linesize[4] = {0, 0, 0, 0}; | |
714 if (av_image_alloc(rescaled_data, rescaled_linesize, width, height, rescaled_format, 1) >= 0) | |
715 { | |
716 SwsContext *converter = sws_getContext(avframe->width, avframe->height, (AVPixelFormat)avframe->format, | |
717 width, height, rescaled_format, | |
718 SWS_BICUBIC, nullptr, nullptr, nullptr); | |
719 sws_scale(converter, avframe->data, avframe->linesize, 0, avframe->height, rescaled_data, rescaled_linesize); | |
720 sws_freeContext(converter); | |
721 | |
722 memcpy(dst_surface, rescaled_data[0], height * rescaled_linesize[0]); | |
723 | |
724 last_resampled_frame_num = desired_frame_number; | |
725 memcpy(last_resampled_frame_data, rescaled_data, sizeof(rescaled_data)); | |
726 memcpy(last_resampled_frame_linesize, rescaled_linesize, sizeof(rescaled_linesize)); | |
727 } | |
728 } | |
729 else | |
730 memset(dst_surface, 0, width * height * 4); | |
731 } | |
732 | |
733 protected: | |
734 char movie_filename[256]; | |
735 int width; | |
736 int height; | |
737 AVFormatContext *format_ctx; | |
738 double playback_time; | |
739 bool end_of_file; | |
740 | |
741 AVPacket *decoding_packet; | |
742 AVFrame *decoding_frame; | |
743 | |
744 AVAudioStream audio; | |
745 int num_audio_frames; | |
746 int num_audio_samples; | |
747 OpenALSoundProvider::StreamingTrackBuffer *audio_data_in_device; | |
748 | |
749 AVVideoStream video; | |
750 int last_resampled_frame_num; | |
751 uint8_t *last_resampled_frame_data[4]; | |
752 int last_resampled_frame_linesize[4]; | |
753 }; | |
754 | |
755 | |
756 ITrack *Player::LoadTrack(const wchar_t *filename) | |
757 { | |
758 auto track = new Track; | |
759 if (!track->Load(filename)) | |
760 { | |
761 delete track; | |
762 track = nullptr; | |
763 } | |
764 return track; | |
765 } | |
766 | |
767 | |
768 IMovie *Player::LoadMovie(const wchar_t *filename, int width, int height, int cache_ms) | |
769 { | |
770 auto movie = new Movie; | |
771 if (!movie->Load(filename, width, height, cache_ms)) | |
772 { | |
773 delete movie; | |
774 movie = nullptr; | |
775 } | |
776 return movie; | |
777 } | |
778 | |
779 | |
780 | |
781 | |
782 | |
783 | |
784 void av_logger(void *, int, const char *format, va_list args) | |
785 { | |
786 va_list va; | |
787 va_start(va, format); | |
788 char msg[256]; | |
789 vsprintf(msg, format, va); | |
790 va_end(va); | |
791 | |
792 log("av: %s", msg); | |
793 } | |
794 | |
795 Player::Player() | |
796 { | |
797 static int libavcodec_initialized = false; | |
798 | |
799 if (!libavcodec_initialized) | |
800 { | |
801 av_log_set_callback(av_logger); | |
802 avcodec_register_all(); | |
803 av_register_all(); | |
804 | |
805 libavcodec_initialized = true; | |
806 } | |
807 | |
808 if (!provider) | |
809 { | |
810 provider = new OpenALSoundProvider; | |
811 provider->Initialize(); | |
812 } | |
813 } | |
814 | |
815 Player::~Player() | |
816 { | |
817 } |