Mercurial > mm7
comparison VideoPlayer.h @ 2345:182effc4b0ee
for MultimediaPlayer
author | Ritor1 |
---|---|
date | Mon, 07 Apr 2014 19:15:13 +0600 |
parents | ddb803517a48 |
children | d57505d3c70c |
comparison
equal
deleted
inserted
replaced
2336:d6887ee81068 | 2345:182effc4b0ee |
---|---|
1 #pragma once | 1 #pragma once |
2 #include "OSWindow.h" | 2 #include "OSWindow.h" |
3 #include "Texture.h" | 3 #include "Texture.h" |
4 #include "MediaPlayer.h" | |
4 | 5 |
5 | 6 |
6 | 7 |
7 | 8 |
8 | 9 |
386 | 387 |
387 volatile int done = false; | 388 volatile int done = false; |
388 do | 389 do |
389 { | 390 { |
390 int ret; | 391 int ret; |
392 //Функция avcodec_decode_video2 осуществляет декодирование пакета в фрейм с использованием кодека, | |
393 //который мы получили раньше (codec_context). Функция устанавливает положительное значение frame_finished в случае | |
394 //если фрейм декодирован целиком (то есть один фрейм может занимать несколько пакетов и frame_finished будет | |
395 //установлен только при декодировании последнего пакета). | |
391 if ((ret = avcodec_decode_video2(dec_ctx, f, (int *)&done, p)) < 0) | 396 if ((ret = avcodec_decode_video2(dec_ctx, f, (int *)&done, p)) < 0) |
392 return ret; | 397 return ret; |
393 } while (!done); | 398 } while (!done); |
394 if (Rescale(f, width, height, AV_PIX_FMT_RGB32, rescaled_data, rescaled_linesize)) | 399 if (Rescale(f, width, height, AV_PIX_FMT_RGB32, rescaled_data, rescaled_linesize)) |
395 return 0; | 400 return 0; |
407 | 412 |
408 bool Rescale(AVFrame *frame, int dst_width, int dst_height, AVPixelFormat format, uint8_t **out_data, int *out_linesize) | 413 bool Rescale(AVFrame *frame, int dst_width, int dst_height, AVPixelFormat format, uint8_t **out_data, int *out_linesize) |
409 { | 414 { |
410 if (av_image_alloc(out_data, out_linesize, dst_width, dst_height, format, 1) < 0) | 415 if (av_image_alloc(out_data, out_linesize, dst_width, dst_height, format, 1) < 0) |
411 return false; | 416 return false; |
412 | 417 // создание контекста для преобразования |
413 SwsContext *converter = sws_getContext(frame->width, frame->height, (AVPixelFormat)frame->format, | 418 SwsContext *converter = sws_getContext(frame->width, frame->height, (AVPixelFormat)frame->format, |
414 dst_width, dst_height, format, | 419 dst_width, dst_height, format, SWS_BICUBIC, nullptr, nullptr, nullptr); |
415 SWS_BICUBIC, nullptr, nullptr, nullptr); | 420 // преобразование кадра |
416 sws_scale(converter, frame->data, frame->linesize, 0, frame->height, out_data, out_linesize); | 421 sws_scale(converter, frame->data, frame->linesize, 0, frame->height, out_data, out_linesize); |
417 sws_freeContext(converter); | 422 sws_freeContext(converter); |
418 | 423 |
419 return true; | 424 return true; |
420 } | 425 } |
442 avcodec_get_frame_defaults(f); | 447 avcodec_get_frame_defaults(f); |
443 | 448 |
444 volatile int done = false; | 449 volatile int done = false; |
445 do | 450 do |
446 { | 451 { |
452 //Декодирование аудио-пакета осуществляется функцией avcodec_decode_audio4 | |
447 int ret; | 453 int ret; |
448 if ((ret = avcodec_decode_audio4(dec_ctx, f, (int *)&done, p)) < 0) | 454 if ((ret = avcodec_decode_audio4(dec_ctx, f, (int *)&done, p)) < 0) |
449 return ret; | 455 return ret; |
450 } while (!done); | 456 } while (!done); |
451 if (Resample(f, f->channel_layout, f->sample_rate, | 457 if (Resample(f, f->channel_layout, f->sample_rate, |
520 | 526 |
521 template<int NUM_PRECACHED_FRAMES> | 527 template<int NUM_PRECACHED_FRAMES> |
522 class MovieCached | 528 class MovieCached |
523 { | 529 { |
524 public: | 530 public: |
525 bool Stopped() { return stopped; } | 531 //bool Stopped() { return stopped; } |
526 int GetWidth() { return width; } | 532 int GetWidth() { return width; } |
527 int GetHeight() { return height; } | 533 int GetHeight() { return height; } |
528 inline ~MovieCached() | 534 inline ~MovieCached() |
529 { | 535 { |
530 Release(); | 536 Release(); |
551 ioBuffer = nullptr; | 557 ioBuffer = nullptr; |
552 format_ctx = nullptr; | 558 format_ctx = nullptr; |
553 avioContext = nullptr; | 559 avioContext = nullptr; |
554 } | 560 } |
555 | 561 |
556 bool LoadFromLOD(HANDLE h, int readFunction(void*, uint8_t*, int), int64_t seekFunction(void*, int64_t, int), int width, int height) | 562 /*bool LoadFromLOD(HANDLE h, int readFunction(void*, uint8_t*, int), int64_t seekFunction(void*, int64_t, int), int width, int height) |
557 { | 563 { |
558 if (!ioBuffer) | 564 if (!ioBuffer) |
559 ioBuffer = (unsigned char *)av_malloc(16384 + FF_INPUT_BUFFER_PADDING_SIZE); // can get av_free()ed by libav | 565 ioBuffer = (unsigned char *)av_malloc(16384 + FF_INPUT_BUFFER_PADDING_SIZE); // can get av_free()ed by libav |
560 if (!avioContext) | 566 if (!avioContext) |
561 avioContext = avio_alloc_context(ioBuffer, 16384, 0, h, &readFunction, NULL, &seekFunction); | 567 avioContext = avio_alloc_context(ioBuffer, 16384, 0, h, &readFunction, NULL, &seekFunction); |
562 if (!format_ctx) | 568 if (!format_ctx) |
563 format_ctx = avformat_alloc_context(); | 569 format_ctx = avformat_alloc_context(); |
564 format_ctx->pb = avioContext; | 570 format_ctx->pb = avioContext; |
565 return Load("dummyFilename", width, height); | 571 return Load("dummyFilename", width, height); |
566 } | 572 } */ |
567 | 573 |
568 bool Load(const char *video_filename, int width, int height) | 574 /*bool Load(const char *video_filename, int width, int height) |
569 { | 575 { |
570 this->width = width; | 576 this->width = width; |
571 this->height = height; | 577 this->height = height; |
572 | 578 // Open video file |
579 //откроем входной файл(Шаг 2) | |
580 //Функция avformat_open_input читает файловый заголовок и сохраняет информацию о найденных форматах в структуре | |
581 //AVFormatContext. Остальные аргументы могут быть установлены в NULL, в этом случае libavformat использует | |
582 //автоматическое определение параметров. | |
573 if (avformat_open_input(&format_ctx, video_filename, nullptr, nullptr) >= 0) | 583 if (avformat_open_input(&format_ctx, video_filename, nullptr, nullptr) >= 0) |
574 { | 584 { |
585 // Retrieve stream information | |
586 //Т.к. avformat_open_input читает только заголовок файла, то следующим шагом нужно получить информацию о потоках | |
587 //в файле. Это делается функцией avformat_find_stream_info.(Шаг 3) | |
575 if (avformat_find_stream_info(format_ctx, nullptr) >= 0) | 588 if (avformat_find_stream_info(format_ctx, nullptr) >= 0) |
576 { | 589 { |
590 // Dump information about file onto standard error | |
591 //После этого format_context->streams содержит все существующие потоки файла. | |
592 //Их количество равно format_context->nb_streams. | |
593 //Вывести подробную информацию о файле и обо всех потоках можно функцией av_dump_format. | |
577 av_dump_format(format_ctx, 0, video_filename, 0); | 594 av_dump_format(format_ctx, 0, video_filename, 0); |
578 | 595 |
579 video_stream_idx = OpenStream(AVMEDIA_TYPE_VIDEO, &video_stream, &video_stream_dec, &video_stream_dec_ctx); | 596 video_stream_idx = OpenStream(AVMEDIA_TYPE_VIDEO, &video_stream, &video_stream_dec, &video_stream_dec_ctx); |
580 if (video_stream_idx < 0) | 597 if (video_stream_idx < 0) |
581 return Release(), false; | 598 return Release(), false; |
588 audio_stream_idx = OpenStream(AVMEDIA_TYPE_AUDIO, &audio_stream, &audio_stream_dec, &audio_stream_dec_ctx); | 605 audio_stream_idx = OpenStream(AVMEDIA_TYPE_AUDIO, &audio_stream, &audio_stream_dec, &audio_stream_dec_ctx); |
589 if (audio_stream_idx < 0) | 606 if (audio_stream_idx < 0) |
590 return Release(), false; | 607 return Release(), false; |
591 | 608 |
592 strcpy(movie_name, video_filename); | 609 strcpy(movie_name, video_filename); |
610 //Данные из файла читаются пакетами (AVPacket) | |
593 packet = new AVPacket; | 611 packet = new AVPacket; |
594 av_init_packet(packet); | 612 av_init_packet(packet); |
595 return true; | 613 return true; |
596 } | 614 } |
597 } | 615 fprintf(stderr, "ffmpeg: Unable to find stream info\n"); |
616 return Release(), false; | |
617 } | |
618 fprintf(stderr, "ffmpeg: Unable to open input file\n"); | |
598 return Release(), false; | 619 return Release(), false; |
599 } | 620 } */ |
600 | 621 |
601 bool Release() | 622 bool Release() |
602 { | 623 { |
603 if (packet) | 624 if (packet) |
604 { | 625 { |
610 if (video_stream_idx >= 0) | 631 if (video_stream_idx >= 0) |
611 { | 632 { |
612 video_stream_idx = -1; | 633 video_stream_idx = -1; |
613 video_stream = nullptr; | 634 video_stream = nullptr; |
614 video_stream_dec = nullptr; | 635 video_stream_dec = nullptr; |
636 | |
637 // закрытие видео кодека | |
615 avcodec_close(video_stream_dec_ctx); | 638 avcodec_close(video_stream_dec_ctx); |
616 video_stream_dec_ctx = nullptr; | 639 video_stream_dec_ctx = nullptr; |
617 } | 640 } |
618 | 641 |
619 if (audio_stream_idx >= 0) | 642 if (audio_stream_idx >= 0) |
620 { | 643 { |
621 audio_stream_idx = -1; | 644 audio_stream_idx = -1; |
622 audio_stream = nullptr; | 645 audio_stream = nullptr; |
623 audio_stream_dec = nullptr; | 646 audio_stream_dec = nullptr; |
647 | |
648 // закрытие аудио кодека | |
624 avcodec_close(audio_stream_dec_ctx); | 649 avcodec_close(audio_stream_dec_ctx); |
625 | 650 |
626 } | 651 } |
627 if (avioContext) | 652 if (avioContext) |
628 { | 653 { |
636 } | 661 } |
637 return true; | 662 return true; |
638 } | 663 } |
639 | 664 |
640 | 665 |
641 int OpenStream(AVMediaType type, AVStream **out_stream, AVCodec **out_dec, AVCodecContext **out_dec_ctx) | 666 /*int OpenStream(AVMediaType type, AVStream **out_stream, AVCodec **out_dec, AVCodecContext **out_dec_ctx) |
642 { | 667 { |
643 int stream_idx = av_find_best_stream(format_ctx, type, -1, -1, nullptr, 0); | 668 int stream_idx = av_find_best_stream(format_ctx, type, -1, -1, nullptr, 0); |
644 if (stream_idx < 0) | 669 if (stream_idx < 0) |
645 return stream_idx; | 670 return stream_idx; |
646 | 671 |
647 auto stream = format_ctx->streams[stream_idx]; | 672 auto stream = format_ctx->streams[stream_idx]; |
673 //Информация о кодеке в потоке называется «контекстом кодека» (AVCodecContext). | |
674 //Используя эту информацию, мы можем найти необходимый кодек (AVCodec) и открыть его. | |
648 auto dec_ctx = stream->codec; | 675 auto dec_ctx = stream->codec; |
649 auto dec = avcodec_find_decoder(dec_ctx->codec_id); | 676 auto dec = avcodec_find_decoder(dec_ctx->codec_id); |
650 if (dec) | 677 if (dec) |
651 { | 678 { |
652 if (avcodec_open2(dec_ctx, dec, nullptr) >= 0) | 679 if (avcodec_open2(dec_ctx, dec, nullptr) >= 0) |
655 *out_dec = dec; | 682 *out_dec = dec; |
656 *out_dec_ctx = dec_ctx; | 683 *out_dec_ctx = dec_ctx; |
657 return stream_idx; | 684 return stream_idx; |
658 } | 685 } |
659 } | 686 } |
687 fprintf(stderr, "ffmpeg: Unable to open codec\n"); | |
660 return -1; | 688 return -1; |
661 } | 689 } */ |
662 | 690 |
663 MultimediaFrame::Ptr GetNextFrame() | 691 MultimediaFrame::Ptr GetNextFrame() |
664 { | 692 { |
665 packet->data = nullptr; | 693 packet->data = nullptr; |
666 packet->size = 0; | 694 packet->size = 0; |
667 | 695 |
668 volatile int got_frame = false; | 696 volatile int got_frame = false; |
697 //чтение пакетов | |
669 do | 698 do |
670 { | 699 { |
671 if (av_read_frame(format_ctx, packet) < 0) | 700 if (av_read_frame(format_ctx, packet) < 0) |
672 { | 701 { |
673 stopped = true; | 702 stopped = true; |
674 return nullptr; | 703 return nullptr; |
675 } | 704 } |
676 } while (packet->stream_index != video_stream_idx && | 705 } while (packet->stream_index != video_stream_idx && //пока пакет не пренадлежит к видеопотоку |
677 packet->stream_index != audio_stream_idx); | 706 packet->stream_index != audio_stream_idx); //и не принадлежит аудиопотоку |
678 | 707 |
679 if (packet->stream_index == video_stream_idx) | 708 if (packet->stream_index == video_stream_idx) |
680 return MultimediaFrame::Ptr(new MultimediaVideoFrame(AVMEDIA_TYPE_VIDEO, packet, video_stream_dec_ctx, width, height)); | 709 return MultimediaFrame::Ptr(new MultimediaVideoFrame(AVMEDIA_TYPE_VIDEO, packet, video_stream_dec_ctx, width, height)); |
681 else if (packet->stream_index == audio_stream_idx) | 710 else if (packet->stream_index == audio_stream_idx) |
682 return MultimediaFrame::Ptr(new MultimediaAudioFrame(AVMEDIA_TYPE_AUDIO, packet, audio_stream_dec_ctx)); | 711 return MultimediaFrame::Ptr(new MultimediaAudioFrame(AVMEDIA_TYPE_AUDIO, packet, audio_stream_dec_ctx)); |
686 | 715 |
687 | 716 |
688 char movie_name[256]; | 717 char movie_name[256]; |
689 int width; | 718 int width; |
690 int height; | 719 int height; |
691 bool stopped; | 720 //bool stopped; |
692 AVFormatContext *format_ctx; | 721 AVFormatContext *format_ctx; |
693 //AVFrame *frame; | 722 //AVFrame *frame; |
694 AVPacket *packet; | 723 AVPacket *packet; |
695 //MultimediaFrame *frames[NUM_PRECACHED_FRAMES]; | 724 //MultimediaFrame *frames[NUM_PRECACHED_FRAMES]; |
696 OpenALSoundProvider *sound_provider; | 725 OpenALSoundProvider *sound_provider; |
697 | 726 |
698 int video_stream_idx; | 727 int video_stream_idx; |
699 AVStream *video_stream; | 728 AVStream *video_stream;//содержат информацию о видео потоке |
700 AVCodec *video_stream_dec; | 729 AVCodec *video_stream_dec; |
701 AVCodecContext *video_stream_dec_ctx; | 730 AVCodecContext *video_stream_dec_ctx; |
702 | 731 |
703 int audio_stream_idx; | 732 int audio_stream_idx; |
704 AVStream *audio_stream; | 733 AVStream *audio_stream;//содержат информацию о аудио потоке |
705 AVCodec *audio_stream_dec; | 734 AVCodec *audio_stream_dec; |
706 AVCodecContext *audio_stream_dec_ctx; | 735 AVCodecContext *audio_stream_dec_ctx; |
707 unsigned char * ioBuffer; | 736 unsigned char * ioBuffer; |
708 AVIOContext *avioContext; | 737 AVIOContext *avioContext; |
709 }; | 738 }; |
710 typedef MovieCached<10> Movie; | 739 //typedef MovieCached<10> Movie; |
711 | 740 |
712 | 741 |
713 | 742 |
714 | 743 |
715 class MultimediaPlayer | 744 /*class MultimediaPlayer |
716 { | 745 { |
717 public: | 746 public: |
718 inline MultimediaPlayer() | 747 inline MultimediaPlayer() |
719 { | 748 { |
720 } | 749 } |
723 { | 752 { |
724 if (!libavcodec_initialized) | 753 if (!libavcodec_initialized) |
725 { | 754 { |
726 av_log_set_callback(Logger); | 755 av_log_set_callback(Logger); |
727 avcodec_register_all(); | 756 avcodec_register_all(); |
757 | |
758 // Register all available file formats and codecs | |
759 //инициализируем библиотеку ffmpeg(Шаг 1) | |
760 //Во время инициализации регистрируются все имеющиеся в библиотеке форматы файлов и кодеков. | |
761 //После этого они будут использоваться автоматически при открытии файлов этого формата и с этими кодеками. | |
728 av_register_all(); | 762 av_register_all(); |
729 | 763 |
730 libavcodec_initialized = true; | 764 libavcodec_initialized = true; |
731 } | 765 } |
732 | 766 |
734 sound_provider->Initialize(); | 768 sound_provider->Initialize(); |
735 | 769 |
736 return true; | 770 return true; |
737 } | 771 } |
738 | 772 |
739 Movie *LoadMovieFromLOD(HANDLE h, int readFunction(void*, uint8_t*, int), int64_t seekFunction(void*, int64_t, int), int width, int height) | 773 /*Movie *LoadMovieFromLOD(HANDLE h, int readFunction(void*, uint8_t*, int), int64_t seekFunction(void*, int64_t, int), int width, int height) |
740 { | 774 { |
741 auto movie = new Movie(sound_provider); | 775 auto movie = new Movie(sound_provider); |
742 if (movie) | 776 if (movie) |
743 { | 777 { |
744 if (movie->LoadFromLOD(h, readFunction, seekFunction, width, height)) | 778 if (movie->LoadFromLOD(h, readFunction, seekFunction, width, height)) |
756 return current_movie = movie; | 790 return current_movie = movie; |
757 } | 791 } |
758 delete movie; | 792 delete movie; |
759 } | 793 } |
760 return nullptr; | 794 return nullptr; |
761 } | 795 } */ |
762 | 796 |
763 Movie *LoadMovie(const char *filename, int width, int height) | 797 /*Movie *LoadMovie(const char *filename, int width, int height) |
764 { | 798 { |
765 auto movie = new Movie(sound_provider); | 799 auto movie = new Movie(sound_provider); |
766 if (movie) | 800 if (movie) |
767 { | 801 { |
768 if (movie->Load(filename, width, height)) | 802 if (movie->Load(filename, width, height)) |
772 return current_movie = movie; | 806 return current_movie = movie; |
773 } | 807 } |
774 delete movie; | 808 delete movie; |
775 } | 809 } |
776 return nullptr; | 810 return nullptr; |
777 } | 811 } |
778 | 812 |
779 inline char *DoFrame() | 813 inline char *DoFrame() |
780 { | 814 { |
781 if (!current_movie) | 815 if (!current_movie) |
782 return nullptr; | 816 return nullptr; |
819 | 853 |
820 protected: | 854 protected: |
821 static void Logger(void *, int, const char *format, va_list args); | 855 static void Logger(void *, int, const char *format, va_list args); |
822 | 856 |
823 OpenALSoundProvider *sound_provider; | 857 OpenALSoundProvider *sound_provider; |
824 Movie *current_movie; | 858 //Movie *current_movie; |
825 int current_movie_width; | 859 int current_movie_width; |
826 int current_movie_height; | 860 int current_movie_height; |
827 | 861 |
828 static bool libavcodec_initialized; | 862 static bool libavcodec_initialized; |
829 }; | 863 };*/ |
830 | 864 |
831 | 865 |
832 | 866 |
833 | 867 |
834 | 868 |
898 unsigned int uMovieFormat; | 932 unsigned int uMovieFormat; |
899 int uMovieFormatSwapped; | 933 int uMovieFormatSwapped; |
900 char pCurrentMovieName[64]; | 934 char pCurrentMovieName[64]; |
901 char pVideoFrameTextureFilename[32]; | 935 char pVideoFrameTextureFilename[32]; |
902 int field_104; | 936 int field_104; |
903 MultimediaPlayer *pPlayer; | 937 Media::Player *pPlayer; |
904 Movie *pMovie; | 938 Media::IMovie *pMovie; |
905 HANDLE hVidFile; | 939 HANDLE hVidFile; |
906 int uSize; | 940 int uSize; |
907 int uOffset; | 941 int uOffset; |
908 void UpdatePalette(); | 942 void UpdatePalette(); |
909 static int readFunction(void *, uint8_t *, int); | 943 static int readFunction(void *, uint8_t *, int); |
910 static int64_t seekFunction(void *, int64_t, int); | 944 static int64_t seekFunction(void *, int64_t, int); |
911 void LoadMovie(const char *); | 945 void LoadMovie(const char *); |
946 void PlayAudio(const wchar_t * pFilename); | |
947 void PlayMovie(const wchar_t * pFilename); | |
912 }; | 948 }; |
913 #pragma pack(pop) | 949 #pragma pack(pop) |
914 | 950 |
915 | 951 |
916 | 952 |